|
@@ -338,6 +338,10 @@ static const struct net_device_ops qlcnic_netdev_ops = {
|
|
|
#endif
|
|
|
};
|
|
|
|
|
|
+static const struct net_device_ops qlcnic_netdev_failed_ops = {
|
|
|
+ .ndo_open = qlcnic_open,
|
|
|
+};
|
|
|
+
|
|
|
static struct qlcnic_nic_template qlcnic_ops = {
|
|
|
.config_bridged_mode = qlcnic_config_bridged_mode,
|
|
|
.config_led = qlcnic_config_led,
|
|
@@ -1623,8 +1627,9 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
|
|
|
|
err = adapter->nic_ops->start_firmware(adapter);
|
|
|
if (err) {
|
|
|
- dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n");
|
|
|
- goto err_out_decr_ref;
|
|
|
+ dev_err(&pdev->dev, "Loading fw failed. Please Reboot\n"
|
|
|
+ "\t\tIf reboot doesn't help, try flashing the card\n");
|
|
|
+ goto err_out_maintenance_mode;
|
|
|
}
|
|
|
|
|
|
if (qlcnic_read_mac_addr(adapter))
|
|
@@ -1695,6 +1700,18 @@ err_out_disable_pdev:
|
|
|
pci_set_drvdata(pdev, NULL);
|
|
|
pci_disable_device(pdev);
|
|
|
return err;
|
|
|
+
|
|
|
+err_out_maintenance_mode:
|
|
|
+ netdev->netdev_ops = &qlcnic_netdev_failed_ops;
|
|
|
+ SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_failed_ops);
|
|
|
+ err = register_netdev(netdev);
|
|
|
+ if (err) {
|
|
|
+ dev_err(&pdev->dev, "failed to register net device\n");
|
|
|
+ goto err_out_decr_ref;
|
|
|
+ }
|
|
|
+ pci_set_drvdata(pdev, adapter);
|
|
|
+ qlcnic_create_diag_entries(adapter);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
static void __devexit qlcnic_remove(struct pci_dev *pdev)
|
|
@@ -1831,8 +1848,14 @@ done:
|
|
|
static int qlcnic_open(struct net_device *netdev)
|
|
|
{
|
|
|
struct qlcnic_adapter *adapter = netdev_priv(netdev);
|
|
|
+ u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
|
|
|
int err;
|
|
|
|
|
|
+ if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) {
|
|
|
+ netdev_err(netdev, "Device in FAILED state\n");
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+
|
|
|
netif_carrier_off(netdev);
|
|
|
|
|
|
err = qlcnic_attach(adapter);
|
|
@@ -3018,6 +3041,12 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
|
|
|
return;
|
|
|
|
|
|
state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
|
|
|
+ if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) {
|
|
|
+ netdev_err(adapter->netdev,
|
|
|
+ "Device is in FAILED state, Please Reboot\n");
|
|
|
+ qlcnic_api_unlock(adapter);
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
if (state == QLCNIC_DEV_READY) {
|
|
|
QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET);
|
|
@@ -3061,6 +3090,9 @@ qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter)
|
|
|
while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
|
|
|
msleep(10);
|
|
|
|
|
|
+ if (!adapter->fw_work.work.func)
|
|
|
+ return;
|
|
|
+
|
|
|
cancel_delayed_work_sync(&adapter->fw_work);
|
|
|
}
|
|
|
|
|
@@ -4280,6 +4312,7 @@ static void
|
|
|
qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
|
|
|
{
|
|
|
struct device *dev = &adapter->pdev->dev;
|
|
|
+ u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
|
|
|
|
|
|
if (device_create_bin_file(dev, &bin_attr_port_stats))
|
|
|
dev_info(dev, "failed to create port stats sysfs entry");
|
|
@@ -4288,14 +4321,19 @@ qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
|
|
|
return;
|
|
|
if (device_create_file(dev, &dev_attr_diag_mode))
|
|
|
dev_info(dev, "failed to create diag_mode sysfs entry\n");
|
|
|
- if (device_create_file(dev, &dev_attr_beacon))
|
|
|
- dev_info(dev, "failed to create beacon sysfs entry");
|
|
|
if (device_create_bin_file(dev, &bin_attr_crb))
|
|
|
dev_info(dev, "failed to create crb sysfs entry\n");
|
|
|
if (device_create_bin_file(dev, &bin_attr_mem))
|
|
|
dev_info(dev, "failed to create mem sysfs entry\n");
|
|
|
+
|
|
|
+ if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
|
|
|
+ return;
|
|
|
+
|
|
|
if (device_create_bin_file(dev, &bin_attr_pci_config))
|
|
|
dev_info(dev, "failed to create pci config sysfs entry");
|
|
|
+ if (device_create_file(dev, &dev_attr_beacon))
|
|
|
+ dev_info(dev, "failed to create beacon sysfs entry");
|
|
|
+
|
|
|
if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
|
|
|
return;
|
|
|
if (device_create_bin_file(dev, &bin_attr_esw_config))
|
|
@@ -4314,16 +4352,19 @@ static void
|
|
|
qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
|
|
|
{
|
|
|
struct device *dev = &adapter->pdev->dev;
|
|
|
+ u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
|
|
|
|
|
|
device_remove_bin_file(dev, &bin_attr_port_stats);
|
|
|
|
|
|
if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
|
|
|
return;
|
|
|
device_remove_file(dev, &dev_attr_diag_mode);
|
|
|
- device_remove_file(dev, &dev_attr_beacon);
|
|
|
device_remove_bin_file(dev, &bin_attr_crb);
|
|
|
device_remove_bin_file(dev, &bin_attr_mem);
|
|
|
+ if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
|
|
|
+ return;
|
|
|
device_remove_bin_file(dev, &bin_attr_pci_config);
|
|
|
+ device_remove_file(dev, &dev_attr_beacon);
|
|
|
if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
|
|
|
return;
|
|
|
device_remove_bin_file(dev, &bin_attr_esw_config);
|