From 6583441f541ef2c10d97f02480500667b7339c81 Mon Sep 17 00:00:00 2001 From: Tsuyoshi Uchida Date: Mon, 7 Nov 2016 12:14:47 -0800 Subject: [PATCH] bdev: add members for SCSI sense information in spdk_bdev_io (#59) Custom bdev modules can return any SCSI status and SCSI sense information to a host by this patch. This is usefull when a custome bdev module detect an error in the module and need to return meaningful information to a host. --- include/spdk/bdev.h | 14 ++++++++++ lib/bdev/bdev.c | 11 ++++++++ lib/scsi/scsi_bdev.c | 36 +++++++++++++++----------- test/lib/scsi/scsi_bdev/scsi_bdev_ut.c | 13 +++++++++- 4 files changed, 58 insertions(+), 16 deletions(-) diff --git a/include/spdk/bdev.h b/include/spdk/bdev.h index 2b81766b6..fd2ab0433 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_SCSI_ERROR = -3, SPDK_BDEV_IO_STATUS_NVME_ERROR = -2, SPDK_BDEV_IO_STATUS_FAILED = -1, SPDK_BDEV_IO_STATUS_PENDING = 0, @@ -252,6 +253,17 @@ struct spdk_bdev_io { /** NVMe status code */ int sc; } nvme; + /** Only valid when status is SPDK_BDEV_IO_STATUS_SCSI_ERROR */ + struct { + /** SCSI status code */ + enum spdk_scsi_status sc; + /** SCSI sense key */ + enum spdk_scsi_sense sk; + /** SCSI additional sense code */ + uint8_t asc; + /** SCSI additional sense code qualifier */ + uint8_t ascq; + } scsi; } error; /** User function that will be called when this completes */ @@ -321,4 +333,6 @@ int spdk_bdev_free_io(struct spdk_bdev_io *bdev_io); int spdk_bdev_reset(struct spdk_bdev *bdev, enum spdk_bdev_reset_type, spdk_bdev_io_completion_cb cb, void *cb_arg); struct spdk_io_channel *spdk_bdev_get_io_channel(struct spdk_bdev *bdev, uint32_t priority); +void spdk_bdev_io_set_scsi_error(struct spdk_bdev_io *bdev_io, enum spdk_scsi_status sc, + enum spdk_scsi_sense sk, uint8_t asc, uint8_t ascq); #endif /* SPDK_BDEV_H_ */ diff --git a/lib/bdev/bdev.c b/lib/bdev/bdev.c index e5544315b..c0b79a808 100644 --- a/lib/bdev/bdev.c +++ b/lib/bdev/bdev.c @@ -836,6 +836,17 @@ spdk_bdev_io_complete(struct spdk_bdev_io *bdev_io, enum spdk_bdev_io_status sta spdk_event_call(bdev_io->cb_event); } +void +spdk_bdev_io_set_scsi_error(struct spdk_bdev_io *bdev_io, enum spdk_scsi_status sc, + enum spdk_scsi_sense sk, uint8_t asc, uint8_t ascq) +{ + bdev_io->status = SPDK_BDEV_IO_STATUS_SCSI_ERROR; + bdev_io->error.scsi.sc = sc; + bdev_io->error.scsi.sk = sk; + bdev_io->error.scsi.asc = asc; + bdev_io->error.scsi.ascq = ascq; +} + void spdk_bdev_register(struct spdk_bdev *bdev) { diff --git a/lib/scsi/scsi_bdev.c b/lib/scsi/scsi_bdev.c index a94a08e0f..ff159f809 100644 --- a/lib/scsi/scsi_bdev.c +++ b/lib/scsi/scsi_bdev.c @@ -1283,23 +1283,29 @@ 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) { - int sc, sk, asc, ascq; - - switch (bdev_io->status) { - case SPDK_BDEV_IO_STATUS_SUCCESS: + if (status == 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); + } else { + int sc, sk, asc, ascq; + + switch (status) { + case SPDK_BDEV_IO_STATUS_NVME_ERROR: + spdk_scsi_nvme_translate(bdev_io, &sc, &sk, &asc, &ascq); + break; + case SPDK_BDEV_IO_STATUS_SCSI_ERROR: + sc = bdev_io->error.scsi.sc; + sk = bdev_io->error.scsi.sk; + asc = bdev_io->error.scsi.asc; + ascq = bdev_io->error.scsi.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; + break; + } 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 */ diff --git a/test/lib/scsi/scsi_bdev/scsi_bdev_ut.c b/test/lib/scsi/scsi_bdev/scsi_bdev_ut.c index 6e64060ff..78d2cd9a4 100644 --- a/test/lib/scsi/scsi_bdev/scsi_bdev_ut.c +++ b/test/lib/scsi/scsi_bdev/scsi_bdev_ut.c @@ -483,10 +483,21 @@ task_complete_test(void) spdk_bdev_scsi_task_complete(&event); CU_ASSERT_EQUAL(task.status, SPDK_SCSI_STATUS_GOOD); + bdev_io.status = SPDK_BDEV_IO_STATUS_SCSI_ERROR; + bdev_io.error.scsi.sc = SPDK_SCSI_STATUS_CHECK_CONDITION; + bdev_io.error.scsi.sk = SPDK_SCSI_SENSE_HARDWARE_ERROR; + bdev_io.error.scsi.asc = SPDK_SCSI_ASC_WARNING; + bdev_io.error.scsi.ascq = SPDK_SCSI_ASCQ_POWER_LOSS_EXPECTED; + spdk_bdev_scsi_task_complete(&event); + CU_ASSERT_EQUAL(task.status, SPDK_SCSI_STATUS_CHECK_CONDITION); + CU_ASSERT_EQUAL(task.sense_data[2] & 0xf, SPDK_SCSI_SENSE_HARDWARE_ERROR); + CU_ASSERT_EQUAL(task.sense_data[12], SPDK_SCSI_ASC_WARNING); + CU_ASSERT_EQUAL(task.sense_data[13], SPDK_SCSI_ASCQ_POWER_LOSS_EXPECTED); + 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[2], SPDK_SCSI_SENSE_ABORTED_COMMAND); + CU_ASSERT_EQUAL(task.sense_data[2] & 0xf, SPDK_SCSI_SENSE_ABORTED_COMMAND); CU_ASSERT_EQUAL(task.sense_data[12], SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE); CU_ASSERT_EQUAL(task.sense_data[13], SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); }