Merge pull request #41 from plieven/iovec
SCSI add support for iovectors
This commit is contained in:
@@ -33,6 +33,9 @@ extern "C" {
|
||||
struct iscsi_context;
|
||||
struct sockaddr;
|
||||
|
||||
/* FEATURES */
|
||||
#define LIBISCSI_FEATURE_IOVECTOR (1)
|
||||
|
||||
#define MAX_STRING_SIZE (255)
|
||||
|
||||
/*
|
||||
@@ -947,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.
|
||||
|
||||
@@ -197,6 +197,22 @@ enum scsi_residual {
|
||||
SCSI_RESIDUAL_OVERFLOW
|
||||
};
|
||||
|
||||
/* struct scsi_iovec follows the POSIX struct iovec
|
||||
definition and *MUST* never change. */
|
||||
struct scsi_iovec {
|
||||
void *iov_base;
|
||||
size_t iov_len;
|
||||
};
|
||||
|
||||
struct scsi_iovector {
|
||||
struct scsi_iovec *iov;
|
||||
int niov;
|
||||
int nalloc;
|
||||
size_t size;
|
||||
size_t offset;
|
||||
int consumed;
|
||||
};
|
||||
|
||||
struct scsi_task {
|
||||
int status;
|
||||
|
||||
@@ -217,7 +233,8 @@ struct scsi_task {
|
||||
uint32_t cmdsn;
|
||||
uint32_t lun;
|
||||
|
||||
struct scsi_data_buffer *in_buffers;
|
||||
struct scsi_iovector iovector_in;
|
||||
struct scsi_iovector iovector_out;
|
||||
};
|
||||
|
||||
/* This function will free a scsi task structure.
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "iscsi-private.h"
|
||||
#include "slist.h"
|
||||
|
||||
|
||||
inline void* iscsi_malloc(struct iscsi_context *iscsi, size_t size) {
|
||||
void * ptr = malloc(size);
|
||||
if (ptr != NULL) iscsi->mallocs++;
|
||||
|
||||
@@ -176,4 +176,7 @@ scsi_sense_ascq_str
|
||||
scsi_sense_key_str
|
||||
scsi_set_task_private_ptr
|
||||
scsi_task_add_data_in_buffer
|
||||
scsi_task_add_data_out_buffer
|
||||
scsi_task_set_iov_in
|
||||
scsi_task_set_iov_out
|
||||
scsi_version_to_str
|
||||
|
||||
@@ -174,4 +174,7 @@ scsi_sense_ascq_str
|
||||
scsi_sense_key_str
|
||||
scsi_set_task_private_ptr
|
||||
scsi_task_add_data_in_buffer
|
||||
scsi_task_add_data_out_buffer
|
||||
scsi_task_set_iov_in
|
||||
scsi_task_set_iov_out
|
||||
scsi_version_to_str
|
||||
|
||||
@@ -2533,58 +2533,119 @@ scsi_get_task_private_ptr(struct scsi_task *task)
|
||||
return task->ptr;
|
||||
}
|
||||
|
||||
void
|
||||
scsi_task_set_iov_out(struct scsi_task *task, struct scsi_iovec *iov, int niov)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
struct scsi_data_buffer {
|
||||
struct scsi_data_buffer *next;
|
||||
uint32_t len;
|
||||
unsigned char *data;
|
||||
};
|
||||
#define IOVECTOR_INITAL_ALLOC (16)
|
||||
|
||||
int
|
||||
scsi_iovector_add(struct scsi_task *task, struct scsi_iovector *iovector, int len, unsigned char *buf)
|
||||
{
|
||||
if (len < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (iovector->iov == NULL) {
|
||||
iovector->iov = scsi_malloc(task, IOVECTOR_INITAL_ALLOC*sizeof(struct iovec));
|
||||
if (iovector->iov == NULL) {
|
||||
return -1;
|
||||
}
|
||||
iovector->nalloc = IOVECTOR_INITAL_ALLOC;
|
||||
}
|
||||
|
||||
/* iovec allocation is too small */
|
||||
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;
|
||||
}
|
||||
memcpy(iovector->iov, old_iov, iovector->niov * sizeof(struct iovec));
|
||||
iovector->nalloc <<= 1;
|
||||
}
|
||||
|
||||
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_iovector *iovector, uint32_t pos, ssize_t *count)
|
||||
{
|
||||
if (iovector->iov == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pos == 0 && count == NULL) return iovector->iov[0].iov_base;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
struct scsi_iovec *iov = &iovector->iov[iovector->consumed];
|
||||
|
||||
pos-= iovector->offset;
|
||||
|
||||
while (pos >= iov->iov_len) {
|
||||
iovector->offset += iov->iov_len;
|
||||
iovector->consumed++;
|
||||
pos -= iov->iov_len;
|
||||
if (iovector->niov <= iovector->consumed) {
|
||||
return NULL;
|
||||
}
|
||||
iov = &iovector->iov[iovector->consumed];
|
||||
}
|
||||
|
||||
if (count && *count >= (ssize_t)(iov->iov_len - pos)) {
|
||||
*count = iov->iov_len - pos;
|
||||
}
|
||||
|
||||
return (unsigned char *) iov->iov_base + pos;
|
||||
}
|
||||
|
||||
int
|
||||
scsi_task_add_data_in_buffer(struct scsi_task *task, int len, unsigned char *buf)
|
||||
{
|
||||
struct scsi_data_buffer *data_buf;
|
||||
|
||||
if (len < 0) {
|
||||
return -1;
|
||||
}
|
||||
data_buf = scsi_malloc(task, sizeof(struct scsi_data_buffer));
|
||||
if (data_buf == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
data_buf->len = len;
|
||||
data_buf->data = buf;
|
||||
|
||||
SLIST_ADD_END(&task->in_buffers, data_buf);
|
||||
return 0;
|
||||
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)
|
||||
{
|
||||
struct scsi_data_buffer *sdb;
|
||||
|
||||
sdb = task->in_buffers;
|
||||
if (sdb == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (pos >= sdb->len) {
|
||||
pos -= sdb->len;
|
||||
sdb = sdb->next;
|
||||
if (sdb == NULL) {
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
if (count && *count > (ssize_t)(sdb->len - pos)) {
|
||||
*count = sdb->len - pos;
|
||||
}
|
||||
|
||||
return &sdb->data[pos];
|
||||
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