Commit 6583441f authored by Tsuyoshi Uchida's avatar Tsuyoshi Uchida Committed by Daniel Verkamp
Browse files

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.
parent 1ffec5d5
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -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_ */
+11 −0
Original line number Diff line number Diff line
@@ -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)
{
+21 −15
Original line number Diff line number Diff line
@@ -1283,24 +1283,30 @@ 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) {
			task->status = SPDK_SCSI_STATUS_GOOD;
		} else {
			int sc, sk, asc, ascq;

		switch (bdev_io->status) {
		case SPDK_BDEV_IO_STATUS_SUCCESS:
			task->status = SPDK_SCSI_STATUS_GOOD;
			break;
			switch (status) {
			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;
			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;
			spdk_scsi_task_set_status(task, sc, sk, asc, ascq);
				break;
			}
			spdk_scsi_task_set_status(task, sc, sk, asc, ascq);
		}

		/* command completed. remove from outstanding task list */
		TAILQ_REMOVE(&task->lun->tasks, task, scsi_link);
+12 −1
Original line number Diff line number Diff line
@@ -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);
}