diff options
author | Ron Mercer <ron.mercer@qlogic.com> | 2009-10-28 04:39:20 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-10-29 04:17:14 -0400 |
commit | 6d190c6edf42a572485cf1b6c7479bfc42753084 (patch) | |
tree | e4688decb302c4a0f17f9d143c6cd16c856c9c7f /drivers | |
parent | 55888dfb6ba7e318bb3d6a44d25009906206bf6a (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')
-rw-r--r-- | drivers/net/qlge/qlge_main.c | 78 |
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. */ | ||
4075 | static 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 | ||