summaryrefslogtreecommitdiff
path: root/drivers/target/target_core_transport.c
diff options
context:
space:
mode:
authorAndré Fabian Silva Delgado <emulatorman@parabola.nu>2015-12-15 14:52:16 -0300
committerAndré Fabian Silva Delgado <emulatorman@parabola.nu>2015-12-15 14:52:16 -0300
commit8d91c1e411f55d7ea91b1183a2e9f8088fb4d5be (patch)
treee9891aa6c295060d065adffd610c4f49ecf884f3 /drivers/target/target_core_transport.c
parenta71852147516bc1cb5b0b3cbd13639bfd4022dc8 (diff)
Linux-libre 4.3.2-gnu
Diffstat (limited to 'drivers/target/target_core_transport.c')
-rw-r--r--drivers/target/target_core_transport.c507
1 files changed, 222 insertions, 285 deletions
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index ce8574b72..5bacc7b5e 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -39,6 +39,7 @@
#include <net/sock.h>
#include <net/tcp.h>
#include <scsi/scsi_proto.h>
+#include <scsi/scsi_common.h>
#include <target/target_core_base.h>
#include <target/target_core_backend.h>
@@ -1074,6 +1075,55 @@ transport_set_vpd_ident(struct t10_vpd *vpd, unsigned char *page_83)
}
EXPORT_SYMBOL(transport_set_vpd_ident);
+static sense_reason_t
+target_check_max_data_sg_nents(struct se_cmd *cmd, struct se_device *dev,
+ unsigned int size)
+{
+ u32 mtl;
+
+ if (!cmd->se_tfo->max_data_sg_nents)
+ return TCM_NO_SENSE;
+ /*
+ * Check if fabric enforced maximum SGL entries per I/O descriptor
+ * exceeds se_cmd->data_length. If true, set SCF_UNDERFLOW_BIT +
+ * residual_count and reduce original cmd->data_length to maximum
+ * length based on single PAGE_SIZE entry scatter-lists.
+ */
+ mtl = (cmd->se_tfo->max_data_sg_nents * PAGE_SIZE);
+ if (cmd->data_length > mtl) {
+ /*
+ * If an existing CDB overflow is present, calculate new residual
+ * based on CDB size minus fabric maximum transfer length.
+ *
+ * If an existing CDB underflow is present, calculate new residual
+ * based on original cmd->data_length minus fabric maximum transfer
+ * length.
+ *
+ * Otherwise, set the underflow residual based on cmd->data_length
+ * minus fabric maximum transfer length.
+ */
+ if (cmd->se_cmd_flags & SCF_OVERFLOW_BIT) {
+ cmd->residual_count = (size - mtl);
+ } else if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) {
+ u32 orig_dl = size + cmd->residual_count;
+ cmd->residual_count = (orig_dl - mtl);
+ } else {
+ cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT;
+ cmd->residual_count = (cmd->data_length - mtl);
+ }
+ cmd->data_length = mtl;
+ /*
+ * Reset sbc_check_prot() calculated protection payload
+ * length based upon the new smaller MTL.
+ */
+ if (cmd->prot_length) {
+ u32 sectors = (mtl / dev->dev_attrib.block_size);
+ cmd->prot_length = dev->prot_length * sectors;
+ }
+ }
+ return TCM_NO_SENSE;
+}
+
sense_reason_t
target_cmd_size_check(struct se_cmd *cmd, unsigned int size)
{
@@ -1087,9 +1137,9 @@ target_cmd_size_check(struct se_cmd *cmd, unsigned int size)
" 0x%02x\n", cmd->se_tfo->get_fabric_name(),
cmd->data_length, size, cmd->t_task_cdb[0]);
- if (cmd->data_direction == DMA_TO_DEVICE) {
- pr_err("Rejecting underflow/overflow"
- " WRITE data\n");
+ if (cmd->data_direction == DMA_TO_DEVICE &&
+ cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) {
+ pr_err("Rejecting underflow/overflow WRITE data\n");
return TCM_INVALID_CDB_FIELD;
}
/*
@@ -1119,7 +1169,7 @@ target_cmd_size_check(struct se_cmd *cmd, unsigned int size)
}
}
- return 0;
+ return target_check_max_data_sg_nents(cmd, dev, size);
}
@@ -1177,14 +1227,7 @@ transport_check_alloc_task_attr(struct se_cmd *cmd)
" emulation is not supported\n");
return TCM_INVALID_CDB_FIELD;
}
- /*
- * Used to determine when ORDERED commands should go from
- * Dormant to Active status.
- */
- cmd->se_ordered_id = atomic_inc_return(&dev->dev_ordered_id);
- pr_debug("Allocated se_ordered_id: %u for Task Attr: 0x%02x on %s\n",
- cmd->se_ordered_id, cmd->sam_task_attr,
- dev->transport->name);
+
return 0;
}
@@ -1246,6 +1289,11 @@ target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb)
}
ret = dev->transport->parse_cdb(cmd);
+ if (ret == TCM_UNSUPPORTED_SCSI_OPCODE)
+ pr_warn_ratelimited("%s/%s: Unsupported SCSI Opcode 0x%02x, sending CHECK_CONDITION.\n",
+ cmd->se_tfo->get_fabric_name(),
+ cmd->se_sess->se_node_acl->initiatorname,
+ cmd->t_task_cdb[0]);
if (ret)
return ret;
@@ -1693,8 +1741,7 @@ void transport_generic_request_failure(struct se_cmd *cmd,
check_stop:
transport_lun_remove_cmd(cmd);
- if (!transport_cmd_check_stop_to_fabric(cmd))
- ;
+ transport_cmd_check_stop_to_fabric(cmd);
return;
queue_full:
@@ -1767,16 +1814,14 @@ static bool target_handle_task_attr(struct se_cmd *cmd)
*/
switch (cmd->sam_task_attr) {
case TCM_HEAD_TAG:
- pr_debug("Added HEAD_OF_QUEUE for CDB: 0x%02x, "
- "se_ordered_id: %u\n",
- cmd->t_task_cdb[0], cmd->se_ordered_id);
+ pr_debug("Added HEAD_OF_QUEUE for CDB: 0x%02x\n",
+ cmd->t_task_cdb[0]);
return false;
case TCM_ORDERED_TAG:
atomic_inc_mb(&dev->dev_ordered_sync);
- pr_debug("Added ORDERED for CDB: 0x%02x to ordered list, "
- " se_ordered_id: %u\n",
- cmd->t_task_cdb[0], cmd->se_ordered_id);
+ pr_debug("Added ORDERED for CDB: 0x%02x to ordered list\n",
+ cmd->t_task_cdb[0]);
/*
* Execute an ORDERED command if no other older commands
@@ -1800,10 +1845,8 @@ static bool target_handle_task_attr(struct se_cmd *cmd)
list_add_tail(&cmd->se_delayed_node, &dev->delayed_cmd_list);
spin_unlock(&dev->delayed_cmd_lock);
- pr_debug("Added CDB: 0x%02x Task Attr: 0x%02x to"
- " delayed CMD list, se_ordered_id: %u\n",
- cmd->t_task_cdb[0], cmd->sam_task_attr,
- cmd->se_ordered_id);
+ pr_debug("Added CDB: 0x%02x Task Attr: 0x%02x to delayed CMD listn",
+ cmd->t_task_cdb[0], cmd->sam_task_attr);
return true;
}
@@ -1888,20 +1931,18 @@ static void transport_complete_task_attr(struct se_cmd *cmd)
if (cmd->sam_task_attr == TCM_SIMPLE_TAG) {
atomic_dec_mb(&dev->simple_cmds);
dev->dev_cur_ordered_id++;
- pr_debug("Incremented dev->dev_cur_ordered_id: %u for"
- " SIMPLE: %u\n", dev->dev_cur_ordered_id,
- cmd->se_ordered_id);
+ pr_debug("Incremented dev->dev_cur_ordered_id: %u for SIMPLE\n",
+ dev->dev_cur_ordered_id);
} else if (cmd->sam_task_attr == TCM_HEAD_TAG) {
dev->dev_cur_ordered_id++;
- pr_debug("Incremented dev_cur_ordered_id: %u for"
- " HEAD_OF_QUEUE: %u\n", dev->dev_cur_ordered_id,
- cmd->se_ordered_id);
+ pr_debug("Incremented dev_cur_ordered_id: %u for HEAD_OF_QUEUE\n",
+ dev->dev_cur_ordered_id);
} else if (cmd->sam_task_attr == TCM_ORDERED_TAG) {
atomic_dec_mb(&dev->dev_ordered_sync);
dev->dev_cur_ordered_id++;
- pr_debug("Incremented dev_cur_ordered_id: %u for ORDERED:"
- " %u\n", dev->dev_cur_ordered_id, cmd->se_ordered_id);
+ pr_debug("Incremented dev_cur_ordered_id: %u for ORDERED\n",
+ dev->dev_cur_ordered_id);
}
target_restart_delayed_cmds(dev);
@@ -2615,37 +2656,159 @@ bool transport_wait_for_tasks(struct se_cmd *cmd)
}
EXPORT_SYMBOL(transport_wait_for_tasks);
-static int transport_get_sense_codes(
- struct se_cmd *cmd,
- u8 *asc,
- u8 *ascq)
+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 = ABORTED_COMMAND,
+ .asc = 0x10,
+ .ascq = 0x01, /* LOGICAL BLOCK GUARD CHECK FAILED */
+ .add_sector_info = true,
+ },
+ [TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED] = {
+ .key = ABORTED_COMMAND,
+ .asc = 0x10,
+ .ascq = 0x02, /* LOGICAL BLOCK APPLICATION TAG CHECK FAILED */
+ .add_sector_info = true,
+ },
+ [TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED] = {
+ .key = ABORTED_COMMAND,
+ .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 int translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason)
{
- *asc = cmd->scsi_asc;
- *ascq = cmd->scsi_ascq;
+ const struct sense_info *si;
+ u8 *buffer = cmd->sense_buffer;
+ int r = (__force int)reason;
+ u8 asc, ascq;
+ bool desc_format = target_sense_desc_format(cmd->se_dev);
- return 0;
-}
+ 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];
-static
-void transport_err_sector_info(unsigned char *buffer, sector_t bad_sector)
-{
- /* Place failed LBA in sense data information descriptor 0. */
- buffer[SPC_ADD_SENSE_LEN_OFFSET] = 0xc;
- buffer[SPC_DESC_TYPE_OFFSET] = 0; /* Information */
- buffer[SPC_ADDITIONAL_DESC_LEN_OFFSET] = 0xa;
- buffer[SPC_VALIDITY_OFFSET] = 0x80;
+ 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;
+ }
+
+ scsi_build_sense_buffer(desc_format, buffer, si->key, asc, ascq);
+ if (si->add_sector_info)
+ return scsi_set_sense_information(buffer,
+ cmd->scsi_sense_length,
+ cmd->bad_sector);
- /* Descriptor Information: failing sector */
- put_unaligned_be64(bad_sector, &buffer[12]);
+ return 0;
}
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) {
@@ -2655,243 +2818,17 @@ 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) {
+ int rc;
- 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;
- transport_get_sense_codes(cmd, &asc, &ascq);
- buffer[SPC_ASC_KEY_OFFSET] = asc;
- buffer[SPC_ASCQ_KEY_OFFSET] = 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;
+ cmd->scsi_status = SAM_STAT_CHECK_CONDITION;
+ cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER;
+ rc = translate_sense_reason(cmd, reason);
+ if (rc)
+ return rc;
}
- /*
- * 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);
}