From 68259b5aac13a57cba797b9605ed9812158f0e72 Mon Sep 17 00:00:00 2001 From: Alex Leung Date: Fri, 21 Mar 2014 22:20:41 -0700 Subject: 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 Cc: Alex Leung Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers/target/target_core_transport.c') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 0a359fa..51a3754 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) void transport_cmd_finish_abort(struct se_cmd *cmd, int remove) { + if (cmd->se_cmd_flags & SCF_SE_LUN_CMD) + transport_lun_remove_cmd(cmd); + if (transport_cmd_check_stop_to_fabric(cmd)) return; if (remove) @@ -2784,13 +2787,17 @@ int transport_check_aborted_status(struct se_cmd *cmd, int send_status) if (!(cmd->transport_state & CMD_T_ABORTED)) return 0; - if (!send_status || (cmd->se_cmd_flags & SCF_SENT_DELAYED_TAS)) + /* + * If cmd has been aborted but either no status is to be sent or it has + * already been sent, just return + */ + if (!send_status || !(cmd->se_cmd_flags & SCF_SEND_DELAYED_TAS)) return 1; pr_debug("Sending delayed SAM_STAT_TASK_ABORTED status for CDB: 0x%02x ITT: 0x%08x\n", cmd->t_task_cdb[0], cmd->se_tfo->get_task_tag(cmd)); - cmd->se_cmd_flags |= SCF_SENT_DELAYED_TAS; + cmd->se_cmd_flags &= ~SCF_SEND_DELAYED_TAS; cmd->scsi_status = SAM_STAT_TASK_ABORTED; trace_target_cmd_complete(cmd); cmd->se_tfo->queue_status(cmd); @@ -2804,7 +2811,7 @@ void transport_send_task_abort(struct se_cmd *cmd) unsigned long flags; spin_lock_irqsave(&cmd->t_state_lock, flags); - if (cmd->se_cmd_flags & (SCF_SENT_CHECK_CONDITION | SCF_SENT_DELAYED_TAS)) { + if (cmd->se_cmd_flags & (SCF_SENT_CHECK_CONDITION)) { spin_unlock_irqrestore(&cmd->t_state_lock, flags); return; } @@ -2819,6 +2826,7 @@ void transport_send_task_abort(struct se_cmd *cmd) if (cmd->data_direction == DMA_TO_DEVICE) { if (cmd->se_tfo->write_pending_status(cmd) != 0) { cmd->transport_state |= CMD_T_ABORTED; + cmd->se_cmd_flags |= SCF_SEND_DELAYED_TAS; smp_mb__after_atomic_inc(); return; } -- cgit v1.1