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.
This commit is contained in:
Tsuyoshi Uchida 2016-11-07 12:14:47 -08:00 committed by Daniel Verkamp
parent 1ffec5d53a
commit 6583441f54
4 changed files with 58 additions and 16 deletions

View File

@ -137,6 +137,7 @@ struct spdk_bdev_fn_table {
/** Blockdev I/O completion status */ /** Blockdev I/O completion status */
enum spdk_bdev_io_status { enum spdk_bdev_io_status {
SPDK_BDEV_IO_STATUS_SCSI_ERROR = -3,
SPDK_BDEV_IO_STATUS_NVME_ERROR = -2, SPDK_BDEV_IO_STATUS_NVME_ERROR = -2,
SPDK_BDEV_IO_STATUS_FAILED = -1, SPDK_BDEV_IO_STATUS_FAILED = -1,
SPDK_BDEV_IO_STATUS_PENDING = 0, SPDK_BDEV_IO_STATUS_PENDING = 0,
@ -252,6 +253,17 @@ struct spdk_bdev_io {
/** NVMe status code */ /** NVMe status code */
int sc; int sc;
} nvme; } 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; } error;
/** User function that will be called when this completes */ /** 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, int spdk_bdev_reset(struct spdk_bdev *bdev, enum spdk_bdev_reset_type,
spdk_bdev_io_completion_cb cb, void *cb_arg); 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); 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_ */ #endif /* SPDK_BDEV_H_ */

View File

@ -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); 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 void
spdk_bdev_register(struct spdk_bdev *bdev) spdk_bdev_register(struct spdk_bdev *bdev)
{ {

View File

@ -1283,23 +1283,29 @@ spdk_bdev_scsi_task_complete(spdk_event_t event)
enum spdk_bdev_io_status status = bdev_io->status; enum spdk_bdev_io_status status = bdev_io->status;
if (task->type == SPDK_SCSI_TASK_TYPE_CMD) { if (task->type == SPDK_SCSI_TASK_TYPE_CMD) {
int sc, sk, asc, ascq; if (status == SPDK_BDEV_IO_STATUS_SUCCESS) {
switch (bdev_io->status) {
case SPDK_BDEV_IO_STATUS_SUCCESS:
task->status = SPDK_SCSI_STATUS_GOOD; task->status = SPDK_SCSI_STATUS_GOOD;
break; } else {
case SPDK_BDEV_IO_STATUS_NVME_ERROR: int sc, sk, asc, ascq;
spdk_scsi_nvme_translate(bdev_io, &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); 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 */ /* command completed. remove from outstanding task list */

View File

@ -483,10 +483,21 @@ task_complete_test(void)
spdk_bdev_scsi_task_complete(&event); spdk_bdev_scsi_task_complete(&event);
CU_ASSERT_EQUAL(task.status, SPDK_SCSI_STATUS_GOOD); 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; bdev_io.status = SPDK_BDEV_IO_STATUS_FAILED;
spdk_bdev_scsi_task_complete(&event); spdk_bdev_scsi_task_complete(&event);
CU_ASSERT_EQUAL(task.status, SPDK_SCSI_STATUS_CHECK_CONDITION); 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[12], SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE);
CU_ASSERT_EQUAL(task.sense_data[13], SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE); CU_ASSERT_EQUAL(task.sense_data[13], SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
} }