aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla2xxx
diff options
context:
space:
mode:
authorSeokmann Ju <seokmann.ju@qlogic.com>2007-09-20 17:07:36 -0400
committerJames Bottomley <jejb@mulgrave.localdomain>2007-10-12 14:49:47 -0400
commit14e660e677ddd3574247495aae4ef63eb8899072 (patch)
treefbf817d4e37887ae31ed46652f72440901c1f94b /drivers/scsi/qla2xxx
parentb7cc176c9eb3aa6989ac099efd8bdd6d0eaa784a (diff)
[SCSI] qla2xxx: Add PCI error recovery support.
Additional cleanups and Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/qla2xxx')
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h1
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c28
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c114
3 files changed, 142 insertions, 1 deletions
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index e1e342889b2..75ab898b02b 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -23,6 +23,7 @@
23#include <linux/interrupt.h> 23#include <linux/interrupt.h>
24#include <linux/workqueue.h> 24#include <linux/workqueue.h>
25#include <linux/firmware.h> 25#include <linux/firmware.h>
26#include <linux/aer.h>
26#include <asm/semaphore.h> 27#include <asm/semaphore.h>
27 28
28#include <scsi/scsi.h> 29#include <scsi/scsi.h>
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index eecae9905ec..dcfb24b198f 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -34,6 +34,7 @@ qla2100_intr_handler(int irq, void *dev_id)
34 int status; 34 int status;
35 unsigned long flags; 35 unsigned long flags;
36 unsigned long iter; 36 unsigned long iter;
37 uint16_t hccr;
37 uint16_t mb[4]; 38 uint16_t mb[4];
38 39
39 ha = (scsi_qla_host_t *) dev_id; 40 ha = (scsi_qla_host_t *) dev_id;
@@ -48,7 +49,23 @@ qla2100_intr_handler(int irq, void *dev_id)
48 49
49 spin_lock_irqsave(&ha->hardware_lock, flags); 50 spin_lock_irqsave(&ha->hardware_lock, flags);
50 for (iter = 50; iter--; ) { 51 for (iter = 50; iter--; ) {
51 if ((RD_REG_WORD(&reg->istatus) & ISR_RISC_INT) == 0) 52 hccr = RD_REG_WORD(&reg->hccr);
53 if (hccr & HCCR_RISC_PAUSE) {
54 if (pci_channel_offline(ha->pdev))
55 break;
56
57 /*
58 * Issue a "HARD" reset in order for the RISC interrupt
59 * bit to be cleared. Schedule a big hammmer to get
60 * out of the RISC PAUSED state.
61 */
62 WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
63 RD_REG_WORD(&reg->hccr);
64
65 ha->isp_ops->fw_dump(ha, 1);
66 set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
67 break;
68 } else if ((RD_REG_WORD(&reg->istatus) & ISR_RISC_INT) == 0)
52 break; 69 break;
53 70
54 if (RD_REG_WORD(&reg->semaphore) & BIT_0) { 71 if (RD_REG_WORD(&reg->semaphore) & BIT_0) {
@@ -127,6 +144,9 @@ qla2300_intr_handler(int irq, void *dev_id)
127 for (iter = 50; iter--; ) { 144 for (iter = 50; iter--; ) {
128 stat = RD_REG_DWORD(&reg->u.isp2300.host_status); 145 stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
129 if (stat & HSR_RISC_PAUSED) { 146 if (stat & HSR_RISC_PAUSED) {
147 if (pci_channel_offline(ha->pdev))
148 break;
149
130 hccr = RD_REG_WORD(&reg->hccr); 150 hccr = RD_REG_WORD(&reg->hccr);
131 if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8)) 151 if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8))
132 qla_printk(KERN_INFO, ha, "Parity error -- " 152 qla_printk(KERN_INFO, ha, "Parity error -- "
@@ -1499,6 +1519,9 @@ qla24xx_intr_handler(int irq, void *dev_id)
1499 for (iter = 50; iter--; ) { 1519 for (iter = 50; iter--; ) {
1500 stat = RD_REG_DWORD(&reg->host_status); 1520 stat = RD_REG_DWORD(&reg->host_status);
1501 if (stat & HSRX_RISC_PAUSED) { 1521 if (stat & HSRX_RISC_PAUSED) {
1522 if (pci_channel_offline(ha->pdev))
1523 break;
1524
1502 hccr = RD_REG_DWORD(&reg->hccr); 1525 hccr = RD_REG_DWORD(&reg->hccr);
1503 1526
1504 qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, " 1527 qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
@@ -1633,6 +1656,9 @@ qla24xx_msix_default(int irq, void *dev_id)
1633 for (iter = 50; iter--; ) { 1656 for (iter = 50; iter--; ) {
1634 stat = RD_REG_DWORD(&reg->host_status); 1657 stat = RD_REG_DWORD(&reg->host_status);
1635 if (stat & HSRX_RISC_PAUSED) { 1658 if (stat & HSRX_RISC_PAUSED) {
1659 if (pci_channel_offline(ha->pdev))
1660 break;
1661
1636 hccr = RD_REG_DWORD(&reg->hccr); 1662 hccr = RD_REG_DWORD(&reg->hccr);
1637 1663
1638 qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, " 1664 qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 2a03400b6f7..a8ab2d3447b 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -385,6 +385,11 @@ qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
385 srb_t *sp; 385 srb_t *sp;
386 int rval; 386 int rval;
387 387
388 if (unlikely(pci_channel_offline(ha->pdev))) {
389 cmd->result = DID_REQUEUE << 16;
390 goto qc_fail_command;
391 }
392
388 rval = fc_remote_port_chkready(rport); 393 rval = fc_remote_port_chkready(rport);
389 if (rval) { 394 if (rval) {
390 cmd->result = rval; 395 cmd->result = rval;
@@ -447,6 +452,11 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
447 int rval; 452 int rval;
448 scsi_qla_host_t *pha = to_qla_parent(ha); 453 scsi_qla_host_t *pha = to_qla_parent(ha);
449 454
455 if (unlikely(pci_channel_offline(ha->pdev))) {
456 cmd->result = DID_REQUEUE << 16;
457 goto qc24_fail_command;
458 }
459
450 rval = fc_remote_port_chkready(rport); 460 rval = fc_remote_port_chkready(rport);
451 if (rval) { 461 if (rval) {
452 cmd->result = rval; 462 cmd->result = rval;
@@ -1571,6 +1581,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
1571 if (pci_enable_device(pdev)) 1581 if (pci_enable_device(pdev))
1572 goto probe_out; 1582 goto probe_out;
1573 1583
1584 if (pci_find_aer_capability(pdev))
1585 if (pci_enable_pcie_error_reporting(pdev))
1586 goto probe_out;
1587
1574 sht = &qla2x00_driver_template; 1588 sht = &qla2x00_driver_template;
1575 if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 || 1589 if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 ||
1576 pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 || 1590 pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 ||
@@ -2814,6 +2828,105 @@ qla2x00_release_firmware(void)
2814 up(&qla_fw_lock); 2828 up(&qla_fw_lock);
2815} 2829}
2816 2830
2831static pci_ers_result_t
2832qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
2833{
2834 switch (state) {
2835 case pci_channel_io_normal:
2836 return PCI_ERS_RESULT_CAN_RECOVER;
2837 case pci_channel_io_frozen:
2838 pci_disable_device(pdev);
2839 return PCI_ERS_RESULT_NEED_RESET;
2840 case pci_channel_io_perm_failure:
2841 qla2x00_remove_one(pdev);
2842 return PCI_ERS_RESULT_DISCONNECT;
2843 }
2844 return PCI_ERS_RESULT_NEED_RESET;
2845}
2846
2847static pci_ers_result_t
2848qla2xxx_pci_mmio_enabled(struct pci_dev *pdev)
2849{
2850 int risc_paused = 0;
2851 uint32_t stat;
2852 unsigned long flags;
2853 scsi_qla_host_t *ha = pci_get_drvdata(pdev);
2854 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
2855 struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
2856
2857 spin_lock_irqsave(&ha->hardware_lock, flags);
2858 if (IS_QLA2100(ha) || IS_QLA2200(ha)){
2859 stat = RD_REG_DWORD(&reg->hccr);
2860 if (stat & HCCR_RISC_PAUSE)
2861 risc_paused = 1;
2862 } else if (IS_QLA23XX(ha)) {
2863 stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
2864 if (stat & HSR_RISC_PAUSED)
2865 risc_paused = 1;
2866 } else if (IS_FWI2_CAPABLE(ha)) {
2867 stat = RD_REG_DWORD(&reg24->host_status);
2868 if (stat & HSRX_RISC_PAUSED)
2869 risc_paused = 1;
2870 }
2871 spin_unlock_irqrestore(&ha->hardware_lock, flags);
2872
2873 if (risc_paused) {
2874 qla_printk(KERN_INFO, ha, "RISC paused -- mmio_enabled, "
2875 "Dumping firmware!\n");
2876 ha->isp_ops->fw_dump(ha, 0);
2877
2878 return PCI_ERS_RESULT_NEED_RESET;
2879 } else
2880 return PCI_ERS_RESULT_RECOVERED;
2881}
2882
2883static pci_ers_result_t
2884qla2xxx_pci_slot_reset(struct pci_dev *pdev)
2885{
2886 pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT;
2887 scsi_qla_host_t *ha = pci_get_drvdata(pdev);
2888
2889 if (pci_enable_device(pdev)) {
2890 qla_printk(KERN_WARNING, ha,
2891 "Can't re-enable PCI device after reset.\n");
2892
2893 return ret;
2894 }
2895 pci_set_master(pdev);
2896
2897 if (ha->isp_ops->pci_config(ha))
2898 return ret;
2899
2900 set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
2901 if (qla2x00_abort_isp(ha)== QLA_SUCCESS)
2902 ret = PCI_ERS_RESULT_RECOVERED;
2903 clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
2904
2905 return ret;
2906}
2907
2908static void
2909qla2xxx_pci_resume(struct pci_dev *pdev)
2910{
2911 scsi_qla_host_t *ha = pci_get_drvdata(pdev);
2912 int ret;
2913
2914 ret = qla2x00_wait_for_hba_online(ha);
2915 if (ret != QLA_SUCCESS) {
2916 qla_printk(KERN_ERR, ha,
2917 "the device failed to resume I/O "
2918 "from slot/link_reset");
2919 }
2920 pci_cleanup_aer_uncorrect_error_status(pdev);
2921}
2922
2923static struct pci_error_handlers qla2xxx_err_handler = {
2924 .error_detected = qla2xxx_pci_error_detected,
2925 .mmio_enabled = qla2xxx_pci_mmio_enabled,
2926 .slot_reset = qla2xxx_pci_slot_reset,
2927 .resume = qla2xxx_pci_resume,
2928};
2929
2817static struct pci_device_id qla2xxx_pci_tbl[] = { 2930static struct pci_device_id qla2xxx_pci_tbl[] = {
2818 { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2100) }, 2931 { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2100) },
2819 { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2200) }, 2932 { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2200) },
@@ -2839,6 +2952,7 @@ static struct pci_driver qla2xxx_pci_driver = {
2839 .id_table = qla2xxx_pci_tbl, 2952 .id_table = qla2xxx_pci_tbl,
2840 .probe = qla2x00_probe_one, 2953 .probe = qla2x00_probe_one,
2841 .remove = __devexit_p(qla2x00_remove_one), 2954 .remove = __devexit_p(qla2x00_remove_one),
2955 .err_handler = &qla2xxx_err_handler,
2842}; 2956};
2843 2957
2844/** 2958/**