From: Nicholas Bellinger <nab@xxxxxxxxxxxxxxx> This patch converts qla_tgt_wait_for_cmds() to hold qla_hw_data->hardware_lock for qla_tgt_cmd state checks related to shutdown logic. This also includes setting ->cmd_free_comp_set for all cases to signal shutdown in tcm_qla2xxx code, and the removal of se_cmd->transport_wait_for_tasks() that forces all outstanding descriptors to complete before tcm_qla2xxx code wakes up ->cmd_free_comp. This patch also adds a secondary check in qla_tgt_handle_cmd_for_atio() for qla_tgt->tgt_stop to prevent incoming I/O during full shutdown before all qla_tgt_sess instances may have their ->tearing_down set, and adds qla_tgt_cmd->cmd_stop_free_comp used by tcm_qla2xxx code to handle a seperate completion race. Reported-by: Roland Dreier <roland@xxxxxxxxxxxxxxx> Cc: Roland Dreier <roland@xxxxxxxxxxxxxxx> Cc: Madhuranath Iyengar <mni@xxxxxxxxxxxxxxxxxxxxx> Signed-off-by: Nicholas Bellinger <nab@xxxxxxxxxxxxxxxxxxxxx> --- drivers/scsi/qla2xxx/qla_target.c | 52 +++++++++++++++--------------------- drivers/scsi/qla2xxx/qla_target.h | 1 + 2 files changed, 23 insertions(+), 30 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 757e971..66eedd6 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -369,13 +369,15 @@ void qla_tgt_response_pkt_all_vps(struct scsi_qla_host *vha, response_t *pkt) } -static void qla_tgt_wait_for_cmds(struct qla_tgt_sess *sess) +/* + * Called with qla_hw_data->hardware_lock held. + */ +static void qla_tgt_wait_for_cmds(struct qla_tgt_sess *sess, struct qla_hw_data *ha) { LIST_HEAD(tmp_list); struct qla_tgt_cmd *cmd; struct se_cmd *se_cmd; unsigned long flags; - int cmd_free; spin_lock_irqsave(&sess->sess_cmd_lock, flags); list_splice_init(&sess->sess_cmd_list, &tmp_list); @@ -386,38 +388,27 @@ static void qla_tgt_wait_for_cmds(struct qla_tgt_sess *sess) cmd = list_entry(tmp_list.next, struct qla_tgt_cmd, cmd_list); DEBUG22(qla_printk(KERN_INFO, sess->vha->hw, "Waiting for cmd:" " %p\n", cmd)); + /* + * This will signal that completion should be called from + * tcm_qla2xxx_release_cmd() context. + */ + atomic_set(&cmd->cmd_free_comp_set, 1); + spin_unlock_irq(&ha->hardware_lock); - if ((atomic_read(&cmd->cmd_free) != 0) || - (atomic_read(&cmd->cmd_stop_free) != 0)) - cmd_free = 1; - else { - cmd_free = 0; - atomic_set(&cmd->cmd_free_comp_set, 1); - smp_mb__after_atomic_dec(); - } list_del(&cmd->cmd_list); - DEBUG22(qla_printk(KERN_INFO, sess->vha->hw, "Waiting for cmd: %p," - " cmd_free: %d\n", cmd, cmd_free)); - se_cmd = &cmd->se_cmd; - - if (!cmd_free) { - if (se_cmd->transport_wait_for_tasks) { - DEBUG22(qla_printk(KERN_INFO, sess->vha->hw, "Before" - " se_cmd->transport_wait_for_tasks cmd:" - " %p, se_cmd: %p\n", cmd, se_cmd)); - se_cmd->transport_wait_for_tasks(se_cmd, 0, 0); - - DEBUG22(qla_printk(KERN_INFO, sess->vha->hw, "After" - " se_cmd->transport_wait_for_tasks ----------->\n")); - } - } - + /* + * Wait for completion of the outstanding descriptor in + * tcm_qla2xxx_release_cmd() from transport processing + * context, then a direct call to qla_tgt_free_cmd() below. + */ DEBUG22(qla_printk(KERN_INFO, sess->vha->hw, "Before" " wait_for_completion(&cmd->cmd_free_comp); cmd: %p," " se_cmd: %p\n", cmd, se_cmd)); + wait_for_completion(&cmd->cmd_free_comp); + DEBUG22(qla_printk(KERN_INFO, sess->vha->hw, "After" " wait_for_completion(&cmd->cmd_free_comp); cmd: %p," " se_cmd: %p\n", cmd, se_cmd)); @@ -429,6 +420,8 @@ static void qla_tgt_wait_for_cmds(struct qla_tgt_sess *sess) DEBUG22(qla_printk(KERN_INFO, sess->vha->hw, "After" " qla_tgt_free_cmd --------------------->\n")); + + spin_lock_irq(&ha->hardware_lock); } } @@ -444,9 +437,7 @@ static void qla_tgt_free_session_done(struct qla_tgt_sess *sess) tgt = sess->tgt; sess->tearing_down = 1; - spin_unlock_irq(&ha->hardware_lock); - qla_tgt_wait_for_cmds(sess); - spin_lock_irq(&ha->hardware_lock); + qla_tgt_wait_for_cmds(sess, ha); /* * Release the target session for FC Nexus from fabric module code. @@ -3294,6 +3285,7 @@ static int qla_tgt_handle_cmd_for_atio(struct scsi_qla_host *vha, atio_t *atio) INIT_LIST_HEAD(&cmd->cmd_list); init_completion(&cmd->cmd_free_comp); + init_completion(&cmd->cmd_stop_free_comp); memcpy(&cmd->atio.atio2x, atio, sizeof(*atio)); cmd->state = QLA_TGT_STATE_NEW; @@ -3324,7 +3316,7 @@ static int qla_tgt_handle_cmd_for_atio(struct scsi_qla_host *vha, atio_t *atio) } } - if (sess->tearing_down) + if (sess->tearing_down || tgt->tgt_stop) goto out_free_cmd; res = qla_tgt_send_cmd_to_target(vha, cmd, sess); diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index 42d5479..0e5cbfd8 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -902,6 +902,7 @@ struct qla_tgt_cmd { atomic_t cmd_free; atomic_t cmd_free_comp_set; struct completion cmd_free_comp; + struct completion cmd_stop_free_comp; struct se_cmd se_cmd; /* Sense buffer that will be mapped into outgoing status */ unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER]; -- 1.7.2.5 -- To unsubscribe from this list: send the line "unsubscribe target-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html