target: Split transport_send_check_condition_and_sense()
Move the code for translating a sense_reason_t code into a SCSI status ASC and ASCQ codes from transport_send_check_condition_and_sense() into the new function translate_sense_reason(). Convert the switch statement that performs the translation into table-driven code. Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Signed-off-by: Sagi Grimberg <sagig@mellanox.com> Reviewed-by: Hannes Reinecke <hare@suse.de> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
This commit is contained in:
parent
46d5bd62ef
commit
ab78fef4d5
@ -2628,13 +2628,155 @@ void transport_err_sector_info(unsigned char *buffer, sector_t bad_sector)
|
||||
put_unaligned_be64(bad_sector, &buffer[12]);
|
||||
}
|
||||
|
||||
struct sense_info {
|
||||
u8 key;
|
||||
u8 asc;
|
||||
u8 ascq;
|
||||
bool add_sector_info;
|
||||
};
|
||||
|
||||
static const struct sense_info sense_info_table[] = {
|
||||
[TCM_NO_SENSE] = {
|
||||
.key = NOT_READY
|
||||
},
|
||||
[TCM_NON_EXISTENT_LUN] = {
|
||||
.key = ILLEGAL_REQUEST,
|
||||
.asc = 0x25 /* LOGICAL UNIT NOT SUPPORTED */
|
||||
},
|
||||
[TCM_UNSUPPORTED_SCSI_OPCODE] = {
|
||||
.key = ILLEGAL_REQUEST,
|
||||
.asc = 0x20, /* INVALID COMMAND OPERATION CODE */
|
||||
},
|
||||
[TCM_SECTOR_COUNT_TOO_MANY] = {
|
||||
.key = ILLEGAL_REQUEST,
|
||||
.asc = 0x20, /* INVALID COMMAND OPERATION CODE */
|
||||
},
|
||||
[TCM_UNKNOWN_MODE_PAGE] = {
|
||||
.key = ILLEGAL_REQUEST,
|
||||
.asc = 0x24, /* INVALID FIELD IN CDB */
|
||||
},
|
||||
[TCM_CHECK_CONDITION_ABORT_CMD] = {
|
||||
.key = ABORTED_COMMAND,
|
||||
.asc = 0x29, /* BUS DEVICE RESET FUNCTION OCCURRED */
|
||||
.ascq = 0x03,
|
||||
},
|
||||
[TCM_INCORRECT_AMOUNT_OF_DATA] = {
|
||||
.key = ABORTED_COMMAND,
|
||||
.asc = 0x0c, /* WRITE ERROR */
|
||||
.ascq = 0x0d, /* NOT ENOUGH UNSOLICITED DATA */
|
||||
},
|
||||
[TCM_INVALID_CDB_FIELD] = {
|
||||
.key = ILLEGAL_REQUEST,
|
||||
.asc = 0x24, /* INVALID FIELD IN CDB */
|
||||
},
|
||||
[TCM_INVALID_PARAMETER_LIST] = {
|
||||
.key = ILLEGAL_REQUEST,
|
||||
.asc = 0x26, /* INVALID FIELD IN PARAMETER LIST */
|
||||
},
|
||||
[TCM_PARAMETER_LIST_LENGTH_ERROR] = {
|
||||
.key = ILLEGAL_REQUEST,
|
||||
.asc = 0x1a, /* PARAMETER LIST LENGTH ERROR */
|
||||
},
|
||||
[TCM_UNEXPECTED_UNSOLICITED_DATA] = {
|
||||
.key = ILLEGAL_REQUEST,
|
||||
.asc = 0x0c, /* WRITE ERROR */
|
||||
.ascq = 0x0c, /* UNEXPECTED_UNSOLICITED_DATA */
|
||||
},
|
||||
[TCM_SERVICE_CRC_ERROR] = {
|
||||
.key = ABORTED_COMMAND,
|
||||
.asc = 0x47, /* PROTOCOL SERVICE CRC ERROR */
|
||||
.ascq = 0x05, /* N/A */
|
||||
},
|
||||
[TCM_SNACK_REJECTED] = {
|
||||
.key = ABORTED_COMMAND,
|
||||
.asc = 0x11, /* READ ERROR */
|
||||
.ascq = 0x13, /* FAILED RETRANSMISSION REQUEST */
|
||||
},
|
||||
[TCM_WRITE_PROTECTED] = {
|
||||
.key = DATA_PROTECT,
|
||||
.asc = 0x27, /* WRITE PROTECTED */
|
||||
},
|
||||
[TCM_ADDRESS_OUT_OF_RANGE] = {
|
||||
.key = ILLEGAL_REQUEST,
|
||||
.asc = 0x21, /* LOGICAL BLOCK ADDRESS OUT OF RANGE */
|
||||
},
|
||||
[TCM_CHECK_CONDITION_UNIT_ATTENTION] = {
|
||||
.key = UNIT_ATTENTION,
|
||||
},
|
||||
[TCM_CHECK_CONDITION_NOT_READY] = {
|
||||
.key = NOT_READY,
|
||||
},
|
||||
[TCM_MISCOMPARE_VERIFY] = {
|
||||
.key = MISCOMPARE,
|
||||
.asc = 0x1d, /* MISCOMPARE DURING VERIFY OPERATION */
|
||||
.ascq = 0x00,
|
||||
},
|
||||
[TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED] = {
|
||||
.key = ILLEGAL_REQUEST,
|
||||
.asc = 0x10,
|
||||
.ascq = 0x01, /* LOGICAL BLOCK GUARD CHECK FAILED */
|
||||
.add_sector_info = true,
|
||||
},
|
||||
[TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED] = {
|
||||
.key = ILLEGAL_REQUEST,
|
||||
.asc = 0x10,
|
||||
.ascq = 0x02, /* LOGICAL BLOCK APPLICATION TAG CHECK FAILED */
|
||||
.add_sector_info = true,
|
||||
},
|
||||
[TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED] = {
|
||||
.key = ILLEGAL_REQUEST,
|
||||
.asc = 0x10,
|
||||
.ascq = 0x03, /* LOGICAL BLOCK REFERENCE TAG CHECK FAILED */
|
||||
.add_sector_info = true,
|
||||
},
|
||||
[TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE] = {
|
||||
/*
|
||||
* Returning ILLEGAL REQUEST would cause immediate IO errors on
|
||||
* Solaris initiators. Returning NOT READY instead means the
|
||||
* operations will be retried a finite number of times and we
|
||||
* can survive intermittent errors.
|
||||
*/
|
||||
.key = NOT_READY,
|
||||
.asc = 0x08, /* LOGICAL UNIT COMMUNICATION FAILURE */
|
||||
},
|
||||
};
|
||||
|
||||
static void translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason)
|
||||
{
|
||||
const struct sense_info *si;
|
||||
u8 *buffer = cmd->sense_buffer;
|
||||
int r = (__force int)reason;
|
||||
u8 asc, ascq;
|
||||
|
||||
if (r < ARRAY_SIZE(sense_info_table) && sense_info_table[r].key)
|
||||
si = &sense_info_table[r];
|
||||
else
|
||||
si = &sense_info_table[(__force int)
|
||||
TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE];
|
||||
|
||||
buffer[SPC_SENSE_KEY_OFFSET] = si->key;
|
||||
if (reason == TCM_CHECK_CONDITION_UNIT_ATTENTION) {
|
||||
core_scsi3_ua_for_check_condition(cmd, &asc, &ascq);
|
||||
WARN_ON_ONCE(asc == 0);
|
||||
} else if (si->asc == 0) {
|
||||
WARN_ON_ONCE(cmd->scsi_asc == 0);
|
||||
asc = cmd->scsi_asc;
|
||||
ascq = cmd->scsi_ascq;
|
||||
} else {
|
||||
asc = si->asc;
|
||||
ascq = si->ascq;
|
||||
}
|
||||
buffer[SPC_ASC_KEY_OFFSET] = asc;
|
||||
buffer[SPC_ASCQ_KEY_OFFSET] = ascq;
|
||||
if (si->add_sector_info)
|
||||
transport_err_sector_info(cmd->sense_buffer, cmd->bad_sector);
|
||||
}
|
||||
|
||||
int
|
||||
transport_send_check_condition_and_sense(struct se_cmd *cmd,
|
||||
sense_reason_t reason, int from_transport)
|
||||
{
|
||||
unsigned char *buffer = cmd->sense_buffer;
|
||||
unsigned long flags;
|
||||
u8 asc = 0, ascq = 0;
|
||||
|
||||
spin_lock_irqsave(&cmd->t_state_lock, flags);
|
||||
if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) {
|
||||
@ -2644,242 +2786,13 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd,
|
||||
cmd->se_cmd_flags |= SCF_SENT_CHECK_CONDITION;
|
||||
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
|
||||
|
||||
if (!reason && from_transport)
|
||||
goto after_reason;
|
||||
|
||||
if (!from_transport)
|
||||
if (!from_transport) {
|
||||
cmd->se_cmd_flags |= SCF_EMULATED_TASK_SENSE;
|
||||
|
||||
/*
|
||||
* Actual SENSE DATA, see SPC-3 7.23.2 SPC_SENSE_KEY_OFFSET uses
|
||||
* SENSE KEY values from include/scsi/scsi.h
|
||||
*/
|
||||
switch (reason) {
|
||||
case TCM_NO_SENSE:
|
||||
/* CURRENT ERROR */
|
||||
buffer[0] = 0x70;
|
||||
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
|
||||
/* Not Ready */
|
||||
buffer[SPC_SENSE_KEY_OFFSET] = NOT_READY;
|
||||
/* NO ADDITIONAL SENSE INFORMATION */
|
||||
buffer[SPC_ASC_KEY_OFFSET] = 0;
|
||||
buffer[SPC_ASCQ_KEY_OFFSET] = 0;
|
||||
break;
|
||||
case TCM_NON_EXISTENT_LUN:
|
||||
/* CURRENT ERROR */
|
||||
buffer[0] = 0x70;
|
||||
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
|
||||
/* ILLEGAL REQUEST */
|
||||
buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
|
||||
/* LOGICAL UNIT NOT SUPPORTED */
|
||||
buffer[SPC_ASC_KEY_OFFSET] = 0x25;
|
||||
break;
|
||||
case TCM_UNSUPPORTED_SCSI_OPCODE:
|
||||
case TCM_SECTOR_COUNT_TOO_MANY:
|
||||
/* CURRENT ERROR */
|
||||
buffer[0] = 0x70;
|
||||
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
|
||||
/* ILLEGAL REQUEST */
|
||||
buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
|
||||
/* INVALID COMMAND OPERATION CODE */
|
||||
buffer[SPC_ASC_KEY_OFFSET] = 0x20;
|
||||
break;
|
||||
case TCM_UNKNOWN_MODE_PAGE:
|
||||
/* CURRENT ERROR */
|
||||
buffer[0] = 0x70;
|
||||
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
|
||||
/* ILLEGAL REQUEST */
|
||||
buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
|
||||
/* INVALID FIELD IN CDB */
|
||||
buffer[SPC_ASC_KEY_OFFSET] = 0x24;
|
||||
break;
|
||||
case TCM_CHECK_CONDITION_ABORT_CMD:
|
||||
/* CURRENT ERROR */
|
||||
buffer[0] = 0x70;
|
||||
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
|
||||
/* ABORTED COMMAND */
|
||||
buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
|
||||
/* BUS DEVICE RESET FUNCTION OCCURRED */
|
||||
buffer[SPC_ASC_KEY_OFFSET] = 0x29;
|
||||
buffer[SPC_ASCQ_KEY_OFFSET] = 0x03;
|
||||
break;
|
||||
case TCM_INCORRECT_AMOUNT_OF_DATA:
|
||||
/* CURRENT ERROR */
|
||||
buffer[0] = 0x70;
|
||||
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
|
||||
/* ABORTED COMMAND */
|
||||
buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
|
||||
/* WRITE ERROR */
|
||||
buffer[SPC_ASC_KEY_OFFSET] = 0x0c;
|
||||
/* NOT ENOUGH UNSOLICITED DATA */
|
||||
buffer[SPC_ASCQ_KEY_OFFSET] = 0x0d;
|
||||
break;
|
||||
case TCM_INVALID_CDB_FIELD:
|
||||
/* CURRENT ERROR */
|
||||
buffer[0] = 0x70;
|
||||
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
|
||||
/* ILLEGAL REQUEST */
|
||||
buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
|
||||
/* INVALID FIELD IN CDB */
|
||||
buffer[SPC_ASC_KEY_OFFSET] = 0x24;
|
||||
break;
|
||||
case TCM_INVALID_PARAMETER_LIST:
|
||||
/* CURRENT ERROR */
|
||||
buffer[0] = 0x70;
|
||||
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
|
||||
/* ILLEGAL REQUEST */
|
||||
buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
|
||||
/* INVALID FIELD IN PARAMETER LIST */
|
||||
buffer[SPC_ASC_KEY_OFFSET] = 0x26;
|
||||
break;
|
||||
case TCM_PARAMETER_LIST_LENGTH_ERROR:
|
||||
/* CURRENT ERROR */
|
||||
buffer[0] = 0x70;
|
||||
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
|
||||
/* ILLEGAL REQUEST */
|
||||
buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
|
||||
/* PARAMETER LIST LENGTH ERROR */
|
||||
buffer[SPC_ASC_KEY_OFFSET] = 0x1a;
|
||||
break;
|
||||
case TCM_UNEXPECTED_UNSOLICITED_DATA:
|
||||
/* CURRENT ERROR */
|
||||
buffer[0] = 0x70;
|
||||
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
|
||||
/* ABORTED COMMAND */
|
||||
buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
|
||||
/* WRITE ERROR */
|
||||
buffer[SPC_ASC_KEY_OFFSET] = 0x0c;
|
||||
/* UNEXPECTED_UNSOLICITED_DATA */
|
||||
buffer[SPC_ASCQ_KEY_OFFSET] = 0x0c;
|
||||
break;
|
||||
case TCM_SERVICE_CRC_ERROR:
|
||||
/* CURRENT ERROR */
|
||||
buffer[0] = 0x70;
|
||||
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
|
||||
/* ABORTED COMMAND */
|
||||
buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
|
||||
/* PROTOCOL SERVICE CRC ERROR */
|
||||
buffer[SPC_ASC_KEY_OFFSET] = 0x47;
|
||||
/* N/A */
|
||||
buffer[SPC_ASCQ_KEY_OFFSET] = 0x05;
|
||||
break;
|
||||
case TCM_SNACK_REJECTED:
|
||||
/* CURRENT ERROR */
|
||||
buffer[0] = 0x70;
|
||||
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
|
||||
/* ABORTED COMMAND */
|
||||
buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND;
|
||||
/* READ ERROR */
|
||||
buffer[SPC_ASC_KEY_OFFSET] = 0x11;
|
||||
/* FAILED RETRANSMISSION REQUEST */
|
||||
buffer[SPC_ASCQ_KEY_OFFSET] = 0x13;
|
||||
break;
|
||||
case TCM_WRITE_PROTECTED:
|
||||
/* CURRENT ERROR */
|
||||
buffer[0] = 0x70;
|
||||
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
|
||||
/* DATA PROTECT */
|
||||
buffer[SPC_SENSE_KEY_OFFSET] = DATA_PROTECT;
|
||||
/* WRITE PROTECTED */
|
||||
buffer[SPC_ASC_KEY_OFFSET] = 0x27;
|
||||
break;
|
||||
case TCM_ADDRESS_OUT_OF_RANGE:
|
||||
/* CURRENT ERROR */
|
||||
buffer[0] = 0x70;
|
||||
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
|
||||
/* ILLEGAL REQUEST */
|
||||
buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
|
||||
/* LOGICAL BLOCK ADDRESS OUT OF RANGE */
|
||||
buffer[SPC_ASC_KEY_OFFSET] = 0x21;
|
||||
break;
|
||||
case TCM_CHECK_CONDITION_UNIT_ATTENTION:
|
||||
/* CURRENT ERROR */
|
||||
buffer[0] = 0x70;
|
||||
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
|
||||
/* UNIT ATTENTION */
|
||||
buffer[SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION;
|
||||
core_scsi3_ua_for_check_condition(cmd, &asc, &ascq);
|
||||
buffer[SPC_ASC_KEY_OFFSET] = asc;
|
||||
buffer[SPC_ASCQ_KEY_OFFSET] = ascq;
|
||||
break;
|
||||
case TCM_CHECK_CONDITION_NOT_READY:
|
||||
/* CURRENT ERROR */
|
||||
buffer[0] = 0x70;
|
||||
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
|
||||
/* Not Ready */
|
||||
buffer[SPC_SENSE_KEY_OFFSET] = NOT_READY;
|
||||
buffer[SPC_ASC_KEY_OFFSET] = cmd->scsi_asc;
|
||||
buffer[SPC_ASCQ_KEY_OFFSET] = cmd->scsi_ascq;
|
||||
break;
|
||||
case TCM_MISCOMPARE_VERIFY:
|
||||
/* CURRENT ERROR */
|
||||
buffer[0] = 0x70;
|
||||
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
|
||||
buffer[SPC_SENSE_KEY_OFFSET] = MISCOMPARE;
|
||||
/* MISCOMPARE DURING VERIFY OPERATION */
|
||||
buffer[SPC_ASC_KEY_OFFSET] = 0x1d;
|
||||
buffer[SPC_ASCQ_KEY_OFFSET] = 0x00;
|
||||
break;
|
||||
case TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED:
|
||||
/* CURRENT ERROR */
|
||||
buffer[0] = 0x70;
|
||||
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
|
||||
/* ILLEGAL REQUEST */
|
||||
buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
|
||||
/* LOGICAL BLOCK GUARD CHECK FAILED */
|
||||
buffer[SPC_ASC_KEY_OFFSET] = 0x10;
|
||||
buffer[SPC_ASCQ_KEY_OFFSET] = 0x01;
|
||||
transport_err_sector_info(buffer, cmd->bad_sector);
|
||||
break;
|
||||
case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED:
|
||||
/* CURRENT ERROR */
|
||||
buffer[0] = 0x70;
|
||||
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
|
||||
/* ILLEGAL REQUEST */
|
||||
buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
|
||||
/* LOGICAL BLOCK APPLICATION TAG CHECK FAILED */
|
||||
buffer[SPC_ASC_KEY_OFFSET] = 0x10;
|
||||
buffer[SPC_ASCQ_KEY_OFFSET] = 0x02;
|
||||
transport_err_sector_info(buffer, cmd->bad_sector);
|
||||
break;
|
||||
case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED:
|
||||
/* CURRENT ERROR */
|
||||
buffer[0] = 0x70;
|
||||
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
|
||||
/* ILLEGAL REQUEST */
|
||||
buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
|
||||
/* LOGICAL BLOCK REFERENCE TAG CHECK FAILED */
|
||||
buffer[SPC_ASC_KEY_OFFSET] = 0x10;
|
||||
buffer[SPC_ASCQ_KEY_OFFSET] = 0x03;
|
||||
transport_err_sector_info(buffer, cmd->bad_sector);
|
||||
break;
|
||||
case TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE:
|
||||
default:
|
||||
/* CURRENT ERROR */
|
||||
buffer[0] = 0x70;
|
||||
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
|
||||
/*
|
||||
* Returning ILLEGAL REQUEST would cause immediate IO errors on
|
||||
* Solaris initiators. Returning NOT READY instead means the
|
||||
* operations will be retried a finite number of times and we
|
||||
* can survive intermittent errors.
|
||||
*/
|
||||
buffer[SPC_SENSE_KEY_OFFSET] = NOT_READY;
|
||||
/* LOGICAL UNIT COMMUNICATION FAILURE */
|
||||
buffer[SPC_ASC_KEY_OFFSET] = 0x08;
|
||||
break;
|
||||
translate_sense_reason(cmd, reason);
|
||||
cmd->scsi_status = SAM_STAT_CHECK_CONDITION;
|
||||
cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER;
|
||||
}
|
||||
/*
|
||||
* This code uses linux/include/scsi/scsi.h SAM status codes!
|
||||
*/
|
||||
cmd->scsi_status = SAM_STAT_CHECK_CONDITION;
|
||||
/*
|
||||
* Automatically padded, this value is encoded in the fabric's
|
||||
* data_length response PDU containing the SCSI defined sense data.
|
||||
*/
|
||||
cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER;
|
||||
|
||||
after_reason:
|
||||
trace_target_cmd_complete(cmd);
|
||||
return cmd->se_tfo->queue_status(cmd);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user