It is not real zero-copy since the data is still copied in the kernel,
but it avoids copying the data inside libiscsi as well as in the callback.
For SCSI tasks that will return data from the target, the application can now
specify application buffers for libiscsi to read the data directly into.
This is done by calling scsi_task_add_data_in_buffer(task, ...
These buffers need not be linear, you can specify different areas to read into
by calling this function several times.
See examples/iscsiclient.c for an example.
We dotn need two interfaces that only diuffer in whether they return a pointer or NULL vs an semiidentical interface that returns 0 or <0
All uses of _async() for scsi tasks should be replaced with the equivalent _task() function instead
iscsi-dd can be used to copy the content of one iscsi lun onto a different
iscsi lun of the exact same sixe.
This example illustrates how to "steal" a task structure from a callback
so we can use store it and have it remains valid after the read10 callback
has completed.
It also illustrates the async api of libiscsi for read10/write10.
Initially a number of read10 calls are made asynchronously until the
queue is full.
As each read10 completes and returns data, we issue a write10 to write
that data to the other lun.
As soon as a write10 completes, we "release" the initial read10 task corresponding to what we wrote and issue a new read10 to continue copying the next set of un-read data.
Using the async api, it should be easy to get very high performance and
throughput even from one single thread.
Update the "send scsi command" fucntion to honour
"FirstBurstLength" so that we only send this many bytes as unsolicited data.
The wait for a train of R2T from the target to clock out additional
busrts of data until the full task data has been sent to the Target.
We should now honour, and handle the case of
ImmediateData=No
InitialR2T=No
correctly for targets that are limited on receiveing data too fast.