Commit aaa00cc9 authored by Bart Van Assche's avatar Bart Van Assche Committed by Martin K. Petersen

scsi: target/core: Fix TAS handling for aborted commands

The TASK ABORTED STATUS (TAS) bit is defined as follows in SAM:
"TASK_ABORTED: this status shall be returned if a command is aborted by a
command or task management function on another I_T nexus and the control
mode page TAS bit is set to one". TAS handling is spread over the target
core and the iSCSI target driver. If a LUN RESET is received, the target
core will send the TASK_ABORTED response for all commands for which such a
response has to be sent. If an ABORT TASK is received, only the iSCSI
target driver will send the TASK_ABORTED response for the commands for
which that response has to be sent.  That is a bug since all target drivers
have to honor the TAS bit. Fix this by moving the code that handles TAS
from the iSCSI target driver into the target core. Additionally, if a
command has been aborted, instead of sending the TASK_ABORTED status from
the context that processes the SCSI command send it from the context of the
ABORT TMF.  The core_tmr_abort_task() change in this patch causes the
CMD_T_TAS flag to be set if a TASK_ABORTED status has to be sent back to
the initiator that submitted the command. If that flag has been set
transport_cmd_finish_abort() will send the TASK_ABORTED response.

Cc: Nicholas Bellinger <nab@linux-iscsi.org>
Cc: Mike Christie <mchristi@redhat.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: David Disseldorp <ddiss@suse.de>
Cc: Hannes Reinecke <hare@suse.de>
Signed-off-by: default avatarBart Van Assche <bvanassche@acm.org>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent fbbd4923
...@@ -1493,8 +1493,6 @@ __iscsit_check_dataout_hdr(struct iscsi_conn *conn, void *buf, ...@@ -1493,8 +1493,6 @@ __iscsit_check_dataout_hdr(struct iscsi_conn *conn, void *buf,
if (hdr->flags & ISCSI_FLAG_CMD_FINAL) if (hdr->flags & ISCSI_FLAG_CMD_FINAL)
iscsit_stop_dataout_timer(cmd); iscsit_stop_dataout_timer(cmd);
transport_check_aborted_status(se_cmd,
(hdr->flags & ISCSI_FLAG_CMD_FINAL));
return iscsit_dump_data_payload(conn, payload_length, 1); return iscsit_dump_data_payload(conn, payload_length, 1);
} }
} else { } else {
...@@ -1509,12 +1507,9 @@ __iscsit_check_dataout_hdr(struct iscsi_conn *conn, void *buf, ...@@ -1509,12 +1507,9 @@ __iscsit_check_dataout_hdr(struct iscsi_conn *conn, void *buf,
* TASK_ABORTED status. * TASK_ABORTED status.
*/ */
if (se_cmd->transport_state & CMD_T_ABORTED) { if (se_cmd->transport_state & CMD_T_ABORTED) {
if (hdr->flags & ISCSI_FLAG_CMD_FINAL) if (hdr->flags & ISCSI_FLAG_CMD_FINAL &&
if (--cmd->outstanding_r2ts < 1) { --cmd->outstanding_r2ts < 1)
iscsit_stop_dataout_timer(cmd); iscsit_stop_dataout_timer(cmd);
transport_check_aborted_status(
se_cmd, 1);
}
return iscsit_dump_data_payload(conn, payload_length, 1); return iscsit_dump_data_payload(conn, payload_length, 1);
} }
......
...@@ -943,20 +943,8 @@ int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo) ...@@ -943,20 +943,8 @@ int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo)
return 0; return 0;
} }
spin_unlock_bh(&cmd->istate_lock); spin_unlock_bh(&cmd->istate_lock);
/* if (cmd->se_cmd.transport_state & CMD_T_ABORTED)
* Determine if delayed TASK_ABORTED status for WRITEs
* should be sent now if no unsolicited data out
* payloads are expected, or if the delayed status
* should be sent after unsolicited data out with
* ISCSI_FLAG_CMD_FINAL set in iscsi_handle_data_out()
*/
if (transport_check_aborted_status(se_cmd,
(cmd->unsolicited_data == 0)) != 0)
return 0; return 0;
/*
* Otherwise send CHECK_CONDITION and sense for
* exception
*/
return transport_send_check_condition_and_sense(se_cmd, return transport_send_check_condition_and_sense(se_cmd,
cmd->sense_reason, 0); cmd->sense_reason, 0);
} }
...@@ -974,13 +962,7 @@ int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo) ...@@ -974,13 +962,7 @@ int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo)
if (!(cmd->cmd_flags & if (!(cmd->cmd_flags &
ICF_NON_IMMEDIATE_UNSOLICITED_DATA)) { ICF_NON_IMMEDIATE_UNSOLICITED_DATA)) {
/* if (cmd->se_cmd.transport_state & CMD_T_ABORTED)
* Send the delayed TASK_ABORTED status for
* WRITEs if no more unsolicitied data is
* expected.
*/
if (transport_check_aborted_status(se_cmd, 1)
!= 0)
return 0; return 0;
iscsit_set_dataout_sequence_values(cmd); iscsit_set_dataout_sequence_values(cmd);
...@@ -995,11 +977,7 @@ int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo) ...@@ -995,11 +977,7 @@ int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo)
if ((cmd->data_direction == DMA_TO_DEVICE) && if ((cmd->data_direction == DMA_TO_DEVICE) &&
!(cmd->cmd_flags & ICF_NON_IMMEDIATE_UNSOLICITED_DATA)) { !(cmd->cmd_flags & ICF_NON_IMMEDIATE_UNSOLICITED_DATA)) {
/* if (cmd->se_cmd.transport_state & CMD_T_ABORTED)
* Send the delayed TASK_ABORTED status for WRITEs if
* no more nsolicitied data is expected.
*/
if (transport_check_aborted_status(se_cmd, 1) != 0)
return 0; return 0;
iscsit_set_unsoliticed_dataout(cmd); iscsit_set_unsoliticed_dataout(cmd);
......
...@@ -165,7 +165,8 @@ void core_tmr_abort_task( ...@@ -165,7 +165,8 @@ void core_tmr_abort_task(
printk("ABORT_TASK: Found referenced %s task_tag: %llu\n", printk("ABORT_TASK: Found referenced %s task_tag: %llu\n",
se_cmd->se_tfo->fabric_name, ref_tag); se_cmd->se_tfo->fabric_name, ref_tag);
if (!__target_check_io_state(se_cmd, se_sess, 0)) if (!__target_check_io_state(se_cmd, se_sess,
dev->dev_attrib.emulate_tas))
continue; continue;
spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
......
...@@ -1805,7 +1805,7 @@ void transport_generic_request_failure(struct se_cmd *cmd, ...@@ -1805,7 +1805,7 @@ void transport_generic_request_failure(struct se_cmd *cmd,
if (cmd->transport_complete_callback) if (cmd->transport_complete_callback)
cmd->transport_complete_callback(cmd, false, NULL); cmd->transport_complete_callback(cmd, false, NULL);
if (transport_check_aborted_status(cmd, 1)) if (cmd->transport_state & CMD_T_ABORTED)
return; return;
switch (sense_reason) { switch (sense_reason) {
...@@ -2012,8 +2012,6 @@ static bool target_handle_task_attr(struct se_cmd *cmd) ...@@ -2012,8 +2012,6 @@ static bool target_handle_task_attr(struct se_cmd *cmd)
return true; return true;
} }
static int __transport_check_aborted_status(struct se_cmd *, int);
void target_execute_cmd(struct se_cmd *cmd) void target_execute_cmd(struct se_cmd *cmd)
{ {
/* /*
...@@ -2023,7 +2021,7 @@ void target_execute_cmd(struct se_cmd *cmd) ...@@ -2023,7 +2021,7 @@ void target_execute_cmd(struct se_cmd *cmd)
* If the received CDB has already been aborted stop processing it here. * If the received CDB has already been aborted stop processing it here.
*/ */
spin_lock_irq(&cmd->t_state_lock); spin_lock_irq(&cmd->t_state_lock);
if (__transport_check_aborted_status(cmd, 1)) { if (cmd->transport_state & CMD_T_ABORTED) {
spin_unlock_irq(&cmd->t_state_lock); spin_unlock_irq(&cmd->t_state_lock);
return; return;
} }
...@@ -3237,55 +3235,6 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd, ...@@ -3237,55 +3235,6 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd,
} }
EXPORT_SYMBOL(transport_send_check_condition_and_sense); EXPORT_SYMBOL(transport_send_check_condition_and_sense);
static int __transport_check_aborted_status(struct se_cmd *cmd, int send_status)
__releases(&cmd->t_state_lock)
__acquires(&cmd->t_state_lock)
{
int ret;
assert_spin_locked(&cmd->t_state_lock);
WARN_ON_ONCE(!irqs_disabled());
if (!(cmd->transport_state & CMD_T_ABORTED))
return 0;
/*
* 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)) {
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%08llx\n", cmd->t_task_cdb[0], cmd->tag);
cmd->se_cmd_flags &= ~SCF_SEND_DELAYED_TAS;
cmd->scsi_status = SAM_STAT_TASK_ABORTED;
trace_target_cmd_complete(cmd);
spin_unlock_irq(&cmd->t_state_lock);
ret = cmd->se_tfo->queue_status(cmd);
if (ret)
transport_handle_queue_full(cmd, cmd->se_dev, ret, false);
spin_lock_irq(&cmd->t_state_lock);
return 1;
}
int transport_check_aborted_status(struct se_cmd *cmd, int send_status)
{
int ret;
spin_lock_irq(&cmd->t_state_lock);
ret = __transport_check_aborted_status(cmd, send_status);
spin_unlock_irq(&cmd->t_state_lock);
return ret;
}
EXPORT_SYMBOL(transport_check_aborted_status);
void transport_send_task_abort(struct se_cmd *cmd) void transport_send_task_abort(struct se_cmd *cmd)
{ {
unsigned long flags; unsigned long flags;
......
...@@ -136,7 +136,6 @@ enum se_cmd_flags_table { ...@@ -136,7 +136,6 @@ enum se_cmd_flags_table {
SCF_SENT_CHECK_CONDITION = 0x00000800, SCF_SENT_CHECK_CONDITION = 0x00000800,
SCF_OVERFLOW_BIT = 0x00001000, SCF_OVERFLOW_BIT = 0x00001000,
SCF_UNDERFLOW_BIT = 0x00002000, SCF_UNDERFLOW_BIT = 0x00002000,
SCF_SEND_DELAYED_TAS = 0x00004000,
SCF_ALUA_NON_OPTIMIZED = 0x00008000, SCF_ALUA_NON_OPTIMIZED = 0x00008000,
SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00020000, SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00020000,
SCF_COMPARE_AND_WRITE = 0x00080000, SCF_COMPARE_AND_WRITE = 0x00080000,
......
...@@ -171,7 +171,6 @@ void target_execute_cmd(struct se_cmd *cmd); ...@@ -171,7 +171,6 @@ void target_execute_cmd(struct se_cmd *cmd);
int transport_generic_free_cmd(struct se_cmd *, int); int transport_generic_free_cmd(struct se_cmd *, int);
bool transport_wait_for_tasks(struct se_cmd *); bool transport_wait_for_tasks(struct se_cmd *);
int transport_check_aborted_status(struct se_cmd *, int);
int transport_send_check_condition_and_sense(struct se_cmd *, int transport_send_check_condition_and_sense(struct se_cmd *,
sense_reason_t, int); sense_reason_t, int);
int target_get_sess_cmd(struct se_cmd *, bool); int target_get_sess_cmd(struct se_cmd *, bool);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment