diff options
author | Seokmann Ju <seokmann.ju@qlogic.com> | 2007-09-20 17:07:36 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.localdomain> | 2007-10-12 14:49:47 -0400 |
commit | 14e660e677ddd3574247495aae4ef63eb8899072 (patch) | |
tree | fbf817d4e37887ae31ed46652f72440901c1f94b /drivers/scsi/qla2xxx/qla_os.c | |
parent | b7cc176c9eb3aa6989ac099efd8bdd6d0eaa784a (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/qla_os.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 2a03400b6f72..a8ab2d3447ba 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 | ||
2831 | static pci_ers_result_t | ||
2832 | qla2xxx_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 | |||
2847 | static pci_ers_result_t | ||
2848 | qla2xxx_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(®->hccr); | ||
2860 | if (stat & HCCR_RISC_PAUSE) | ||
2861 | risc_paused = 1; | ||
2862 | } else if (IS_QLA23XX(ha)) { | ||
2863 | stat = RD_REG_DWORD(®->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(®24->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 | |||
2883 | static pci_ers_result_t | ||
2884 | qla2xxx_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 | |||
2908 | static void | ||
2909 | qla2xxx_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 | |||
2923 | static 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 | |||
2817 | static struct pci_device_id qla2xxx_pci_tbl[] = { | 2930 | static 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 | /** |