diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2012-02-13 02:38:14 -0800 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2012-02-25 14:37:49 -0800 |
commit | 3d28934aaae5e924afedf0f5cb42e1316514da6b (patch) | |
tree | 6a11e13b7da8187339f262c14726107ccb32eb1b /drivers/target/target_core_transport.c | |
parent | ffc32d5259d107a3aa1b822e22f20b69cb9ec0a5 (diff) |
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.c | 20 |
1 files changed, 13 insertions, 7 deletions
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 52a66710a29..19804b6fdba 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: |