From e7cc6dc1cad5430380cf9c85f81ac0414b3aa30c Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Fri, 23 Nov 2012 15:43:00 +0100 Subject: [PATCH] SCSI add support for POSIX compatible iovectos This patch defines an scsi_iovec struct which is guaranteed to be POSIX compatible. It furthermore adds support for in+out iovectors for bi-directional operations Signed-off-by: Peter Lieven --- include/iscsi.h | 5 +++ include/scsi-lowlevel.h | 17 ++++---- lib/init.c | 1 - lib/libiscsi.def | 4 +- lib/libiscsi.syms | 4 +- lib/scsi-lowlevel.c | 92 ++++++++++++++++++++++++----------------- 6 files changed, 74 insertions(+), 49 deletions(-) diff --git a/include/iscsi.h b/include/iscsi.h index b893ce7..cddd298 100644 --- a/include/iscsi.h +++ b/include/iscsi.h @@ -950,6 +950,11 @@ iscsi_report_supported_opcodes_sync(struct iscsi_context *iscsi, int lun, * task->datain.data will be NULL */ 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); + +struct scsi_iovec; +EXTERN void scsi_task_set_iov_out(struct scsi_task *task, struct scsi_iovec *iov, int niov); +EXTERN void scsi_task_set_iov_in(struct scsi_task *task, struct scsi_iovec *iov, int niov); /* * This function is used when you want to cancel a scsi task. diff --git a/include/scsi-lowlevel.h b/include/scsi-lowlevel.h index 7c173c7..40707b4 100644 --- a/include/scsi-lowlevel.h +++ b/include/scsi-lowlevel.h @@ -197,18 +197,20 @@ enum scsi_residual { SCSI_RESIDUAL_OVERFLOW }; -#if !defined(_SYS_UIO_H) && !defined(CONFIG_IOVEC) -struct iovec { +/* struct scsi_iovec follows the POSIX struct iovec + definition and *MUST* never change. */ +struct scsi_iovec { void *iov_base; size_t iov_len; }; -#endif struct scsi_iovector { - struct iovec *iov; + struct scsi_iovec *iov; int niov; int nalloc; size_t size; + size_t offset; + int consumed; }; struct scsi_task { @@ -231,9 +233,8 @@ struct scsi_task { uint32_t cmdsn; uint32_t lun; - size_t buffers_offset; - int buffers_consumed; - struct scsi_iovector *buffers; + struct scsi_iovector iovector_in; + struct scsi_iovector iovector_out; }; /* This function will free a scsi task structure. @@ -723,8 +724,6 @@ EXTERN struct scsi_task *scsi_cdb_report_supported_opcodes(int report_timeouts, void *scsi_malloc(struct scsi_task *task, size_t size); -EXTERN void scsi_iovector_assign(struct scsi_task *task, struct scsi_iovector *iov); - #ifdef __cplusplus } #endif diff --git a/lib/init.c b/lib/init.c index 521f4a2..d5c4351 100644 --- a/lib/init.c +++ b/lib/init.c @@ -32,7 +32,6 @@ #include "iscsi.h" #include "iscsi-private.h" #include "slist.h" -#include "scsi-lowlevel.h" inline void* iscsi_malloc(struct iscsi_context *iscsi, size_t size) { diff --git a/lib/libiscsi.def b/lib/libiscsi.def index d24f487..ea01803 100644 --- a/lib/libiscsi.def +++ b/lib/libiscsi.def @@ -176,5 +176,7 @@ scsi_sense_ascq_str scsi_sense_key_str scsi_set_task_private_ptr scsi_task_add_data_in_buffer -scsi_iovector_assign +scsi_task_add_data_out_buffer +scsi_task_set_iov_in +scsi_task_set_iov_out scsi_version_to_str diff --git a/lib/libiscsi.syms b/lib/libiscsi.syms index 48b53d2..3344061 100644 --- a/lib/libiscsi.syms +++ b/lib/libiscsi.syms @@ -174,5 +174,7 @@ scsi_sense_ascq_str scsi_sense_key_str scsi_set_task_private_ptr scsi_task_add_data_in_buffer -scsi_iovector_assign +scsi_task_add_data_out_buffer +scsi_task_set_iov_in +scsi_task_set_iov_out scsi_version_to_str diff --git a/lib/scsi-lowlevel.c b/lib/scsi-lowlevel.c index 3cb2eb2..ab2940f 100644 --- a/lib/scsi-lowlevel.c +++ b/lib/scsi-lowlevel.c @@ -2534,83 +2534,89 @@ scsi_get_task_private_ptr(struct scsi_task *task) } void -scsi_iovector_assign(struct scsi_task *task, struct scsi_iovector *iov) +scsi_task_set_iov_out(struct scsi_task *task, struct scsi_iovec *iov, int niov) { - task->buffers = iov; + task->iovector_out.iov = iov; + task->iovector_out.niov = niov; +} + +void +scsi_task_set_iov_in(struct scsi_task *task, struct scsi_iovec *iov, int niov) +{ + task->iovector_in.iov = iov; + task->iovector_in.niov = niov; } #define IOVECTOR_INITAL_ALLOC (16) int -scsi_iovector_add(struct scsi_task *task, int len, unsigned char *buf) +scsi_iovector_add(struct scsi_task *task, struct scsi_iovector *iovector, int len, unsigned char *buf) { if (len < 0) { return -1; } - if (task->buffers == NULL) { - task->buffers = scsi_malloc(task, sizeof(struct scsi_iovector) - + IOVECTOR_INITAL_ALLOC*sizeof(struct iovec) + 15); - if (task->buffers == NULL) { + if (iovector->iov == NULL) { + iovector->iov = scsi_malloc(task, IOVECTOR_INITAL_ALLOC*sizeof(struct iovec)); + if (iovector->iov == NULL) { return -1; } - - memset(task->buffers, 0, sizeof(struct scsi_iovector)); - /* align by 16 bytes */ - task->buffers->iov = (struct iovec *) (((uintptr_t)task->buffers + - sizeof(struct scsi_iovector) + 15)&~0xf); - task->buffers->nalloc = IOVECTOR_INITAL_ALLOC; + iovector->nalloc = IOVECTOR_INITAL_ALLOC; } /* iovec allocation is too small */ - if (task->buffers->nalloc < task->buffers->niov + 1) { - struct iovec *old_iov = task->buffers->iov; - task->buffers->iov = scsi_malloc(task, 2 * task->buffers->nalloc * sizeof(struct iovec)); - if (task->buffers->iov == NULL) { + if (iovector->nalloc < iovector->niov + 1) { + struct scsi_iovec *old_iov = iovector->iov; + iovector->iov = scsi_malloc(task, 2 * iovector->nalloc * sizeof(struct iovec)); + if (iovector->iov == NULL) { return -1; } - if (old_iov != NULL) { - memcpy(task->buffers->iov, old_iov, task->buffers->niov * sizeof(struct iovec)); - } - task->buffers->nalloc <<= 1; + memcpy(iovector->iov, old_iov, iovector->niov * sizeof(struct iovec)); + iovector->nalloc <<= 1; } - task->buffers->iov[task->buffers->niov].iov_len = len; - task->buffers->iov[task->buffers->niov].iov_base = buf; - task->buffers->niov++; - task->buffers->size += len; + iovector->iov[iovector->niov].iov_len = len; + iovector->iov[iovector->niov].iov_base = buf; + iovector->niov++; + iovector->size += len; return 0; } unsigned char * -scsi_iovector_get_buffer(struct scsi_task *task, uint32_t pos, ssize_t *count) +scsi_iovector_get_buffer(struct scsi_iovector *iovector, uint32_t pos, ssize_t *count) { - if (task->buffers == NULL) { + if (iovector->iov == NULL) { return NULL; } - if (pos == 0 && count == NULL) return task->buffers->iov[0].iov_base; + if (pos == 0 && count == NULL) return iovector->iov[0].iov_base; - if (task->buffers->niov <= task->buffers_consumed) { + if (pos < iovector->offset) { + /* start over in case we are going backwards */ + iovector->offset = 0; + iovector->consumed = 0; + } + + if (iovector->niov <= iovector->consumed) { /* someone issued a read but did not provide enough user buffers for all the data. * maybe someone tried to read just 512 bytes off a MMC device? */ return NULL; } - pos-= task->buffers_offset; + struct scsi_iovec *iov = &iovector->iov[iovector->consumed]; - struct iovec *iov = &task->buffers->iov[task->buffers_consumed]; + pos-= iovector->offset; while (pos >= iov->iov_len) { - task->buffers_offset += iov->iov_len; - task->buffers_consumed++; + iovector->offset += iov->iov_len; + iovector->consumed++; pos -= iov->iov_len; - if (task->buffers->niov <= task->buffers_consumed) { + if (iovector->niov <= iovector->consumed) { return NULL; } - iov = &task->buffers->iov[task->buffers_consumed]; + iov = &iovector->iov[iovector->consumed]; } if (count && *count >= (ssize_t)(iov->iov_len - pos)) { @@ -2623,11 +2629,23 @@ scsi_iovector_get_buffer(struct scsi_task *task, uint32_t pos, ssize_t *count) int scsi_task_add_data_in_buffer(struct scsi_task *task, int len, unsigned char *buf) { - return scsi_iovector_add(task, len, buf); + return scsi_iovector_add(task, &task->iovector_in, len, buf); } unsigned char * scsi_task_get_data_in_buffer(struct scsi_task *task, uint32_t pos, ssize_t *count) { - return scsi_iovector_get_buffer(task, pos, count); + return scsi_iovector_get_buffer(&task->iovector_in, pos, count); +} + +int +scsi_task_add_data_out_buffer(struct scsi_task *task, int len, unsigned char *buf) +{ + return scsi_iovector_add(task, &task->iovector_out, len, buf); +} + +unsigned char * +scsi_task_get_data_out_buffer(struct scsi_task *task, uint32_t pos, ssize_t *count) +{ + return scsi_iovector_get_buffer(&task->iovector_out, pos, count); }