@@ -109,25 +109,43 @@ static int target_check_cdb_and_preempt(struct list_head *list,
return 1;
}
+static bool target_check_abort_state(struct se_cmd *se_cmd)
+{
+ return (se_cmd->transport_state & (CMD_T_COMPLETE | CMD_T_FABRIC_STOP));
+}
+
+static bool target_check_lur_state(struct se_cmd *se_cmd)
+{
+ return ((se_cmd->transport_state & CMD_T_FABRIC_STOP) ||
+ (!(se_cmd->transport_state & CMD_T_ACTIVE) &&
+ (se_cmd->transport_state & CMD_T_SENT)));
+}
+
static bool __target_check_io_state(struct se_cmd *se_cmd,
- struct se_session *tmr_sess, int tas)
+ struct se_session *tmr_sess, int tas,
+ bool (*check_transport_state)(struct se_cmd *))
{
struct se_session *sess = se_cmd->se_sess;
assert_spin_locked(&sess->sess_cmd_lock);
WARN_ON_ONCE(!irqs_disabled());
/*
- * If command already reached CMD_T_COMPLETE state within
- * target_complete_cmd() or CMD_T_FABRIC_STOP due to shutdown,
- * this se_cmd has been passed to fabric driver and will
- * not be aborted.
+ * For ABORT_TASK, if command already reached CMD_T_COMPLETE
+ * state within target_complete_cmd() or CMD_T_FABRIC_STOP
+ * due to shutdown, this se_cmd has been passed to fabric
+ * driver and will not be aborted.
+ *
+ * For LUN_RESET, this is checked using !CMD_T_ACTIVE and
+ * CMD_T_SENT to determine if se_cmd has already been
+ * handed off to fabric driver code, and abort here needs
+ * to be ignored.
*
* Otherwise, obtain a local se_cmd->cmd_kref now for TMR
* ABORT_TASK + LUN_RESET for CMD_T_ABORTED processing as
* long as se_cmd->cmd_kref is still active unless zero.
*/
spin_lock(&se_cmd->t_state_lock);
- if (se_cmd->transport_state & (CMD_T_COMPLETE | CMD_T_FABRIC_STOP)) {
+ if (check_transport_state(se_cmd)) {
pr_debug("Attempted to abort io tag: %llu already complete or"
" fabric stop, skipping\n", se_cmd->tag);
spin_unlock(&se_cmd->t_state_lock);
@@ -175,7 +193,8 @@ void core_tmr_abort_task(
printk("ABORT_TASK: Found referenced %s task_tag: %llu\n",
se_cmd->se_tfo->get_fabric_name(), ref_tag);
- if (!__target_check_io_state(se_cmd, se_sess, 0))
+ if (!__target_check_io_state(se_cmd, se_sess, 0,
+ target_check_abort_state))
continue;
list_del_init(&se_cmd->se_cmd_list);
@@ -339,7 +358,8 @@ static void core_tmr_drain_state_list(
continue;
spin_lock(&sess->sess_cmd_lock);
- rc = __target_check_io_state(cmd, tmr_sess, tas);
+ rc = __target_check_io_state(cmd, tmr_sess, tas,
+ target_check_lur_state);
spin_unlock(&sess->sess_cmd_lock);
if (!rc)
continue;
@@ -2082,6 +2082,10 @@ static void target_complete_ok_work(struct work_struct *work)
*/
if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) {
WARN_ON(!cmd->scsi_status);
+
+ if (cmd->transport_state & CMD_T_ABORTED)
+ goto queue_out;
+
ret = transport_send_check_condition_and_sense(
cmd, 0, 1);
if (ret == -EAGAIN || ret == -ENOMEM)
@@ -2108,6 +2112,9 @@ static void target_complete_ok_work(struct work_struct *work)
return;
} else if (rc) {
+ if (cmd->transport_state & CMD_T_ABORTED)
+ goto queue_out;
+
ret = transport_send_check_condition_and_sense(cmd,
rc, 0);
if (ret == -EAGAIN || ret == -ENOMEM)
@@ -2120,6 +2127,9 @@ static void target_complete_ok_work(struct work_struct *work)
}
queue_rsp:
+ if (cmd->transport_state & CMD_T_ABORTED)
+ goto queue_out;
+
switch (cmd->data_direction) {
case DMA_FROM_DEVICE:
if (cmd->scsi_status)
@@ -2174,6 +2184,7 @@ static void target_complete_ok_work(struct work_struct *work)
break;
}
+queue_out:
transport_lun_remove_cmd(cmd);
transport_cmd_check_stop_to_fabric(cmd);
return;