qlcnic: modify reset recovery path in diag mode
authorSony Chacko <sony.chacko@qlogic.com>
Thu, 23 May 2013 21:04:32 +0000 (21:04 +0000)
committerDavid S. Miller <davem@davemloft.net>
Sat, 25 May 2013 06:04:54 +0000 (23:04 -0700)
Provide diagnostics routines enough time to unwind before
proceeding with reset recovery.

Signed-off-by: Sony Chacko <sony.chacko@qlogic.com>
Signed-off-by: Shahed Shaikh <shahed.shaikh@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c

index 8affec5e6eb8e6dc12306855947dcfa304f7f29d..4ff0625a0cef49378cb26164bdeab23288abb963 100644 (file)
@@ -1477,7 +1477,6 @@ int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter);
 void qlcnic_update_cmd_producer(struct qlcnic_host_tx_ring *);
 
 /* Functions from qlcnic_ethtool.c */
-
 int qlcnic_check_loopback_buff(unsigned char *, u8 []);
 int qlcnic_do_lb_test(struct qlcnic_adapter *, u8);
 int qlcnic_loopback_test(struct net_device *, u8);
@@ -1897,6 +1896,11 @@ static inline void qlcnic_release_diag_lock(struct qlcnic_adapter *adapter)
        clear_bit(__QLCNIC_DIAG_MODE, &adapter->state);
 }
 
+static inline int qlcnic_check_diag_status(struct qlcnic_adapter *adapter)
+{
+       return test_bit(__QLCNIC_DIAG_MODE, &adapter->state);
+}
+
 extern const struct ethtool_ops qlcnic_sriov_vf_ethtool_ops;
 extern const struct ethtool_ops qlcnic_ethtool_ops;
 extern const struct ethtool_ops qlcnic_ethtool_failed_ops;
index f5db67fc9f55a0dd319112462b0952af932f3ffe..1bfe283a94125f6b6ba0abbeaa4692c00e37f491 100644 (file)
@@ -314,6 +314,7 @@ struct qlc_83xx_idc {
        u8              vnic_state;
        u8              vnic_wait_limit;
        u8              quiesce_req;
+       u8              delay_reset;
        char            **name;
 };
 
index 5e7fb1dfb97b54c63c46314eea8eeccd9dbbc643..aa26250d73740e7eadf0c9b442ac4f6fa627bfef 100644 (file)
@@ -649,6 +649,7 @@ static void qlcnic_83xx_idc_update_idc_params(struct qlcnic_adapter *adapter)
        ahw->idc.collect_dump = 0;
        ahw->reset_context = 0;
        adapter->tx_timeo_cnt = 0;
+       ahw->idc.delay_reset = 0;
 
        clear_bit(__QLCNIC_RESETTING, &adapter->state);
 }
@@ -883,21 +884,41 @@ static int qlcnic_83xx_idc_need_reset_state(struct qlcnic_adapter *adapter)
        int ret = 0;
 
        if (adapter->ahw->idc.prev_state != QLC_83XX_IDC_DEV_NEED_RESET) {
-               qlcnic_83xx_idc_update_drv_ack_reg(adapter, 1, 1);
                qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
                set_bit(__QLCNIC_RESETTING, &adapter->state);
                clear_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
                if (adapter->ahw->nic_mode == QLC_83XX_VIRTUAL_NIC_MODE)
                        qlcnic_83xx_disable_vnic_mode(adapter, 1);
-               qlcnic_83xx_idc_detach_driver(adapter);
+
+               if (qlcnic_check_diag_status(adapter)) {
+                       dev_info(&adapter->pdev->dev,
+                                "%s: Wait for diag completion\n", __func__);
+                       adapter->ahw->idc.delay_reset = 1;
+                       return 0;
+               } else {
+                       qlcnic_83xx_idc_update_drv_ack_reg(adapter, 1, 1);
+                       qlcnic_83xx_idc_detach_driver(adapter);
+               }
        }
 
-       /* Check ACK from other functions */
-       ret = qlcnic_83xx_idc_check_reset_ack_reg(adapter);
-       if (ret) {
+       if (qlcnic_check_diag_status(adapter)) {
                dev_info(&adapter->pdev->dev,
-                        "%s: Waiting for reset ACK\n", __func__);
-               return 0;
+                        "%s: Wait for diag completion\n", __func__);
+               return  -1;
+       } else {
+               if (adapter->ahw->idc.delay_reset) {
+                       qlcnic_83xx_idc_update_drv_ack_reg(adapter, 1, 1);
+                       qlcnic_83xx_idc_detach_driver(adapter);
+                       adapter->ahw->idc.delay_reset = 0;
+               }
+
+               /* Check for ACK from other functions */
+               ret = qlcnic_83xx_idc_check_reset_ack_reg(adapter);
+               if (ret) {
+                       dev_info(&adapter->pdev->dev,
+                                "%s: Waiting for reset ACK\n", __func__);
+                       return -1;
+               }
        }
 
        /* Transit to INIT state and restart the HW */