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 <pl@kamp.de>
This commit is contained in:
Peter Lieven
2012-11-23 15:43:00 +01:00
parent 55f76cfb0c
commit e7cc6dc1ca
6 changed files with 74 additions and 49 deletions

View File

@@ -950,6 +950,11 @@ iscsi_report_supported_opcodes_sync(struct iscsi_context *iscsi, int lun,
* task->datain.data will be NULL * 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_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. * This function is used when you want to cancel a scsi task.

View File

@@ -197,18 +197,20 @@ enum scsi_residual {
SCSI_RESIDUAL_OVERFLOW SCSI_RESIDUAL_OVERFLOW
}; };
#if !defined(_SYS_UIO_H) && !defined(CONFIG_IOVEC) /* struct scsi_iovec follows the POSIX struct iovec
struct iovec { definition and *MUST* never change. */
struct scsi_iovec {
void *iov_base; void *iov_base;
size_t iov_len; size_t iov_len;
}; };
#endif
struct scsi_iovector { struct scsi_iovector {
struct iovec *iov; struct scsi_iovec *iov;
int niov; int niov;
int nalloc; int nalloc;
size_t size; size_t size;
size_t offset;
int consumed;
}; };
struct scsi_task { struct scsi_task {
@@ -231,9 +233,8 @@ struct scsi_task {
uint32_t cmdsn; uint32_t cmdsn;
uint32_t lun; uint32_t lun;
size_t buffers_offset; struct scsi_iovector iovector_in;
int buffers_consumed; struct scsi_iovector iovector_out;
struct scsi_iovector *buffers;
}; };
/* This function will free a scsi task structure. /* 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); 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 #ifdef __cplusplus
} }
#endif #endif

View File

@@ -32,7 +32,6 @@
#include "iscsi.h" #include "iscsi.h"
#include "iscsi-private.h" #include "iscsi-private.h"
#include "slist.h" #include "slist.h"
#include "scsi-lowlevel.h"
inline void* iscsi_malloc(struct iscsi_context *iscsi, size_t size) { inline void* iscsi_malloc(struct iscsi_context *iscsi, size_t size) {

View File

@@ -176,5 +176,7 @@ scsi_sense_ascq_str
scsi_sense_key_str scsi_sense_key_str
scsi_set_task_private_ptr scsi_set_task_private_ptr
scsi_task_add_data_in_buffer 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 scsi_version_to_str

View File

@@ -174,5 +174,7 @@ scsi_sense_ascq_str
scsi_sense_key_str scsi_sense_key_str
scsi_set_task_private_ptr scsi_set_task_private_ptr
scsi_task_add_data_in_buffer 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 scsi_version_to_str

View File

@@ -2534,83 +2534,89 @@ scsi_get_task_private_ptr(struct scsi_task *task)
} }
void 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) #define IOVECTOR_INITAL_ALLOC (16)
int 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) { if (len < 0) {
return -1; return -1;
} }
if (task->buffers == NULL) { if (iovector->iov == NULL) {
task->buffers = scsi_malloc(task, sizeof(struct scsi_iovector) iovector->iov = scsi_malloc(task, IOVECTOR_INITAL_ALLOC*sizeof(struct iovec));
+ IOVECTOR_INITAL_ALLOC*sizeof(struct iovec) + 15); if (iovector->iov == NULL) {
if (task->buffers == NULL) {
return -1; return -1;
} }
iovector->nalloc = IOVECTOR_INITAL_ALLOC;
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;
} }
/* iovec allocation is too small */ /* iovec allocation is too small */
if (task->buffers->nalloc < task->buffers->niov + 1) { if (iovector->nalloc < iovector->niov + 1) {
struct iovec *old_iov = task->buffers->iov; struct scsi_iovec *old_iov = iovector->iov;
task->buffers->iov = scsi_malloc(task, 2 * task->buffers->nalloc * sizeof(struct iovec)); iovector->iov = scsi_malloc(task, 2 * iovector->nalloc * sizeof(struct iovec));
if (task->buffers->iov == NULL) { if (iovector->iov == NULL) {
return -1; return -1;
} }
if (old_iov != NULL) { memcpy(iovector->iov, old_iov, iovector->niov * sizeof(struct iovec));
memcpy(task->buffers->iov, old_iov, task->buffers->niov * sizeof(struct iovec)); iovector->nalloc <<= 1;
}
task->buffers->nalloc <<= 1;
} }
task->buffers->iov[task->buffers->niov].iov_len = len; iovector->iov[iovector->niov].iov_len = len;
task->buffers->iov[task->buffers->niov].iov_base = buf; iovector->iov[iovector->niov].iov_base = buf;
task->buffers->niov++; iovector->niov++;
task->buffers->size += len; iovector->size += len;
return 0; return 0;
} }
unsigned char * 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; 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. /* 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? * maybe someone tried to read just 512 bytes off a MMC device?
*/ */
return NULL; 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) { while (pos >= iov->iov_len) {
task->buffers_offset += iov->iov_len; iovector->offset += iov->iov_len;
task->buffers_consumed++; iovector->consumed++;
pos -= iov->iov_len; pos -= iov->iov_len;
if (task->buffers->niov <= task->buffers_consumed) { if (iovector->niov <= iovector->consumed) {
return NULL; return NULL;
} }
iov = &task->buffers->iov[task->buffers_consumed]; iov = &iovector->iov[iovector->consumed];
} }
if (count && *count >= (ssize_t)(iov->iov_len - pos)) { 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 int
scsi_task_add_data_in_buffer(struct scsi_task *task, int len, unsigned char *buf) 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 * unsigned char *
scsi_task_get_data_in_buffer(struct scsi_task *task, uint32_t pos, ssize_t *count) 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);
} }