diff options
author | Alex Leung <amleung21@yahoo.com> | 2014-03-22 01:20:41 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2014-04-07 04:48:50 -0400 |
commit | 68259b5aac13a57cba797b9605ed9812158f0e72 (patch) | |
tree | 914de31ac9381cb8a1f591af859ab91adaeee4db | |
parent | f46d6a8a01d6bbd83a97140f30a72a89b038807b (diff) |
target: Fix Task Aborted Status (TAS) handling
This patch addresses three of long standing issues wrt to Task
Aborted Status (TAS) handling.
The first is the incorrect assumption in core_tmr_handle_tas_abort()
that TASK_ABORTED status is sent for the task referenced by TMR
ABORT_TASK, and sending TASK_ABORTED status for TMR LUN_RESET on
the same nexus the LUN_RESET was received.
The second is to ensure the lun reference count is dropped within
transport_cmd_finish_abort() by calling transport_lun_remove_cmd()
before invoking transport_cmd_check_stop_to_fabric().
The last is to fix the delayed TAS handling to allow outstanding
WRITEs to complete before sending the TASK_ABORTED status. This
includes changing transport_check_aborted_status() to avoid
processing when SCF_SEND_DELAYED_TAS has not be set, and updating
transport_send_task_abort() to drop the SCF_SENT_DELAYED_TAS
check.
Signed-off-by: Alex Leung <amleung21@yahoo.com>
Cc: Alex Leung <amleung21@yahoo.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r-- | drivers/target/target_core_tmr.c | 18 | ||||
-rw-r--r-- | drivers/target/target_core_transport.c | 14 | ||||
-rw-r--r-- | include/target/target_core_base.h | 2 |
3 files changed, 18 insertions, 16 deletions
diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 70c638f730af..3f0338fff240 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c | |||
@@ -87,14 +87,17 @@ static void core_tmr_handle_tas_abort( | |||
87 | struct se_cmd *cmd, | 87 | struct se_cmd *cmd, |
88 | int tas) | 88 | int tas) |
89 | { | 89 | { |
90 | bool remove = true; | ||
90 | /* | 91 | /* |
91 | * TASK ABORTED status (TAS) bit support | 92 | * TASK ABORTED status (TAS) bit support |
92 | */ | 93 | */ |
93 | if ((tmr_nacl && | 94 | if ((tmr_nacl && |
94 | (tmr_nacl == cmd->se_sess->se_node_acl)) || tas) | 95 | (tmr_nacl != cmd->se_sess->se_node_acl)) && tas) { |
96 | remove = false; | ||
95 | transport_send_task_abort(cmd); | 97 | transport_send_task_abort(cmd); |
98 | } | ||
96 | 99 | ||
97 | transport_cmd_finish_abort(cmd, 0); | 100 | transport_cmd_finish_abort(cmd, remove); |
98 | } | 101 | } |
99 | 102 | ||
100 | static int target_check_cdb_and_preempt(struct list_head *list, | 103 | static int target_check_cdb_and_preempt(struct list_head *list, |
@@ -150,18 +153,9 @@ void core_tmr_abort_task( | |||
150 | 153 | ||
151 | cancel_work_sync(&se_cmd->work); | 154 | cancel_work_sync(&se_cmd->work); |
152 | transport_wait_for_tasks(se_cmd); | 155 | transport_wait_for_tasks(se_cmd); |
153 | /* | ||
154 | * Now send SAM_STAT_TASK_ABORTED status for the referenced | ||
155 | * se_cmd descriptor.. | ||
156 | */ | ||
157 | transport_send_task_abort(se_cmd); | ||
158 | /* | ||
159 | * Also deal with possible extra acknowledge reference.. | ||
160 | */ | ||
161 | if (se_cmd->se_cmd_flags & SCF_ACK_KREF) | ||
162 | target_put_sess_cmd(se_sess, se_cmd); | ||
163 | 156 | ||
164 | target_put_sess_cmd(se_sess, se_cmd); | 157 | target_put_sess_cmd(se_sess, se_cmd); |
158 | transport_cmd_finish_abort(se_cmd, true); | ||
165 | 159 | ||
166 | printk("ABORT_TASK: Sending TMR_FUNCTION_COMPLETE for" | 160 | printk("ABORT_TASK: Sending TMR_FUNCTION_COMPLETE for" |
167 | " ref_tag: %d\n", ref_tag); | 161 | " ref_tag: %d\n", ref_tag); |
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 0a359fa82bd3..51a375453d9b 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
@@ -603,6 +603,9 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd) | |||
603 | 603 | ||
604 | void transport_cmd_finish_abort(struct se_cmd *cmd, int remove) | 604 | void transport_cmd_finish_abort(struct se_cmd *cmd, int remove) |
605 | { | 605 | { |
606 | if (cmd->se_cmd_flags & SCF_SE_LUN_CMD) | ||
607 | transport_lun_remove_cmd(cmd); | ||
608 | |||
606 | if (transport_cmd_check_stop_to_fabric(cmd)) | 609 | if (transport_cmd_check_stop_to_fabric(cmd)) |
607 | return; | 610 | return; |
608 | if (remove) | 611 | if (remove) |
@@ -2784,13 +2787,17 @@ int transport_check_aborted_status(struct se_cmd *cmd, int send_status) | |||
2784 | if (!(cmd->transport_state & CMD_T_ABORTED)) | 2787 | if (!(cmd->transport_state & CMD_T_ABORTED)) |
2785 | return 0; | 2788 | return 0; |
2786 | 2789 | ||
2787 | if (!send_status || (cmd->se_cmd_flags & SCF_SENT_DELAYED_TAS)) | 2790 | /* |
2791 | * If cmd has been aborted but either no status is to be sent or it has | ||
2792 | * already been sent, just return | ||
2793 | */ | ||
2794 | if (!send_status || !(cmd->se_cmd_flags & SCF_SEND_DELAYED_TAS)) | ||
2788 | return 1; | 2795 | return 1; |
2789 | 2796 | ||
2790 | pr_debug("Sending delayed SAM_STAT_TASK_ABORTED status for CDB: 0x%02x ITT: 0x%08x\n", | 2797 | pr_debug("Sending delayed SAM_STAT_TASK_ABORTED status for CDB: 0x%02x ITT: 0x%08x\n", |
2791 | cmd->t_task_cdb[0], cmd->se_tfo->get_task_tag(cmd)); | 2798 | cmd->t_task_cdb[0], cmd->se_tfo->get_task_tag(cmd)); |
2792 | 2799 | ||
2793 | cmd->se_cmd_flags |= SCF_SENT_DELAYED_TAS; | 2800 | cmd->se_cmd_flags &= ~SCF_SEND_DELAYED_TAS; |
2794 | cmd->scsi_status = SAM_STAT_TASK_ABORTED; | 2801 | cmd->scsi_status = SAM_STAT_TASK_ABORTED; |
2795 | trace_target_cmd_complete(cmd); | 2802 | trace_target_cmd_complete(cmd); |
2796 | cmd->se_tfo->queue_status(cmd); | 2803 | cmd->se_tfo->queue_status(cmd); |
@@ -2804,7 +2811,7 @@ void transport_send_task_abort(struct se_cmd *cmd) | |||
2804 | unsigned long flags; | 2811 | unsigned long flags; |
2805 | 2812 | ||
2806 | spin_lock_irqsave(&cmd->t_state_lock, flags); | 2813 | spin_lock_irqsave(&cmd->t_state_lock, flags); |
2807 | if (cmd->se_cmd_flags & (SCF_SENT_CHECK_CONDITION | SCF_SENT_DELAYED_TAS)) { | 2814 | if (cmd->se_cmd_flags & (SCF_SENT_CHECK_CONDITION)) { |
2808 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | 2815 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); |
2809 | return; | 2816 | return; |
2810 | } | 2817 | } |
@@ -2819,6 +2826,7 @@ void transport_send_task_abort(struct se_cmd *cmd) | |||
2819 | if (cmd->data_direction == DMA_TO_DEVICE) { | 2826 | if (cmd->data_direction == DMA_TO_DEVICE) { |
2820 | if (cmd->se_tfo->write_pending_status(cmd) != 0) { | 2827 | if (cmd->se_tfo->write_pending_status(cmd) != 0) { |
2821 | cmd->transport_state |= CMD_T_ABORTED; | 2828 | cmd->transport_state |= CMD_T_ABORTED; |
2829 | cmd->se_cmd_flags |= SCF_SEND_DELAYED_TAS; | ||
2822 | smp_mb__after_atomic_inc(); | 2830 | smp_mb__after_atomic_inc(); |
2823 | return; | 2831 | return; |
2824 | } | 2832 | } |
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index f13fd09d91dc..ec3e3a3ff4f6 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h | |||
@@ -162,7 +162,7 @@ enum se_cmd_flags_table { | |||
162 | SCF_SENT_CHECK_CONDITION = 0x00000800, | 162 | SCF_SENT_CHECK_CONDITION = 0x00000800, |
163 | SCF_OVERFLOW_BIT = 0x00001000, | 163 | SCF_OVERFLOW_BIT = 0x00001000, |
164 | SCF_UNDERFLOW_BIT = 0x00002000, | 164 | SCF_UNDERFLOW_BIT = 0x00002000, |
165 | SCF_SENT_DELAYED_TAS = 0x00004000, | 165 | SCF_SEND_DELAYED_TAS = 0x00004000, |
166 | SCF_ALUA_NON_OPTIMIZED = 0x00008000, | 166 | SCF_ALUA_NON_OPTIMIZED = 0x00008000, |
167 | SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00020000, | 167 | SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00020000, |
168 | SCF_ACK_KREF = 0x00040000, | 168 | SCF_ACK_KREF = 0x00040000, |