aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChad Dupuis <chad.dupuis@qlogic.com>2013-10-30 03:38:16 -0400
committerJames Bottomley <JBottomley@Parallels.com>2013-12-19 10:38:58 -0500
commitf3ddac1918fe963bcbf8d407a3a3c0881b47248b (patch)
tree307e736319180d8930154ce40309f017e3696673
parentfe1b806f4f7172b1eae18ddeebb7d8fb351043f7 (diff)
[SCSI] qla2xxx: Disable adapter when we encounter a PCI disconnect.
If we become disconnected from the PCI bus/PCIe fabric, there can be long delays in register reads which can cause erroneous decisions to be made and cause a soft lockup if a lock is held too long. As a preventative measure, check for a disconnection (register reads that return -1) and then disable the board if we find ourselves in this condition. For now, check in our interrupt handlers and the per adapter one second timer. Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com> Signed-off-by: Saurav Kashyap <saurav.kashyap@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h1
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h4
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c50
-rw-r--r--drivers/scsi/qla2xxx/qla_mr.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.c18
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c77
7 files changed, 148 insertions, 6 deletions
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index acc1ea422cbc..149a1b5f6616 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -11,7 +11,7 @@
11 * ---------------------------------------------------------------------- 11 * ----------------------------------------------------------------------
12 * | Level | Last Value Used | Holes | 12 * | Level | Last Value Used | Holes |
13 * ---------------------------------------------------------------------- 13 * ----------------------------------------------------------------------
14 * | Module Init and Probe | 0x015a | 0x4b,0xba,0xfa | 14 * | Module Init and Probe | 0x015b | 0x4b,0xba,0xfa |
15 * | Mailbox commands | 0x1181 | 0x111a-0x111b | 15 * | Mailbox commands | 0x1181 | 0x111a-0x111b |
16 * | | | 0x1155-0x1158 | 16 * | | | 0x1155-0x1158 |
17 * | | | 0x1018-0x1019 | 17 * | | | 0x1018-0x1019 |
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 82b18c0c7e08..0fb01e1e213c 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -3301,6 +3301,7 @@ struct qla_hw_data {
3301 struct work_struct nic_core_reset; 3301 struct work_struct nic_core_reset;
3302 struct work_struct idc_state_handler; 3302 struct work_struct idc_state_handler;
3303 struct work_struct nic_core_unrecoverable; 3303 struct work_struct nic_core_unrecoverable;
3304 struct work_struct board_disable;
3304 3305
3305 struct mr_data_fx00 mr; 3306 struct mr_data_fx00 mr;
3306 3307
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index df52f73acabd..359d0d9e09d9 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -159,6 +159,9 @@ extern int qla83xx_clear_drv_presence(scsi_qla_host_t *vha);
159extern int __qla83xx_clear_drv_presence(scsi_qla_host_t *vha); 159extern int __qla83xx_clear_drv_presence(scsi_qla_host_t *vha);
160extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32); 160extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32);
161 161
162extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32);
163extern void qla2x00_disable_board_on_pci_error(struct work_struct *);
164
162/* 165/*
163 * Global Functions in qla_mid.c source file. 166 * Global Functions in qla_mid.c source file.
164 */ 167 */
@@ -454,6 +457,7 @@ extern uint8_t *qla25xx_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
454extern int qla25xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t, 457extern int qla25xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
455 uint32_t); 458 uint32_t);
456extern int qla2x00_is_a_vp_did(scsi_qla_host_t *, uint32_t); 459extern int qla2x00_is_a_vp_did(scsi_qla_host_t *, uint32_t);
460bool qla2x00_check_reg_for_disconnect(scsi_qla_host_t *, uint32_t);
457 461
458extern int qla2x00_beacon_on(struct scsi_qla_host *); 462extern int qla2x00_beacon_on(struct scsi_qla_host *);
459extern int qla2x00_beacon_off(struct scsi_qla_host *); 463extern int qla2x00_beacon_off(struct scsi_qla_host *);
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 2e6eae3298d7..0b1b297712ee 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -56,6 +56,16 @@ qla2100_intr_handler(int irq, void *dev_id)
56 vha = pci_get_drvdata(ha->pdev); 56 vha = pci_get_drvdata(ha->pdev);
57 for (iter = 50; iter--; ) { 57 for (iter = 50; iter--; ) {
58 hccr = RD_REG_WORD(&reg->hccr); 58 hccr = RD_REG_WORD(&reg->hccr);
59 /* Check for PCI disconnection */
60 if (hccr == 0xffff) {
61 /*
62 * Schedule this on the default system workqueue so that
63 * all the adapter workqueues and the DPC thread can be
64 * shutdown cleanly.
65 */
66 schedule_work(&ha->board_disable);
67 break;
68 }
59 if (hccr & HCCR_RISC_PAUSE) { 69 if (hccr & HCCR_RISC_PAUSE) {
60 if (pci_channel_offline(ha->pdev)) 70 if (pci_channel_offline(ha->pdev))
61 break; 71 break;
@@ -110,6 +120,22 @@ qla2100_intr_handler(int irq, void *dev_id)
110 return (IRQ_HANDLED); 120 return (IRQ_HANDLED);
111} 121}
112 122
123bool
124qla2x00_check_reg_for_disconnect(scsi_qla_host_t *vha, uint32_t reg)
125{
126 /* Check for PCI disconnection */
127 if (reg == 0xffffffff) {
128 /*
129 * Schedule this on the default system workqueue so that all the
130 * adapter workqueues and the DPC thread can be shutdown
131 * cleanly.
132 */
133 schedule_work(&vha->hw->board_disable);
134 return true;
135 } else
136 return false;
137}
138
113/** 139/**
114 * qla2300_intr_handler() - Process interrupts for the ISP23xx and ISP63xx. 140 * qla2300_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
115 * @irq: 141 * @irq:
@@ -148,11 +174,14 @@ qla2300_intr_handler(int irq, void *dev_id)
148 vha = pci_get_drvdata(ha->pdev); 174 vha = pci_get_drvdata(ha->pdev);
149 for (iter = 50; iter--; ) { 175 for (iter = 50; iter--; ) {
150 stat = RD_REG_DWORD(&reg->u.isp2300.host_status); 176 stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
177 if (qla2x00_check_reg_for_disconnect(vha, stat))
178 break;
151 if (stat & HSR_RISC_PAUSED) { 179 if (stat & HSR_RISC_PAUSED) {
152 if (unlikely(pci_channel_offline(ha->pdev))) 180 if (unlikely(pci_channel_offline(ha->pdev)))
153 break; 181 break;
154 182
155 hccr = RD_REG_WORD(&reg->hccr); 183 hccr = RD_REG_WORD(&reg->hccr);
184
156 if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8)) 185 if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8))
157 ql_log(ql_log_warn, vha, 0x5026, 186 ql_log(ql_log_warn, vha, 0x5026,
158 "Parity error -- HCCR=%x, Dumping " 187 "Parity error -- HCCR=%x, Dumping "
@@ -2571,6 +2600,8 @@ qla24xx_intr_handler(int irq, void *dev_id)
2571 vha = pci_get_drvdata(ha->pdev); 2600 vha = pci_get_drvdata(ha->pdev);
2572 for (iter = 50; iter--; ) { 2601 for (iter = 50; iter--; ) {
2573 stat = RD_REG_DWORD(&reg->host_status); 2602 stat = RD_REG_DWORD(&reg->host_status);
2603 if (qla2x00_check_reg_for_disconnect(vha, stat))
2604 break;
2574 if (stat & HSRX_RISC_PAUSED) { 2605 if (stat & HSRX_RISC_PAUSED) {
2575 if (unlikely(pci_channel_offline(ha->pdev))) 2606 if (unlikely(pci_channel_offline(ha->pdev)))
2576 break; 2607 break;
@@ -2640,6 +2671,7 @@ qla24xx_msix_rsp_q(int irq, void *dev_id)
2640 struct device_reg_24xx __iomem *reg; 2671 struct device_reg_24xx __iomem *reg;
2641 struct scsi_qla_host *vha; 2672 struct scsi_qla_host *vha;
2642 unsigned long flags; 2673 unsigned long flags;
2674 uint32_t stat = 0;
2643 2675
2644 rsp = (struct rsp_que *) dev_id; 2676 rsp = (struct rsp_que *) dev_id;
2645 if (!rsp) { 2677 if (!rsp) {
@@ -2653,11 +2685,19 @@ qla24xx_msix_rsp_q(int irq, void *dev_id)
2653 spin_lock_irqsave(&ha->hardware_lock, flags); 2685 spin_lock_irqsave(&ha->hardware_lock, flags);
2654 2686
2655 vha = pci_get_drvdata(ha->pdev); 2687 vha = pci_get_drvdata(ha->pdev);
2688 /*
2689 * Use host_status register to check to PCI disconnection before we
2690 * we process the response queue.
2691 */
2692 stat = RD_REG_DWORD(&reg->host_status);
2693 if (qla2x00_check_reg_for_disconnect(vha, stat))
2694 goto out;
2656 qla24xx_process_response_queue(vha, rsp); 2695 qla24xx_process_response_queue(vha, rsp);
2657 if (!ha->flags.disable_msix_handshake) { 2696 if (!ha->flags.disable_msix_handshake) {
2658 WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT); 2697 WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
2659 RD_REG_DWORD_RELAXED(&reg->hccr); 2698 RD_REG_DWORD_RELAXED(&reg->hccr);
2660 } 2699 }
2700out:
2661 spin_unlock_irqrestore(&ha->hardware_lock, flags); 2701 spin_unlock_irqrestore(&ha->hardware_lock, flags);
2662 2702
2663 return IRQ_HANDLED; 2703 return IRQ_HANDLED;
@@ -2667,9 +2707,11 @@ static irqreturn_t
2667qla25xx_msix_rsp_q(int irq, void *dev_id) 2707qla25xx_msix_rsp_q(int irq, void *dev_id)
2668{ 2708{
2669 struct qla_hw_data *ha; 2709 struct qla_hw_data *ha;
2710 scsi_qla_host_t *vha;
2670 struct rsp_que *rsp; 2711 struct rsp_que *rsp;
2671 struct device_reg_24xx __iomem *reg; 2712 struct device_reg_24xx __iomem *reg;
2672 unsigned long flags; 2713 unsigned long flags;
2714 uint32_t hccr = 0;
2673 2715
2674 rsp = (struct rsp_que *) dev_id; 2716 rsp = (struct rsp_que *) dev_id;
2675 if (!rsp) { 2717 if (!rsp) {
@@ -2678,17 +2720,21 @@ qla25xx_msix_rsp_q(int irq, void *dev_id)
2678 return IRQ_NONE; 2720 return IRQ_NONE;
2679 } 2721 }
2680 ha = rsp->hw; 2722 ha = rsp->hw;
2723 vha = pci_get_drvdata(ha->pdev);
2681 2724
2682 /* Clear the interrupt, if enabled, for this response queue */ 2725 /* Clear the interrupt, if enabled, for this response queue */
2683 if (!ha->flags.disable_msix_handshake) { 2726 if (!ha->flags.disable_msix_handshake) {
2684 reg = &ha->iobase->isp24; 2727 reg = &ha->iobase->isp24;
2685 spin_lock_irqsave(&ha->hardware_lock, flags); 2728 spin_lock_irqsave(&ha->hardware_lock, flags);
2686 WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT); 2729 WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
2687 RD_REG_DWORD_RELAXED(&reg->hccr); 2730 hccr = RD_REG_DWORD_RELAXED(&reg->hccr);
2688 spin_unlock_irqrestore(&ha->hardware_lock, flags); 2731 spin_unlock_irqrestore(&ha->hardware_lock, flags);
2689 } 2732 }
2733 if (qla2x00_check_reg_for_disconnect(vha, hccr))
2734 goto out;
2690 queue_work_on((int) (rsp->id - 1), ha->wq, &rsp->q_work); 2735 queue_work_on((int) (rsp->id - 1), ha->wq, &rsp->q_work);
2691 2736
2737out:
2692 return IRQ_HANDLED; 2738 return IRQ_HANDLED;
2693} 2739}
2694 2740
@@ -2719,6 +2765,8 @@ qla24xx_msix_default(int irq, void *dev_id)
2719 vha = pci_get_drvdata(ha->pdev); 2765 vha = pci_get_drvdata(ha->pdev);
2720 do { 2766 do {
2721 stat = RD_REG_DWORD(&reg->host_status); 2767 stat = RD_REG_DWORD(&reg->host_status);
2768 if (qla2x00_check_reg_for_disconnect(vha, stat))
2769 break;
2722 if (stat & HSRX_RISC_PAUSED) { 2770 if (stat & HSRX_RISC_PAUSED) {
2723 if (unlikely(pci_channel_offline(ha->pdev))) 2771 if (unlikely(pci_channel_offline(ha->pdev)))
2724 break; 2772 break;
diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c
index cd3bedd00487..7c17b9277c3f 100644
--- a/drivers/scsi/qla2xxx/qla_mr.c
+++ b/drivers/scsi/qla2xxx/qla_mr.c
@@ -3017,6 +3017,8 @@ qlafx00_intr_handler(int irq, void *dev_id)
3017 vha = pci_get_drvdata(ha->pdev); 3017 vha = pci_get_drvdata(ha->pdev);
3018 for (iter = 50; iter--; clr_intr = 0) { 3018 for (iter = 50; iter--; clr_intr = 0) {
3019 stat = QLAFX00_RD_INTR_REG(ha); 3019 stat = QLAFX00_RD_INTR_REG(ha);
3020 if (qla2x00_check_reg_for_disconnect(vha, stat))
3021 break;
3020 if ((stat & QLAFX00_HST_INT_STS_BITS) == 0) 3022 if ((stat & QLAFX00_HST_INT_STS_BITS) == 0)
3021 break; 3023 break;
3022 3024
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
index 11ce53dcbe7e..3da237209f85 100644
--- a/drivers/scsi/qla2xxx/qla_nx.c
+++ b/drivers/scsi/qla2xxx/qla_nx.c
@@ -2096,6 +2096,7 @@ qla82xx_msix_default(int irq, void *dev_id)
2096 int status = 0; 2096 int status = 0;
2097 unsigned long flags; 2097 unsigned long flags;
2098 uint32_t stat = 0; 2098 uint32_t stat = 0;
2099 uint32_t host_int = 0;
2099 uint16_t mb[4]; 2100 uint16_t mb[4];
2100 2101
2101 rsp = (struct rsp_que *) dev_id; 2102 rsp = (struct rsp_que *) dev_id;
@@ -2111,7 +2112,10 @@ qla82xx_msix_default(int irq, void *dev_id)
2111 spin_lock_irqsave(&ha->hardware_lock, flags); 2112 spin_lock_irqsave(&ha->hardware_lock, flags);
2112 vha = pci_get_drvdata(ha->pdev); 2113 vha = pci_get_drvdata(ha->pdev);
2113 do { 2114 do {
2114 if (RD_REG_DWORD(&reg->host_int)) { 2115 host_int = RD_REG_DWORD(&reg->host_int);
2116 if (qla2x00_check_reg_for_disconnect(vha, host_int))
2117 break;
2118 if (host_int) {
2115 stat = RD_REG_DWORD(&reg->host_status); 2119 stat = RD_REG_DWORD(&reg->host_status);
2116 2120
2117 switch (stat & 0xff) { 2121 switch (stat & 0xff) {
@@ -2156,6 +2160,7 @@ qla82xx_msix_rsp_q(int irq, void *dev_id)
2156 struct rsp_que *rsp; 2160 struct rsp_que *rsp;
2157 struct device_reg_82xx __iomem *reg; 2161 struct device_reg_82xx __iomem *reg;
2158 unsigned long flags; 2162 unsigned long flags;
2163 uint32_t host_int = 0;
2159 2164
2160 rsp = (struct rsp_que *) dev_id; 2165 rsp = (struct rsp_que *) dev_id;
2161 if (!rsp) { 2166 if (!rsp) {
@@ -2168,8 +2173,12 @@ qla82xx_msix_rsp_q(int irq, void *dev_id)
2168 reg = &ha->iobase->isp82; 2173 reg = &ha->iobase->isp82;
2169 spin_lock_irqsave(&ha->hardware_lock, flags); 2174 spin_lock_irqsave(&ha->hardware_lock, flags);
2170 vha = pci_get_drvdata(ha->pdev); 2175 vha = pci_get_drvdata(ha->pdev);
2176 host_int = RD_REG_DWORD(&reg->host_int);
2177 if (qla2x00_check_reg_for_disconnect(vha, host_int))
2178 goto out;
2171 qla24xx_process_response_queue(vha, rsp); 2179 qla24xx_process_response_queue(vha, rsp);
2172 WRT_REG_DWORD(&reg->host_int, 0); 2180 WRT_REG_DWORD(&reg->host_int, 0);
2181out:
2173 spin_unlock_irqrestore(&ha->hardware_lock, flags); 2182 spin_unlock_irqrestore(&ha->hardware_lock, flags);
2174 return IRQ_HANDLED; 2183 return IRQ_HANDLED;
2175} 2184}
@@ -2183,6 +2192,7 @@ qla82xx_poll(int irq, void *dev_id)
2183 struct device_reg_82xx __iomem *reg; 2192 struct device_reg_82xx __iomem *reg;
2184 int status = 0; 2193 int status = 0;
2185 uint32_t stat; 2194 uint32_t stat;
2195 uint32_t host_int = 0;
2186 uint16_t mb[4]; 2196 uint16_t mb[4];
2187 unsigned long flags; 2197 unsigned long flags;
2188 2198
@@ -2198,7 +2208,10 @@ qla82xx_poll(int irq, void *dev_id)
2198 spin_lock_irqsave(&ha->hardware_lock, flags); 2208 spin_lock_irqsave(&ha->hardware_lock, flags);
2199 vha = pci_get_drvdata(ha->pdev); 2209 vha = pci_get_drvdata(ha->pdev);
2200 2210
2201 if (RD_REG_DWORD(&reg->host_int)) { 2211 host_int = RD_REG_DWORD(&reg->host_int);
2212 if (qla2x00_check_reg_for_disconnect(vha, host_int))
2213 goto out;
2214 if (host_int) {
2202 stat = RD_REG_DWORD(&reg->host_status); 2215 stat = RD_REG_DWORD(&reg->host_status);
2203 switch (stat & 0xff) { 2216 switch (stat & 0xff) {
2204 case 0x1: 2217 case 0x1:
@@ -2226,6 +2239,7 @@ qla82xx_poll(int irq, void *dev_id)
2226 } 2239 }
2227 } 2240 }
2228 WRT_REG_DWORD(&reg->host_int, 0); 2241 WRT_REG_DWORD(&reg->host_int, 0);
2242out:
2229 spin_unlock_irqrestore(&ha->hardware_lock, flags); 2243 spin_unlock_irqrestore(&ha->hardware_lock, flags);
2230} 2244}
2231 2245
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index c9e4372698a2..690b626df930 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -2738,6 +2738,8 @@ que_init:
2738 */ 2738 */
2739 qla2xxx_wake_dpc(base_vha); 2739 qla2xxx_wake_dpc(base_vha);
2740 2740
2741 INIT_WORK(&ha->board_disable, qla2x00_disable_board_on_pci_error);
2742
2741 if (IS_QLA8031(ha) || IS_MCTP_CAPABLE(ha)) { 2743 if (IS_QLA8031(ha) || IS_MCTP_CAPABLE(ha)) {
2742 sprintf(wq_name, "qla2xxx_%lu_dpc_lp_wq", base_vha->host_no); 2744 sprintf(wq_name, "qla2xxx_%lu_dpc_lp_wq", base_vha->host_no);
2743 ha->dpc_lp_wq = create_singlethread_workqueue(wq_name); 2745 ha->dpc_lp_wq = create_singlethread_workqueue(wq_name);
@@ -4673,6 +4675,66 @@ exit:
4673 return rval; 4675 return rval;
4674} 4676}
4675 4677
4678void
4679qla2x00_disable_board_on_pci_error(struct work_struct *work)
4680{
4681 struct qla_hw_data *ha = container_of(work, struct qla_hw_data,
4682 board_disable);
4683 struct pci_dev *pdev = ha->pdev;
4684 scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
4685
4686 ql_log(ql_log_warn, base_vha, 0x015b,
4687 "Disabling adapter.\n");
4688
4689 set_bit(UNLOADING, &base_vha->dpc_flags);
4690
4691 qla2x00_delete_all_vps(ha, base_vha);
4692
4693 qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16);
4694
4695 qla2x00_dfs_remove(base_vha);
4696
4697 qla84xx_put_chip(base_vha);
4698
4699 if (base_vha->timer_active)
4700 qla2x00_stop_timer(base_vha);
4701
4702 base_vha->flags.online = 0;
4703
4704 qla2x00_destroy_deferred_work(ha);
4705
4706 /*
4707 * Do not try to stop beacon blink as it will issue a mailbox
4708 * command.
4709 */
4710 qla2x00_free_sysfs_attr(base_vha, false);
4711
4712 fc_remove_host(base_vha->host);
4713
4714 scsi_remove_host(base_vha->host);
4715
4716 base_vha->flags.init_done = 0;
4717 qla25xx_delete_queues(base_vha);
4718 qla2x00_free_irqs(base_vha);
4719 qla2x00_free_fcports(base_vha);
4720 qla2x00_mem_free(ha);
4721 qla82xx_md_free(base_vha);
4722 qla2x00_free_queues(ha);
4723
4724 scsi_host_put(base_vha->host);
4725
4726 qla2x00_unmap_iobases(ha);
4727
4728 pci_release_selected_regions(ha->pdev, ha->bars);
4729 kfree(ha);
4730 ha = NULL;
4731
4732 pci_disable_pcie_error_reporting(pdev);
4733 pci_disable_device(pdev);
4734 pci_set_drvdata(pdev, NULL);
4735
4736}
4737
4676/************************************************************************** 4738/**************************************************************************
4677* qla2x00_do_dpc 4739* qla2x00_do_dpc
4678* This kernel thread is a task that is schedule by the interrupt handler 4740* This kernel thread is a task that is schedule by the interrupt handler
@@ -5026,9 +5088,20 @@ qla2x00_timer(scsi_qla_host_t *vha)
5026 return; 5088 return;
5027 } 5089 }
5028 5090
5029 /* Hardware read to raise pending EEH errors during mailbox waits. */ 5091 /*
5030 if (!pci_channel_offline(ha->pdev)) 5092 * Hardware read to raise pending EEH errors during mailbox waits. If
5093 * the read returns -1 then disable the board.
5094 */
5095 if (!pci_channel_offline(ha->pdev)) {
5031 pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); 5096 pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w);
5097 if (w == 0xffff)
5098 /*
5099 * Schedule this on the default system workqueue so that
5100 * all the adapter workqueues and the DPC thread can be
5101 * shutdown cleanly.
5102 */
5103 schedule_work(&ha->board_disable);
5104 }
5032 5105
5033 /* Make sure qla82xx_watchdog is run only for physical port */ 5106 /* Make sure qla82xx_watchdog is run only for physical port */
5034 if (!vha->vp_idx && IS_P3P_TYPE(ha)) { 5107 if (!vha->vp_idx && IS_P3P_TYPE(ha)) {