@@ -1822,7 +1822,10 @@ void transport_generic_request_failure(struct se_cmd *cmd,
}
ret = transport_send_check_condition_and_sense(cmd, sense_reason, 0);
- if (ret)
+ if (ret == -EBUSY) {
+ cmd->scsi_status = SAM_STAT_BUSY;
+ goto queue_status;
+ } else if (ret)
goto queue_full;
check_stop:
@@ -3149,10 +3152,13 @@ static int 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;
+ int r;
u8 asc, ascq;
bool desc_format = target_sense_desc_format(cmd->se_dev);
+lookup_reason:
+ r = (__force int)reason;
+
if (r < ARRAY_SIZE(sense_info_table) && sense_info_table[r].key)
si = &sense_info_table[r];
else
@@ -3160,7 +3166,13 @@ static int translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason)
TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE];
if (reason == TCM_CHECK_CONDITION_UNIT_ATTENTION) {
- core_scsi3_ua_for_check_condition(cmd, &asc, &ascq);
+ reason = core_scsi3_ua_for_check_condition(cmd, &asc, &ascq);
+ if (reason == TCM_LUN_BUSY) {
+ return -EBUSY;
+ } else if (reason != TCM_CHECK_CONDITION_UNIT_ATTENTION) {
+ goto lookup_reason;
+ }
+
WARN_ON_ONCE(asc == 0);
} else if (si->asc == 0) {
WARN_ON_ONCE(cmd->scsi_asc == 0);
@@ -3172,11 +3184,13 @@ static int translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason)
}
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);
-
+ if (si->add_sector_info) {
+ if (scsi_set_sense_information(buffer, cmd->scsi_sense_length,
+ cmd->bad_sector)) {
+ reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+ goto lookup_reason;
+ }
+ }
return 0;
}
@@ -3197,12 +3211,16 @@ static int translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason)
if (!from_transport) {
int rc;
+ rc = translate_sense_reason(cmd, reason);
+ if (rc) {
+ spin_lock_irqsave(&cmd->t_state_lock, flags);
+ cmd->se_cmd_flags &= ~SCF_SENT_CHECK_CONDITION;
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+ return rc;
+ }
cmd->se_cmd_flags |= SCF_EMULATED_TASK_SENSE;
cmd->scsi_status = SAM_STAT_CHECK_CONDITION;
cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER;
- rc = translate_sense_reason(cmd, reason);
- if (rc)
- return rc;
}
trace_target_cmd_complete(cmd);
@@ -202,7 +202,7 @@ void core_scsi3_ua_release_all(
spin_unlock(&deve->ua_lock);
}
-void core_scsi3_ua_for_check_condition(
+sense_reason_t core_scsi3_ua_for_check_condition(
struct se_cmd *cmd,
u8 *asc,
u8 *ascq)
@@ -213,24 +213,27 @@ void core_scsi3_ua_for_check_condition(
struct se_node_acl *nacl;
struct se_ua *ua = NULL, *ua_p;
int head = 1;
+ bool found = false;
if (!sess)
- return;
+ return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
nacl = sess->se_node_acl;
- if (!nacl)
- return;
+ if (WARN_ON_ONCE(!nacl))
+ return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
rcu_read_lock();
deve = target_nacl_find_deve(nacl, cmd->orig_fe_lun);
if (!deve) {
rcu_read_unlock();
- return;
+ return TCM_NON_EXISTENT_LUN;
}
+
if (!atomic_read(&deve->ua_count)) {
rcu_read_unlock();
- return;
+ goto ua_not_found;
}
+
/*
* The highest priority Unit Attentions are placed at the head of the
* struct se_dev_entry->ua_list, and will be returned in CHECK_CONDITION +
@@ -246,6 +249,7 @@ void core_scsi3_ua_for_check_condition(
if (dev->dev_attrib.emulate_ua_intlck_ctrl != 0) {
*asc = ua->ua_asc;
*ascq = ua->ua_ascq;
+ found = true;
break;
}
/*
@@ -257,6 +261,7 @@ void core_scsi3_ua_for_check_condition(
*asc = ua->ua_asc;
*ascq = ua->ua_ascq;
head = 0;
+ found = true;
}
list_del(&ua->ua_nacl_list);
kmem_cache_free(se_ua_cache, ua);
@@ -266,6 +271,15 @@ void core_scsi3_ua_for_check_condition(
spin_unlock(&deve->ua_lock);
rcu_read_unlock();
+ if (!found) {
+ua_not_found:
+ /*
+ * Multiple commands might have raced and hit the ua_count>0
+ * check in target_scsi3_ua_check.
+ */
+ return TCM_LUN_BUSY;
+ }
+
pr_debug("[%s]: %s UNIT ATTENTION condition with"
" INTLCK_CTRL: %d, mapped LUN: %llu, got CDB: 0x%02x"
" reported ASC: 0x%02x, ASCQ: 0x%02x\n",
@@ -273,6 +287,7 @@ void core_scsi3_ua_for_check_condition(
(dev->dev_attrib.emulate_ua_intlck_ctrl != 0) ? "Reporting" :
"Releasing", dev->dev_attrib.emulate_ua_intlck_ctrl,
cmd->orig_fe_lun, cmd->t_task_cdb[0], *asc, *ascq);
+ return TCM_CHECK_CONDITION_UNIT_ATTENTION;
}
int core_scsi3_ua_clear_for_request_sense(
@@ -38,7 +38,8 @@
extern int core_scsi3_ua_allocate(struct se_dev_entry *, u8, u8);
extern void target_ua_allocate_lun(struct se_node_acl *, u32, u8, u8);
extern void core_scsi3_ua_release_all(struct se_dev_entry *);
-extern void core_scsi3_ua_for_check_condition(struct se_cmd *, u8 *, u8 *);
+extern sense_reason_t core_scsi3_ua_for_check_condition(struct se_cmd *, u8 *,
+ u8 *);
extern int core_scsi3_ua_clear_for_request_sense(struct se_cmd *,
u8 *, u8 *);