scsi: translate nvme error to scsi error (#54)

This patch translates NVMe status code to SCSI sense according to NVM
Express: SCSI Translation Reference.

http://nvmexpress.org/wp-content/uploads/NVM_Express_-_SCSI_Translation_Reference-1_5_20150624_Gold.pdf
This commit is contained in:
Tsuyoshi Uchida 2016-10-28 12:56:36 -07:00 committed by Daniel Verkamp
parent c257e5b4ad
commit a5f0327897
19 changed files with 668 additions and 69 deletions

View File

@ -137,6 +137,7 @@ struct spdk_bdev_fn_table {
/** Blockdev I/O completion status */
enum spdk_bdev_io_status {
SPDK_BDEV_IO_STATUS_NVME_ERROR = -2,
SPDK_BDEV_IO_STATUS_FAILED = -1,
SPDK_BDEV_IO_STATUS_PENDING = 0,
SPDK_BDEV_IO_STATUS_SUCCESS = 1,
@ -242,6 +243,17 @@ struct spdk_bdev_io {
} reset;
} u;
/** Error information from a device */
union {
/** Only valid when status is SPDK_BDEV_IO_STATUS_NVME_ERROR */
struct {
/** NVMe status code type */
int sct;
/** NVMe status code */
int sc;
} nvme;
} error;
/** User function that will be called when this completes */
spdk_bdev_io_completion_cb cb;

View File

@ -260,8 +260,8 @@ void spdk_scsi_task_alloc_data(struct spdk_scsi_task *task, uint32_t alloc_len,
uint8_t **data);
void spdk_scsi_task_build_sense_data(struct spdk_scsi_task *task, int sk, int asc,
int ascq);
void spdk_scsi_task_set_check_condition(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,
int ascq);
static inline struct spdk_scsi_task *
spdk_scsi_task_get_primary(struct spdk_scsi_task *task)

View File

@ -85,6 +85,38 @@ enum spdk_scsi_sense {
SPDK_SCSI_SENSE_MISCOMPARE = 0x0e,
};
enum spdk_scsi_asc {
SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE = 0x00,
SPDK_SCSI_ASC_PERIPHERAL_DEVICE_WRITE_FAULT = 0x03,
SPDK_SCSI_ASC_LOGICAL_UNIT_NOT_READY = 0x04,
SPDK_SCSI_ASC_WARNING = 0x0b,
SPDK_SCSI_ASC_LOGICAL_BLOCK_GUARD_CHECK_FAILED = 0x10,
SPDK_SCSI_ASC_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED = 0x10,
SPDK_SCSI_ASC_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED = 0x10,
SPDK_SCSI_ASC_UNRECOVERED_READ_ERROR = 0x11,
SPDK_SCSI_ASC_MISCOMPARE_DURING_VERIFY_OPERATION = 0x1d,
SPDK_SCSI_ASC_INVALID_COMMAND_OPERATION_CODE = 0x20,
SPDK_SCSI_ASC_ACCESS_DENIED = 0x20,
SPDK_SCSI_ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE = 0x21,
SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB = 0x24,
SPDK_SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED = 0x25,
SPDK_SCSI_ASC_WRITE_PROTECTED = 0x27,
SPDK_SCSI_ASC_FORMAT_COMMAND_FAILED = 0x31,
SPDK_SCSI_ASC_INTERNAL_TARGET_FAILURE = 0x44,
};
enum spdk_scsi_ascq {
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE = 0x00,
SPDK_SCSI_ASCQ_BECOMING_READY = 0x01,
SPDK_SCSI_ASCQ_FORMAT_COMMAND_FAILED = 0x01,
SPDK_SCSI_ASCQ_LOGICAL_BLOCK_GUARD_CHECK_FAILED = 0x01,
SPDK_SCSI_ASCQ_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED = 0x02,
SPDK_SCSI_ASCQ_NO_ACCESS_RIGHTS = 0x02,
SPDK_SCSI_ASCQ_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED = 0x03,
SPDK_SCSI_ASCQ_POWER_LOSS_EXPECTED = 0x08,
SPDK_SCSI_ASCQ_INVALID_LU_IDENTIFIER = 0x09,
};
enum spdk_spc_opcode {
/* SPC3 related */
SPDK_SPC_ACCESS_CONTROL_IN = 0x86,

View File

@ -602,16 +602,18 @@ nvme_ctrlr_initialize_blockdevs(struct spdk_nvme_ctrlr *ctrlr, int bdev_per_ns,
static void
queued_done(void *ref, const struct spdk_nvme_cpl *cpl)
{
struct nvme_blockio *bio = ref;
struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx((struct nvme_blockio *)ref);
enum spdk_bdev_io_status status;
if (spdk_nvme_cpl_is_error(cpl)) {
status = SPDK_BDEV_IO_STATUS_FAILED;
bdev_io->error.nvme.sct = cpl->status.sct;
bdev_io->error.nvme.sc = cpl->status.sc;
status = SPDK_BDEV_IO_STATUS_NVME_ERROR;
} else {
status = SPDK_BDEV_IO_STATUS_SUCCESS;
}
spdk_bdev_io_complete(spdk_bdev_io_from_ctx(bio), status);
spdk_bdev_io_complete(bdev_io, status);
}
static void

View File

@ -35,7 +35,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
CFLAGS += $(ENV_CFLAGS)
C_SRCS = dev.c lun.c lun_db.c port.c scsi.c scsi_bdev.c scsi_rpc.c task.c
C_SRCS = dev.c lun.c lun_db.c port.c scsi.c scsi_bdev.c scsi_nvme.c scsi_rpc.c task.c
LIBNAME = scsi
include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk

View File

@ -66,14 +66,19 @@ spdk_scsi_lun_clear_all(struct spdk_scsi_lun *lun)
TAILQ_FOREACH_SAFE(task, &lun->tasks, scsi_link, task_tmp) {
TAILQ_REMOVE(&lun->tasks, task, scsi_link);
spdk_scsi_task_set_check_condition(task, SPDK_SCSI_SENSE_ABORTED_COMMAND, 0, 0);
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_ABORTED_COMMAND,
SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
spdk_scsi_lun_complete_task(lun, task);
}
TAILQ_FOREACH_SAFE(task, &lun->pending_tasks, scsi_link, task_tmp) {
TAILQ_REMOVE(&lun->pending_tasks, task, scsi_link);
spdk_scsi_task_set_check_condition(task, SPDK_SCSI_SENSE_ABORTED_COMMAND,
0, 0);
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_ABORTED_COMMAND,
SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
spdk_scsi_lun_complete_task(lun, task);
}
}
@ -200,8 +205,10 @@ complete_task_with_no_lun(struct spdk_scsi_task *task)
task->status = SPDK_SCSI_STATUS_GOOD;
} else {
/* LOGICAL UNIT NOT SUPPORTED */
spdk_scsi_task_set_check_condition(task,
SPDK_SCSI_SENSE_ILLEGAL_REQUEST, 0x25, 0x00);
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
SPDK_SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
task->data_transferred = 0;
}
spdk_scsi_lun_complete_task(NULL, task);

View File

@ -175,9 +175,10 @@ spdk_bdev_scsi_inquiry(struct spdk_bdev *bdev, struct spdk_scsi_task *task,
evpd = inq->evpd & 0x1;
if (!evpd && pc) {
spdk_scsi_task_set_check_condition(task,
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
0x24, 0x0);
SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
return -1;
}
@ -246,9 +247,10 @@ spdk_bdev_scsi_inquiry(struct spdk_bdev *bdev, struct spdk_scsi_task *task,
len += sizeof(struct spdk_scsi_desig_desc) + 4;
len += sizeof(struct spdk_scsi_desig_desc) + 4;
if (sizeof(struct spdk_scsi_vpd_page) + len > task->alloc_len) {
spdk_scsi_task_set_check_condition(task,
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
0x24, 0x0);
SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
return -1;
}
@ -361,9 +363,10 @@ spdk_bdev_scsi_inquiry(struct spdk_bdev *bdev, struct spdk_scsi_task *task,
/* should not exceed the data_in buffer length */
if (sizeof(struct spdk_scsi_vpd_page) + len > alloc_len) {
spdk_scsi_task_set_check_condition(task,
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
0x24, 0x0);
SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
return -1;
}
to_be16(vpage->alloc_len, len);
@ -770,9 +773,10 @@ spdk_bdev_scsi_inquiry(struct spdk_bdev *bdev, struct spdk_scsi_task *task,
inq_error:
task->data_transferred = 0;
spdk_scsi_task_set_check_condition(task,
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_NO_SENSE,
0x0, 0x0);
SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
return -1;
}
@ -1279,16 +1283,23 @@ spdk_bdev_scsi_task_complete(spdk_event_t event)
enum spdk_bdev_io_status status = bdev_io->status;
if (task->type == SPDK_SCSI_TASK_TYPE_CMD) {
if (status != SPDK_BDEV_IO_STATUS_SUCCESS) {
spdk_scsi_task_set_check_condition(task,
SPDK_SCSI_SENSE_ABORTED_COMMAND, 0, 0);
}
int sc, sk, asc, ascq;
/* If status was not set to CHECK_CONDITION yet, then we can set
* status to GOOD.
*/
if (task->status != SPDK_SCSI_STATUS_CHECK_CONDITION) {
switch (bdev_io->status) {
case SPDK_BDEV_IO_STATUS_SUCCESS:
task->status = SPDK_SCSI_STATUS_GOOD;
break;
case SPDK_BDEV_IO_STATUS_NVME_ERROR:
spdk_scsi_nvme_translate(bdev_io, &sc, &sk, &asc, &ascq);
spdk_scsi_task_set_status(task, sc, sk, asc, ascq);
break;
default:
sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
sk = SPDK_SCSI_SENSE_ABORTED_COMMAND;
asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE;
ascq = SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
spdk_scsi_task_set_status(task, sc, sk, asc, ascq);
break;
}
/* command completed. remove from outstanding task list */
@ -1427,7 +1438,10 @@ spdk_bdev_scsi_sync(struct spdk_bdev *bdev, struct spdk_scsi_task *task,
if (lba >= maxlba || llen > maxlba || lba > (maxlba - llen)) {
SPDK_ERRLOG("end of media\n");
spdk_scsi_task_set_check_condition(task, SPDK_SCSI_SENSE_NO_SENSE, 0x0, 0x0);
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_NO_SENSE,
SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
return SPDK_SCSI_TASK_COMPLETE;
}
@ -1436,7 +1450,10 @@ spdk_bdev_scsi_sync(struct spdk_bdev *bdev, struct spdk_scsi_task *task,
if (!task->blockdev_io) {
SPDK_ERRLOG("spdk_bdev_flush() failed\n");
spdk_scsi_task_set_check_condition(task, SPDK_SCSI_SENSE_NO_SENSE, 0x0, 0x0);
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_NO_SENSE,
SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
return SPDK_SCSI_TASK_COMPLETE;
}
task->data_transferred = 0;
@ -1457,13 +1474,19 @@ spdk_bdev_scsi_readwrite(struct spdk_bdev *bdev,
rc = spdk_bdev_scsi_write(bdev, task, lba, xfer_len);
} else {
SPDK_ERRLOG("Incorrect data direction\n");
spdk_scsi_task_set_check_condition(task, SPDK_SCSI_SENSE_NO_SENSE, 0x0, 0x0);
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_NO_SENSE,
SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
return SPDK_SCSI_TASK_COMPLETE;
}
if (rc < 0) {
SPDK_ERRLOG("disk op (rw) failed\n");
spdk_scsi_task_set_check_condition(task, SPDK_SCSI_SENSE_NO_SENSE, 0x0, 0x0);
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_NO_SENSE,
SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
return SPDK_SCSI_TASK_COMPLETE;
} else {
@ -1497,9 +1520,10 @@ spdk_bdev_scsi_unmap(struct spdk_bdev *bdev,
if (bdesc_count > bdev->max_unmap_bdesc_count) {
SPDK_ERRLOG("Error - supported unmap block descriptor count limit"
" is %u\n", bdev->max_unmap_bdesc_count);
spdk_scsi_task_set_check_condition(task,
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_NO_SENSE,
0x0, 0x0);
SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
return SPDK_SCSI_TASK_COMPLETE;
}
@ -1509,9 +1533,10 @@ spdk_bdev_scsi_unmap(struct spdk_bdev *bdev,
if (!task->blockdev_io) {
SPDK_ERRLOG("SCSI Unmapping failed\n");
spdk_scsi_task_set_check_condition(task,
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_NO_SENSE,
0x0, 0x0);
SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
return SPDK_SCSI_TASK_COMPLETE;
}
@ -1659,15 +1684,20 @@ spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
alloc_len = from_be32(&cdb[6]);
if (alloc_len < 16) {
/* INVALID FIELD IN CDB */
spdk_scsi_task_set_check_condition(task,
SPDK_SCSI_SENSE_ILLEGAL_REQUEST, 0x24, 0x00);
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;
}
spdk_scsi_task_alloc_data(task, alloc_len, &data);
data_len = spdk_bdev_scsi_report_luns(task->lun, sel, data, task->alloc_len);
if (data_len < 0) {
spdk_scsi_task_set_check_condition(task, SPDK_SCSI_SENSE_NO_SENSE, 0x0, 0x0);
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_NO_SENSE,
SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
break;
}
@ -1696,14 +1726,18 @@ spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
} 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_check_condition(task,
SPDK_SCSI_SENSE_ILLEGAL_REQUEST, 0x24, 0x00);
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_check_condition(task,
SPDK_SCSI_SENSE_ILLEGAL_REQUEST, 0x24, 0x00);
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;
}
@ -1723,9 +1757,10 @@ spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
&data[md + bdlen],
pllen - (md + bdlen));
if (data_len != 0) {
spdk_scsi_task_set_check_condition(task,
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_NO_SENSE,
0x0, 0x0);
SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
break;
}
@ -1771,8 +1806,10 @@ spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
if (data_len < 0) {
/* INVALID FIELD IN CDB */
spdk_scsi_task_set_check_condition(task,
SPDK_SCSI_SENSE_ILLEGAL_REQUEST, 0x24, 0x00);
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;
}
@ -1787,8 +1824,10 @@ spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
desc = cdb[1] & 0x1;
if (desc != 0) {
/* INVALID FIELD IN CDB */
spdk_scsi_task_set_check_condition(task,
SPDK_SCSI_SENSE_ILLEGAL_REQUEST, 0x24, 0x00);
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;
}
@ -1819,8 +1858,10 @@ spdk_bdev_scsi_process_primary(struct spdk_bdev *bdev,
}
/* INVALID COMMAND OPERATION CODE */
spdk_scsi_task_set_check_condition(task,
SPDK_SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
SPDK_SCSI_ASC_INVALID_COMMAND_OPERATION_CODE,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
break;
case SPDK_SPC_TEST_UNIT_READY:
@ -1851,9 +1892,10 @@ spdk_bdev_scsi_execute(struct spdk_bdev *bdev, struct spdk_scsi_task *task)
if ((rc = spdk_bdev_scsi_process_primary(bdev, task)) == SPDK_SCSI_TASK_UNKNOWN) {
SPDK_TRACELOG(SPDK_TRACE_SCSI, "unsupported SCSI OP=0x%x\n", task->cdb[0]);
/* INVALID COMMAND OPERATION CODE */
spdk_scsi_task_set_check_condition(task,
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_CHECK_CONDITION,
SPDK_SCSI_SENSE_ILLEGAL_REQUEST,
0x20, 0x00);
SPDK_SCSI_ASC_INVALID_COMMAND_OPERATION_CODE,
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
return SPDK_SCSI_TASK_COMPLETE;
}
}

View File

@ -99,6 +99,8 @@ struct spdk_scsi_dev *spdk_scsi_dev_get_list(void);
int spdk_bdev_scsi_execute(struct spdk_bdev *bdev, struct spdk_scsi_task *task);
int spdk_bdev_scsi_reset(struct spdk_bdev *bdev, struct spdk_scsi_task *task);
void spdk_scsi_nvme_translate(struct spdk_bdev_io *bdev_io, int *sc, int *sk, int *asc, int *ascq);
struct spdk_scsi_parameters {
uint32_t max_unmap_lba_count;
uint32_t max_unmap_block_descriptor_count;

261
lib/scsi/scsi_nvme.c Normal file
View File

@ -0,0 +1,261 @@
/*-
* BSD LICENSE
*
* Copyright (c) 2016 FUJITSU LIMITED, All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "scsi_internal.h"
#include "spdk/nvme_spec.h"
void
spdk_scsi_nvme_translate(struct spdk_bdev_io *bdev_io, int *sc, int *sk,
int *asc, int *ascq)
{
int nvme_sct = bdev_io->error.nvme.sct;
int nvme_sc = bdev_io->error.nvme.sc;
switch (nvme_sct) {
case SPDK_NVME_SCT_GENERIC:
switch (nvme_sc) {
case SPDK_NVME_SC_SUCCESS:
*sc = SPDK_SCSI_STATUS_GOOD;
*sk = SPDK_SCSI_SENSE_NO_SENSE;
*asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE;
*ascq = SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case SPDK_NVME_SC_INVALID_OPCODE:
*sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
*sk = SPDK_SCSI_SENSE_ILLEGAL_REQUEST;
*asc = SPDK_SCSI_ASC_INVALID_COMMAND_OPERATION_CODE;
*ascq = SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case SPDK_NVME_SC_INVALID_FIELD:
*sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
*sk = SPDK_SCSI_SENSE_ILLEGAL_REQUEST;
*asc = SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB;
*ascq = SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case SPDK_NVME_SC_DATA_TRANSFER_ERROR:
case SPDK_NVME_SC_CAPACITY_EXCEEDED:
*sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
*sk = SPDK_SCSI_SENSE_MEDIUM_ERROR;
*asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE;
*ascq = SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case SPDK_NVME_SC_ABORTED_POWER_LOSS:
*sc = SPDK_SCSI_STATUS_TASK_ABORTED;
*sk = SPDK_SCSI_SENSE_ABORTED_COMMAND;
*asc = SPDK_SCSI_ASC_WARNING;
*ascq = SPDK_SCSI_ASCQ_POWER_LOSS_EXPECTED;
break;
case SPDK_NVME_SC_INTERNAL_DEVICE_ERROR:
*sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
*sk = SPDK_SCSI_SENSE_HARDWARE_ERROR;
*asc = SPDK_SCSI_ASC_INTERNAL_TARGET_FAILURE;
*ascq = SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case SPDK_NVME_SC_ABORTED_BY_REQUEST:
case SPDK_NVME_SC_ABORTED_SQ_DELETION:
case SPDK_NVME_SC_ABORTED_FAILED_FUSED:
case SPDK_NVME_SC_ABORTED_MISSING_FUSED:
*sc = SPDK_SCSI_STATUS_TASK_ABORTED;
*sk = SPDK_SCSI_SENSE_ABORTED_COMMAND;
*asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE;
*ascq = SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case SPDK_NVME_SC_INVALID_NAMESPACE_OR_FORMAT:
*sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
*sk = SPDK_SCSI_SENSE_ILLEGAL_REQUEST;
*asc = SPDK_SCSI_ASC_ACCESS_DENIED;
*ascq = SPDK_SCSI_ASCQ_INVALID_LU_IDENTIFIER;
break;
case SPDK_NVME_SC_LBA_OUT_OF_RANGE:
*sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
*sk = SPDK_SCSI_SENSE_ILLEGAL_REQUEST;
*asc = SPDK_SCSI_ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
*ascq = SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case SPDK_NVME_SC_NAMESPACE_NOT_READY:
*sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
*sk = SPDK_SCSI_SENSE_NOT_READY;
*asc = SPDK_SCSI_ASC_LOGICAL_UNIT_NOT_READY;
*ascq = SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case SPDK_NVME_SC_RESERVATION_CONFLICT:
*sc = SPDK_SCSI_STATUS_RESERVATION_CONFLICT;
*sk = SPDK_SCSI_SENSE_NO_SENSE;
*asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE;
*ascq = SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case SPDK_NVME_SC_COMMAND_ID_CONFLICT:
case SPDK_NVME_SC_COMMAND_SEQUENCE_ERROR:
case SPDK_NVME_SC_INVALID_SGL_SEG_DESCRIPTOR:
case SPDK_NVME_SC_INVALID_NUM_SGL_DESCIRPTORS:
case SPDK_NVME_SC_DATA_SGL_LENGTH_INVALID:
case SPDK_NVME_SC_METADATA_SGL_LENGTH_INVALID:
case SPDK_NVME_SC_SGL_DESCRIPTOR_TYPE_INVALID:
case SPDK_NVME_SC_INVALID_CONTROLLER_MEM_BUF:
case SPDK_NVME_SC_INVALID_PRP_OFFSET:
case SPDK_NVME_SC_ATOMIC_WRITE_UNIT_EXCEEDED:
case SPDK_NVME_SC_INVALID_SGL_OFFSET:
case SPDK_NVME_SC_INVALID_SGL_SUBTYPE:
case SPDK_NVME_SC_HOSTID_INCONSISTENT_FORMAT:
case SPDK_NVME_SC_KEEP_ALIVE_EXPIRED:
case SPDK_NVME_SC_KEEP_ALIVE_INVALID:
case SPDK_NVME_SC_FORMAT_IN_PROGRESS:
default:
*sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
*sk = SPDK_SCSI_SENSE_ILLEGAL_REQUEST;
*asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE;
*ascq = SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
}
break;
case SPDK_NVME_SCT_COMMAND_SPECIFIC:
switch (nvme_sc) {
case SPDK_NVME_SC_COMPLETION_QUEUE_INVALID:
case SPDK_NVME_SC_ABORT_COMMAND_LIMIT_EXCEEDED:
*sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
*sk = SPDK_SCSI_SENSE_ILLEGAL_REQUEST;
*asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE;
*ascq = SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case SPDK_NVME_SC_INVALID_FORMAT:
*sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
*sk = SPDK_SCSI_SENSE_ILLEGAL_REQUEST;
*asc = SPDK_SCSI_ASC_FORMAT_COMMAND_FAILED;
*ascq = SPDK_SCSI_ASCQ_FORMAT_COMMAND_FAILED;
break;
case SPDK_NVME_SC_CONFLICTING_ATTRIBUTES:
*sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
*sk = SPDK_SCSI_SENSE_ILLEGAL_REQUEST;
*asc = SPDK_SCSI_ASC_INVALID_FIELD_IN_CDB;
*ascq = SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case SPDK_NVME_SC_ATTEMPTED_WRITE_TO_RO_PAGE:
*sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
*sk = SPDK_SCSI_SENSE_DATA_PROTECT;
*asc = SPDK_SCSI_ASC_WRITE_PROTECTED;
*ascq = SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case SPDK_NVME_SC_INVALID_QUEUE_IDENTIFIER:
case SPDK_NVME_SC_MAXIMUM_QUEUE_SIZE_EXCEEDED:
case SPDK_NVME_SC_ASYNC_EVENT_REQUEST_LIMIT_EXCEEDED:
case SPDK_NVME_SC_INVALID_FIRMWARE_SLOT:
case SPDK_NVME_SC_INVALID_FIRMWARE_IMAGE:
case SPDK_NVME_SC_INVALID_INTERRUPT_VECTOR:
case SPDK_NVME_SC_INVALID_LOG_PAGE:
case SPDK_NVME_SC_FIRMWARE_REQ_CONVENTIONAL_RESET:
case SPDK_NVME_SC_INVALID_QUEUE_DELETION:
case SPDK_NVME_SC_FEATURE_ID_NOT_SAVEABLE:
case SPDK_NVME_SC_FEATURE_NOT_CHANGEABLE:
case SPDK_NVME_SC_FEATURE_NOT_NAMESPACE_SPECIFIC:
case SPDK_NVME_SC_FIRMWARE_REQ_NVM_RESET:
case SPDK_NVME_SC_FIRMWARE_REQ_RESET:
case SPDK_NVME_SC_FIRMWARE_REQ_MAX_TIME_VIOLATION:
case SPDK_NVME_SC_FIRMWARE_ACTIVATION_PROHIBITED:
case SPDK_NVME_SC_OVERLAPPING_RANGE:
case SPDK_NVME_SC_NAMESPACE_INSUFFICIENT_CAPACITY:
case SPDK_NVME_SC_NAMESPACE_ID_UNAVAILABLE:
case SPDK_NVME_SC_NAMESPACE_ALREADY_ATTACHED:
case SPDK_NVME_SC_NAMESPACE_IS_PRIVATE:
case SPDK_NVME_SC_NAMESPACE_NOT_ATTACHED:
case SPDK_NVME_SC_THINPROVISIONING_NOT_SUPPORTED:
case SPDK_NVME_SC_CONTROLLER_LIST_INVALID:
case SPDK_NVME_SC_INVALID_PROTECTION_INFO:
default:
*sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
*sk = SPDK_SCSI_SENSE_ILLEGAL_REQUEST;
*asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE;
*ascq = SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
}
break;
case SPDK_NVME_SCT_MEDIA_ERROR:
switch (nvme_sc) {
case SPDK_NVME_SC_WRITE_FAULTS:
*sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
*sk = SPDK_SCSI_SENSE_MEDIUM_ERROR;
*asc = SPDK_SCSI_ASC_PERIPHERAL_DEVICE_WRITE_FAULT;
*ascq = SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case SPDK_NVME_SC_UNRECOVERED_READ_ERROR:
*sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
*sk = SPDK_SCSI_SENSE_MEDIUM_ERROR;
*asc = SPDK_SCSI_ASC_UNRECOVERED_READ_ERROR;
*ascq = SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case SPDK_NVME_SC_GUARD_CHECK_ERROR:
*sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
*sk = SPDK_SCSI_SENSE_MEDIUM_ERROR;
*asc = SPDK_SCSI_ASC_LOGICAL_BLOCK_GUARD_CHECK_FAILED;
*ascq = SPDK_SCSI_ASCQ_LOGICAL_BLOCK_GUARD_CHECK_FAILED;
break;
case SPDK_NVME_SC_APPLICATION_TAG_CHECK_ERROR:
*sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
*sk = SPDK_SCSI_SENSE_MEDIUM_ERROR;
*asc = SPDK_SCSI_ASC_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED;
*ascq = SPDK_SCSI_ASCQ_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED;
break;
case SPDK_NVME_SC_REFERENCE_TAG_CHECK_ERROR:
*sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
*sk = SPDK_SCSI_SENSE_MEDIUM_ERROR;
*asc = SPDK_SCSI_ASC_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED;
*ascq = SPDK_SCSI_ASCQ_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED;
break;
case SPDK_NVME_SC_COMPARE_FAILURE:
*sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
*sk = SPDK_SCSI_SENSE_MISCOMPARE;
*asc = SPDK_SCSI_ASC_MISCOMPARE_DURING_VERIFY_OPERATION;
*ascq = SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
case SPDK_NVME_SC_ACCESS_DENIED:
*sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
*sk = SPDK_SCSI_SENSE_DATA_PROTECT;
*asc = SPDK_SCSI_ASC_ACCESS_DENIED;
*ascq = SPDK_SCSI_ASCQ_NO_ACCESS_RIGHTS;
break;
case SPDK_NVME_SC_DEALLOCATED_OR_UNWRITTEN_BLOCK:
default:
*sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
*sk = SPDK_SCSI_SENSE_ILLEGAL_REQUEST;
*asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE;
*ascq = SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
}
break;
case SPDK_NVME_SCT_VENDOR_SPECIFIC:
default:
*sc = SPDK_SCSI_STATUS_CHECK_CONDITION;
*sk = SPDK_SCSI_SENSE_ILLEGAL_REQUEST;
*asc = SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE;
*ascq = SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE;
break;
}
}

View File

@ -178,8 +178,9 @@ spdk_scsi_task_build_sense_data(struct spdk_scsi_task *task, int sk, int asc, in
}
void
spdk_scsi_task_set_check_condition(struct spdk_scsi_task *task, int sk, int asc, int ascq)
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 = SPDK_SCSI_STATUS_CHECK_CONDITION;
task->status = sc;
}

View File

@ -154,6 +154,6 @@ spdk_scsi_dev_print(struct spdk_scsi_dev *dev)
}
void
spdk_scsi_task_set_check_condition(struct spdk_scsi_task *task, int sk, int asc, int ascq)
spdk_scsi_task_set_status(struct spdk_scsi_task *task, int sc, int sk, int asc, int ascq)
{
}

View File

@ -34,7 +34,7 @@
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
DIRS-y = dev init lun scsi_bdev
DIRS-y = dev init lun scsi_bdev scsi_nvme
.PHONY: all clean $(DIRS-y)

View File

@ -82,10 +82,11 @@ spdk_scsi_task_put(struct spdk_scsi_task *task)
free(task);
}
void spdk_scsi_task_set_check_condition(struct spdk_scsi_task *task, int sk,
void
spdk_scsi_task_set_status(struct spdk_scsi_task *task, int sc, int sk,
int asc, int ascq)
{
task->status = SPDK_SCSI_STATUS_CHECK_CONDITION;
task->status = sc;
}
void

View File

@ -12,5 +12,6 @@ $valgrind $testdir/dev/dev_ut
$testdir/init/init_ut
$valgrind $testdir/lun/lun_ut
$testdir/scsi_bdev/scsi_bdev_ut
$valgrind $testdir/scsi_nvme/scsi_nvme_ut
timing_exit scsi

View File

@ -54,10 +54,11 @@ spdk_scsi_lun_complete_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *ta
}
void
spdk_scsi_task_set_check_condition(struct spdk_scsi_task *task, int sk, int asc, int ascq)
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 = SPDK_SCSI_STATUS_CHECK_CONDITION;
task->status = sc;
}
void
@ -119,6 +120,12 @@ spdk_scsi_task_build_sense_data(struct spdk_scsi_task *task, int sk, int asc, in
task->sense_data_len = 20;
}
void
spdk_scsi_nvme_translate(struct spdk_bdev_io *bdev_io, int *sc, int *sk,
int *asc, int *ascq)
{
}
struct spdk_bdev_io *
spdk_bdev_read(struct spdk_bdev *bdev, struct spdk_io_channel *ch,
void *buf, uint64_t offset, uint64_t nbytes,
@ -459,6 +466,37 @@ inquiry_overflow_test(void)
}
}
/*
* This test is to verify specific error translation from bdev to scsi.
*/
static void
task_complete_test(void)
{
struct spdk_event event;
struct spdk_scsi_task task = {};
struct spdk_bdev_io bdev_io = {};
struct spdk_scsi_lun lun;
TAILQ_INIT(&lun.tasks);
TAILQ_INSERT_TAIL(&lun.tasks, &task, scsi_link);
task.lun = &lun;
event.arg1 = &task;
event.arg2 = &bdev_io;
task.type = SPDK_SCSI_TASK_TYPE_CMD;
bdev_io.status = SPDK_BDEV_IO_STATUS_SUCCESS;
spdk_bdev_scsi_task_complete(&event);
CU_ASSERT_EQUAL(task.status, SPDK_SCSI_STATUS_GOOD);
bdev_io.status = SPDK_BDEV_IO_STATUS_FAILED;
spdk_bdev_scsi_task_complete(&event);
CU_ASSERT_EQUAL(task.status, SPDK_SCSI_STATUS_CHECK_CONDITION);
CU_ASSERT_EQUAL(task.sense_data[4], SPDK_SCSI_SENSE_ABORTED_COMMAND);
CU_ASSERT_EQUAL(task.sense_data[14], SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE);
CU_ASSERT_EQUAL(task.sense_data[15], SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
}
int
main(int argc, char **argv)
{
@ -483,6 +521,7 @@ main(int argc, char **argv)
|| CU_add_test(suite, "inquiry evpd test", inquiry_evpd_test) == NULL
|| CU_add_test(suite, "inquiry standard test", inquiry_standard_test) == NULL
|| CU_add_test(suite, "inquiry overflow test", inquiry_overflow_test) == NULL
|| CU_add_test(suite, "task complete test", task_complete_test) == NULL
) {
CU_cleanup_registry();
return CU_get_error();

1
test/lib/scsi/scsi_nvme/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
scsi_nvme_ut

View File

@ -0,0 +1,55 @@
#
# BSD LICENSE
#
# Copyright (c) 2016 FUJITSU LIMITED, All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
SPDK_LIBS += $(SPDK_ROOT_DIR)/lib/log/libspdk_log.a \
$(SPDK_ROOT_DIR)/lib/cunit/libspdk_cunit.a
CFLAGS += -I$(SPDK_ROOT_DIR)/test
CFLAGS += -I$(SPDK_ROOT_DIR)/lib/scsi
LIBS += $(SPDK_LIBS)
LIBS += -lcunit
APP = scsi_nvme_ut
C_SRCS = scsi_nvme_ut.c
all: $(APP)
$(APP): $(OBJS) $(SPDK_LIBS)
$(LINK_C)
clean:
$(CLEAN_C) $(APP)
include $(SPDK_ROOT_DIR)/mk/spdk.deps.mk

View File

@ -0,0 +1,142 @@
/*-
* BSD LICENSE
*
* Copyright (c) 2016 FUJITSU LIMITED, All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "spdk_cunit.h"
#include "scsi_nvme.c"
static int
null_init(void)
{
return 0;
}
static int
null_clean(void)
{
return 0;
}
static void
scsi_nvme_translate_test(void)
{
struct spdk_bdev_io bdev_io;
int sc, sk, asc, ascq;
/* SPDK_NVME_SCT_GENERIC */
bdev_io.error.nvme.sct = SPDK_NVME_SCT_GENERIC;
bdev_io.error.nvme.sc = SPDK_NVME_SC_ABORTED_POWER_LOSS;
spdk_scsi_nvme_translate(&bdev_io, &sc, &sk, &asc, &ascq);
CU_ASSERT_EQUAL(sc, SPDK_SCSI_STATUS_TASK_ABORTED);
CU_ASSERT_EQUAL(sk, SPDK_SCSI_SENSE_ABORTED_COMMAND);
CU_ASSERT_EQUAL(asc, SPDK_SCSI_ASC_WARNING);
CU_ASSERT_EQUAL(ascq, SPDK_SCSI_ASCQ_POWER_LOSS_EXPECTED);
bdev_io.error.nvme.sc = SPDK_NVME_SC_INVALID_NUM_SGL_DESCIRPTORS;
spdk_scsi_nvme_translate(&bdev_io, &sc, &sk, &asc, &ascq);
CU_ASSERT_EQUAL(sc, SPDK_SCSI_STATUS_CHECK_CONDITION);
CU_ASSERT_EQUAL(sk, SPDK_SCSI_SENSE_ILLEGAL_REQUEST);
CU_ASSERT_EQUAL(asc, SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE);
CU_ASSERT_EQUAL(ascq, SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
/* SPDK_NVME_SCT_COMMAND_SPECIFIC */
bdev_io.error.nvme.sct = SPDK_NVME_SCT_COMMAND_SPECIFIC;
bdev_io.error.nvme.sc = SPDK_NVME_SC_INVALID_FORMAT;
spdk_scsi_nvme_translate(&bdev_io, &sc, &sk, &asc, &ascq);
CU_ASSERT_EQUAL(sc, SPDK_SCSI_STATUS_CHECK_CONDITION);
CU_ASSERT_EQUAL(sk, SPDK_SCSI_SENSE_ILLEGAL_REQUEST);
CU_ASSERT_EQUAL(asc, SPDK_SCSI_ASC_FORMAT_COMMAND_FAILED);
CU_ASSERT_EQUAL(ascq, SPDK_SCSI_ASCQ_FORMAT_COMMAND_FAILED);
bdev_io.error.nvme.sc = SPDK_NVME_SC_OVERLAPPING_RANGE;
spdk_scsi_nvme_translate(&bdev_io, &sc, &sk, &asc, &ascq);
CU_ASSERT_EQUAL(sc, SPDK_SCSI_STATUS_CHECK_CONDITION);
CU_ASSERT_EQUAL(sk, SPDK_SCSI_SENSE_ILLEGAL_REQUEST);
CU_ASSERT_EQUAL(asc, SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE);
CU_ASSERT_EQUAL(ascq, SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
/* SPDK_NVME_SCT_MEDIA_ERROR */
bdev_io.error.nvme.sct = SPDK_NVME_SCT_MEDIA_ERROR;
bdev_io.error.nvme.sc = SPDK_NVME_SC_GUARD_CHECK_ERROR;
spdk_scsi_nvme_translate(&bdev_io, &sc, &sk, &asc, &ascq);
CU_ASSERT_EQUAL(sc, SPDK_SCSI_STATUS_CHECK_CONDITION);
CU_ASSERT_EQUAL(sk, SPDK_SCSI_SENSE_MEDIUM_ERROR);
CU_ASSERT_EQUAL(asc, SPDK_SCSI_ASC_LOGICAL_BLOCK_GUARD_CHECK_FAILED);
CU_ASSERT_EQUAL(ascq, SPDK_SCSI_ASCQ_LOGICAL_BLOCK_GUARD_CHECK_FAILED);
bdev_io.error.nvme.sc = SPDK_NVME_SC_DEALLOCATED_OR_UNWRITTEN_BLOCK;
spdk_scsi_nvme_translate(&bdev_io, &sc, &sk, &asc, &ascq);
CU_ASSERT_EQUAL(sc, SPDK_SCSI_STATUS_CHECK_CONDITION);
CU_ASSERT_EQUAL(sk, SPDK_SCSI_SENSE_ILLEGAL_REQUEST);
CU_ASSERT_EQUAL(asc, SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE);
CU_ASSERT_EQUAL(ascq, SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
/* SPDK_NVME_SCT_VENDOR_SPECIFIC */
bdev_io.error.nvme.sct = SPDK_NVME_SCT_VENDOR_SPECIFIC;
bdev_io.error.nvme.sc = 0xff;
spdk_scsi_nvme_translate(&bdev_io, &sc, &sk, &asc, &ascq);
CU_ASSERT_EQUAL(sc, SPDK_SCSI_STATUS_CHECK_CONDITION);
CU_ASSERT_EQUAL(sk, SPDK_SCSI_SENSE_ILLEGAL_REQUEST);
CU_ASSERT_EQUAL(asc, SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE);
CU_ASSERT_EQUAL(ascq, SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
}
int
main(int argc, char **argv)
{
CU_pSuite suite = NULL;
unsigned int num_failures;
if (CU_initialize_registry() != CUE_SUCCESS) {
return CU_get_error();
}
suite = CU_add_suite("scsi_nvme_suite", null_init, null_clean);
if (suite == NULL) {
CU_cleanup_registry();
return CU_get_error();
}
if (
CU_add_test(suite, "scsi_nvme - translate nvme error to scsi error",
scsi_nvme_translate_test) == NULL
) {
CU_cleanup_registry();
return CU_get_error();
}
CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests();
num_failures = CU_get_number_of_failures();
CU_cleanup_registry();
return num_failures;
}

View File

@ -27,6 +27,7 @@ test/lib/nvmf/subsystem/subsystem_ut
test/lib/scsi/dev/dev_ut
test/lib/scsi/lun/lun_ut
test/lib/scsi/scsi_bdev/scsi_bdev_ut
test/lib/scsi/scsi_nvme/scsi_nvme_ut
test/lib/util/bit_array/bit_array_ut
test/lib/util/io_channel/io_channel_ut