Commit b43e5ee7 authored by Sucheta Chakraborty's avatar Sucheta Chakraborty Committed by David S. Miller

qlcnic: Register device in FAILED state.

o Without failing probe, register netdevice when device is in FAILED state.
o Device will come up with minimum functionality.
Signed-off-by: default avatarSucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Signed-off-by: default avatarAnirban Chakraborty <anirban.chakraborty@qlogic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent feb50ac1
...@@ -1352,6 +1352,8 @@ enum op_codes { ...@@ -1352,6 +1352,8 @@ enum op_codes {
#define QLCNIC_ENABLE_FW_DUMP 0xaddfeed #define QLCNIC_ENABLE_FW_DUMP 0xaddfeed
#define QLCNIC_DISABLE_FW_DUMP 0xbadfeed #define QLCNIC_DISABLE_FW_DUMP 0xbadfeed
#define QLCNIC_FORCE_FW_RESET 0xdeaddead #define QLCNIC_FORCE_FW_RESET 0xdeaddead
#define QLCNIC_SET_QUIESCENT 0xadd00010
#define QLCNIC_RESET_QUIESCENT 0xadd00020
struct qlcnic_dump_operations { struct qlcnic_dump_operations {
enum op_codes opcode; enum op_codes opcode;
...@@ -1559,6 +1561,7 @@ static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring) ...@@ -1559,6 +1561,7 @@ static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring)
} }
extern const struct ethtool_ops qlcnic_ethtool_ops; extern const struct ethtool_ops qlcnic_ethtool_ops;
extern const struct ethtool_ops qlcnic_ethtool_failed_ops;
struct qlcnic_nic_template { struct qlcnic_nic_template {
int (*config_bridged_mode) (struct qlcnic_adapter *, u32); int (*config_bridged_mode) (struct qlcnic_adapter *, u32);
......
...@@ -1132,6 +1132,11 @@ qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump) ...@@ -1132,6 +1132,11 @@ qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
struct qlcnic_adapter *adapter = netdev_priv(netdev); struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
if (!fw_dump->tmpl_hdr) {
netdev_err(adapter->netdev, "FW Dump not supported\n");
return -ENOTSUPP;
}
if (fw_dump->clr) if (fw_dump->clr)
dump->len = fw_dump->tmpl_hdr->size + fw_dump->size; dump->len = fw_dump->tmpl_hdr->size + fw_dump->size;
else else
...@@ -1150,6 +1155,11 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump, ...@@ -1150,6 +1155,11 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
struct qlcnic_adapter *adapter = netdev_priv(netdev); struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
if (!fw_dump->tmpl_hdr) {
netdev_err(netdev, "FW Dump not supported\n");
return -ENOTSUPP;
}
if (!fw_dump->clr) { if (!fw_dump->clr) {
netdev_info(netdev, "Dump not available\n"); netdev_info(netdev, "Dump not available\n");
return -EINVAL; return -EINVAL;
...@@ -1180,9 +1190,14 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val) ...@@ -1180,9 +1190,14 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
int ret = 0; int ret = 0;
struct qlcnic_adapter *adapter = netdev_priv(netdev); struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
u32 state;
switch (val->flag) { switch (val->flag) {
case QLCNIC_FORCE_FW_DUMP_KEY: case QLCNIC_FORCE_FW_DUMP_KEY:
if (!fw_dump->tmpl_hdr) {
netdev_err(netdev, "FW dump not supported\n");
return -ENOTSUPP;
}
if (!fw_dump->enable) { if (!fw_dump->enable) {
netdev_info(netdev, "FW dump not enabled\n"); netdev_info(netdev, "FW dump not enabled\n");
return ret; return ret;
...@@ -1196,35 +1211,47 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val) ...@@ -1196,35 +1211,47 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
qlcnic_dev_request_reset(adapter); qlcnic_dev_request_reset(adapter);
break; break;
case QLCNIC_DISABLE_FW_DUMP: case QLCNIC_DISABLE_FW_DUMP:
if (fw_dump->enable) { if (fw_dump->enable && fw_dump->tmpl_hdr) {
netdev_info(netdev, "Disabling FW dump\n"); netdev_info(netdev, "Disabling FW dump\n");
fw_dump->enable = 0; fw_dump->enable = 0;
} }
break; return ret;
case QLCNIC_ENABLE_FW_DUMP: case QLCNIC_ENABLE_FW_DUMP:
if (!fw_dump->enable && fw_dump->tmpl_hdr) { if (!fw_dump->tmpl_hdr) {
netdev_err(netdev, "FW dump not supported\n");
return -ENOTSUPP;
}
if (!fw_dump->enable) {
netdev_info(netdev, "Enabling FW dump\n"); netdev_info(netdev, "Enabling FW dump\n");
fw_dump->enable = 1; fw_dump->enable = 1;
} }
break; return ret;
case QLCNIC_FORCE_FW_RESET: case QLCNIC_FORCE_FW_RESET:
netdev_info(netdev, "Forcing a FW reset\n"); netdev_info(netdev, "Forcing a FW reset\n");
qlcnic_dev_request_reset(adapter); qlcnic_dev_request_reset(adapter);
adapter->flags &= ~QLCNIC_FW_RESET_OWNER; adapter->flags &= ~QLCNIC_FW_RESET_OWNER;
break; return ret;
case QLCNIC_SET_QUIESCENT:
case QLCNIC_RESET_QUIESCENT:
state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
netdev_info(netdev, "Device in FAILED state\n");
return ret;
default: default:
if (!fw_dump->tmpl_hdr) {
netdev_err(netdev, "FW dump not supported\n");
return -ENOTSUPP;
}
if (val->flag > QLCNIC_DUMP_MASK_MAX || if (val->flag > QLCNIC_DUMP_MASK_MAX ||
val->flag < QLCNIC_DUMP_MASK_MIN) { val->flag < QLCNIC_DUMP_MASK_MIN) {
netdev_info(netdev, netdev_info(netdev,
"Invalid dump level: 0x%x\n", val->flag); "Invalid dump level: 0x%x\n", val->flag);
ret = -EINVAL; return -EINVAL;
goto out;
} }
fw_dump->tmpl_hdr->drv_cap_mask = val->flag & 0xff; fw_dump->tmpl_hdr->drv_cap_mask = val->flag & 0xff;
netdev_info(netdev, "Driver mask changed to: 0x%x\n", netdev_info(netdev, "Driver mask changed to: 0x%x\n",
fw_dump->tmpl_hdr->drv_cap_mask); fw_dump->tmpl_hdr->drv_cap_mask);
} }
out:
return ret; return ret;
} }
...@@ -1258,3 +1285,10 @@ const struct ethtool_ops qlcnic_ethtool_ops = { ...@@ -1258,3 +1285,10 @@ const struct ethtool_ops qlcnic_ethtool_ops = {
.get_dump_data = qlcnic_get_dump_data, .get_dump_data = qlcnic_get_dump_data,
.set_dump = qlcnic_set_dump, .set_dump = qlcnic_set_dump,
}; };
const struct ethtool_ops qlcnic_ethtool_failed_ops = {
.get_settings = qlcnic_get_settings,
.get_drvinfo = qlcnic_get_drvinfo,
.set_msglevel = qlcnic_set_msglevel,
.get_msglevel = qlcnic_get_msglevel,
};
...@@ -704,6 +704,8 @@ enum { ...@@ -704,6 +704,8 @@ enum {
#define QLCNIC_DEV_FAILED 0x6 #define QLCNIC_DEV_FAILED 0x6
#define QLCNIC_DEV_QUISCENT 0x7 #define QLCNIC_DEV_QUISCENT 0x7
#define QLCNIC_DEV_BADBAD 0xbad0bad0
#define QLCNIC_DEV_NPAR_NON_OPER 0 /* NON Operational */ #define QLCNIC_DEV_NPAR_NON_OPER 0 /* NON Operational */
#define QLCNIC_DEV_NPAR_OPER 1 /* NPAR Operational */ #define QLCNIC_DEV_NPAR_OPER 1 /* NPAR Operational */
#define QLCNIC_DEV_NPAR_OPER_TIMEO 30 /* Operational time out */ #define QLCNIC_DEV_NPAR_OPER_TIMEO 30 /* Operational time out */
......
...@@ -338,6 +338,10 @@ static const struct net_device_ops qlcnic_netdev_ops = { ...@@ -338,6 +338,10 @@ static const struct net_device_ops qlcnic_netdev_ops = {
#endif #endif
}; };
static const struct net_device_ops qlcnic_netdev_failed_ops = {
.ndo_open = qlcnic_open,
};
static struct qlcnic_nic_template qlcnic_ops = { static struct qlcnic_nic_template qlcnic_ops = {
.config_bridged_mode = qlcnic_config_bridged_mode, .config_bridged_mode = qlcnic_config_bridged_mode,
.config_led = qlcnic_config_led, .config_led = qlcnic_config_led,
...@@ -1623,8 +1627,9 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1623,8 +1627,9 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = adapter->nic_ops->start_firmware(adapter); err = adapter->nic_ops->start_firmware(adapter);
if (err) { if (err) {
dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n"); dev_err(&pdev->dev, "Loading fw failed. Please Reboot\n"
goto err_out_decr_ref; "\t\tIf reboot doesn't help, try flashing the card\n");
goto err_out_maintenance_mode;
} }
if (qlcnic_read_mac_addr(adapter)) if (qlcnic_read_mac_addr(adapter))
...@@ -1695,6 +1700,18 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -1695,6 +1700,18 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_drvdata(pdev, NULL); pci_set_drvdata(pdev, NULL);
pci_disable_device(pdev); pci_disable_device(pdev);
return err; 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) static void __devexit qlcnic_remove(struct pci_dev *pdev)
...@@ -1831,8 +1848,14 @@ qlcnic_resume(struct pci_dev *pdev) ...@@ -1831,8 +1848,14 @@ qlcnic_resume(struct pci_dev *pdev)
static int qlcnic_open(struct net_device *netdev) static int qlcnic_open(struct net_device *netdev)
{ {
struct qlcnic_adapter *adapter = netdev_priv(netdev); struct qlcnic_adapter *adapter = netdev_priv(netdev);
u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
int err; 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); netif_carrier_off(netdev);
err = qlcnic_attach(adapter); err = qlcnic_attach(adapter);
...@@ -3018,6 +3041,12 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter) ...@@ -3018,6 +3041,12 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
return; return;
state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); 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) { if (state == QLCNIC_DEV_READY) {
QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET); QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET);
...@@ -3061,6 +3090,9 @@ qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter) ...@@ -3061,6 +3090,9 @@ qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter)
while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
msleep(10); msleep(10);
if (!adapter->fw_work.work.func)
return;
cancel_delayed_work_sync(&adapter->fw_work); cancel_delayed_work_sync(&adapter->fw_work);
} }
...@@ -4280,6 +4312,7 @@ static void ...@@ -4280,6 +4312,7 @@ static void
qlcnic_create_diag_entries(struct qlcnic_adapter *adapter) qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
{ {
struct device *dev = &adapter->pdev->dev; struct device *dev = &adapter->pdev->dev;
u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
if (device_create_bin_file(dev, &bin_attr_port_stats)) if (device_create_bin_file(dev, &bin_attr_port_stats))
dev_info(dev, "failed to create port stats sysfs entry"); dev_info(dev, "failed to create port stats sysfs entry");
...@@ -4288,14 +4321,19 @@ qlcnic_create_diag_entries(struct qlcnic_adapter *adapter) ...@@ -4288,14 +4321,19 @@ qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
return; return;
if (device_create_file(dev, &dev_attr_diag_mode)) if (device_create_file(dev, &dev_attr_diag_mode))
dev_info(dev, "failed to create diag_mode sysfs entry\n"); 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)) if (device_create_bin_file(dev, &bin_attr_crb))
dev_info(dev, "failed to create crb sysfs entry\n"); dev_info(dev, "failed to create crb sysfs entry\n");
if (device_create_bin_file(dev, &bin_attr_mem)) if (device_create_bin_file(dev, &bin_attr_mem))
dev_info(dev, "failed to create mem sysfs entry\n"); 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)) if (device_create_bin_file(dev, &bin_attr_pci_config))
dev_info(dev, "failed to create pci config sysfs entry"); 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)) if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
return; return;
if (device_create_bin_file(dev, &bin_attr_esw_config)) if (device_create_bin_file(dev, &bin_attr_esw_config))
...@@ -4314,16 +4352,19 @@ static void ...@@ -4314,16 +4352,19 @@ static void
qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter) qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
{ {
struct device *dev = &adapter->pdev->dev; struct device *dev = &adapter->pdev->dev;
u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
device_remove_bin_file(dev, &bin_attr_port_stats); device_remove_bin_file(dev, &bin_attr_port_stats);
if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
return; return;
device_remove_file(dev, &dev_attr_diag_mode); 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_crb);
device_remove_bin_file(dev, &bin_attr_mem); 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_bin_file(dev, &bin_attr_pci_config);
device_remove_file(dev, &dev_attr_beacon);
if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
return; return;
device_remove_bin_file(dev, &bin_attr_esw_config); device_remove_bin_file(dev, &bin_attr_esw_config);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment