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:
parent
8c5738ec5c
commit
a1948352a3
@ -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
|
* 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
|
* 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.
|
* 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 task Task struct
|
||||||
* \param alloc_len Size of allocated buffer.
|
* \param alloc_len Size of allocated buffer.
|
||||||
* \return Pointer to buffer or NULL on error.
|
* \return Pointer to buffer or NULL on error.
|
||||||
*/
|
*/
|
||||||
void *spdk_scsi_task_alloc_data(struct spdk_scsi_task *task, uint32_t alloc_len);
|
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,
|
void spdk_scsi_task_build_sense_data(struct spdk_scsi_task *task, int sk, int asc,
|
||||||
int ascq);
|
int ascq);
|
||||||
void spdk_scsi_task_set_status(struct spdk_scsi_task *task, int sc, int sk, int asc,
|
void spdk_scsi_task_set_status(struct spdk_scsi_task *task, int sc, int sk, int asc,
|
||||||
|
@ -184,7 +184,6 @@ static void
|
|||||||
complete_task_with_no_lun(struct spdk_scsi_task *task)
|
complete_task_with_no_lun(struct spdk_scsi_task *task)
|
||||||
{
|
{
|
||||||
uint8_t buffer[36];
|
uint8_t buffer[36];
|
||||||
uint8_t *data;
|
|
||||||
uint32_t allocation_len;
|
uint32_t allocation_len;
|
||||||
uint32_t data_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
|
* must be served with PERIPHERAL QUALIFIER = 0x3 and
|
||||||
* PERIPHERAL DEVICE TYPE = 0x1F.
|
* PERIPHERAL DEVICE TYPE = 0x1F.
|
||||||
*/
|
*/
|
||||||
allocation_len = from_be16(&task->cdb[3]);
|
|
||||||
data_len = sizeof(buffer);
|
data_len = sizeof(buffer);
|
||||||
if (allocation_len > data_len)
|
|
||||||
allocation_len = data_len;
|
|
||||||
|
|
||||||
if (allocation_len) {
|
|
||||||
memset(buffer, 0, data_len);
|
memset(buffer, 0, data_len);
|
||||||
/* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
|
/* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
|
||||||
buffer[0] = 0x03 << 5 | 0x1f;
|
buffer[0] = 0x03 << 5 | 0x1f;
|
||||||
/* ADDITIONAL LENGTH */
|
/* ADDITIONAL LENGTH */
|
||||||
buffer[4] = data_len - 5;
|
buffer[4] = data_len - 5;
|
||||||
|
|
||||||
data = spdk_scsi_task_alloc_data(task, allocation_len);
|
allocation_len = from_be16(&task->cdb[3]);
|
||||||
memcpy(data, buffer, allocation_len);
|
if (spdk_scsi_task_scatter_data(task, buffer, SPDK_MIN(allocation_len, data_len)) >= 0) {
|
||||||
}
|
|
||||||
|
|
||||||
task->data_transferred = data_len;
|
task->data_transferred = data_len;
|
||||||
task->status = SPDK_SCSI_STATUS_GOOD;
|
task->status = SPDK_SCSI_STATUS_GOOD;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* LOGICAL UNIT NOT SUPPORTED */
|
/* LOGICAL UNIT NOT SUPPORTED */
|
||||||
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
|
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
|
||||||
|
@ -1455,9 +1455,17 @@ spdk_bdev_scsi_unmap(struct spdk_bdev *bdev,
|
|||||||
{
|
{
|
||||||
|
|
||||||
uint8_t *data;
|
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 = (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
|
* 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_data_len = from_be16(&data[2]);
|
||||||
bdesc_count = bdesc_data_len / 16;
|
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) {
|
if (bdesc_count > bdev->max_unmap_bdesc_count) {
|
||||||
SPDK_ERRLOG("Error - supported unmap block descriptor count limit"
|
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_ASC_NO_ADDITIONAL_SENSE,
|
||||||
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
|
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
|
||||||
return SPDK_SCSI_TASK_COMPLETE;
|
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,
|
bdesc_count, spdk_bdev_scsi_task_complete,
|
||||||
task);
|
task);
|
||||||
|
|
||||||
@ -1504,7 +1529,6 @@ spdk_bdev_scsi_process_block(struct spdk_bdev *bdev,
|
|||||||
uint32_t xfer_len;
|
uint32_t xfer_len;
|
||||||
uint32_t len = 0;
|
uint32_t len = 0;
|
||||||
uint8_t *cdb = task->cdb;
|
uint8_t *cdb = task->cdb;
|
||||||
uint8_t *data;
|
|
||||||
|
|
||||||
/* XXX: We need to support FUA bit for writes! */
|
/* XXX: We need to support FUA bit for writes! */
|
||||||
switch (cdb[0]) {
|
switch (cdb[0]) {
|
||||||
@ -1547,13 +1571,11 @@ spdk_bdev_scsi_process_block(struct spdk_bdev *bdev,
|
|||||||
}
|
}
|
||||||
to_be32(&buffer[4], bdev->blocklen);
|
to_be32(&buffer[4], bdev->blocklen);
|
||||||
|
|
||||||
len = task->length < 8 ? task->length : sizeof(buffer);
|
len = SPDK_MIN(task->length, sizeof(buffer));
|
||||||
if (len) {
|
if (spdk_scsi_task_scatter_data(task, buffer, len) < 0)
|
||||||
data = spdk_scsi_task_alloc_data(task, len);
|
break;
|
||||||
memcpy(data, buffer, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
task->data_transferred = 8;
|
task->data_transferred = len;
|
||||||
task->status = SPDK_SCSI_STATUS_GOOD;
|
task->status = SPDK_SCSI_STATUS_GOOD;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1574,12 +1596,9 @@ spdk_bdev_scsi_process_block(struct spdk_bdev *bdev,
|
|||||||
buffer[14] |= 1 << 7;
|
buffer[14] |= 1 << 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = from_be32(&cdb[10]);
|
len = SPDK_MIN(from_be32(&cdb[10]), sizeof(buffer));
|
||||||
if (len) {
|
if (spdk_scsi_task_scatter_data(task, buffer, len) < 0)
|
||||||
len = len < sizeof(buffer) ? len : sizeof(buffer);
|
break;
|
||||||
data = spdk_scsi_task_alloc_data(task, len);
|
|
||||||
memcpy(data, buffer, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
task->data_transferred = len;
|
task->data_transferred = len;
|
||||||
task->status = SPDK_SCSI_STATUS_GOOD;
|
task->status = SPDK_SCSI_STATUS_GOOD;
|
||||||
@ -1618,38 +1637,48 @@ spdk_bdev_scsi_process_block(struct spdk_bdev *bdev,
|
|||||||
return SPDK_SCSI_TASK_COMPLETE;
|
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
|
static int
|
||||||
spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
|
spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
|
||||||
struct spdk_scsi_task *task)
|
struct spdk_scsi_task *task)
|
||||||
{
|
{
|
||||||
int alloc_len;
|
int alloc_len = -1;
|
||||||
int data_len;
|
int data_len = -1;
|
||||||
uint8_t *cdb = task->cdb;
|
uint8_t *cdb = task->cdb;
|
||||||
uint8_t *data;
|
uint8_t *data = NULL;
|
||||||
|
int rc = 0;
|
||||||
int pllen, md = 0;
|
int pllen, md = 0;
|
||||||
int pf, sp;
|
int pf, sp;
|
||||||
int bdlen, llba;
|
int bdlen, llba;
|
||||||
int dbd, pc, page, subpage;
|
int dbd, pc, page, subpage;
|
||||||
int cmd_parsed = 0;
|
int cmd_parsed = 0;
|
||||||
|
|
||||||
|
|
||||||
switch (cdb[0]) {
|
switch (cdb[0]) {
|
||||||
case SPDK_SPC_INQUIRY:
|
case SPDK_SPC_INQUIRY:
|
||||||
alloc_len = from_be16(&cdb[3]);
|
alloc_len = from_be16(&cdb[3]);
|
||||||
if (alloc_len) {
|
data_len = SPDK_MAX(4096, alloc_len);
|
||||||
data = spdk_scsi_task_alloc_data(task, alloc_len);
|
data = spdk_zmalloc(data_len, 0, NULL);
|
||||||
} else {
|
rc = spdk_bdev_scsi_inquiry(bdev, task, cdb, data, data_len);
|
||||||
data = NULL;
|
data_len = SPDK_MIN(rc, data_len);
|
||||||
}
|
if (rc < 0) {
|
||||||
|
|
||||||
data_len = spdk_bdev_scsi_inquiry(bdev, task, cdb,
|
|
||||||
data, alloc_len);
|
|
||||||
if (data_len < 0) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
SPDK_TRACEDUMP(SPDK_TRACE_DEBUG, "INQUIRY", data, data_len);
|
SPDK_TRACEDUMP(SPDK_TRACE_DEBUG, "INQUIRY", data, data_len);
|
||||||
task->data_transferred = (uint64_t)data_len;
|
|
||||||
task->status = SPDK_SCSI_STATUS_GOOD;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPDK_SPC_REPORT_LUNS: {
|
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);
|
SPDK_TRACELOG(SPDK_TRACE_DEBUG, "sel=%x\n", sel);
|
||||||
|
|
||||||
alloc_len = from_be32(&cdb[6]);
|
alloc_len = from_be32(&cdb[6]);
|
||||||
if (alloc_len < 16) {
|
rc = spdk_bdev_scsi_check_len(task, alloc_len, 16);
|
||||||
/* INVALID FIELD IN CDB */
|
if (rc < 0) {
|
||||||
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
data = spdk_scsi_task_alloc_data(task, alloc_len);
|
data_len = SPDK_MAX(4096, alloc_len);
|
||||||
data_len = spdk_bdev_scsi_report_luns(task->lun, sel, data, task->alloc_len);
|
data = spdk_zmalloc(data_len, 0, NULL);
|
||||||
if (data_len < 0) {
|
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_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
|
||||||
SPDK_SCSI_SENSE_NO_SENSE,
|
SPDK_SCSI_SENSE_NO_SENSE,
|
||||||
SPDK_SCSI_ASC_NO_ADDITIONAL_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);
|
SPDK_TRACEDUMP(SPDK_TRACE_DEBUG, "REPORT LUNS", data, data_len);
|
||||||
task->data_transferred = (uint64_t)data_len;
|
|
||||||
task->status = SPDK_SCSI_STATUS_GOOD;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SPDK_SPC_MODE_SELECT_6:
|
case SPDK_SPC_MODE_SELECT_6:
|
||||||
case SPDK_SPC_MODE_SELECT_10:
|
case SPDK_SPC_MODE_SELECT_10:
|
||||||
data = task->iovs[0].iov_base;
|
|
||||||
|
|
||||||
if (cdb[0] == SPDK_SPC_MODE_SELECT_6) {
|
if (cdb[0] == SPDK_SPC_MODE_SELECT_6) {
|
||||||
|
/* MODE_SELECT(6) must have at least a 4 byte header. */
|
||||||
md = 4;
|
md = 4;
|
||||||
pllen = cdb[4];
|
pllen = cdb[4];
|
||||||
} else {
|
} else {
|
||||||
|
/* MODE_SELECT(10) must have at least an 8 byte header. */
|
||||||
md = 8;
|
md = 8;
|
||||||
pllen = from_be16(&cdb[7]);
|
pllen = from_be16(&cdb[7]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pllen == 0) {
|
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;
|
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) {
|
if (cdb[0] == SPDK_SPC_MODE_SELECT_6) {
|
||||||
|
rc = spdk_bdev_scsi_check_len(task, data_len, 4);
|
||||||
|
if (rc >= 0) {
|
||||||
bdlen = data[3];
|
bdlen = data[3];
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
rc = spdk_bdev_scsi_check_len(task, data_len, 8);
|
||||||
|
if (rc >= 0) {
|
||||||
bdlen = from_be16(&data[6]);
|
bdlen = from_be16(&data[6]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
pf = !!(cdb[1] & 0x10);
|
pf = !!(cdb[1] & 0x10);
|
||||||
sp = !!(cdb[1] & 0x1);
|
sp = !!(cdb[1] & 0x1);
|
||||||
|
|
||||||
/* page data */
|
/* page data */
|
||||||
data_len = spdk_bdev_scsi_mode_select_page(
|
rc = spdk_bdev_scsi_mode_select_page(
|
||||||
bdev, cdb,
|
bdev, cdb,
|
||||||
pf, sp,
|
pf, sp,
|
||||||
&data[md + bdlen],
|
&data[md + bdlen],
|
||||||
pllen - (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_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
|
||||||
SPDK_SCSI_SENSE_NO_SENSE,
|
SPDK_SCSI_SENSE_NO_SENSE,
|
||||||
SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
|
SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
|
||||||
@ -1741,8 +1769,8 @@ spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
task->data_transferred = pllen;
|
rc = pllen;
|
||||||
task->status = SPDK_SCSI_STATUS_GOOD;
|
data_len = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPDK_SPC_MODE_SENSE_6:
|
case SPDK_SPC_MODE_SENSE_6:
|
||||||
@ -1764,11 +1792,23 @@ spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
|
|||||||
subpage = cdb[3];
|
subpage = cdb[3];
|
||||||
|
|
||||||
/* First call with no buffer to discover needed buffer size */
|
/* 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,
|
cdb, dbd, llba, pc,
|
||||||
page, subpage,
|
page, subpage,
|
||||||
NULL);
|
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 */
|
/* INVALID FIELD IN CDB */
|
||||||
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
|
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
|
||||||
SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
|
SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
|
||||||
@ -1776,29 +1816,6 @@ spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
|
|||||||
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
|
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
|
||||||
break;
|
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;
|
break;
|
||||||
|
|
||||||
case SPDK_SPC_REQUEST_SENSE: {
|
case SPDK_SPC_REQUEST_SENSE: {
|
||||||
@ -1816,7 +1833,6 @@ spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
alloc_len = cdb[4];
|
alloc_len = cdb[4];
|
||||||
data = spdk_scsi_task_alloc_data(task, alloc_len);
|
|
||||||
|
|
||||||
/* NO ADDITIONAL SENSE INFORMATION */
|
/* NO ADDITIONAL SENSE INFORMATION */
|
||||||
sk = SPDK_SCSI_SENSE_NO_SENSE;
|
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);
|
spdk_scsi_task_build_sense_data(task, sk, asc, ascq);
|
||||||
|
|
||||||
data_len = task->sense_data_len;
|
data_len = task->sense_data_len;
|
||||||
|
data = spdk_zmalloc(data_len, 0, NULL);
|
||||||
memcpy(data, task->sense_data, data_len);
|
memcpy(data, task->sense_data, data_len);
|
||||||
task->data_transferred = (uint64_t)data_len;
|
|
||||||
task->status = SPDK_SCSI_STATUS_GOOD;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1845,6 +1860,7 @@ spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
|
|||||||
SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
|
SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
|
||||||
SPDK_SCSI_ASC_INVALID_COMMAND_OPERATION_CODE,
|
SPDK_SCSI_ASC_INVALID_COMMAND_OPERATION_CODE,
|
||||||
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
|
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
|
||||||
|
rc = -1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPDK_SPC_TEST_UNIT_READY:
|
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");
|
SPDK_TRACELOG(SPDK_TRACE_SCSI, "START_STOP_UNIT\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
task->data_transferred = 0;
|
rc = 0;
|
||||||
task->status = SPDK_SCSI_STATUS_GOOD;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return SPDK_SCSI_TASK_UNKNOWN;
|
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;
|
return SPDK_SCSI_TASK_COMPLETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +56,25 @@
|
|||||||
|
|
||||||
#include "spdk_internal/log.h"
|
#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 {
|
enum {
|
||||||
SPDK_SCSI_TASK_UNKNOWN = -1,
|
SPDK_SCSI_TASK_UNKNOWN = -1,
|
||||||
SPDK_SCSI_TASK_COMPLETE,
|
SPDK_SCSI_TASK_COMPLETE,
|
||||||
|
@ -122,21 +122,87 @@ spdk_scsi_task_alloc_data(struct spdk_scsi_task *task, uint32_t alloc_len)
|
|||||||
{
|
{
|
||||||
assert(task->alloc_len == 0);
|
assert(task->alloc_len == 0);
|
||||||
|
|
||||||
/* Only one buffer is managable */
|
task->iov.iov_base = spdk_zmalloc(alloc_len, 0, NULL);
|
||||||
if (task->iovcnt != 1) {
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is workaround for buffers shorter than 4kb */
|
buf = spdk_malloc(buf_len, 0, NULL);
|
||||||
if (task->iov.iov_base == NULL) {
|
if (buf == NULL) {
|
||||||
task->iov.iov_base = spdk_zmalloc(alloc_len, 0, NULL);
|
*len = -1;
|
||||||
task->alloc_len = alloc_len;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
task->iov.iov_len = alloc_len;
|
pos = buf;
|
||||||
assert(&task->iov == task->iovs);
|
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
|
void
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
|
|
||||||
#include "spdk_cunit.h"
|
#include "spdk_cunit.h"
|
||||||
|
|
||||||
|
#include "task.c"
|
||||||
#include "lun.c"
|
#include "lun.c"
|
||||||
#include "lun_db.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 *
|
static struct spdk_scsi_task *
|
||||||
spdk_get_task(uint32_t *owner_task_ctr)
|
spdk_get_task(uint32_t *owner_task_ctr)
|
||||||
{
|
{
|
||||||
@ -65,43 +72,41 @@ spdk_get_task(uint32_t *owner_task_ctr)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
task->id = g_task_count;
|
spdk_scsi_task_construct(task, &g_task_count, NULL);
|
||||||
task->iovs = &task->iov;
|
task->free_fn = spdk_lun_ut_free_task;
|
||||||
task->iovcnt = 1;
|
|
||||||
|
|
||||||
g_task_count++;
|
|
||||||
|
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void *
|
||||||
spdk_scsi_task_put(struct spdk_scsi_task *task)
|
spdk_malloc(size_t size, size_t align, uint64_t *phys_addr)
|
||||||
{
|
{
|
||||||
g_task_count--;
|
void *buf = malloc(size);
|
||||||
if (task->alloc_len) {
|
if (phys_addr)
|
||||||
free(task->iov.iov_base);
|
*phys_addr = (uint64_t)buf;
|
||||||
}
|
return buf;
|
||||||
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 *
|
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)
|
void *buf = calloc(size, 1);
|
||||||
alloc_len = 4096;
|
if (phys_addr)
|
||||||
|
*phys_addr = (uint64_t)buf;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
task->iovs = &task->iov;
|
void
|
||||||
task->iov.iov_base = malloc(alloc_len);
|
spdk_free(void *buf)
|
||||||
task->iov.iov_len = alloc_len;
|
{
|
||||||
task->alloc_len = alloc_len;
|
free(buf);
|
||||||
return task->iov.iov_base;
|
}
|
||||||
|
|
||||||
|
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,
|
void spdk_scsi_dev_queue_mgmt_task(struct spdk_scsi_dev *dev,
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "task.c"
|
||||||
#include "scsi_bdev.c"
|
#include "scsi_bdev.c"
|
||||||
|
|
||||||
#include "spdk_cunit.h"
|
#include "spdk_cunit.h"
|
||||||
@ -43,12 +44,23 @@ SPDK_LOG_REGISTER_TRACE_FLAG("scsi", SPDK_TRACE_SCSI)
|
|||||||
|
|
||||||
struct spdk_scsi_globals g_spdk_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 *
|
void *
|
||||||
spdk_zmalloc(size_t size, size_t align, uint64_t *phys_addr)
|
spdk_zmalloc(size_t size, size_t align, uint64_t *phys_addr)
|
||||||
{
|
{
|
||||||
void *buf = calloc(size, 1);
|
void *buf = calloc(size, 1);
|
||||||
if (phys_addr)
|
if (phys_addr)
|
||||||
*phys_addr = (uint64_t)buf;
|
*phys_addr = (uint64_t)buf;
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,6 +69,14 @@ spdk_free(void *buf)
|
|||||||
{
|
{
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
spdk_bdev_free_io(struct spdk_bdev_io *bdev_io)
|
||||||
|
{
|
||||||
|
CU_ASSERT(0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
spdk_scsi_lun_clear_all(struct spdk_scsi_lun *lun)
|
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
|
static void
|
||||||
spdk_put_task(struct spdk_scsi_task *task)
|
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;
|
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
|
void
|
||||||
spdk_scsi_nvme_translate(struct spdk_bdev_io *bdev_io, int *sc, int *sk,
|
spdk_scsi_nvme_translate(struct spdk_bdev_io *bdev_io, int *sc, int *sk,
|
||||||
int *asc, int *ascq)
|
int *asc, int *ascq)
|
||||||
|
Loading…
Reference in New Issue
Block a user