aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/target/target_core_transport.c
diff options
context:
space:
mode:
authorNicholas Bellinger <nab@linux-iscsi.org>2012-02-13 02:38:14 -0800
committerNicholas Bellinger <nab@linux-iscsi.org>2012-02-25 14:37:49 -0800
commit3d28934aaae5e924afedf0f5cb42e1316514da6b (patch)
tree6a11e13b7da8187339f262c14726107ccb32eb1b /drivers/target/target_core_transport.c
parenttarget: Make target_release_cmd_kref release on empty list (diff)
downloadlinux-dev-3d28934aaae5e924afedf0f5cb42e1316514da6b.tar.xz
linux-dev-3d28934aaae5e924afedf0f5cb42e1316514da6b.zip
target: Add TMR_ABORT_TASK task management support
This patch adds initial support for TMR_ABORT_TASK ops for se_cmd descriptors using se_sess->sess_cmd_list and se_cmd->cmd_kref counting. It will perform an explict abort for all outstanding se_cmd ops based upon tmr->ref_task_tag that have not been set CMD_T_COMPLETE. It will cancel se_cmd->work and wait for backing I/O to complete before attempting to send SAM_STAT_TASK_ABORTED and perform target_put_sess_cmd() to release the referenced descriptor. It also adds a CMD_T_ABORTED check into transport_complete_task() to catch the completion from backend I/O that has been aborted, and updates transport_wait_for_tasks() to allow CMD_T_ABORTED usage with core_tmr_abort_task() context. Reported-by: Roland Dreier <roland@purestorage.com> Cc: Christoph Hellwig <hch@lst.de> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target/target_core_transport.c')
-rw-r--r--drivers/target/target_core_transport.c20
1 files changed, 13 insertions, 7 deletions
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 52a66710a293..19804b6fdbaa 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -699,17 +699,24 @@ void transport_complete_task(struct se_task *task, int success)
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
return;
}
-
- if (cmd->transport_state & CMD_T_FAILED) {
+ /*
+ * Check for case where an explict ABORT_TASK has been received
+ * and transport_wait_for_tasks() will be waiting for completion..
+ */
+ if (cmd->transport_state & CMD_T_ABORTED &&
+ cmd->transport_state & CMD_T_STOP) {
+ spin_unlock_irqrestore(&cmd->t_state_lock, flags);
+ complete(&cmd->t_transport_stop_comp);
+ return;
+ } else if (cmd->transport_state & CMD_T_FAILED) {
cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
INIT_WORK(&cmd->work, target_complete_failure_work);
} else {
- cmd->transport_state |= CMD_T_COMPLETE;
INIT_WORK(&cmd->work, target_complete_ok_work);
}
cmd->t_state = TRANSPORT_COMPLETE;
- cmd->transport_state |= CMD_T_ACTIVE;
+ cmd->transport_state |= (CMD_T_COMPLETE | CMD_T_ACTIVE);
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
queue_work(target_completion_wq, &cmd->work);
@@ -4374,8 +4381,7 @@ bool transport_wait_for_tasks(struct se_cmd *cmd)
cmd->transport_state &= ~CMD_T_LUN_STOP;
}
- if (!(cmd->transport_state & CMD_T_ACTIVE) ||
- (cmd->transport_state & CMD_T_ABORTED)) {
+ if (!(cmd->transport_state & CMD_T_ACTIVE)) {
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
return false;
}
@@ -4681,7 +4687,7 @@ static int transport_generic_do_tmr(struct se_cmd *cmd)
switch (tmr->function) {
case TMR_ABORT_TASK:
- tmr->response = TMR_FUNCTION_REJECTED;
+ core_tmr_abort_task(dev, tmr, cmd->se_sess);
break;
case TMR_ABORT_TASK_SET:
case TMR_CLEAR_ACA: