The very first sight of iblock was iblock_emulate_sync_cache() calling submit_bio(). And I found that iblock_do_task() did the very same thing as I did to call submit_bio() at SCSI host target module.
Let's take a look at how iblock_do_task() works:
// source linux-2.6.32-279.el6
iblock_do_task()
{..
for_each_sg(task->task_sg, sg, task->task_sg_nents, i) {
...}
iblock_bio_done
{...
iblock_bio_done();
if (!atomic_dec_and_test(&ibr->ib_bio_cnt))
return;
...}
transport_allocate_data_tasks()
struct fc4_prov ft_prov = {
.prli = ft_prli,
.prlo = ft_prlo,
.recv = ft_recv,
.module = THIS_MODULE,
};
ft_init() -> fc_fc4_register_provider(FC_TYPE_FCP, &ft_prov)
ft_recv() ->
ft_recv_req() ->
ft_recv_cmd() ->
ft_send_work() ->
[transport_generic_allocate_tasks()->
transport_generic_cmd_sequencer()] ->
transport_handle_cdb_direct() ->
transport_generic_new_cmd()->
[transport_allocate_data_tasks -> list_add_tail(&task->t_list, &cmd->t_task_list)] ->
transport_execute_tasks ->
__transport_execute_tasks
__transport_execute_tasks()
{...
if (cmd->execute_task)
error = cmd->execute_task(task); // -> iblock_do_task
else
error = dev->transport->do_task(task); // -> iblock_emulate_sync_cache
}
ref: http://linux-iscsi.org/wiki/Target