From: Chad Dupuis <chad.dup...@qlogic.com>

Wait for the IDC complete AEN before returning the loopback operation back to
the application to make sure the port is put back into normal operations.

Signed-off-by: Chad Dupuis <chad.dup...@qlogic.com>
Signed-off-by: Saurav Kashyap <saurav.kash...@qlogic.com>
---
 drivers/scsi/qla2xxx/qla_bsg.c |   39 +++++++++++++++++++++++++++++----------
 drivers/scsi/qla2xxx/qla_def.h |    6 ++++++
 drivers/scsi/qla2xxx/qla_isr.c |    3 +++
 drivers/scsi/qla2xxx/qla_os.c  |    1 +
 4 files changed, 39 insertions(+), 10 deletions(-)

diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index 169dc85..5d4f5cb 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -535,7 +535,7 @@ done:
 /* Disable loopback mode */
 static inline int
 qla81xx_reset_loopback_mode(scsi_qla_host_t *vha, uint16_t *config,
-    int wait)
+    int wait, int wait2)
 {
        int ret = 0;
        int rval = 0;
@@ -556,28 +556,45 @@ qla81xx_reset_loopback_mode(scsi_qla_host_t *vha, 
uint16_t *config,
                memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ;
 
                ha->notify_dcbx_comp = wait;
+               ha->notify_lb_portup_comp = wait2;
+
                ret = qla81xx_set_port_config(vha, new_config);
                if (ret != QLA_SUCCESS) {
                        ql_log(ql_log_warn, vha, 0x7025,
                            "Set port config failed.\n");
                        ha->notify_dcbx_comp = 0;
+                       ha->notify_lb_portup_comp = 0;
                        rval = -EINVAL;
                        goto done_reset_internal;
                }
 
                /* Wait for DCBX complete event */
                if (wait && !wait_for_completion_timeout(&ha->dcbx_comp,
-                       (20 * HZ))) {
+                       (DCBX_COMP_TIMEOUT * HZ))) {
                        ql_dbg(ql_dbg_user, vha, 0x7026,
-                           "State change notification not received.\n");
+                           "DCBX completion not received.\n");
                        ha->notify_dcbx_comp = 0;
+                       ha->notify_lb_portup_comp = 0;
                        rval = -EINVAL;
                        goto done_reset_internal;
                } else
                        ql_dbg(ql_dbg_user, vha, 0x7027,
-                           "State change received.\n");
+                           "DCBX completion received.\n");
+
+               if (wait2 &&
+                   !wait_for_completion_timeout(&ha->lb_portup_comp,
+                   (LB_PORTUP_COMP_TIMEOUT * HZ))) {
+                       ql_dbg(ql_dbg_user, vha, 0x70c5,
+                           "Port up completion not received.\n");
+                       ha->notify_lb_portup_comp = 0;
+                       rval = -EINVAL;
+                       goto done_reset_internal;
+               } else
+                       ql_dbg(ql_dbg_user, vha, 0x70c6,
+                           "Port up completion received.\n");
 
                ha->notify_dcbx_comp = 0;
+               ha->notify_lb_portup_comp = 0;
        }
 done_reset_internal:
        return rval;
@@ -618,10 +635,11 @@ qla81xx_set_loopback_mode(scsi_qla_host_t *vha, uint16_t 
*config,
        }
 
        /* Wait for DCBX complete event */
-       if (!wait_for_completion_timeout(&ha->dcbx_comp, (20 * HZ))) {
+       if (!wait_for_completion_timeout(&ha->dcbx_comp,
+           (DCBX_COMP_TIMEOUT * HZ))) {
                ql_dbg(ql_dbg_user, vha, 0x7022,
-                   "State change notification not received.\n");
-               ret = qla81xx_reset_loopback_mode(vha, new_config, 0);
+                   "DCBX completion not received.\n");
+               ret = qla81xx_reset_loopback_mode(vha, new_config, 0, 0);
                /*
                 * If the reset of the loopback mode doesn't work take a FCoE
                 * dump and reset the chip.
@@ -639,7 +657,7 @@ qla81xx_set_loopback_mode(scsi_qla_host_t *vha, uint16_t 
*config,
                        ha->flags.idc_compl_status = 0;
                } else
                        ql_dbg(ql_dbg_user, vha, 0x7023,
-                           "State change received.\n");
+                           "DCBX completion received.\n");
        }
 
        ha->notify_dcbx_comp = 0;
@@ -749,6 +767,7 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
                if (IS_QLA81XX(ha) || IS_QLA8031(ha)) {
                        memset(config, 0, sizeof(config));
                        memset(new_config, 0, sizeof(new_config));
+
                        if (qla81xx_get_port_config(vha, config)) {
                                ql_log(ql_log_warn, vha, 0x701f,
                                    "Get port config failed.\n");
@@ -773,7 +792,7 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
                                            config, new_config, elreq.options);
                                else
                                        rval = qla81xx_reset_loopback_mode(vha,
-                                           config, 1);
+                                           config, 1, 0);
                        else
                                rval = qla81xx_set_loopback_mode(vha, config,
                                    new_config, elreq.options);
@@ -817,7 +836,7 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
                                 * Also clear internal loopback
                                 */
                                ret = qla81xx_reset_loopback_mode(vha,
-                                   new_config, 0);
+                                   new_config, 0, 1);
                                if (ret) {
                                        /*
                                         * If the reset of the loopback mode
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index c081882..c650991 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2882,7 +2882,13 @@ struct qla_hw_data {
        struct completion mbx_cmd_comp; /* Serialize mbx access */
        struct completion mbx_intr_comp;  /* Used for completion notification */
        struct completion dcbx_comp;    /* For set port config notification */
+       struct completion lb_portup_comp; /* Used to wait for link up during
+                                          * loopback */
+#define DCBX_COMP_TIMEOUT      20
+#define LB_PORTUP_COMP_TIMEOUT 10
+
        int notify_dcbx_comp;
+       int notify_lb_portup_comp;
        struct mutex selflogin_lock;
 
        /* Basic firmware related information. */
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index cbf6a43..e9dbd74 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -1032,6 +1032,9 @@ skip_rio:
                        }
                }
        case MBA_IDC_COMPLETE:
+               if (ha->notify_lb_portup_comp)
+                       complete(&ha->lb_portup_comp);
+               /* Fallthru */
        case MBA_IDC_TIME_EXT:
                if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw))
                        qla81xx_idc_event(vha, mb[0], mb[1]);
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index c484e21..2c6dd3d 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -2465,6 +2465,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct 
pci_device_id *id)
        complete(&ha->mbx_cmd_comp);
        init_completion(&ha->mbx_intr_comp);
        init_completion(&ha->dcbx_comp);
+       init_completion(&ha->lb_portup_comp);
 
        set_bit(0, (unsigned long *) ha->vp_idx_map);
 
-- 
1.7.7

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to