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:
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user