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 */
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_ */

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);
}
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)
{

View File

@ -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 */

View File

@ -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);
}