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: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com> Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
feb50ac19e
Коммит
b43e5ee76a
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
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 = {
|
||||||
.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 {
|
||||||
#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 = {
|
||||||
#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)
|
||||||
|
|
||||||
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 @@ err_out_disable_pdev:
|
||||||
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 @@ done:
|
||||||
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)
|
||||||
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)
|
||||||
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
|
||||||
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)
|
||||||
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
|
||||||
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);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче