qlcnic: Register netdev in FAILED state for 83xx/84xx
authorSucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Mon, 4 Nov 2013 18:31:29 +0000 (13:31 -0500)
committerDavid S. Miller <davem@davemloft.net>
Mon, 4 Nov 2013 20:33:19 +0000 (15:33 -0500)
o Without failing probe, register netdev when device is in FAILED state.
o Device will come up with minimum functionality and allow diagnostics and
  repair of the adapter.

Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@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.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c

index 0c2405dbc970eed07e69dc411bf73c1f1c65bfe0..db83edfac723c2035d6a7ab8d9d284c603fe68ae 100644 (file)
@@ -961,6 +961,7 @@ struct qlcnic_ipaddr {
 #define __QLCNIC_SRIOV_CAPABLE         11
 #define __QLCNIC_MBX_POLL_ENABLE       12
 #define __QLCNIC_DIAG_MODE             13
+#define __QLCNIC_MAINTENANCE_MODE      16
 
 #define QLCNIC_INTERRUPT_TEST          1
 #define QLCNIC_LOOPBACK_TEST           2
index a44b9395b37a78ff2cc905fe557b675bbb8c9638..359e0f279b71b871376c823712f8865921c101a7 100644 (file)
@@ -325,7 +325,8 @@ inline void qlcnic_83xx_clear_legacy_intr_mask(struct qlcnic_adapter *adapter)
 
 inline void qlcnic_83xx_set_legacy_intr_mask(struct qlcnic_adapter *adapter)
 {
-       writel(1, adapter->tgt_mask_reg);
+       if (adapter->tgt_mask_reg)
+               writel(1, adapter->tgt_mask_reg);
 }
 
 /* Enable MSI-x and INT-x interrupts */
@@ -498,8 +499,11 @@ void qlcnic_83xx_free_mbx_intr(struct qlcnic_adapter *adapter)
                num_msix = 0;
 
        msleep(20);
-       synchronize_irq(adapter->msix_entries[num_msix].vector);
-       free_irq(adapter->msix_entries[num_msix].vector, adapter);
+
+       if (adapter->msix_entries) {
+               synchronize_irq(adapter->msix_entries[num_msix].vector);
+               free_irq(adapter->msix_entries[num_msix].vector, adapter);
+       }
 }
 
 int qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *adapter)
@@ -760,6 +764,9 @@ int qlcnic_83xx_issue_cmd(struct qlcnic_adapter *adapter,
        int cmd_type, err, opcode;
        unsigned long timeout;
 
+       if (!mbx)
+               return -EIO;
+
        opcode = LSW(cmd->req.arg[0]);
        cmd_type = cmd->type;
        err = mbx->ops->enqueue_cmd(adapter, cmd, &timeout);
@@ -3049,11 +3056,14 @@ int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter,
        int status = 0;
        struct qlcnic_hardware_context *ahw = adapter->ahw;
 
-       /* Get port configuration info */
-       status = qlcnic_83xx_get_port_info(adapter);
-       /* Get Link Status related info */
-       config = qlcnic_83xx_test_link(adapter);
-       ahw->module_type = QLC_83XX_SFP_MODULE_TYPE(config);
+       if (!test_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state)) {
+               /* Get port configuration info */
+               status = qlcnic_83xx_get_port_info(adapter);
+               /* Get Link Status related info */
+               config = qlcnic_83xx_test_link(adapter);
+               ahw->module_type = QLC_83XX_SFP_MODULE_TYPE(config);
+       }
+
        /* hard code until there is a way to get it from flash */
        ahw->board_type = QLCNIC_BRDTYPE_83XX_10G;
 
@@ -3530,6 +3540,9 @@ void qlcnic_83xx_reinit_mbx_work(struct qlcnic_mailbox *mbx)
 
 void qlcnic_83xx_free_mailbox(struct qlcnic_mailbox *mbx)
 {
+       if (!mbx)
+               return;
+
        destroy_workqueue(mbx->work_q);
        kfree(mbx);
 }
@@ -3650,6 +3663,9 @@ void qlcnic_83xx_detach_mailbox_work(struct qlcnic_adapter *adapter)
 {
        struct qlcnic_mailbox *mbx = adapter->ahw->mailbox;
 
+       if (!mbx)
+               return;
+
        clear_bit(QLC_83XX_MBX_READY, &mbx->status);
        complete(&mbx->completion);
        cancel_work_sync(&mbx->work);
index e2cd48417041c1e749058d89f235a02822eaf159..4a8a3f1b0345c679138692efebfa19b1bd3d7d7d 100644 (file)
@@ -2190,20 +2190,24 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac)
                        return err;
        }
 
+       if (qlcnic_83xx_read_flash_descriptor_table(adapter) ||
+           qlcnic_83xx_read_flash_mfg_id(adapter)) {
+               dev_err(&adapter->pdev->dev, "Failed reading flash mfg id\n");
+               err = -ENOTRECOVERABLE;
+               goto detach_mbx;
+       }
+
        err = qlcnic_83xx_check_hw_status(adapter);
        if (err)
                goto detach_mbx;
 
-       if (!qlcnic_83xx_read_flash_descriptor_table(adapter))
-               qlcnic_83xx_read_flash_mfg_id(adapter);
-
        err = qlcnic_83xx_get_fw_info(adapter);
        if (err)
                goto detach_mbx;
 
        err = qlcnic_83xx_idc_init(adapter);
        if (err)
-               goto clear_fw_info;
+               goto detach_mbx;
 
        err = qlcnic_setup_intr(adapter, 0, 0);
        if (err) {
@@ -2247,12 +2251,10 @@ disable_mbx_intr:
 disable_intr:
        qlcnic_teardown_intr(adapter);
 
-clear_fw_info:
-       kfree(ahw->fw_info);
-
 detach_mbx:
        qlcnic_83xx_detach_mailbox_work(adapter);
        qlcnic_83xx_free_mailbox(ahw->mailbox);
+       ahw->mailbox = NULL;
 exit:
        return err;
 }
index b2a8805997ca98ccde591cd05dc0b2951470ef19..0aaa52b3bcedb20e8cd93be630d3ea1fd66014cb 100644 (file)
@@ -1685,7 +1685,6 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
        struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
        bool valid_mask = false;
        int i, ret = 0;
-       u32 state;
 
        switch (val->flag) {
        case QLCNIC_FORCE_FW_DUMP_KEY:
@@ -1738,9 +1737,8 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
 
        case QLCNIC_SET_QUIESCENT:
        case QLCNIC_RESET_QUIESCENT:
-               state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
-               if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
-                       netdev_info(netdev, "Device in FAILED state\n");
+               if (test_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state))
+                       netdev_info(netdev, "Device is in non-operational state\n");
                break;
 
        default:
index b97e4a0079d1982183aa3b104bc173d5cacd5646..47a33fe0824f52858a2951b41edeaecd029d21e3 100644 (file)
@@ -2307,10 +2307,23 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                qlcnic_83xx_check_vf(adapter, ent);
                adapter->portnum = adapter->ahw->pci_func;
                err = qlcnic_83xx_init(adapter, pci_using_dac);
+
                if (err) {
-                       dev_err(&pdev->dev, "%s: failed\n", __func__);
-                       goto err_out_free_hw;
+                       switch (err) {
+                       case -ENOTRECOVERABLE:
+                               dev_err(&pdev->dev, "Adapter initialization failed due to a faulty hardware. Please reboot\n");
+                               dev_err(&pdev->dev, "If reboot doesn't help, please replace the adapter with new one and return the faulty adapter for repair\n");
+                               goto err_out_free_hw;
+                       case -ENOMEM:
+                               dev_err(&pdev->dev, "Adapter initialization failed. Please reboot\n");
+                               goto err_out_free_hw;
+                       default:
+                               dev_err(&pdev->dev, "Adapter initialization failed. A reboot may be required to recover from this failure\n");
+                               dev_err(&pdev->dev, "If reboot does not help to recover from this failure, try a flash update of the adapter\n");
+                               goto err_out_maintenance_mode;
+                       }
                }
+
                if (qlcnic_sriov_vf_check(adapter))
                        return 0;
        } else {
@@ -2412,8 +2425,16 @@ err_out_disable_pdev:
        return err;
 
 err_out_maintenance_mode:
+       set_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state);
        netdev->netdev_ops = &qlcnic_netdev_failed_ops;
        SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_failed_ops);
+       ahw->port_type = QLCNIC_XGBE;
+
+       if (qlcnic_83xx_check(adapter))
+               adapter->tgt_status_reg = NULL;
+       else
+               ahw->board_type = QLCNIC_BRDTYPE_P3P_10G_SFP_PLUS;
+
        err = register_netdev(netdev);
 
        if (err) {
@@ -2535,12 +2556,11 @@ static int qlcnic_resume(struct pci_dev *pdev)
 static int qlcnic_open(struct net_device *netdev)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
-       u32 state;
        int err;
 
-       state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
-       if (state == QLCNIC_DEV_FAILED || state == QLCNIC_DEV_BADBAD) {
-               netdev_err(netdev, "%s: Device is in FAILED state\n", __func__);
+       if (test_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state)) {
+               netdev_err(netdev, "%s: Device is in non-operational state\n",
+                          __func__);
 
                return -EIO;
        }
@@ -3253,8 +3273,9 @@ void qlcnic_82xx_dev_request_reset(struct qlcnic_adapter *adapter, u32 key)
                return;
 
        state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
-       if (state == QLCNIC_DEV_FAILED || state == QLCNIC_DEV_BADBAD) {
-               netdev_err(adapter->netdev, "%s: Device is in FAILED state\n",
+
+       if (test_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state)) {
+               netdev_err(adapter->netdev, "%s: Device is in non-operational state\n",
                           __func__);
                qlcnic_api_unlock(adapter);
 
index 019f4377307f025df8d7f93d3e473e7811f4101a..e8b1ce64c33abd2b613ff53d18b2c227dd6454f5 100644 (file)
@@ -1272,7 +1272,6 @@ void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter)
 void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
 {
        struct device *dev = &adapter->pdev->dev;
-       u32 state;
 
        if (device_create_bin_file(dev, &bin_attr_port_stats))
                dev_info(dev, "failed to create port stats sysfs entry");
@@ -1286,8 +1285,7 @@ void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
        if (device_create_bin_file(dev, &bin_attr_mem))
                dev_info(dev, "failed to create mem sysfs entry\n");
 
-       state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
-       if (state == QLCNIC_DEV_FAILED || state == QLCNIC_DEV_BADBAD)
+       if (test_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state))
                return;
 
        if (device_create_bin_file(dev, &bin_attr_pci_config))
@@ -1313,7 +1311,6 @@ void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
 void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
 {
        struct device *dev = &adapter->pdev->dev;
-       u32 state;
 
        device_remove_bin_file(dev, &bin_attr_port_stats);
 
@@ -1323,8 +1320,7 @@ void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
        device_remove_bin_file(dev, &bin_attr_crb);
        device_remove_bin_file(dev, &bin_attr_mem);
 
-       state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
-       if (state == QLCNIC_DEV_FAILED || state == QLCNIC_DEV_BADBAD)
+       if (test_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state))
                return;
 
        device_remove_bin_file(dev, &bin_attr_pci_config);