diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index 617cc3cbb..1e315e06f 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -5036,6 +5036,88 @@ static int scst_translate_lun(struct scst_cmd *cmd) return res; } +static void scst_handle_aca(struct scst_cmd *cmd) +{ + struct scst_order_data *order_data = cmd->cur_order_data; + unsigned long flags; + +again: + if (likely(!order_data->aca_tgt_dev)) { + if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_ACA)) { + TRACE_MGMT_DBG("Refusing ACA cmd %p, because there's no ACA, tgt_dev %p", + cmd, cmd->tgt_dev); + scst_set_cmd_error(cmd, + SCST_LOAD_SENSE(scst_sense_invalid_message)); + scst_set_cmd_abnormal_done_state(cmd); + } + return; + } + + spin_lock_irqsave(&order_data->sn_lock, flags); + if (!order_data->aca_tgt_dev) { + spin_unlock_irqrestore(&order_data->sn_lock, flags); + goto again; + } + + if (order_data->aca_tgt_dev == (unsigned long)cmd->tgt_dev) { + if (cmd->queue_type != SCST_CMD_QUEUE_ACA || + order_data->aca_cmd || cmd->dev->tmf_only) { + TRACE_DBG("Refusing cmd %p, because ACA active (aca_cmd %p, tgt_dev %p)", + cmd, order_data->aca_cmd, + cmd->tgt_dev); + goto out_unlock_aca_active; + } else { + TRACE_MGMT_DBG("ACA cmd %p (tgt_dev %p)", + cmd, cmd->tgt_dev); + order_data->aca_cmd = cmd; + /* allow it */ + } + } else { + /* Non-faulted I_T nexus */ + EXTRACHECKS_BUG_ON(cmd->dev->tst != SCST_TST_0_SINGLE_TASK_SET); + if (cmd->queue_type == SCST_CMD_QUEUE_ACA) { + TRACE_MGMT_DBG("Refusing ACA cmd %p from wrong I_T nexus (aca_tgt_dev %ld, cmd->tgt_dev %p)", + cmd, order_data->aca_tgt_dev, + cmd->tgt_dev); + scst_set_cmd_error(cmd, + SCST_LOAD_SENSE(scst_sense_invalid_message)); + goto out_unlock_aca_active; + } else { + if (cmd->cdb[0] == PERSISTENT_RESERVE_OUT && + (cmd->cdb[1] & 0x1f) == PR_PREEMPT_AND_ABORT) { + TRACE_MGMT_DBG("Allow PR PREEMPT AND ABORT cmd %p during ACA (tgt_dev %p)", + cmd, cmd->tgt_dev); + /* allow it */ + } else { + TRACE_DBG("Refusing other IT-nexus cmd %p, because ACA active (tgt_dev %p)", + cmd, cmd->tgt_dev); + if (cmd->cmd_naca) { + goto out_unlock_aca_active; + } else { + spin_unlock_irqrestore(&order_data->sn_lock, flags); + scst_set_cmd_error_status(cmd, SAM_STAT_BUSY); + goto out_bypass_aca; + } + } + } + } + + cmd->cmd_aca_allowed = 1; + + spin_unlock_irqrestore(&order_data->sn_lock, flags); + + return; + +out_unlock_aca_active: + spin_unlock_irqrestore(&order_data->sn_lock, flags); + scst_set_cmd_error_status(cmd, SAM_STAT_ACA_ACTIVE); + +out_bypass_aca: + cmd->cmd_aca_allowed = 1; /* for check in scst_pre_xmit_response2() */ + scst_set_cmd_abnormal_done_state(cmd); + return; +} + /* * No locks, but might be on IRQ. * @@ -5045,8 +5127,6 @@ static int scst_translate_lun(struct scst_cmd *cmd) static int __scst_init_cmd(struct scst_cmd *cmd) { int res = 0; - unsigned long flags; - struct scst_order_data *order_data; TRACE_ENTRY(); @@ -5055,8 +5135,6 @@ static int __scst_init_cmd(struct scst_cmd *cmd) int cnt; bool failure = false; - order_data = cmd->cur_order_data; - scst_set_cmd_state(cmd, SCST_CMD_STATE_PARSE); cnt = atomic_inc_return(&cmd->tgt_dev->tgt_dev_cmd_count); @@ -5102,73 +5180,9 @@ static int __scst_init_cmd(struct scst_cmd *cmd) * queue_type to change it if needed. ToDo. */ scst_pre_parse(cmd); -again: - if (unlikely(order_data->aca_tgt_dev != 0)) { - spin_lock_irqsave(&order_data->sn_lock, flags); - - if (order_data->aca_tgt_dev == 0) { - spin_unlock_irqrestore(&order_data->sn_lock, flags); - goto again; - } - - if (order_data->aca_tgt_dev == (unsigned long)cmd->tgt_dev) { - if ((cmd->queue_type != SCST_CMD_QUEUE_ACA) || - (order_data->aca_cmd != NULL) || - cmd->dev->tmf_only) { - TRACE_DBG("Refusing cmd %p, because ACA " - "active (aca_cmd %p, tgt_dev %p)", - cmd, order_data->aca_cmd, - cmd->tgt_dev); - goto out_unlock_aca_active; - } else { - TRACE_MGMT_DBG("ACA cmd %p (tgt_dev %p)", - cmd, cmd->tgt_dev); - order_data->aca_cmd = cmd; - /* allow it */ - } - } else { - /* Non-faulted I_T nexus */ - EXTRACHECKS_BUG_ON(cmd->dev->tst != SCST_TST_0_SINGLE_TASK_SET); - if (cmd->queue_type == SCST_CMD_QUEUE_ACA) { - TRACE_MGMT_DBG("Refusing ACA cmd %p " - "from wrong I_T nexus (aca_tgt_dev %ld, " - "cmd->tgt_dev %p)", cmd, - order_data->aca_tgt_dev, cmd->tgt_dev); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_invalid_message)); - goto out_unlock_aca_active; - } else { - if ((cmd->cdb[0] == PERSISTENT_RESERVE_OUT) && - ((cmd->cdb[1] & 0x1f) == PR_PREEMPT_AND_ABORT)) { - TRACE_MGMT_DBG("Allow PR PREEMPT AND " - "ABORT cmd %p during ACA " - "(tgt_dev %p)", cmd, cmd->tgt_dev); - /* allow it */ - } else { - TRACE_DBG("Refusing other IT-nexus " - "cmd %p, because ACA active " - "(tgt_dev %p)", cmd, cmd->tgt_dev); - if (cmd->cmd_naca) - goto out_unlock_aca_active; - else { - spin_unlock_irqrestore(&order_data->sn_lock, flags); - scst_set_cmd_error_status(cmd, SAM_STAT_BUSY); - goto out_bypass_aca; - } - } - } - } - - cmd->cmd_aca_allowed = 1; - - spin_unlock_irqrestore(&order_data->sn_lock, flags); - } else if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_ACA)) { - TRACE_MGMT_DBG("Refusing ACA cmd %p, because there's no ACA, " - "tgt_dev %p", cmd, cmd->tgt_dev); - scst_set_cmd_error(cmd, - SCST_LOAD_SENSE(scst_sense_invalid_message)); - goto out_abnormal; - } + scst_handle_aca(cmd); + if (cmd->completed) + goto out; if (!cmd->set_sn_on_restart_cmd) { if (!cmd->tgtt->multithreaded_init_done) @@ -5194,18 +5208,11 @@ out: out_busy_bypass_aca: scst_set_busy(cmd); - -out_bypass_aca: cmd->cmd_aca_allowed = 1; /* for check in scst_pre_xmit_response2() */ out_abnormal: scst_set_cmd_abnormal_done_state(cmd); goto out; - -out_unlock_aca_active: - spin_unlock_irqrestore(&order_data->sn_lock, flags); - scst_set_cmd_error_status(cmd, SAM_STAT_ACA_ACTIVE); - goto out_bypass_aca; } /* Called under scst_init_lock and IRQs disabled */