aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSucheta Chakraborty <sucheta.chakraborty@qlogic.com>2012-04-26 06:31:29 -0400
committerDavid S. Miller <davem@davemloft.net>2012-04-27 00:03:35 -0400
commitb43e5ee76a4320c070cf0fe65cf4927198fbb4d1 (patch)
tree86e9cbe0022ffc4f7f4ef309dcd0a6f8d8b3c073
parentfeb50ac19e3527c3c68391718f07272349639a84 (diff)
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>
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic.h3
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c50
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h2
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c51
4 files changed, 93 insertions, 13 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index 385a4d5c7c25..f419965f3a6d 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -1352,6 +1352,8 @@ enum op_codes {
1352#define QLCNIC_ENABLE_FW_DUMP 0xaddfeed 1352#define QLCNIC_ENABLE_FW_DUMP 0xaddfeed
1353#define QLCNIC_DISABLE_FW_DUMP 0xbadfeed 1353#define QLCNIC_DISABLE_FW_DUMP 0xbadfeed
1354#define QLCNIC_FORCE_FW_RESET 0xdeaddead 1354#define QLCNIC_FORCE_FW_RESET 0xdeaddead
1355#define QLCNIC_SET_QUIESCENT 0xadd00010
1356#define QLCNIC_RESET_QUIESCENT 0xadd00020
1355 1357
1356struct qlcnic_dump_operations { 1358struct qlcnic_dump_operations {
1357 enum op_codes opcode; 1359 enum op_codes opcode;
@@ -1559,6 +1561,7 @@ static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring)
1559} 1561}
1560 1562
1561extern const struct ethtool_ops qlcnic_ethtool_ops; 1563extern const struct ethtool_ops qlcnic_ethtool_ops;
1564extern const struct ethtool_ops qlcnic_ethtool_failed_ops;
1562 1565
1563struct qlcnic_nic_template { 1566struct qlcnic_nic_template {
1564 int (*config_bridged_mode) (struct qlcnic_adapter *, u32); 1567 int (*config_bridged_mode) (struct qlcnic_adapter *, u32);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
index 89ddf7f7d7df..f19e11ed7b09 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
@@ -1132,6 +1132,11 @@ qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
1132 struct qlcnic_adapter *adapter = netdev_priv(netdev); 1132 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1133 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; 1133 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
1134 1134
1135 if (!fw_dump->tmpl_hdr) {
1136 netdev_err(adapter->netdev, "FW Dump not supported\n");
1137 return -ENOTSUPP;
1138 }
1139
1135 if (fw_dump->clr) 1140 if (fw_dump->clr)
1136 dump->len = fw_dump->tmpl_hdr->size + fw_dump->size; 1141 dump->len = fw_dump->tmpl_hdr->size + fw_dump->size;
1137 else 1142 else
@@ -1150,6 +1155,11 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
1150 struct qlcnic_adapter *adapter = netdev_priv(netdev); 1155 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1151 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; 1156 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
1152 1157
1158 if (!fw_dump->tmpl_hdr) {
1159 netdev_err(netdev, "FW Dump not supported\n");
1160 return -ENOTSUPP;
1161 }
1162
1153 if (!fw_dump->clr) { 1163 if (!fw_dump->clr) {
1154 netdev_info(netdev, "Dump not available\n"); 1164 netdev_info(netdev, "Dump not available\n");
1155 return -EINVAL; 1165 return -EINVAL;
@@ -1180,9 +1190,14 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
1180 int ret = 0; 1190 int ret = 0;
1181 struct qlcnic_adapter *adapter = netdev_priv(netdev); 1191 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1182 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; 1192 struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
1193 u32 state;
1183 1194
1184 switch (val->flag) { 1195 switch (val->flag) {
1185 case QLCNIC_FORCE_FW_DUMP_KEY: 1196 case QLCNIC_FORCE_FW_DUMP_KEY:
1197 if (!fw_dump->tmpl_hdr) {
1198 netdev_err(netdev, "FW dump not supported\n");
1199 return -ENOTSUPP;
1200 }
1186 if (!fw_dump->enable) { 1201 if (!fw_dump->enable) {
1187 netdev_info(netdev, "FW dump not enabled\n"); 1202 netdev_info(netdev, "FW dump not enabled\n");
1188 return ret; 1203 return ret;
@@ -1196,35 +1211,47 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
1196 qlcnic_dev_request_reset(adapter); 1211 qlcnic_dev_request_reset(adapter);
1197 break; 1212 break;
1198 case QLCNIC_DISABLE_FW_DUMP: 1213 case QLCNIC_DISABLE_FW_DUMP:
1199 if (fw_dump->enable) { 1214 if (fw_dump->enable && fw_dump->tmpl_hdr) {
1200 netdev_info(netdev, "Disabling FW dump\n"); 1215 netdev_info(netdev, "Disabling FW dump\n");
1201 fw_dump->enable = 0; 1216 fw_dump->enable = 0;
1202 } 1217 }
1203 break; 1218 return ret;
1204 case QLCNIC_ENABLE_FW_DUMP: 1219 case QLCNIC_ENABLE_FW_DUMP:
1205 if (!fw_dump->enable && fw_dump->tmpl_hdr) { 1220 if (!fw_dump->tmpl_hdr) {
1221 netdev_err(netdev, "FW dump not supported\n");
1222 return -ENOTSUPP;
1223 }
1224 if (!fw_dump->enable) {
1206 netdev_info(netdev, "Enabling FW dump\n"); 1225 netdev_info(netdev, "Enabling FW dump\n");
1207 fw_dump->enable = 1; 1226 fw_dump->enable = 1;
1208 } 1227 }
1209 break; 1228 return ret;
1210 case QLCNIC_FORCE_FW_RESET: 1229 case QLCNIC_FORCE_FW_RESET:
1211 netdev_info(netdev, "Forcing a FW reset\n"); 1230 netdev_info(netdev, "Forcing a FW reset\n");
1212 qlcnic_dev_request_reset(adapter); 1231 qlcnic_dev_request_reset(adapter);
1213 adapter->flags &= ~QLCNIC_FW_RESET_OWNER; 1232 adapter->flags &= ~QLCNIC_FW_RESET_OWNER;
1214 break; 1233 return ret;
1234 case QLCNIC_SET_QUIESCENT:
1235 case QLCNIC_RESET_QUIESCENT:
1236 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
1237 if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
1238 netdev_info(netdev, "Device in FAILED state\n");
1239 return ret;
1215 default: 1240 default:
1241 if (!fw_dump->tmpl_hdr) {
1242 netdev_err(netdev, "FW dump not supported\n");
1243 return -ENOTSUPP;
1244 }
1216 if (val->flag > QLCNIC_DUMP_MASK_MAX || 1245 if (val->flag > QLCNIC_DUMP_MASK_MAX ||
1217 val->flag < QLCNIC_DUMP_MASK_MIN) { 1246 val->flag < QLCNIC_DUMP_MASK_MIN) {
1218 netdev_info(netdev, 1247 netdev_info(netdev,
1219 "Invalid dump level: 0x%x\n", val->flag); 1248 "Invalid dump level: 0x%x\n", val->flag);
1220 ret = -EINVAL; 1249 return -EINVAL;
1221 goto out;
1222 } 1250 }
1223 fw_dump->tmpl_hdr->drv_cap_mask = val->flag & 0xff; 1251 fw_dump->tmpl_hdr->drv_cap_mask = val->flag & 0xff;
1224 netdev_info(netdev, "Driver mask changed to: 0x%x\n", 1252 netdev_info(netdev, "Driver mask changed to: 0x%x\n",
1225 fw_dump->tmpl_hdr->drv_cap_mask); 1253 fw_dump->tmpl_hdr->drv_cap_mask);
1226 } 1254 }
1227out:
1228 return ret; 1255 return ret;
1229} 1256}
1230 1257
@@ -1258,3 +1285,10 @@ const struct ethtool_ops qlcnic_ethtool_ops = {
1258 .get_dump_data = qlcnic_get_dump_data, 1285 .get_dump_data = qlcnic_get_dump_data,
1259 .set_dump = qlcnic_set_dump, 1286 .set_dump = qlcnic_set_dump,
1260}; 1287};
1288
1289const struct ethtool_ops qlcnic_ethtool_failed_ops = {
1290 .get_settings = qlcnic_get_settings,
1291 .get_drvinfo = qlcnic_get_drvinfo,
1292 .set_msglevel = qlcnic_set_msglevel,
1293 .get_msglevel = qlcnic_get_msglevel,
1294};
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
index a52819303d1b..e6a77feeb44a 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
@@ -704,6 +704,8 @@ enum {
704#define QLCNIC_DEV_FAILED 0x6 704#define QLCNIC_DEV_FAILED 0x6
705#define QLCNIC_DEV_QUISCENT 0x7 705#define QLCNIC_DEV_QUISCENT 0x7
706 706
707#define QLCNIC_DEV_BADBAD 0xbad0bad0
708
707#define QLCNIC_DEV_NPAR_NON_OPER 0 /* NON Operational */ 709#define QLCNIC_DEV_NPAR_NON_OPER 0 /* NON Operational */
708#define QLCNIC_DEV_NPAR_OPER 1 /* NPAR Operational */ 710#define QLCNIC_DEV_NPAR_OPER 1 /* NPAR Operational */
709#define QLCNIC_DEV_NPAR_OPER_TIMEO 30 /* Operational time out */ 711#define QLCNIC_DEV_NPAR_OPER_TIMEO 30 /* Operational time out */
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 75c32e875fef..5c4713521d4c 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -338,6 +338,10 @@ static const struct net_device_ops qlcnic_netdev_ops = {
338#endif 338#endif
339}; 339};
340 340
341static const struct net_device_ops qlcnic_netdev_failed_ops = {
342 .ndo_open = qlcnic_open,
343};
344
341static struct qlcnic_nic_template qlcnic_ops = { 345static struct qlcnic_nic_template qlcnic_ops = {
342 .config_bridged_mode = qlcnic_config_bridged_mode, 346 .config_bridged_mode = qlcnic_config_bridged_mode,
343 .config_led = qlcnic_config_led, 347 .config_led = qlcnic_config_led,
@@ -1623,8 +1627,9 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
1623 1627
1624 err = adapter->nic_ops->start_firmware(adapter); 1628 err = adapter->nic_ops->start_firmware(adapter);
1625 if (err) { 1629 if (err) {
1626 dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n"); 1630 dev_err(&pdev->dev, "Loading fw failed. Please Reboot\n"
1627 goto err_out_decr_ref; 1631 "\t\tIf reboot doesn't help, try flashing the card\n");
1632 goto err_out_maintenance_mode;
1628 } 1633 }
1629 1634
1630 if (qlcnic_read_mac_addr(adapter)) 1635 if (qlcnic_read_mac_addr(adapter))
@@ -1695,6 +1700,18 @@ err_out_disable_pdev:
1695 pci_set_drvdata(pdev, NULL); 1700 pci_set_drvdata(pdev, NULL);
1696 pci_disable_device(pdev); 1701 pci_disable_device(pdev);
1697 return err; 1702 return err;
1703
1704err_out_maintenance_mode:
1705 netdev->netdev_ops = &qlcnic_netdev_failed_ops;
1706 SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_failed_ops);
1707 err = register_netdev(netdev);
1708 if (err) {
1709 dev_err(&pdev->dev, "failed to register net device\n");
1710 goto err_out_decr_ref;
1711 }
1712 pci_set_drvdata(pdev, adapter);
1713 qlcnic_create_diag_entries(adapter);
1714 return 0;
1698} 1715}
1699 1716
1700static void __devexit qlcnic_remove(struct pci_dev *pdev) 1717static void __devexit qlcnic_remove(struct pci_dev *pdev)
@@ -1831,8 +1848,14 @@ done:
1831static int qlcnic_open(struct net_device *netdev) 1848static int qlcnic_open(struct net_device *netdev)
1832{ 1849{
1833 struct qlcnic_adapter *adapter = netdev_priv(netdev); 1850 struct qlcnic_adapter *adapter = netdev_priv(netdev);
1851 u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
1834 int err; 1852 int err;
1835 1853
1854 if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) {
1855 netdev_err(netdev, "Device in FAILED state\n");
1856 return -EIO;
1857 }
1858
1836 netif_carrier_off(netdev); 1859 netif_carrier_off(netdev);
1837 1860
1838 err = qlcnic_attach(adapter); 1861 err = qlcnic_attach(adapter);
@@ -3018,6 +3041,12 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
3018 return; 3041 return;
3019 3042
3020 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE); 3043 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
3044 if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD)) {
3045 netdev_err(adapter->netdev,
3046 "Device is in FAILED state, Please Reboot\n");
3047 qlcnic_api_unlock(adapter);
3048 return;
3049 }
3021 3050
3022 if (state == QLCNIC_DEV_READY) { 3051 if (state == QLCNIC_DEV_READY) {
3023 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET); 3052 QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET);
@@ -3061,6 +3090,9 @@ qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter)
3061 while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) 3090 while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
3062 msleep(10); 3091 msleep(10);
3063 3092
3093 if (!adapter->fw_work.work.func)
3094 return;
3095
3064 cancel_delayed_work_sync(&adapter->fw_work); 3096 cancel_delayed_work_sync(&adapter->fw_work);
3065} 3097}
3066 3098
@@ -4280,6 +4312,7 @@ static void
4280qlcnic_create_diag_entries(struct qlcnic_adapter *adapter) 4312qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
4281{ 4313{
4282 struct device *dev = &adapter->pdev->dev; 4314 struct device *dev = &adapter->pdev->dev;
4315 u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
4283 4316
4284 if (device_create_bin_file(dev, &bin_attr_port_stats)) 4317 if (device_create_bin_file(dev, &bin_attr_port_stats))
4285 dev_info(dev, "failed to create port stats sysfs entry"); 4318 dev_info(dev, "failed to create port stats sysfs entry");
@@ -4288,14 +4321,19 @@ qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
4288 return; 4321 return;
4289 if (device_create_file(dev, &dev_attr_diag_mode)) 4322 if (device_create_file(dev, &dev_attr_diag_mode))
4290 dev_info(dev, "failed to create diag_mode sysfs entry\n"); 4323 dev_info(dev, "failed to create diag_mode sysfs entry\n");
4291 if (device_create_file(dev, &dev_attr_beacon))
4292 dev_info(dev, "failed to create beacon sysfs entry");
4293 if (device_create_bin_file(dev, &bin_attr_crb)) 4324 if (device_create_bin_file(dev, &bin_attr_crb))
4294 dev_info(dev, "failed to create crb sysfs entry\n"); 4325 dev_info(dev, "failed to create crb sysfs entry\n");
4295 if (device_create_bin_file(dev, &bin_attr_mem)) 4326 if (device_create_bin_file(dev, &bin_attr_mem))
4296 dev_info(dev, "failed to create mem sysfs entry\n"); 4327 dev_info(dev, "failed to create mem sysfs entry\n");
4328
4329 if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
4330 return;
4331
4297 if (device_create_bin_file(dev, &bin_attr_pci_config)) 4332 if (device_create_bin_file(dev, &bin_attr_pci_config))
4298 dev_info(dev, "failed to create pci config sysfs entry"); 4333 dev_info(dev, "failed to create pci config sysfs entry");
4334 if (device_create_file(dev, &dev_attr_beacon))
4335 dev_info(dev, "failed to create beacon sysfs entry");
4336
4299 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) 4337 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
4300 return; 4338 return;
4301 if (device_create_bin_file(dev, &bin_attr_esw_config)) 4339 if (device_create_bin_file(dev, &bin_attr_esw_config))
@@ -4314,16 +4352,19 @@ static void
4314qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter) 4352qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
4315{ 4353{
4316 struct device *dev = &adapter->pdev->dev; 4354 struct device *dev = &adapter->pdev->dev;
4355 u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
4317 4356
4318 device_remove_bin_file(dev, &bin_attr_port_stats); 4357 device_remove_bin_file(dev, &bin_attr_port_stats);
4319 4358
4320 if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) 4359 if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
4321 return; 4360 return;
4322 device_remove_file(dev, &dev_attr_diag_mode); 4361 device_remove_file(dev, &dev_attr_diag_mode);
4323 device_remove_file(dev, &dev_attr_beacon);
4324 device_remove_bin_file(dev, &bin_attr_crb); 4362 device_remove_bin_file(dev, &bin_attr_crb);
4325 device_remove_bin_file(dev, &bin_attr_mem); 4363 device_remove_bin_file(dev, &bin_attr_mem);
4364 if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
4365 return;
4326 device_remove_bin_file(dev, &bin_attr_pci_config); 4366 device_remove_bin_file(dev, &bin_attr_pci_config);
4367 device_remove_file(dev, &dev_attr_beacon);
4327 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) 4368 if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
4328 return; 4369 return;
4329 device_remove_bin_file(dev, &bin_attr_esw_config); 4370 device_remove_bin_file(dev, &bin_attr_esw_config);