From 580ef169d0edc584fcdbf72a1102a3150ef7690a Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Mon, 19 Nov 2012 18:07:32 -0800 Subject: [PATCH 01/11] zero copy change iscsiclient so we can use it as a test tool --- examples/iscsiclient.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/examples/iscsiclient.c b/examples/iscsiclient.c index a627716..d1dc897 100644 --- a/examples/iscsiclient.c +++ b/examples/iscsiclient.c @@ -32,7 +32,7 @@ */ /* This is the host/port we connect to.*/ -#define TARGET "10.1.1.116:3260" +#define TARGET "127.0.0.1:3260" #if defined(WIN32) #include @@ -124,8 +124,10 @@ void write10_cb(struct iscsi_context *iscsi _U_, int status, void *command_data, void read10_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) { + struct client_state *clnt = (struct client_state *)private_data; struct scsi_task *task = command_data; int i; + unsigned char wb[512]; if (status == SCSI_STATUS_CHECK_CONDITION) { printf("Read10 failed with sense key:%d ascq:%04x\n", task->sense.key, task->sense.ascq); @@ -142,7 +144,9 @@ void read10_cb(struct iscsi_context *iscsi, int status, void *command_data, void break; } printf("...\n"); + scsi_free_scsi_task(task); +#if 0 printf("Finished, wont try to write data since that will likely destroy your LUN :-(\n"); printf("Send NOP-OUT\n"); if (iscsi_nop_out_async(iscsi, nop_out_cb, (unsigned char *)"Ping!", 6, private_data) != 0) { @@ -150,13 +154,19 @@ void read10_cb(struct iscsi_context *iscsi, int status, void *command_data, void scsi_free_scsi_task(task); exit(10); } -// printf("write the block back\n"); -// if (iscsi_write10_async(iscsi, clnt->lun, task->data.datain, task->datain.size, 0, 0, 0, clnt->block_size, write10_cb, private_data) != 0) { -// printf("failed to send write10 command\n"); -// scsi_free_scsi_task(task); -// exit(10); -// } - scsi_free_scsi_task(task); +#else + printf("write the block\n"); + for (i = 0;i < 512; i++) { + wb[i] = i; + } + task = iscsi_write10_task(iscsi, clnt->lun, 0, wb, 512, 512, + 0, 0, 0, 0, 0, + write10_cb, private_data); + if (task == NULL) { + printf("failed to send write10 command\n"); + exit(10); + } +#endif } void read6_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) From ccf81c74a77eb8dbe0e952adc45d2d39b0a599d9 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Sun, 25 Nov 2012 14:11:59 -0800 Subject: [PATCH 02/11] make scsi_iovector_add() static --- lib/scsi-lowlevel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scsi-lowlevel.c b/lib/scsi-lowlevel.c index 04febce..0f2e5f3 100644 --- a/lib/scsi-lowlevel.c +++ b/lib/scsi-lowlevel.c @@ -2560,7 +2560,7 @@ scsi_task_set_iov_in(struct scsi_task *task, struct scsi_iovec *iov, int niov) #define IOVECTOR_INITAL_ALLOC (16) -int +static int scsi_iovector_add(struct scsi_task *task, struct scsi_iovector *iovector, int len, unsigned char *buf) { if (len < 0) { From beed0809a511313f0dca42c1a8ac11b33c7d62a4 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Sun, 25 Nov 2012 14:12:33 -0800 Subject: [PATCH 03/11] Fix indentation --- include/scsi-lowlevel.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/scsi-lowlevel.h b/include/scsi-lowlevel.h index 109694c..c2701fe 100644 --- a/include/scsi-lowlevel.h +++ b/include/scsi-lowlevel.h @@ -205,10 +205,10 @@ struct scsi_iovec { }; struct scsi_iovector { - struct scsi_iovec *iov; - int niov; - int nalloc; - size_t size; + struct scsi_iovec *iov; + int niov; + int nalloc; + size_t size; size_t offset; int consumed; }; From 3ac9fdcbffe2f2489c748c7fc6ceaa19c6058623 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Sun, 25 Nov 2012 18:17:51 -0800 Subject: [PATCH 04/11] Change iscsi_scsi_command_async() to use iovectors for writes. Change iscsi_scsi_command_async() to write data-out using iovectors attached to the scsi task structure instead of copying the data into the buffer holding the header. Still allow passing the data via an argument to the funtcion so that the ABI does not change but then just conver the data to an iovector. Update the write_to_socket functions to know about the iovectors and write them as part of the pdu. Convert write10_task to use iovectors. This will allow 'zero-copy' writes through libiscsi. However, as 'zero-copy writes does mean that we do more send() calls into the kernel this may degrade performance for very small i/o. A scsi write will not take at least 2 send() calls. One send call for the iscsi header structure and a second send call for the payload data. This will be more expensive than the old memcpy() of payload data plus one send() call since the send() will be a lot more expensive than memcpy() of a small amount of data. --- include/iscsi-private.h | 9 ++- include/scsi-lowlevel.h | 3 + lib/iscsi-command.c | 134 +++++++++++++++++++--------------------- lib/socket.c | 66 +++++++++++++++----- 4 files changed, 121 insertions(+), 91 deletions(-) diff --git a/include/iscsi-private.h b/include/iscsi-private.h index 48b757a..1a5d36e 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -211,7 +211,11 @@ struct iscsi_pdu { void *private_data; int written; - struct iscsi_data outdata; /* Header and Immediate Data */ + + struct iscsi_data outdata; /* Header for PDU to send */ + uint32_t out_offset; /* Offset into data-out iovector */ + uint32_t out_len; /* Amount of data to sent */ + struct iscsi_data indata; struct iscsi_data nidata; /* Non-Immediate Data */ @@ -296,7 +300,8 @@ void iscsi_set_error(struct iscsi_context *iscsi, const char *error_string, ...) __attribute__((format(printf, 2, 3))); unsigned char *iscsi_get_user_in_buffer(struct iscsi_context *iscsi, struct iscsi_in_pdu *in, uint32_t pos, ssize_t *count); -unsigned char *scsi_task_get_data_in_buffer(struct scsi_task *task, uint32_t pos, ssize_t *count); +unsigned char *iscsi_get_user_out_buffer(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, uint32_t pos, ssize_t *count); + inline void* iscsi_malloc(struct iscsi_context *iscsi, size_t size); inline void* iscsi_zmalloc(struct iscsi_context *iscsi, size_t size); diff --git a/include/scsi-lowlevel.h b/include/scsi-lowlevel.h index c2701fe..beca19d 100644 --- a/include/scsi-lowlevel.h +++ b/include/scsi-lowlevel.h @@ -690,6 +690,9 @@ EXTERN int scsi_datain_getfullsize(struct scsi_task *task); EXTERN void *scsi_datain_unmarshall(struct scsi_task *task); EXTERN void *scsi_cdb_unmarshall(struct scsi_task *task, enum scsi_opcode opcode); +unsigned char *scsi_task_get_data_in_buffer(struct scsi_task *task, uint32_t pos, ssize_t *count); +unsigned char *scsi_task_get_data_out_buffer(struct scsi_task *task, uint32_t pos, ssize_t *count); + EXTERN struct scsi_task *scsi_cdb_read6(uint32_t lba, uint32_t xferlen, int blocksize); EXTERN struct scsi_task *scsi_cdb_read10(uint32_t lba, uint32_t xferlen, int blocksize, int rdprotect, int dpo, int fua, int fua_nv, int group_number); EXTERN struct scsi_task *scsi_cdb_read12(uint32_t lba, uint32_t xferlen, int blocksize, int rdprotect, int dpo, int fua, int fua_nv, int group_number); diff --git a/lib/iscsi-command.c b/lib/iscsi-command.c index 7e6781a..3364f15 100644 --- a/lib/iscsi-command.c +++ b/lib/iscsi-command.c @@ -74,7 +74,7 @@ iscsi_scsi_response_cb(struct iscsi_context *iscsi, int status, static int iscsi_send_data_out(struct iscsi_context *iscsi, struct iscsi_pdu *cmd_pdu, - uint32_t ttt, uint32_t offset, uint32_t tot_len) + uint32_t ttt, uint32_t offset, uint32_t tot_len) { while (tot_len > 0) { uint32_t len = tot_len; @@ -85,11 +85,10 @@ iscsi_send_data_out(struct iscsi_context *iscsi, struct iscsi_pdu *cmd_pdu, len = iscsi->target_max_recv_data_segment_length; } - pdu = iscsi_allocate_pdu_with_itt_flags_size(iscsi, ISCSI_PDU_DATA_OUT, + pdu = iscsi_allocate_pdu_with_itt_flags(iscsi, ISCSI_PDU_DATA_OUT, ISCSI_PDU_NO_PDU, cmd_pdu->itt, - ISCSI_PDU_DELETE_WHEN_SENT|ISCSI_PDU_NO_CALLBACK, - len); + ISCSI_PDU_DELETE_WHEN_SENT|ISCSI_PDU_NO_CALLBACK); if (pdu == NULL) { iscsi_set_error(iscsi, "Out-of-memory, Failed to allocate " "scsi data out pdu."); @@ -126,18 +125,11 @@ iscsi_send_data_out(struct iscsi_context *iscsi, struct iscsi_pdu *cmd_pdu, /* buffer offset */ iscsi_pdu_set_bufferoffset(pdu, offset); - if (iscsi_pdu_add_data(iscsi, pdu, cmd_pdu->nidata.data + offset, len) - != 0) { - iscsi_set_error(iscsi, "Out-of-memory: Failed to " - "add outdata to the pdu."); - SLIST_REMOVE(&iscsi->outqueue, cmd_pdu); - SLIST_REMOVE(&iscsi->waitpdu, cmd_pdu); - cmd_pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, - cmd_pdu->private_data); - iscsi_free_pdu(iscsi, cmd_pdu); - iscsi_free_pdu(iscsi, pdu); - return -1; - } + pdu->out_offset = offset; + pdu->out_len = len; + + /* update data segment length */ + scsi_set_uint32(&pdu->outdata.data[4], pdu->out_len); pdu->callback = cmd_pdu->callback; pdu->private_data = cmd_pdu->private_data; @@ -160,21 +152,19 @@ iscsi_send_data_out(struct iscsi_context *iscsi, struct iscsi_pdu *cmd_pdu, return 0; } +/* Using 'struct iscsi_data *d' for data-out is depreciated. + * Instead the task should have a data-out iovector attached to it. + * See iscsi_write10_task for an example. + */ int iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun, - struct scsi_task *task, iscsi_command_cb cb, - struct iscsi_data *d, void *private_data) + struct scsi_task *task, iscsi_command_cb cb, + struct iscsi_data *d, void *private_data) { struct iscsi_pdu *pdu; struct iscsi_scsi_cbdata *scsi_cbdata; - struct iscsi_data data; - uint32_t offset = 0; - int flags; - data.data = (d != NULL) ? d->data : NULL; - data.size = (d != NULL) ? d->size : 0; - if (iscsi->session_type != ISCSI_SESSION_NORMAL) { iscsi_set_error(iscsi, "Trying to send command on " "discovery session."); @@ -187,6 +177,21 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun, return -1; } + /* Convert old-style callers to the new 'iovector assigned to the task structure' + * model. + */ + if (d != NULL && d->data != NULL) { + struct scsi_iovec *iov; + + iov = scsi_malloc(task, sizeof(struct scsi_iovec)); + if (iov == NULL) { + return -1; + } + iov->iov_base = d->data; + iov->iov_len = d->size; + scsi_task_set_iov_out(task, iov, 1); + } + scsi_cbdata = iscsi_zmalloc(iscsi, sizeof(struct iscsi_scsi_cbdata)); if (scsi_cbdata == NULL) { iscsi_set_error(iscsi, "Out-of-memory: failed to allocate " @@ -200,8 +205,8 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun, scsi_set_task_private_ptr(task, scsi_cbdata); - pdu = iscsi_allocate_pdu_size(iscsi, ISCSI_PDU_SCSI_REQUEST, - ISCSI_PDU_SCSI_RESPONSE, data.size); + pdu = iscsi_allocate_pdu(iscsi, ISCSI_PDU_SCSI_REQUEST, + ISCSI_PDU_SCSI_RESPONSE); if (pdu == NULL) { iscsi_set_error(iscsi, "Out-of-memory, Failed to allocate " "scsi pdu."); @@ -220,51 +225,21 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun, break; case SCSI_XFER_WRITE: flags |= ISCSI_PDU_SCSI_WRITE; - if (data.size == 0) { - iscsi_set_error(iscsi, "DATA-OUT command but data " - "== NULL."); - iscsi_free_pdu(iscsi, pdu); - return -1; - } - if (data.size != task->expxferlen) { - iscsi_set_error(iscsi, "Data size:%d is not same as " - "expected data transfer " - "length:%d.", data.size, - task->expxferlen); - iscsi_free_pdu(iscsi, pdu); - return -1; - } - - /* Assume all data is non-immediate data */ - pdu->nidata.data = data.data; - pdu->nidata.size = data.size; /* Are we allowed to send immediate data ? */ if (iscsi->use_immediate_data == ISCSI_IMMEDIATE_DATA_YES) { - uint32_t len = data.size; + uint32_t len = task->expxferlen; if (len > iscsi->first_burst_length) { len = iscsi->first_burst_length; } - if (iscsi_pdu_add_data(iscsi, pdu, data.data, len) - != 0) { - iscsi_set_error(iscsi, "Out-of-memory: Failed to " - "add outdata to the pdu."); - iscsi_free_pdu(iscsi, pdu); - return -1; - } - offset = len; + pdu->out_offset = 0; + pdu->out_len = len; - if (len == (uint32_t)data.size) { - /* We managed to send it all as immediate data, so there is no non-immediate data left */ - pdu->nidata.data = NULL; - pdu->nidata.size = 0; - - } - } - - if (pdu->nidata.size > 0 && iscsi->use_initial_r2t == ISCSI_INITIAL_R2T_NO) { + /* update data segment length */ + scsi_set_uint32(&pdu->outdata.data[4], pdu->out_len); + } else if (iscsi->use_initial_r2t == ISCSI_INITIAL_R2T_NO) { /* We have more data to send, and we are allowed to send * unsolicited data, so dont flag this PDU as final. */ @@ -303,13 +278,14 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun, } /* Can we send some unsolicited data ? */ - if (pdu->nidata.size != 0 && iscsi->use_initial_r2t == ISCSI_INITIAL_R2T_NO && iscsi->use_immediate_data == ISCSI_IMMEDIATE_DATA_NO) { - uint32_t len = pdu->nidata.size - offset; + if (pdu->out_len != 0 && iscsi->use_initial_r2t == ISCSI_INITIAL_R2T_NO && iscsi->use_immediate_data == ISCSI_IMMEDIATE_DATA_NO) { + uint32_t len = task->expxferlen - pdu->out_len; if (len > iscsi->first_burst_length) { len = iscsi->first_burst_length; } - iscsi_send_data_out(iscsi, pdu, 0xffffffff, offset, len); + iscsi_send_data_out(iscsi, pdu, 0xffffffff, + pdu->out_offset, len); } /* remember cmdsn and itt so we can use task management */ @@ -320,7 +296,6 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun, return 0; } - int iscsi_process_scsi_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, struct iscsi_in_pdu *in) @@ -804,7 +779,6 @@ iscsi_write10_task(struct iscsi_context *iscsi, int lun, uint32_t lba, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; - struct iscsi_data outdata; if (datalen % blocksize != 0) { iscsi_set_error(iscsi, "Datalen:%d is not a multiple of the " @@ -819,16 +793,25 @@ iscsi_write10_task(struct iscsi_context *iscsi, int lun, uint32_t lba, "write10 cdb."); return NULL; } + if (data != NULL) { + struct scsi_iovec *iov; - outdata.data = data; - outdata.size = datalen; + iov = scsi_malloc(task, sizeof(struct scsi_iovec)); + if (iov == NULL) { + scsi_free_scsi_task(task); + return NULL; + } + iov->iov_base = data; + iov->iov_len = datalen; + scsi_task_set_iov_out(task, iov, 1); + } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, &outdata, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } - + return task; } @@ -1641,3 +1624,10 @@ iscsi_scsi_cancel_all_tasks(struct iscsi_context *iscsi) iscsi_free_pdu(iscsi, pdu); } } + +unsigned char * +iscsi_get_user_out_buffer(struct iscsi_context *iscsi _U_, struct iscsi_pdu *pdu, uint32_t pos, ssize_t *count) +{ + return scsi_task_get_data_out_buffer(pdu->scsi_cbdata->task, pos, count); +} + diff --git a/lib/socket.c b/lib/socket.c index ebb6fed..ba1e254 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -427,41 +427,73 @@ static int iscsi_write_to_socket(struct iscsi_context *iscsi) { ssize_t count; + struct iscsi_pdu *pdu; if (iscsi->fd == -1) { iscsi_set_error(iscsi, "trying to write but not connected"); return -1; } - while (iscsi->outqueue) { + while ((pdu = iscsi->outqueue) != NULL) { ssize_t total; - if (iscsi->outqueue->cmdsn > iscsi->maxcmdsn) { + if (pdu->cmdsn > iscsi->maxcmdsn) { /* stop sending. maxcmdsn is reached */ return 0; } - total = iscsi->outqueue->outdata.size; + total = pdu->outdata.size; total = (total + 3) & 0xfffffffc; - count = send(iscsi->fd, - iscsi->outqueue->outdata.data - + iscsi->outqueue->written, - total - iscsi->outqueue->written, - 0); - if (count == -1) { - if (errno == EAGAIN || errno == EWOULDBLOCK) { - return 0; + /* Write header and any immediate data */ + if (pdu->written < total) { + count = send(iscsi->fd, + pdu->outdata.data + pdu->written, + total - pdu->written, + 0); + if (count == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + return 0; + } + iscsi_set_error(iscsi, "Error when writing to " + "socket :%d", errno); + return -1; } - iscsi_set_error(iscsi, "Error when writing to " - "socket :%d", errno); - return -1; + pdu->written += count; + } + /* if we havent written the full header yet. */ + if (pdu->written != total) { + return 0; } - iscsi->outqueue->written += count; - if (iscsi->outqueue->written == total) { - struct iscsi_pdu *pdu = iscsi->outqueue; + /* Write any iovectors that might have been passed to us */ + while (pdu->out_len > 0) { + unsigned char *buf; + count = pdu->out_len; + buf = iscsi_get_user_out_buffer(iscsi, pdu, pdu->out_offset, &count); + if (buf == NULL) { + iscsi_set_error(iscsi, "Can't find iovector data for DATA-OUT"); + return -1; + } + + count = send(iscsi->fd, + buf, + count, + 0); + if (count == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + return 0; + } + iscsi_set_error(iscsi, "Error when writing to " + "socket :%d", errno); + return -1; + } + pdu->out_offset += count; + pdu->out_len -= count; + } + + if (pdu->written == total) { SLIST_REMOVE(&iscsi->outqueue, pdu); if (pdu->flags & ISCSI_PDU_DELETE_WHEN_SENT) { iscsi_free_pdu(iscsi, pdu); From e86703b3aac9350830aa3d2dc63fc0816906a734 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Sun, 25 Nov 2012 18:45:36 -0800 Subject: [PATCH 05/11] Convert all scsi task functions to use iovectors. --- lib/iscsi-command.c | 340 ++++++++++++++++++++++++++++---------------- 1 file changed, 214 insertions(+), 126 deletions(-) diff --git a/lib/iscsi-command.c b/lib/iscsi-command.c index 3364f15..c34d901 100644 --- a/lib/iscsi-command.c +++ b/lib/iscsi-command.c @@ -530,8 +530,8 @@ iscsi_testunitready_task(struct iscsi_context *iscsi, int lun, "testunitready cdb."); return NULL; } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -559,8 +559,8 @@ iscsi_reportluns_task(struct iscsi_context *iscsi, int report_type, return NULL; } /* report luns are always sent to lun 0 */ - if (iscsi_scsi_command_async(iscsi, 0, task, cb, NULL, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, 0, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -581,8 +581,8 @@ iscsi_inquiry_task(struct iscsi_context *iscsi, int lun, int evpd, "inquiry cdb."); return NULL; } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -602,8 +602,8 @@ iscsi_readcapacity10_task(struct iscsi_context *iscsi, int lun, int lba, "readcapacity10 cdb."); return NULL; } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -623,8 +623,8 @@ iscsi_readcapacity16_task(struct iscsi_context *iscsi, int lun, "readcapacity16 cdb."); return NULL; } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -645,8 +645,8 @@ iscsi_get_lba_status_task(struct iscsi_context *iscsi, int lun, "get-lba-status cdb."); return NULL; } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -673,8 +673,8 @@ iscsi_read6_task(struct iscsi_context *iscsi, int lun, uint32_t lba, "read6 cdb."); return NULL; } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -703,8 +703,8 @@ iscsi_read10_task(struct iscsi_context *iscsi, int lun, uint32_t lba, "read10 cdb."); return NULL; } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -733,8 +733,8 @@ iscsi_read12_task(struct iscsi_context *iscsi, int lun, uint32_t lba, "read12 cdb."); return NULL; } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -763,8 +763,8 @@ iscsi_read16_task(struct iscsi_context *iscsi, int lun, uint64_t lba, "read16 cdb."); return NULL; } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -807,7 +807,7 @@ iscsi_write10_task(struct iscsi_context *iscsi, int lun, uint32_t lba, } if (iscsi_scsi_command_async(iscsi, lun, task, cb, - NULL, private_data) != 0) { + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -822,7 +822,6 @@ iscsi_write12_task(struct iscsi_context *iscsi, int lun, uint32_t lba, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; - struct iscsi_data outdata; if (datalen % blocksize != 0) { iscsi_set_error(iscsi, "Datalen:%d is not a multiple of the " @@ -837,12 +836,21 @@ iscsi_write12_task(struct iscsi_context *iscsi, int lun, uint32_t lba, "write12 cdb."); return NULL; } + if (data != NULL) { + struct scsi_iovec *iov; - outdata.data = data; - outdata.size = datalen; + iov = scsi_malloc(task, sizeof(struct scsi_iovec)); + if (iov == NULL) { + scsi_free_scsi_task(task); + return NULL; + } + iov->iov_base = data; + iov->iov_len = datalen; + scsi_task_set_iov_out(task, iov, 1); + } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, &outdata, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -857,7 +865,6 @@ iscsi_write16_task(struct iscsi_context *iscsi, int lun, uint64_t lba, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; - struct iscsi_data outdata; if (datalen % blocksize != 0) { iscsi_set_error(iscsi, "Datalen:%d is not a multiple of the " @@ -872,12 +879,21 @@ iscsi_write16_task(struct iscsi_context *iscsi, int lun, uint64_t lba, "write16 cdb."); return NULL; } + if (data != NULL) { + struct scsi_iovec *iov; - outdata.data = data; - outdata.size = datalen; + iov = scsi_malloc(task, sizeof(struct scsi_iovec)); + if (iov == NULL) { + scsi_free_scsi_task(task); + return NULL; + } + iov->iov_base = data; + iov->iov_len = datalen; + scsi_task_set_iov_out(task, iov, 1); + } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, &outdata, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -892,7 +908,6 @@ iscsi_orwrite_task(struct iscsi_context *iscsi, int lun, uint64_t lba, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; - struct iscsi_data outdata; if (datalen % blocksize != 0) { iscsi_set_error(iscsi, "Datalen:%d is not a multiple of the " @@ -907,12 +922,21 @@ iscsi_orwrite_task(struct iscsi_context *iscsi, int lun, uint64_t lba, "orwrite cdb."); return NULL; } + if (data != NULL) { + struct scsi_iovec *iov; - outdata.data = data; - outdata.size = datalen; + iov = scsi_malloc(task, sizeof(struct scsi_iovec)); + if (iov == NULL) { + scsi_free_scsi_task(task); + return NULL; + } + iov->iov_base = data; + iov->iov_len = datalen; + scsi_task_set_iov_out(task, iov, 1); + } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, &outdata, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -927,7 +951,6 @@ iscsi_compareandwrite_task(struct iscsi_context *iscsi, int lun, uint64_t lba, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; - struct iscsi_data outdata; if (datalen % blocksize != 0) { iscsi_set_error(iscsi, "Datalen:%d is not a multiple of the " @@ -942,12 +965,21 @@ iscsi_compareandwrite_task(struct iscsi_context *iscsi, int lun, uint64_t lba, "compareandwrite cdb."); return NULL; } + if (data != NULL) { + struct scsi_iovec *iov; - outdata.data = data; - outdata.size = datalen; + iov = scsi_malloc(task, sizeof(struct scsi_iovec)); + if (iov == NULL) { + scsi_free_scsi_task(task); + return NULL; + } + iov->iov_base = data; + iov->iov_len = datalen; + scsi_task_set_iov_out(task, iov, 1); + } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, &outdata, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -962,7 +994,6 @@ iscsi_writeverify10_task(struct iscsi_context *iscsi, int lun, uint32_t lba, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; - struct iscsi_data outdata; if (datalen % blocksize != 0) { iscsi_set_error(iscsi, "Datalen:%d is not a multiple of the " @@ -977,12 +1008,21 @@ iscsi_writeverify10_task(struct iscsi_context *iscsi, int lun, uint32_t lba, "writeverify10 cdb."); return NULL; } + if (data != NULL) { + struct scsi_iovec *iov; - outdata.data = data; - outdata.size = datalen; + iov = scsi_malloc(task, sizeof(struct scsi_iovec)); + if (iov == NULL) { + scsi_free_scsi_task(task); + return NULL; + } + iov->iov_base = data; + iov->iov_len = datalen; + scsi_task_set_iov_out(task, iov, 1); + } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, &outdata, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -997,7 +1037,6 @@ iscsi_writeverify12_task(struct iscsi_context *iscsi, int lun, uint32_t lba, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; - struct iscsi_data outdata; if (datalen % blocksize != 0) { iscsi_set_error(iscsi, "Datalen:%d is not a multiple of the " @@ -1012,12 +1051,21 @@ iscsi_writeverify12_task(struct iscsi_context *iscsi, int lun, uint32_t lba, "writeverify12 cdb."); return NULL; } + if (data != NULL) { + struct scsi_iovec *iov; - outdata.data = data; - outdata.size = datalen; + iov = scsi_malloc(task, sizeof(struct scsi_iovec)); + if (iov == NULL) { + scsi_free_scsi_task(task); + return NULL; + } + iov->iov_base = data; + iov->iov_len = datalen; + scsi_task_set_iov_out(task, iov, 1); + } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, &outdata, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -1032,7 +1080,6 @@ iscsi_writeverify16_task(struct iscsi_context *iscsi, int lun, uint64_t lba, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; - struct iscsi_data outdata; if (datalen % blocksize != 0) { iscsi_set_error(iscsi, "Datalen:%d is not a multiple of the " @@ -1047,12 +1094,21 @@ iscsi_writeverify16_task(struct iscsi_context *iscsi, int lun, uint64_t lba, "writeverify16 cdb."); return NULL; } + if (data != NULL) { + struct scsi_iovec *iov; - outdata.data = data; - outdata.size = datalen; + iov = scsi_malloc(task, sizeof(struct scsi_iovec)); + if (iov == NULL) { + scsi_free_scsi_task(task); + return NULL; + } + iov->iov_base = data; + iov->iov_len = datalen; + scsi_task_set_iov_out(task, iov, 1); + } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, &outdata, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -1066,7 +1122,6 @@ iscsi_verify10_task(struct iscsi_context *iscsi, int lun, unsigned char *data, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; - struct iscsi_data outdata; if (datalen % blocksize != 0) { iscsi_set_error(iscsi, "Datalen:%d is not a multiple of the " @@ -1080,13 +1135,21 @@ iscsi_verify10_task(struct iscsi_context *iscsi, int lun, unsigned char *data, "verify10 cdb."); return NULL; } + if (data != NULL) { + struct scsi_iovec *iov; - /* We only transfer data if BYTCHK is true */ - outdata.data = bytchk ? data : NULL; - outdata.size = bytchk ? datalen : 0; + iov = scsi_malloc(task, sizeof(struct scsi_iovec)); + if (iov == NULL) { + scsi_free_scsi_task(task); + return NULL; + } + iov->iov_base = data; + iov->iov_len = datalen; + scsi_task_set_iov_out(task, iov, 1); + } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, &outdata, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -1100,7 +1163,6 @@ iscsi_verify12_task(struct iscsi_context *iscsi, int lun, unsigned char *data, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; - struct iscsi_data outdata; if (datalen % blocksize != 0) { iscsi_set_error(iscsi, "Datalen:%d is not a multiple of the " @@ -1114,13 +1176,21 @@ iscsi_verify12_task(struct iscsi_context *iscsi, int lun, unsigned char *data, "verify12 cdb."); return NULL; } + if (data != NULL) { + struct scsi_iovec *iov; - /* We only transfer data if BYTCHK is true */ - outdata.data = bytchk ? data : NULL; - outdata.size = bytchk ? datalen : 0; + iov = scsi_malloc(task, sizeof(struct scsi_iovec)); + if (iov == NULL) { + scsi_free_scsi_task(task); + return NULL; + } + iov->iov_base = data; + iov->iov_len = datalen; + scsi_task_set_iov_out(task, iov, 1); + } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, &outdata, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -1134,7 +1204,6 @@ iscsi_verify16_task(struct iscsi_context *iscsi, int lun, unsigned char *data, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; - struct iscsi_data outdata; if (datalen % blocksize != 0) { iscsi_set_error(iscsi, "Datalen:%d is not a multiple of the " @@ -1148,13 +1217,21 @@ iscsi_verify16_task(struct iscsi_context *iscsi, int lun, unsigned char *data, "verify16 cdb."); return NULL; } + if (data != NULL) { + struct scsi_iovec *iov; - /* We only transfer data if BYTCHK is true */ - outdata.data = bytchk ? data : NULL; - outdata.size = bytchk ? datalen : 0; + iov = scsi_malloc(task, sizeof(struct scsi_iovec)); + if (iov == NULL) { + scsi_free_scsi_task(task); + return NULL; + } + iov->iov_base = data; + iov->iov_len = datalen; + scsi_task_set_iov_out(task, iov, 1); + } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, &outdata, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -1177,8 +1254,8 @@ iscsi_modesense6_task(struct iscsi_context *iscsi, int lun, int dbd, int pc, "modesense6 cdb."); return NULL; } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -1201,8 +1278,8 @@ iscsi_startstopunit_task(struct iscsi_context *iscsi, int lun, "startstopunit cdb."); return NULL; } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -1223,8 +1300,8 @@ iscsi_preventallow_task(struct iscsi_context *iscsi, int lun, "PreventAllowMediumRemoval cdb."); return NULL; } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -1246,8 +1323,8 @@ iscsi_synchronizecache10_task(struct iscsi_context *iscsi, int lun, int lba, "synchronizecache10 cdb."); return NULL; } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -1269,8 +1346,8 @@ iscsi_synchronizecache16_task(struct iscsi_context *iscsi, int lun, uint64_t lba "synchronizecache16 cdb."); return NULL; } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -1291,8 +1368,8 @@ iscsi_prefetch10_task(struct iscsi_context *iscsi, int lun, uint32_t lba, "prefetch10 cdb."); return NULL; } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -1313,8 +1390,8 @@ iscsi_prefetch16_task(struct iscsi_context *iscsi, int lun, uint64_t lba, "prefetch16 cdb."); return NULL; } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -1331,7 +1408,6 @@ iscsi_writesame10_task(struct iscsi_context *iscsi, int lun, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; - struct iscsi_data outdata; task = scsi_cdb_writesame10(wrprotect, anchor, unmap, pbdata, lbdata, lba, group, num_blocks); if (task == NULL) { @@ -1340,25 +1416,28 @@ iscsi_writesame10_task(struct iscsi_context *iscsi, int lun, return NULL; } - if (datalen) { - outdata.data = data; - outdata.size = datalen; - task->expxferlen = datalen; + if (data != NULL) { + struct scsi_iovec *iov; - if (iscsi_scsi_command_async(iscsi, lun, task, cb, &outdata, - private_data) != 0) { + iov = scsi_malloc(task, sizeof(struct scsi_iovec)); + if (iov == NULL) { scsi_free_scsi_task(task); return NULL; } + iov->iov_base = data; + iov->iov_len = datalen; + scsi_task_set_iov_out(task, iov, 1); + + task->expxferlen = datalen; + } else { task->expxferlen = 0; task->xfer_dir = SCSI_XFER_NONE; - - if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, - private_data) != 0) { - scsi_free_scsi_task(task); - return NULL; - } + } + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { + scsi_free_scsi_task(task); + return NULL; } return task; @@ -1373,7 +1452,6 @@ iscsi_writesame16_task(struct iscsi_context *iscsi, int lun, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; - struct iscsi_data outdata; task = scsi_cdb_writesame16(wrprotect, anchor, unmap, pbdata, lbdata, lba, group, num_blocks); if (task == NULL) { @@ -1382,25 +1460,29 @@ iscsi_writesame16_task(struct iscsi_context *iscsi, int lun, return NULL; } - if (datalen) { - outdata.data = data; - outdata.size = datalen; - task->expxferlen = datalen; + if (data != NULL) { + struct scsi_iovec *iov; - if (iscsi_scsi_command_async(iscsi, lun, task, cb, &outdata, - private_data) != 0) { + iov = scsi_malloc(task, sizeof(struct scsi_iovec)); + if (iov == NULL) { scsi_free_scsi_task(task); return NULL; } + iov->iov_base = data; + iov->iov_len = datalen; + scsi_task_set_iov_out(task, iov, 1); + + task->expxferlen = datalen; + } else { task->expxferlen = 0; task->xfer_dir = SCSI_XFER_NONE; + } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, - private_data) != 0) { - scsi_free_scsi_task(task); - return NULL; - } + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { + scsi_free_scsi_task(task); + return NULL; } return task; @@ -1412,7 +1494,7 @@ iscsi_unmap_task(struct iscsi_context *iscsi, int lun, int anchor, int group, iscsi_command_cb cb, void *private_data) { struct scsi_task *task; - struct iscsi_data outdata; + struct scsi_iovec *iov; unsigned char *data; int xferlen; int i; @@ -1441,11 +1523,17 @@ iscsi_unmap_task(struct iscsi_context *iscsi, int lun, int anchor, int group, scsi_set_uint32(&data[8 + 16 * i + 8], list[0].num); } - outdata.data = data; - outdata.size = xferlen; + iov = scsi_malloc(task, sizeof(struct scsi_iovec)); + if (iov == NULL) { + scsi_free_scsi_task(task); + return NULL; + } + iov->iov_base = data; + iov->iov_len = xferlen; + scsi_task_set_iov_out(task, iov, 1); - if (iscsi_scsi_command_async(iscsi, lun, task, cb, &outdata, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -1492,8 +1580,8 @@ iscsi_readtoc_task(struct iscsi_context *iscsi, int lun, int msf, "read TOC cdb."); return NULL; } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -1513,8 +1601,8 @@ iscsi_reserve6_task(struct iscsi_context *iscsi, int lun, "reserve6 cdb."); return NULL; } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -1534,8 +1622,8 @@ iscsi_release6_task(struct iscsi_context *iscsi, int lun, "release6 cdb."); return NULL; } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } @@ -1556,8 +1644,8 @@ iscsi_report_supported_opcodes_task(struct iscsi_context *iscsi, "Maintenance In/Read Supported Op Codes cdb."); return NULL; } - if (iscsi_scsi_command_async(iscsi, lun, task, cb, NULL, - private_data) != 0) { + if (iscsi_scsi_command_async(iscsi, lun, task, cb, + NULL, private_data) != 0) { scsi_free_scsi_task(task); return NULL; } From 718c71b7a356402b98ae08a0681de81faf103348 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Sun, 25 Nov 2012 18:47:12 -0800 Subject: [PATCH 06/11] Update iscsiclient example to use the new iovector api --- examples/iscsiclient.c | 103 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 94 insertions(+), 9 deletions(-) diff --git a/examples/iscsiclient.c b/examples/iscsiclient.c index d1dc897..caf2002 100644 --- a/examples/iscsiclient.c +++ b/examples/iscsiclient.c @@ -101,7 +101,7 @@ void nop_out_cb(struct iscsi_context *iscsi, int status, void *command_data, voi } -void write10_cb(struct iscsi_context *iscsi _U_, int status, void *command_data, void *private_data _U_) +void write10_1_cb(struct iscsi_context *iscsi _U_, int status, void *command_data, void *private_data _U_) { struct scsi_task *task = command_data; @@ -121,13 +121,56 @@ void write10_cb(struct iscsi_context *iscsi _U_, int status, void *command_data, exit(10); } - -void read10_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) +void write10_cb(struct iscsi_context *iscsi _U_, int status, void *command_data, void *private_data _U_) { struct client_state *clnt = (struct client_state *)private_data; struct scsi_task *task = command_data; int i; - unsigned char wb[512]; + static unsigned char wb[512]; + static struct scsi_iovec iov[3]; + + if (status == SCSI_STATUS_CHECK_CONDITION) { + printf("Write10 failed with sense key:%d ascq:%04x\n", task->sense.key, task->sense.ascq); + scsi_free_scsi_task(task); + exit(10); + } + if (status != SCSI_STATUS_GOOD) { + printf("Write10 failed with %s\n", iscsi_get_error(iscsi)); + scsi_free_scsi_task(task); + exit(10); + } + + printf("Write successful :%d\n", status); + scsi_free_scsi_task(task); + + printf("write the block using an iovector\n"); + for (i = 0;i < 512; i++) { + wb[i] = (511 - i) & 0xff; + } + task = iscsi_write10_task(iscsi, clnt->lun, 0, NULL, 512, 512, + 0, 0, 0, 0, 0, + write10_1_cb, private_data); + if (task == NULL) { + printf("failed to send write10 command\n"); + exit(10); + } + /* provide iovectors where to read the data. + */ + iov[0].iov_base = &wb[0]; + iov[0].iov_len = 4; + iov[1].iov_base = &wb[4]; + iov[1].iov_len = 11; + iov[2].iov_base = &wb[15]; + iov[2].iov_len = 512 - 15; + scsi_task_set_iov_out(task, &iov[0], 3); +} + +void read10_1_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) +{ + struct client_state *clnt = (struct client_state *)private_data; + struct scsi_task *task = command_data; + int i; + static unsigned char wb[512]; if (status == SCSI_STATUS_CHECK_CONDITION) { printf("Read10 failed with sense key:%d ascq:%04x\n", task->sense.key, task->sense.ascq); @@ -135,7 +178,7 @@ void read10_cb(struct iscsi_context *iscsi, int status, void *command_data, void exit(10); } - printf("READ10 successful. Block content:\n"); + printf("READ10 using scsi_task_set_iov_in() successful. Block content:\n"); for (i=0;i<512;i++) { printf("%02x ", small_buffer[i]); if (i%16==15) @@ -155,9 +198,9 @@ void read10_cb(struct iscsi_context *iscsi, int status, void *command_data, void exit(10); } #else - printf("write the block\n"); + printf("write the block normally\n"); for (i = 0;i < 512; i++) { - wb[i] = i; + wb[i] = i & 0xff; } task = iscsi_write10_task(iscsi, clnt->lun, 0, wb, 512, 512, 0, 0, 0, 0, 0, @@ -169,6 +212,47 @@ void read10_cb(struct iscsi_context *iscsi, int status, void *command_data, void #endif } +void read10_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) +{ + struct client_state *clnt = (struct client_state *)private_data; + struct scsi_task *task = command_data; + int i; + static struct scsi_iovec iov[3]; + + if (status == SCSI_STATUS_CHECK_CONDITION) { + printf("Read10 failed with sense key:%d ascq:%04x\n", task->sense.key, task->sense.ascq); + scsi_free_scsi_task(task); + exit(10); + } + + printf("READ10 using scsi_task_add_data_in_buffer() successful. Block content:\n"); + for (i=0;i<512;i++) { + printf("%02x ", small_buffer[i]); + if (i%16==15) + printf("\n"); + if (i==69) + break; + } + printf("...\n"); + scsi_free_scsi_task(task); + + memset(&small_buffer[0], 0, 512); + + if ((task = iscsi_read10_task(iscsi, clnt->lun, 0, clnt->block_size, clnt->block_size, 0, 0, 0, 0, 0, read10_1_cb, private_data)) == NULL) { + printf("failed to send read10 command\n"); + exit(10); + } + /* provide iovectors where to read the data. + */ + iov[0].iov_base = &small_buffer[0]; + iov[0].iov_len = 7; + iov[1].iov_base = &small_buffer[7]; + iov[1].iov_len = 8; + iov[2].iov_base = &small_buffer[15]; + iov[2].iov_len = 512 - 15; + scsi_task_set_iov_in(task, &iov[0], 3); +} + void read6_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) { struct client_state *clnt = (struct client_state *)private_data; @@ -202,8 +286,9 @@ void read6_cb(struct iscsi_context *iscsi, int status, void *command_data, void * of the data. One in libiscsi and one in the application * callback. */ - scsi_task_add_data_in_buffer(task, 128, &small_buffer[0]); - scsi_task_add_data_in_buffer(task, 512-128, &small_buffer[128]); + scsi_task_add_data_in_buffer(task, 7, &small_buffer[0]); + scsi_task_add_data_in_buffer(task, 8, &small_buffer[7]); + scsi_task_add_data_in_buffer(task, 512-15, &small_buffer[15]); } void readcapacity10_cb(struct iscsi_context *iscsi, int status, void *command_data, void *private_data) From cbfb086d408246d023ba5bf3024a7c770c7db317 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Sun, 25 Nov 2012 18:56:33 -0800 Subject: [PATCH 07/11] Update the documentation for read/write iovectors --- include/iscsi.h | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/include/iscsi.h b/include/iscsi.h index cddd298..43b10cc 100644 --- a/include/iscsi.h +++ b/include/iscsi.h @@ -929,25 +929,33 @@ iscsi_report_supported_opcodes_sync(struct iscsi_context *iscsi, int lun, int return_timeouts, int maxsize); /* - * This function is used when the application wants to specify its own buffers to read the data - * from the DATA-IN PDUs into. - * The main use is for SCSI read operations to have them write directly into the application buffers to - * avoid the two copies that would occur otherwise. - * First copy from the individual DATA-IN blobs to linearize the buffer and the second in the callback - * to copy the data from the linearized buffer into the application buffer. + * These functions are used when the application wants to specify its own buffers to read the data + * from the DATA-IN PDUs into, or write the data to DATA-OUT PDUs from. + * The main use is for SCSI READ10/12/16 WRITE10/12/16 operations to have them read/write directly from + * the applications buffer, avoiding coying the data. * * This also supports reading into a vector of buffers by calling this function multiple times. * The individual buffers will be filled in the same order as they were created. * - * Example: + * Example READ10: * task = iscsi_read10_task( ( 2 512byte blocks into two buffers) * scsi_task_add_data_in_buffer(task, first_buffer, 512 * scsi_task_add_data_in_buffer(task, second_buffer, 512 * * - * If you use this function you can not use task->datain in the callback. + * If you use this function you can not use task->datain in the READ callback. * task->datain.size will be 0 and * task->datain.data will be NULL + * + * Example WRITE10: (write 2 blocks) + * static struct scsi_iovec iov[2]; + * + * task = iscsi_write10_task(iscsi, lun, 0, NULL, 512, 512, 0, 0, 0, 0, 0, callback, private_data); + * iov[0].iov_base = first_buffer; + * iov[0].iov_len = 512; + * iov[1].iov_base = second_buffer; + * iov[1].iov_len = 512; + * scsi_task_set_iov_out(task, &iov[0], 2); */ EXTERN int scsi_task_add_data_in_buffer(struct scsi_task *task, int len, unsigned char *buf); EXTERN int scsi_task_add_data_out_buffer(struct scsi_task *task, int len, unsigned char *buf); From 4237d8c2577940a270a52931486f31ce39a49354 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Sun, 25 Nov 2012 19:01:26 -0800 Subject: [PATCH 08/11] Remove 'nidata' from the iscsi pdu structure. We dont use it any more. --- include/iscsi-private.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/iscsi-private.h b/include/iscsi-private.h index 1a5d36e..e422441 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -218,8 +218,6 @@ struct iscsi_pdu { struct iscsi_data indata; - struct iscsi_data nidata; /* Non-Immediate Data */ - struct iscsi_scsi_cbdata *scsi_cbdata; }; From 7b1c0a19bb8b1fb2cbcc97594ccd5cc11fb9e61f Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Sun, 25 Nov 2012 19:02:34 -0800 Subject: [PATCH 09/11] Remove iscsi_allocate_pdu_size. This is not use any more. --- include/iscsi-private.h | 4 ---- lib/pdu.c | 8 -------- 2 files changed, 12 deletions(-) diff --git a/include/iscsi-private.h b/include/iscsi-private.h index e422441..5523433 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -226,10 +226,6 @@ void iscsi_free_scsi_cbdata(struct iscsi_context *iscsi, struct iscsi_scsi_cbdat struct iscsi_pdu *iscsi_allocate_pdu(struct iscsi_context *iscsi, enum iscsi_opcode opcode, enum iscsi_opcode response_opcode); -struct iscsi_pdu *iscsi_allocate_pdu_size(struct iscsi_context *iscsi, - enum iscsi_opcode opcode, - enum iscsi_opcode response_opcode, - size_t payload_size); struct iscsi_pdu *iscsi_allocate_pdu_with_itt_flags(struct iscsi_context *iscsi, enum iscsi_opcode opcode, enum iscsi_opcode response_opcode, diff --git a/lib/pdu.c b/lib/pdu.c index 947c0fc..7be9a7d 100644 --- a/lib/pdu.c +++ b/lib/pdu.c @@ -92,14 +92,6 @@ iscsi_allocate_pdu(struct iscsi_context *iscsi, enum iscsi_opcode opcode, return iscsi_allocate_pdu_with_itt_flags(iscsi, opcode, response_opcode, iscsi->itt++, 0); } -struct iscsi_pdu * -iscsi_allocate_pdu_size(struct iscsi_context *iscsi, enum iscsi_opcode opcode, - enum iscsi_opcode response_opcode, size_t payload_size) -{ - return iscsi_allocate_pdu_with_itt_flags_size(iscsi, opcode, response_opcode, iscsi->itt++, 0, payload_size); -} - - void iscsi_free_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) From bb755104e5f45d4e51028df95dc7e994f77dcf61 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Sun, 25 Nov 2012 19:11:51 -0800 Subject: [PATCH 10/11] Remove iscsi_allocate_pdu_with_itt_flags_size() We dont need this anymore. --- include/iscsi-private.h | 6 ------ lib/login.c | 4 ++-- lib/pdu.c | 16 ++-------------- 3 files changed, 4 insertions(+), 22 deletions(-) diff --git a/include/iscsi-private.h b/include/iscsi-private.h index 5523433..e78a7ba 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -231,12 +231,6 @@ struct iscsi_pdu *iscsi_allocate_pdu_with_itt_flags(struct iscsi_context *iscsi, enum iscsi_opcode response_opcode, uint32_t itt, uint32_t flags); -struct iscsi_pdu *iscsi_allocate_pdu_with_itt_flags_size(struct iscsi_context *iscsi, - enum iscsi_opcode opcode, - enum iscsi_opcode response_opcode, - uint32_t itt, - uint32_t flags, - size_t payload_size); void iscsi_free_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu); void iscsi_pdu_set_pduflags(struct iscsi_pdu *pdu, unsigned char flags); void iscsi_pdu_set_immediate(struct iscsi_pdu *pdu); diff --git a/lib/login.c b/lib/login.c index bf85b73..16d4f1e 100644 --- a/lib/login.c +++ b/lib/login.c @@ -706,10 +706,10 @@ iscsi_login_async(struct iscsi_context *iscsi, iscsi_command_cb cb, return -1; } - pdu = iscsi_allocate_pdu_with_itt_flags_size(iscsi, + pdu = iscsi_allocate_pdu_with_itt_flags(iscsi, ISCSI_PDU_LOGIN_REQUEST, ISCSI_PDU_LOGIN_RESPONSE, - iscsi->itt, 0, 1024); + iscsi->itt, 0); if (pdu == NULL) { iscsi_set_error(iscsi, "Out-of-memory: Failed to allocate " "login pdu."); diff --git a/lib/pdu.c b/lib/pdu.c index 7be9a7d..458190a 100644 --- a/lib/pdu.c +++ b/lib/pdu.c @@ -31,8 +31,8 @@ #include "slist.h" struct iscsi_pdu * -iscsi_allocate_pdu_with_itt_flags_size(struct iscsi_context *iscsi, enum iscsi_opcode opcode, - enum iscsi_opcode response_opcode, uint32_t itt, uint32_t flags, size_t payload_size) +iscsi_allocate_pdu_with_itt_flags(struct iscsi_context *iscsi, enum iscsi_opcode opcode, + enum iscsi_opcode response_opcode, uint32_t itt, uint32_t flags) { struct iscsi_pdu *pdu; @@ -45,11 +45,6 @@ iscsi_allocate_pdu_with_itt_flags_size(struct iscsi_context *iscsi, enum iscsi_o pdu->outdata.size = ISCSI_HEADER_SIZE; pdu->outdata.alloc_size = 64; - /* payload_size is limited by negotiated max_recv_data_segment_length */ - if (payload_size > iscsi->target_max_recv_data_segment_length) - payload_size = iscsi->target_max_recv_data_segment_length; - - while (pdu->outdata.alloc_size < ISCSI_HEADER_SIZE+payload_size) pdu->outdata.alloc_size<<=1; pdu->outdata.data = iscsi_malloc(iscsi, pdu->outdata.alloc_size); memset(pdu->outdata.data, 0, ISCSI_HEADER_SIZE); @@ -78,13 +73,6 @@ iscsi_allocate_pdu_with_itt_flags_size(struct iscsi_context *iscsi, enum iscsi_o return pdu; } -struct iscsi_pdu * -iscsi_allocate_pdu_with_itt_flags(struct iscsi_context *iscsi, enum iscsi_opcode opcode, - enum iscsi_opcode response_opcode, uint32_t itt, uint32_t flags) -{ - return iscsi_allocate_pdu_with_itt_flags_size(iscsi, opcode, response_opcode, itt, flags, 0); -} - struct iscsi_pdu * iscsi_allocate_pdu(struct iscsi_context *iscsi, enum iscsi_opcode opcode, enum iscsi_opcode response_opcode) From 9f741ad2e3925cbce5a25e9d1f37f94712eaf44b Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Sun, 25 Nov 2012 19:22:37 -0800 Subject: [PATCH 11/11] Remove the iscsi data alloc_size field. Avoiding to realloc data over and over should rather be handled with something similar to iovectors instead. --- include/iscsi.h | 1 - lib/iscsi-command.c | 2 +- lib/pdu.c | 31 +++++++++---------------------- 3 files changed, 10 insertions(+), 24 deletions(-) diff --git a/include/iscsi.h b/include/iscsi.h index 43b10cc..827b9de 100644 --- a/include/iscsi.h +++ b/include/iscsi.h @@ -537,7 +537,6 @@ iscsi_task_mgmt_target_cold_reset_async(struct iscsi_context *iscsi, struct iscsi_data { int size; - size_t alloc_size; unsigned char *data; }; diff --git a/lib/iscsi-command.c b/lib/iscsi-command.c index c34d901..f277a27 100644 --- a/lib/iscsi-command.c +++ b/lib/iscsi-command.c @@ -438,7 +438,7 @@ iscsi_process_scsi_data_in(struct iscsi_context *iscsi, struct iscsi_pdu *pdu, /* Dont add to reassembly buffer if we already have a user buffer */ if (scsi_task_get_data_in_buffer(task, 0, NULL) == NULL) { if (task->expxferlen > dsl && pdu->indata.data == NULL) { - pdu->indata.alloc_size = task->expxferlen; + pdu->indata.size = task->expxferlen; pdu->indata.data = iscsi_malloc(iscsi, task->expxferlen); if (pdu->indata.data == NULL) { iscsi_set_error(iscsi, "Out-of-memory: failed to allocate pdu indata buffer"); diff --git a/lib/pdu.c b/lib/pdu.c index 458190a..af0d448 100644 --- a/lib/pdu.c +++ b/lib/pdu.c @@ -43,9 +43,7 @@ iscsi_allocate_pdu_with_itt_flags(struct iscsi_context *iscsi, enum iscsi_opcode } pdu->outdata.size = ISCSI_HEADER_SIZE; - pdu->outdata.alloc_size = 64; - - pdu->outdata.data = iscsi_malloc(iscsi, pdu->outdata.alloc_size); + pdu->outdata.data = iscsi_malloc(iscsi, pdu->outdata.size); memset(pdu->outdata.data, 0, ISCSI_HEADER_SIZE); if (pdu->outdata.data == NULL) { @@ -117,42 +115,31 @@ iscsi_add_data(struct iscsi_context *iscsi, struct iscsi_data *data, } len = data->size + dsize; + aligned = len; if (pdualignment) { aligned = (aligned+3)&0xfffffffc; } - size_t new_alloc_size = data->alloc_size; - if (new_alloc_size < 64) new_alloc_size=64; - - while (aligned > new_alloc_size) new_alloc_size<<=1; - - if (data->data != NULL && data->alloc_size == 0) data->alloc_size=data->size; - - if (data->alloc_size == 0) { - data->data = iscsi_malloc(iscsi, new_alloc_size); + if (data->size == 0) { + data->data = iscsi_malloc(iscsi, aligned); + } else { + data->data = iscsi_realloc(iscsi, data->data, aligned); } - else - if (data->alloc_size != new_alloc_size) { - data->data = iscsi_realloc(iscsi, data->data, new_alloc_size); - } - if (data->data == NULL) { iscsi_set_error(iscsi, "failed to allocate buffer for %d " "bytes", (int) len); return -1; } - - data->alloc_size = new_alloc_size; + memcpy(data->data + data->size, dptr, dsize); + data->size += dsize; if (len != aligned) { /* zero out any padding at the end */ - memset(data->data+len, 0, aligned-len); + memset(data->data + len, 0, aligned - len); } - data->size = len; - return 0; }