lib/scsi: handle scattered input/output buffers for non IO commands

Fix buffer overflow/underflow for commands with alloc length scattered
into multiple preallocated buffers (eg. INQUIRY)

Change-Id: If6f7cabc7a6a7fb384bb015e14dc38548f484d0f
Signed-off-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
This commit is contained in:
Pawel Wodkowski 2016-11-14 20:14:12 +01:00 committed by Jim Harris
parent 8c5738ec5c
commit a1948352a3
7 changed files with 299 additions and 249 deletions

View File

@ -275,14 +275,17 @@ void spdk_scsi_task_set_data(struct spdk_scsi_task *task, void *data, uint32_t l
* returned buffer and must not free it. Caller is permitted to call
* spdk_scsi_task_free_data() to free internal buffer if it is not required
* anymore, but must assert that task is done and not used by library.
* The count of io vectors must by one. Any previously allocated buffer will be
* invalid after this call.
*
* Allocated buffer is stored in iov field of task object.
*
* \param task Task struct
* \param alloc_len Size of allocated buffer.
* \return Pointer to buffer or NULL on error.
*/
void *spdk_scsi_task_alloc_data(struct spdk_scsi_task *task, uint32_t alloc_len);
int spdk_scsi_task_scatter_data(struct spdk_scsi_task *task, const void *src, size_t len);
void *spdk_scsi_task_gather_data(struct spdk_scsi_task *task, int *len);
void spdk_scsi_task_build_sense_data(struct spdk_scsi_task *task, int sk, int asc,
int ascq);
void spdk_scsi_task_set_status(struct spdk_scsi_task *task, int sc, int sk, int asc,

View File

@ -184,7 +184,6 @@ static void
complete_task_with_no_lun(struct spdk_scsi_task *task)
{
uint8_t buffer[36];
uint8_t *data;
uint32_t allocation_len;
uint32_t data_len;
@ -194,24 +193,19 @@ complete_task_with_no_lun(struct spdk_scsi_task *task)
* must be served with PERIPHERAL QUALIFIER = 0x3 and
* PERIPHERAL DEVICE TYPE = 0x1F.
*/
allocation_len = from_be16(&task->cdb[3]);
data_len = sizeof(buffer);
if (allocation_len > data_len)
allocation_len = data_len;
if (allocation_len) {
memset(buffer, 0, data_len);
/* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
buffer[0] = 0x03 << 5 | 0x1f;
/* ADDITIONAL LENGTH */
buffer[4] = data_len - 5;
data = spdk_scsi_task_alloc_data(task, allocation_len);
memcpy(data, buffer, allocation_len);
}
allocation_len = from_be16(&task->cdb[3]);
if (spdk_scsi_task_scatter_data(task, buffer, SPDK_MIN(allocation_len, data_len)) >= 0) {
task->data_transferred = data_len;
task->status = SPDK_SCSI_STATUS_GOOD;
}
} else {
/* LOGICAL UNIT NOT SUPPORTED */
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,

View File

@ -1455,9 +1455,17 @@ spdk_bdev_scsi_unmap(struct spdk_bdev *bdev,
{
uint8_t *data;
uint16_t bdesc_data_len, bdesc_count;
struct spdk_scsi_unmap_bdesc *desc;
uint32_t bdesc_count;
int bdesc_data_len;
int data_len;
if (task->iovcnt == 1) {
data = (uint8_t *)task->iovs[0].iov_base;
data_len = task->iovs[0].iov_len;
} else {
data = spdk_scsi_task_gather_data(task, &data_len);
}
/*
* The UNMAP BLOCK DESCRIPTOR DATA LENGTH field specifies the length in
@ -1469,6 +1477,15 @@ spdk_bdev_scsi_unmap(struct spdk_bdev *bdev,
*/
bdesc_data_len = from_be16(&data[2]);
bdesc_count = bdesc_data_len / 16;
assert(bdesc_data_len <= data_len);
if (task->iovcnt == 1) {
desc = (struct spdk_scsi_unmap_bdesc *)&data[8];
} else {
desc = spdk_scsi_task_alloc_data(task, bdesc_data_len - 8);
memcpy(desc, &data[8], bdesc_data_len - 8);
spdk_free(data);
}
if (bdesc_count > bdev->max_unmap_bdesc_count) {
SPDK_ERRLOG("Error - supported unmap block descriptor count limit"
@ -1478,9 +1495,17 @@ spdk_bdev_scsi_unmap(struct spdk_bdev *bdev,
SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
return SPDK_SCSI_TASK_COMPLETE;
} else if (bdesc_data_len > data_len) {
SPDK_ERRLOG("Error - bdesc_data_len (%d) > data_len (%d)",
bdesc_data_len, data_len);
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
return SPDK_SCSI_TASK_COMPLETE;
}
task->blockdev_io = spdk_bdev_unmap(bdev, task->ch, (struct spdk_scsi_unmap_bdesc *)&data[8],
task->blockdev_io = spdk_bdev_unmap(bdev, task->ch, desc,
bdesc_count, spdk_bdev_scsi_task_complete,
task);
@ -1504,7 +1529,6 @@ spdk_bdev_scsi_process_block(struct spdk_bdev *bdev,
uint32_t xfer_len;
uint32_t len = 0;
uint8_t *cdb = task->cdb;
uint8_t *data;
/* XXX: We need to support FUA bit for writes! */
switch (cdb[0]) {
@ -1547,13 +1571,11 @@ spdk_bdev_scsi_process_block(struct spdk_bdev *bdev,
}
to_be32(&buffer[4], bdev->blocklen);
len = task->length < 8 ? task->length : sizeof(buffer);
if (len) {
data = spdk_scsi_task_alloc_data(task, len);
memcpy(data, buffer, len);
}
len = SPDK_MIN(task->length, sizeof(buffer));
if (spdk_scsi_task_scatter_data(task, buffer, len) < 0)
break;
task->data_transferred = 8;
task->data_transferred = len;
task->status = SPDK_SCSI_STATUS_GOOD;
break;
}
@ -1574,12 +1596,9 @@ spdk_bdev_scsi_process_block(struct spdk_bdev *bdev,
buffer[14] |= 1 << 7;
}
len = from_be32(&cdb[10]);
if (len) {
len = len < sizeof(buffer) ? len : sizeof(buffer);
data = spdk_scsi_task_alloc_data(task, len);
memcpy(data, buffer, len);
}
len = SPDK_MIN(from_be32(&cdb[10]), sizeof(buffer));
if (spdk_scsi_task_scatter_data(task, buffer, len) < 0)
break;
task->data_transferred = len;
task->status = SPDK_SCSI_STATUS_GOOD;
@ -1618,38 +1637,48 @@ spdk_bdev_scsi_process_block(struct spdk_bdev *bdev,
return SPDK_SCSI_TASK_COMPLETE;
}
static int
spdk_bdev_scsi_check_len(struct spdk_scsi_task *task, int len, int min_len)
{
if (len >= min_len)
return 0;
/* INVALID FIELD IN CDB */
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
return -1;
}
static int
spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
struct spdk_scsi_task *task)
{
int alloc_len;
int data_len;
int alloc_len = -1;
int data_len = -1;
uint8_t *cdb = task->cdb;
uint8_t *data;
uint8_t *data = NULL;
int rc = 0;
int pllen, md = 0;
int pf, sp;
int bdlen, llba;
int dbd, pc, page, subpage;
int cmd_parsed = 0;
switch (cdb[0]) {
case SPDK_SPC_INQUIRY:
alloc_len = from_be16(&cdb[3]);
if (alloc_len) {
data = spdk_scsi_task_alloc_data(task, alloc_len);
} else {
data = NULL;
}
data_len = spdk_bdev_scsi_inquiry(bdev, task, cdb,
data, alloc_len);
if (data_len < 0) {
data_len = SPDK_MAX(4096, alloc_len);
data = spdk_zmalloc(data_len, 0, NULL);
rc = spdk_bdev_scsi_inquiry(bdev, task, cdb, data, data_len);
data_len = SPDK_MIN(rc, data_len);
if (rc < 0) {
break;
}
SPDK_TRACEDUMP(SPDK_TRACE_DEBUG, "INQUIRY", data, data_len);
task->data_transferred = (uint64_t)data_len;
task->status = SPDK_SCSI_STATUS_GOOD;
break;
case SPDK_SPC_REPORT_LUNS: {
@ -1659,18 +1688,16 @@ spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "sel=%x\n", sel);
alloc_len = from_be32(&cdb[6]);
if (alloc_len < 16) {
/* INVALID FIELD IN CDB */
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
rc = spdk_bdev_scsi_check_len(task, alloc_len, 16);
if (rc < 0) {
break;
}
data = spdk_scsi_task_alloc_data(task, alloc_len);
data_len = spdk_bdev_scsi_report_luns(task->lun, sel, data, task->alloc_len);
if (data_len < 0) {
data_len = SPDK_MAX(4096, alloc_len);
data = spdk_zmalloc(data_len, 0, NULL);
rc = spdk_bdev_scsi_report_luns(task->lun, sel, data, data_len);
data_len = rc;
if (rc < 0) {
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_NO_SENSE,
SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
@ -1679,61 +1706,62 @@ spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
}
SPDK_TRACEDUMP(SPDK_TRACE_DEBUG, "REPORT LUNS", data, data_len);
task->data_transferred = (uint64_t)data_len;
task->status = SPDK_SCSI_STATUS_GOOD;
break;
}
case SPDK_SPC_MODE_SELECT_6:
case SPDK_SPC_MODE_SELECT_10:
data = task->iovs[0].iov_base;
if (cdb[0] == SPDK_SPC_MODE_SELECT_6) {
/* MODE_SELECT(6) must have at least a 4 byte header. */
md = 4;
pllen = cdb[4];
} else {
/* MODE_SELECT(10) must have at least an 8 byte header. */
md = 8;
pllen = from_be16(&cdb[7]);
}
if (pllen == 0) {
task->data_transferred = 0;
task->status = SPDK_SCSI_STATUS_GOOD;
break;
} else if (cdb[0] == SPDK_SPC_MODE_SELECT_6 && pllen < 4) {
/* MODE_SELECT(6) must have at least a 4 byte header. */
/* INVALID FIELD IN CDB */
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
break;
} else if (cdb[0] == SPDK_SPC_MODE_SELECT_10 && pllen < 8) {
/* MODE_SELECT(10) must have at least an 8 byte header. */
/* INVALID FIELD IN CDB */
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
break;
}
rc = spdk_bdev_scsi_check_len(task, pllen, md);
if (rc < 0) {
break;
}
data = spdk_scsi_task_gather_data(task, &rc);
if (rc < 0) {
break;
}
data_len = rc;
if (cdb[0] == SPDK_SPC_MODE_SELECT_6) {
rc = spdk_bdev_scsi_check_len(task, data_len, 4);
if (rc >= 0) {
bdlen = data[3];
}
} else {
rc = spdk_bdev_scsi_check_len(task, data_len, 8);
if (rc >= 0) {
bdlen = from_be16(&data[6]);
}
}
if (rc < 0) {
break;
}
pf = !!(cdb[1] & 0x10);
sp = !!(cdb[1] & 0x1);
/* page data */
data_len = spdk_bdev_scsi_mode_select_page(
rc = spdk_bdev_scsi_mode_select_page(
bdev, cdb,
pf, sp,
&data[md + bdlen],
pllen - (md + bdlen));
if (data_len != 0) {
if (rc < 0) {
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_NO_SENSE,
SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
@ -1741,8 +1769,8 @@ spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
break;
}
task->data_transferred = pllen;
task->status = SPDK_SCSI_STATUS_GOOD;
rc = pllen;
data_len = 0;
break;
case SPDK_SPC_MODE_SENSE_6:
@ -1764,11 +1792,23 @@ spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
subpage = cdb[3];
/* First call with no buffer to discover needed buffer size */
data_len = spdk_bdev_scsi_mode_sense(bdev, md,
rc = spdk_bdev_scsi_mode_sense(bdev, md,
cdb, dbd, llba, pc,
page, subpage,
NULL);
if (data_len < 0) {
if (rc < 0) {
break;
}
data_len = rc;
data = spdk_zmalloc(data_len, 0, NULL);
/* First call with no buffer to discover needed buffer size */
rc = spdk_bdev_scsi_mode_sense(bdev, md,
cdb, dbd, llba, pc,
page, subpage,
data);
if (rc < 0) {
/* INVALID FIELD IN CDB */
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
@ -1776,29 +1816,6 @@ spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
break;
}
if (alloc_len > data_len)
alloc_len = data_len;
if (alloc_len) {
uint8_t *buffer;
data = spdk_scsi_task_alloc_data(task, alloc_len);
buffer = alloc_len < data_len ? spdk_zmalloc(data_len, 0, NULL) : data;
data_len = spdk_bdev_scsi_mode_sense(bdev, md,
cdb, dbd, llba, pc,
page, subpage,
buffer);
assert(data_len >= 0);
if (buffer != data) {
memcpy(data, buffer, alloc_len);
spdk_free(buffer);
}
}
task->data_transferred = (uint64_t)data_len;
task->status = SPDK_SCSI_STATUS_GOOD;
break;
case SPDK_SPC_REQUEST_SENSE: {
@ -1816,7 +1833,6 @@ spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
}
alloc_len = cdb[4];
data = spdk_scsi_task_alloc_data(task, alloc_len);
/* NO ADDITIONAL SENSE INFORMATION */
sk = SPDK_SCSI_SENSE_NO_SENSE;
@ -1826,9 +1842,8 @@ spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
spdk_scsi_task_build_sense_data(task, sk, asc, ascq);
data_len = task->sense_data_len;
data = spdk_zmalloc(data_len, 0, NULL);
memcpy(data, task->sense_data, data_len);
task->data_transferred = (uint64_t)data_len;
task->status = SPDK_SCSI_STATUS_GOOD;
break;
}
@ -1845,6 +1860,7 @@ spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
SPDK_SCSI_ASC_INVALID_COMMAND_OPERATION_CODE,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
rc = -1;
break;
case SPDK_SPC_TEST_UNIT_READY:
@ -1855,14 +1871,27 @@ spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
SPDK_TRACELOG(SPDK_TRACE_SCSI, "START_STOP_UNIT\n");
}
task->data_transferred = 0;
task->status = SPDK_SCSI_STATUS_GOOD;
rc = 0;
break;
default:
return SPDK_SCSI_TASK_UNKNOWN;
}
if (rc >= 0 && data_len > 0) {
assert(alloc_len >= 0);
spdk_scsi_task_scatter_data(task, data, SPDK_MIN(alloc_len, data_len));
rc = SPDK_MIN(data_len, alloc_len);
}
if (rc >= 0) {
task->data_transferred = rc;
task->status = SPDK_SCSI_STATUS_GOOD;
}
if (data)
spdk_free(data);
return SPDK_SCSI_TASK_COMPLETE;
}

View File

@ -56,6 +56,25 @@
#include "spdk_internal/log.h"
/**
* Macro to return the minimum of two numbers
*/
#define SPDK_MIN(a, b) ({ \
typeof (a) _a = (a); \
typeof (b) _b = (b); \
_a < _b ? _a : _b; \
})
/**
* Macro to return the maximum of two numbers
*/
#define SPDK_MAX(a, b) ({ \
typeof (a) _a = (a); \
typeof (b) _b = (b); \
_a > _b ? _a : _b; \
})
enum {
SPDK_SCSI_TASK_UNKNOWN = -1,
SPDK_SCSI_TASK_COMPLETE,

View File

@ -122,21 +122,87 @@ spdk_scsi_task_alloc_data(struct spdk_scsi_task *task, uint32_t alloc_len)
{
assert(task->alloc_len == 0);
/* Only one buffer is managable */
if (task->iovcnt != 1) {
task->iov.iov_base = spdk_zmalloc(alloc_len, 0, NULL);
task->iov.iov_len = alloc_len;
task->alloc_len = alloc_len;
return task->iov.iov_base;
}
int
spdk_scsi_task_scatter_data(struct spdk_scsi_task *task, const void *src, size_t buf_len)
{
size_t len = 0;
size_t buf_left = buf_len;
int i;
struct iovec *iovs = task->iovs;
const uint8_t *pos;
if (buf_len == 0)
return 0;
if (task->iovcnt == 1 && iovs[0].iov_base == NULL) {
spdk_scsi_task_alloc_data(task, buf_len);
iovs[0] = task->iov;
}
for (i = 0; i < task->iovcnt; i++) {
assert(iovs[i].iov_base != NULL);
len += iovs[i].iov_len;
}
if (len < buf_len) {
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
return -1;
}
pos = src;
for (i = 0; i < task->iovcnt; i++) {
len = SPDK_MIN(iovs[i].iov_len, buf_left);
buf_left -= len;
memcpy(iovs[i].iov_base, pos, len);
pos += len;
}
return buf_len;
}
void *
spdk_scsi_task_gather_data(struct spdk_scsi_task *task, int *len)
{
int i;
struct iovec *iovs = task->iovs;
size_t buf_len = 0;
uint8_t *buf, *pos;
for (i = 0; i < task->iovcnt; i++) {
assert(iovs[i].iov_base != NULL);
buf_len += iovs[i].iov_len;
}
if (buf_len == 0) {
*len = 0;
return NULL;
}
/* This is workaround for buffers shorter than 4kb */
if (task->iov.iov_base == NULL) {
task->iov.iov_base = spdk_zmalloc(alloc_len, 0, NULL);
task->alloc_len = alloc_len;
buf = spdk_malloc(buf_len, 0, NULL);
if (buf == NULL) {
*len = -1;
return NULL;
}
task->iov.iov_len = alloc_len;
assert(&task->iov == task->iovs);
pos = buf;
for (i = 0; i < task->iovcnt; i++) {
memcpy(pos, iovs[i].iov_base, iovs[i].iov_len);
pos += iovs[i].iov_len;
}
return task->iov.iov_base;
*len = buf_len;
return buf;
}
void

View File

@ -38,6 +38,7 @@
#include "spdk_cunit.h"
#include "task.c"
#include "lun.c"
#include "lun_db.c"
@ -55,6 +56,12 @@ void spdk_trace_record(uint16_t tpoint_id, uint16_t poller_id, uint32_t size,
{
}
static void
spdk_lun_ut_free_task(struct spdk_scsi_task *task)
{
free(task);
}
static struct spdk_scsi_task *
spdk_get_task(uint32_t *owner_task_ctr)
{
@ -65,43 +72,41 @@ spdk_get_task(uint32_t *owner_task_ctr)
return NULL;
}
task->id = g_task_count;
task->iovs = &task->iov;
task->iovcnt = 1;
g_task_count++;
spdk_scsi_task_construct(task, &g_task_count, NULL);
task->free_fn = spdk_lun_ut_free_task;
return task;
}
void
spdk_scsi_task_put(struct spdk_scsi_task *task)
void *
spdk_malloc(size_t size, size_t align, uint64_t *phys_addr)
{
g_task_count--;
if (task->alloc_len) {
free(task->iov.iov_base);
}
free(task);
}
void
spdk_scsi_task_set_status(struct spdk_scsi_task *task, int sc, int sk,
int asc, int ascq)
{
task->status = sc;
void *buf = malloc(size);
if (phys_addr)
*phys_addr = (uint64_t)buf;
return buf;
}
void *
spdk_scsi_task_alloc_data(struct spdk_scsi_task *task, uint32_t alloc_len)
spdk_zmalloc(size_t size, size_t align, uint64_t *phys_addr)
{
if (alloc_len < 4096)
alloc_len = 4096;
void *buf = calloc(size, 1);
if (phys_addr)
*phys_addr = (uint64_t)buf;
return buf;
}
task->iovs = &task->iov;
task->iov.iov_base = malloc(alloc_len);
task->iov.iov_len = alloc_len;
task->alloc_len = alloc_len;
return task->iov.iov_base;
void
spdk_free(void *buf)
{
free(buf);
}
int
spdk_bdev_free_io(struct spdk_bdev_io *bdev_io)
{
CU_ASSERT(0);
return -1;
}
void spdk_scsi_dev_queue_mgmt_task(struct spdk_scsi_dev *dev,

View File

@ -35,6 +35,7 @@
#include <stdlib.h>
#include <string.h>
#include "task.c"
#include "scsi_bdev.c"
#include "spdk_cunit.h"
@ -43,12 +44,23 @@ SPDK_LOG_REGISTER_TRACE_FLAG("scsi", SPDK_TRACE_SCSI)
struct spdk_scsi_globals g_spdk_scsi;
void *
spdk_malloc(size_t size, size_t align, uint64_t *phys_addr)
{
void *buf = malloc(size);
if (phys_addr)
*phys_addr = (uint64_t)buf;
return buf;
}
void *
spdk_zmalloc(size_t size, size_t align, uint64_t *phys_addr)
{
void *buf = calloc(size, 1);
if (phys_addr)
*phys_addr = (uint64_t)buf;
return buf;
}
@ -57,6 +69,14 @@ spdk_free(void *buf)
{
free(buf);
}
int
spdk_bdev_free_io(struct spdk_bdev_io *bdev_io)
{
CU_ASSERT(0);
return -1;
}
void
spdk_scsi_lun_clear_all(struct spdk_scsi_lun *lun)
{
@ -67,19 +87,15 @@ spdk_scsi_lun_complete_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *ta
{
}
void
spdk_scsi_task_set_status(struct spdk_scsi_task *task, int sc, int sk,
int asc, int ascq)
{
spdk_scsi_task_build_sense_data(task, sk, asc, ascq);
task->status = sc;
}
static void
spdk_put_task(struct spdk_scsi_task *task)
{
spdk_scsi_task_free_data(task);
if (task->alloc_len)
free(task->iov.iov_base);
task->iov.iov_base = NULL;
task->iov.iov_len = 0;
task->alloc_len = 0;
}
@ -92,88 +108,6 @@ spdk_init_task(struct spdk_scsi_task *task)
task->iovcnt = 1;
}
void
spdk_scsi_task_set_data(struct spdk_scsi_task *task, void *data, uint32_t len)
{
assert(task->alloc_len == 0);
task->iov.iov_base = data;
task->iov.iov_len = len;
task->alloc_len = 0;
}
void *
spdk_scsi_task_alloc_data(struct spdk_scsi_task *task, uint32_t alloc_len)
{
if (task->iov.iov_base != NULL) {
if (task->alloc_len != 0 && alloc_len > task->alloc_len) {
spdk_put_task(task);
} else if (task->alloc_len == 0 && alloc_len > task->iov.iov_len) {
/* External data buffer less than requested. */
return NULL;
}
}
if (task->iov.iov_base == NULL) {
task->iov.iov_base = calloc(alloc_len, 1);
task->alloc_len = alloc_len;
}
task->iov.iov_len = alloc_len;
return task->iov.iov_base;
}
void
spdk_scsi_task_free_data(struct spdk_scsi_task *task)
{
if (task->alloc_len)
free(task->iov.iov_base);
task->iov.iov_base = NULL;
task->iov.iov_len = 0;
task->alloc_len = 0;
}
void
spdk_scsi_task_build_sense_data(struct spdk_scsi_task *task, int sk, int asc, int ascq)
{
uint8_t *cp;
int resp_code;
resp_code = 0x70; /* Current + Fixed format */
/* Sense Data */
cp = task->sense_data;
/* VALID(7) RESPONSE CODE(6-0) */
cp[0] = 0x80 | resp_code;
/* Obsolete */
cp[1] = 0;
/* FILEMARK(7) EOM(6) ILI(5) SENSE KEY(3-0) */
cp[2] = sk & 0xf;
/* INFORMATION */
memset(&cp[3], 0, 4);
/* ADDITIONAL SENSE LENGTH */
cp[7] = 10;
/* COMMAND-SPECIFIC INFORMATION */
memset(&cp[8], 0, 4);
/* ADDITIONAL SENSE CODE */
cp[12] = asc;
/* ADDITIONAL SENSE CODE QUALIFIER */
cp[13] = ascq;
/* FIELD REPLACEABLE UNIT CODE */
cp[14] = 0;
/* SKSV(7) SENSE KEY SPECIFIC(6-0,7-0,7-0) */
cp[15] = 0;
cp[16] = 0;
cp[17] = 0;
/* SenseLength */
task->sense_data_len = 18;
}
void
spdk_scsi_nvme_translate(struct spdk_bdev_io *bdev_io, int *sc, int *sk,
int *asc, int *ascq)