aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorRon Mercer <ron.mercer@qlogic.com>2009-10-28 04:39:20 -0400
committerDavid S. Miller <davem@davemloft.net>2009-10-29 04:17:14 -0400
commit6d190c6edf42a572485cf1b6c7479bfc42753084 (patch)
treee4688decb302c4a0f17f9d143c6cd16c856c9c7f /drivers/net
parent55888dfb6ba7e318bb3d6a44d25009906206bf6a (diff)
qlge: Fix EEH handling.
Clean up driver resources without touch the hardware. Add pci save/restore state. Signed-off-by: Ron Mercer <ron.mercer@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/qlge/qlge_main.c78
1 files changed, 52 insertions, 26 deletions
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 48b45df85ec9..cea7531f4f40 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -3916,6 +3916,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
3916 goto err_out; 3916 goto err_out;
3917 } 3917 }
3918 3918
3919 pci_save_state(pdev);
3919 qdev->reg_base = 3920 qdev->reg_base =
3920 ioremap_nocache(pci_resource_start(pdev, 1), 3921 ioremap_nocache(pci_resource_start(pdev, 1),
3921 pci_resource_len(pdev, 1)); 3922 pci_resource_len(pdev, 1));
@@ -4070,6 +4071,33 @@ static void __devexit qlge_remove(struct pci_dev *pdev)
4070 free_netdev(ndev); 4071 free_netdev(ndev);
4071} 4072}
4072 4073
4074/* Clean up resources without touching hardware. */
4075static void ql_eeh_close(struct net_device *ndev)
4076{
4077 int i;
4078 struct ql_adapter *qdev = netdev_priv(ndev);
4079
4080 if (netif_carrier_ok(ndev)) {
4081 netif_carrier_off(ndev);
4082 netif_stop_queue(ndev);
4083 }
4084
4085 if (test_bit(QL_ADAPTER_UP, &qdev->flags))
4086 cancel_delayed_work_sync(&qdev->asic_reset_work);
4087 cancel_delayed_work_sync(&qdev->mpi_reset_work);
4088 cancel_delayed_work_sync(&qdev->mpi_work);
4089 cancel_delayed_work_sync(&qdev->mpi_idc_work);
4090 cancel_delayed_work_sync(&qdev->mpi_port_cfg_work);
4091
4092 for (i = 0; i < qdev->rss_ring_count; i++)
4093 netif_napi_del(&qdev->rx_ring[i].napi);
4094
4095 clear_bit(QL_ADAPTER_UP, &qdev->flags);
4096 ql_tx_ring_clean(qdev);
4097 ql_free_rx_buffers(qdev);
4098 ql_release_adapter_resources(qdev);
4099}
4100
4073/* 4101/*
4074 * This callback is called by the PCI subsystem whenever 4102 * This callback is called by the PCI subsystem whenever
4075 * a PCI bus error is detected. 4103 * a PCI bus error is detected.
@@ -4078,17 +4106,21 @@ static pci_ers_result_t qlge_io_error_detected(struct pci_dev *pdev,
4078 enum pci_channel_state state) 4106 enum pci_channel_state state)
4079{ 4107{
4080 struct net_device *ndev = pci_get_drvdata(pdev); 4108 struct net_device *ndev = pci_get_drvdata(pdev);
4081 struct ql_adapter *qdev = netdev_priv(ndev);
4082
4083 netif_device_detach(ndev);
4084 4109
4085 if (state == pci_channel_io_perm_failure) 4110 switch (state) {
4111 case pci_channel_io_normal:
4112 return PCI_ERS_RESULT_CAN_RECOVER;
4113 case pci_channel_io_frozen:
4114 netif_device_detach(ndev);
4115 if (netif_running(ndev))
4116 ql_eeh_close(ndev);
4117 pci_disable_device(pdev);
4118 return PCI_ERS_RESULT_NEED_RESET;
4119 case pci_channel_io_perm_failure:
4120 dev_err(&pdev->dev,
4121 "%s: pci_channel_io_perm_failure.\n", __func__);
4086 return PCI_ERS_RESULT_DISCONNECT; 4122 return PCI_ERS_RESULT_DISCONNECT;
4087 4123 }
4088 if (netif_running(ndev))
4089 ql_adapter_down(qdev);
4090
4091 pci_disable_device(pdev);
4092 4124
4093 /* Request a slot reset. */ 4125 /* Request a slot reset. */
4094 return PCI_ERS_RESULT_NEED_RESET; 4126 return PCI_ERS_RESULT_NEED_RESET;
@@ -4105,25 +4137,15 @@ static pci_ers_result_t qlge_io_slot_reset(struct pci_dev *pdev)
4105 struct net_device *ndev = pci_get_drvdata(pdev); 4137 struct net_device *ndev = pci_get_drvdata(pdev);
4106 struct ql_adapter *qdev = netdev_priv(ndev); 4138 struct ql_adapter *qdev = netdev_priv(ndev);
4107 4139
4140 pdev->error_state = pci_channel_io_normal;
4141
4142 pci_restore_state(pdev);
4108 if (pci_enable_device(pdev)) { 4143 if (pci_enable_device(pdev)) {
4109 QPRINTK(qdev, IFUP, ERR, 4144 QPRINTK(qdev, IFUP, ERR,
4110 "Cannot re-enable PCI device after reset.\n"); 4145 "Cannot re-enable PCI device after reset.\n");
4111 return PCI_ERS_RESULT_DISCONNECT; 4146 return PCI_ERS_RESULT_DISCONNECT;
4112 } 4147 }
4113
4114 pci_set_master(pdev); 4148 pci_set_master(pdev);
4115
4116 netif_carrier_off(ndev);
4117 ql_adapter_reset(qdev);
4118
4119 /* Make sure the EEPROM is good */
4120 memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len);
4121
4122 if (!is_valid_ether_addr(ndev->perm_addr)) {
4123 QPRINTK(qdev, IFUP, ERR, "After reset, invalid MAC address.\n");
4124 return PCI_ERS_RESULT_DISCONNECT;
4125 }
4126
4127 return PCI_ERS_RESULT_RECOVERED; 4149 return PCI_ERS_RESULT_RECOVERED;
4128} 4150}
4129 4151
@@ -4131,17 +4153,21 @@ static void qlge_io_resume(struct pci_dev *pdev)
4131{ 4153{
4132 struct net_device *ndev = pci_get_drvdata(pdev); 4154 struct net_device *ndev = pci_get_drvdata(pdev);
4133 struct ql_adapter *qdev = netdev_priv(ndev); 4155 struct ql_adapter *qdev = netdev_priv(ndev);
4156 int err = 0;
4134 4157
4135 pci_set_master(pdev); 4158 if (ql_adapter_reset(qdev))
4136 4159 QPRINTK(qdev, DRV, ERR, "reset FAILED!\n");
4137 if (netif_running(ndev)) { 4160 if (netif_running(ndev)) {
4138 if (ql_adapter_up(qdev)) { 4161 err = qlge_open(ndev);
4162 if (err) {
4139 QPRINTK(qdev, IFUP, ERR, 4163 QPRINTK(qdev, IFUP, ERR,
4140 "Device initialization failed after reset.\n"); 4164 "Device initialization failed after reset.\n");
4141 return; 4165 return;
4142 } 4166 }
4167 } else {
4168 QPRINTK(qdev, IFUP, ERR,
4169 "Device was not running prior to EEH.\n");
4143 } 4170 }
4144
4145 netif_device_attach(ndev); 4171 netif_device_attach(ndev);
4146} 4172}
4147 4173