From a5f032789777dd63b9bc91fdf358bc263dc8463c Mon Sep 17 00:00:00 2001 From: Tsuyoshi Uchida Date: Fri, 28 Oct 2016 12:56:36 -0700 Subject: [PATCH] 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 --- include/spdk/bdev.h | 12 ++ include/spdk/scsi.h | 4 +- include/spdk/scsi_spec.h | 32 +++ lib/bdev/nvme/blockdev_nvme.c | 8 +- lib/scsi/Makefile | 2 +- lib/scsi/lun.c | 17 +- lib/scsi/scsi_bdev.c | 140 ++++++++----- lib/scsi/scsi_internal.h | 2 + lib/scsi/scsi_nvme.c | 261 +++++++++++++++++++++++++ lib/scsi/task.c | 5 +- test/lib/iscsi/common.c | 2 +- test/lib/scsi/Makefile | 2 +- test/lib/scsi/lun/lun_ut.c | 7 +- test/lib/scsi/scsi.sh | 1 + test/lib/scsi/scsi_bdev/scsi_bdev_ut.c | 43 +++- test/lib/scsi/scsi_nvme/.gitignore | 1 + test/lib/scsi/scsi_nvme/Makefile | 55 ++++++ test/lib/scsi/scsi_nvme/scsi_nvme_ut.c | 142 ++++++++++++++ unittest.sh | 1 + 19 files changed, 668 insertions(+), 69 deletions(-) create mode 100644 lib/scsi/scsi_nvme.c create mode 100644 test/lib/scsi/scsi_nvme/.gitignore create mode 100644 test/lib/scsi/scsi_nvme/Makefile create mode 100644 test/lib/scsi/scsi_nvme/scsi_nvme_ut.c diff --git a/include/spdk/bdev.h b/include/spdk/bdev.h index e152d345a4..2b81766b6a 100644 --- a/include/spdk/bdev.h +++ b/include/spdk/bdev.h @@ -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; diff --git a/include/spdk/scsi.h b/include/spdk/scsi.h index 86b75bf89e..502c6a609f 100644 --- a/include/spdk/scsi.h +++ b/include/spdk/scsi.h @@ -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) diff --git a/include/spdk/scsi_spec.h b/include/spdk/scsi_spec.h index 87fc0ac978..e8d949a1d3 100644 --- a/include/spdk/scsi_spec.h +++ b/include/spdk/scsi_spec.h @@ -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, diff --git a/lib/bdev/nvme/blockdev_nvme.c b/lib/bdev/nvme/blockdev_nvme.c index f9c7ba1e70..503040106d 100644 --- a/lib/bdev/nvme/blockdev_nvme.c +++ b/lib/bdev/nvme/blockdev_nvme.c @@ -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 diff --git a/lib/scsi/Makefile b/lib/scsi/Makefile index c394bf3fa2..e2326821ac 100644 --- a/lib/scsi/Makefile +++ b/lib/scsi/Makefile @@ -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 diff --git a/lib/scsi/lun.c b/lib/scsi/lun.c index d85ef0eb96..72296f3509 100644 --- a/lib/scsi/lun.c +++ b/lib/scsi/lun.c @@ -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); diff --git a/lib/scsi/scsi_bdev.c b/lib/scsi/scsi_bdev.c index 5ddccd8a66..cb8e22f777 100644 --- a/lib/scsi/scsi_bdev.c +++ b/lib/scsi/scsi_bdev.c @@ -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_SENSE_ILLEGAL_REQUEST, - 0x24, 0x0); + 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; } @@ -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_SENSE_ILLEGAL_REQUEST, - 0x24, 0x0); + 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; } @@ -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_SENSE_ILLEGAL_REQUEST, - 0x24, 0x0); + 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; } 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_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 -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_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; } @@ -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_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; } @@ -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_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; } @@ -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_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); return SPDK_SCSI_TASK_COMPLETE; } } diff --git a/lib/scsi/scsi_internal.h b/lib/scsi/scsi_internal.h index 1ce04d44c7..3b7904da93 100644 --- a/lib/scsi/scsi_internal.h +++ b/lib/scsi/scsi_internal.h @@ -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; diff --git a/lib/scsi/scsi_nvme.c b/lib/scsi/scsi_nvme.c new file mode 100644 index 0000000000..dc33050f9f --- /dev/null +++ b/lib/scsi/scsi_nvme.c @@ -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; + } +} diff --git a/lib/scsi/task.c b/lib/scsi/task.c index d487a60aa5..d0b65258b9 100644 --- a/lib/scsi/task.c +++ b/lib/scsi/task.c @@ -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; } diff --git a/test/lib/iscsi/common.c b/test/lib/iscsi/common.c index 210ab433d7..89e7efefdb 100644 --- a/test/lib/iscsi/common.c +++ b/test/lib/iscsi/common.c @@ -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) { } diff --git a/test/lib/scsi/Makefile b/test/lib/scsi/Makefile index 5007837182..eeeb49739d 100644 --- a/test/lib/scsi/Makefile +++ b/test/lib/scsi/Makefile @@ -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) diff --git a/test/lib/scsi/lun/lun_ut.c b/test/lib/scsi/lun/lun_ut.c index 8878d001b6..1f544857c8 100644 --- a/test/lib/scsi/lun/lun_ut.c +++ b/test/lib/scsi/lun/lun_ut.c @@ -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, - int asc, int ascq) +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 diff --git a/test/lib/scsi/scsi.sh b/test/lib/scsi/scsi.sh index 9694d47d26..7233e5e9ce 100755 --- a/test/lib/scsi/scsi.sh +++ b/test/lib/scsi/scsi.sh @@ -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 diff --git a/test/lib/scsi/scsi_bdev/scsi_bdev_ut.c b/test/lib/scsi/scsi_bdev/scsi_bdev_ut.c index 36cc814b41..697dcdaca1 100644 --- a/test/lib/scsi/scsi_bdev/scsi_bdev_ut.c +++ b/test/lib/scsi/scsi_bdev/scsi_bdev_ut.c @@ -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(); diff --git a/test/lib/scsi/scsi_nvme/.gitignore b/test/lib/scsi/scsi_nvme/.gitignore new file mode 100644 index 0000000000..75800527de --- /dev/null +++ b/test/lib/scsi/scsi_nvme/.gitignore @@ -0,0 +1 @@ +scsi_nvme_ut diff --git a/test/lib/scsi/scsi_nvme/Makefile b/test/lib/scsi/scsi_nvme/Makefile new file mode 100644 index 0000000000..702a515cc3 --- /dev/null +++ b/test/lib/scsi/scsi_nvme/Makefile @@ -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 diff --git a/test/lib/scsi/scsi_nvme/scsi_nvme_ut.c b/test/lib/scsi/scsi_nvme/scsi_nvme_ut.c new file mode 100644 index 0000000000..ed1c64890d --- /dev/null +++ b/test/lib/scsi/scsi_nvme/scsi_nvme_ut.c @@ -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; +} diff --git a/unittest.sh b/unittest.sh index b22677de54..dc74f07312 100755 --- a/unittest.sh +++ b/unittest.sh @@ -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