diff options
author | Lalit Chandivade <lalit.chandivade@qlogic.com> | 2010-09-03 18:20:50 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-09-05 14:33:07 -0400 |
commit | a5b36321918b3a1295748b77c62976c167233eec (patch) | |
tree | d0e89c61324f72deca2ee2f60d61912eb6e51a59 /drivers/scsi/qla2xxx | |
parent | 6dbdda4d596f201b8a82a276a0c0b50ef2b899e8 (diff) |
[SCSI] qla2xxx: Added AER support for ISP82xx.
Signed-off-by: Giridhar Malavali <giridhar.malavali@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/qla2xxx')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gbl.h | 2 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_nx.c | 7 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 134 |
3 files changed, 138 insertions, 5 deletions
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 1a1b281cea33..4edfc731ea96 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h | |||
@@ -511,6 +511,7 @@ extern void qla82xx_reset_chip(struct scsi_qla_host *); | |||
511 | extern void qla82xx_config_rings(struct scsi_qla_host *); | 511 | extern void qla82xx_config_rings(struct scsi_qla_host *); |
512 | extern int qla82xx_pinit_from_rom(scsi_qla_host_t *); | 512 | extern int qla82xx_pinit_from_rom(scsi_qla_host_t *); |
513 | extern void qla82xx_watchdog(scsi_qla_host_t *); | 513 | extern void qla82xx_watchdog(scsi_qla_host_t *); |
514 | extern int qla82xx_start_firmware(scsi_qla_host_t *); | ||
514 | 515 | ||
515 | /* Firmware and flash related functions */ | 516 | /* Firmware and flash related functions */ |
516 | extern int qla82xx_load_risc(scsi_qla_host_t *, uint32_t *); | 517 | extern int qla82xx_load_risc(scsi_qla_host_t *, uint32_t *); |
@@ -538,6 +539,7 @@ extern void qla82xx_poll(int, void *); | |||
538 | extern void qla82xx_init_flags(struct qla_hw_data *); | 539 | extern void qla82xx_init_flags(struct qla_hw_data *); |
539 | 540 | ||
540 | /* ISP 8021 hardware related */ | 541 | /* ISP 8021 hardware related */ |
542 | extern void qla82xx_set_drv_active(scsi_qla_host_t *); | ||
541 | extern int qla82xx_crb_win_lock(struct qla_hw_data *); | 543 | extern int qla82xx_crb_win_lock(struct qla_hw_data *); |
542 | extern void qla82xx_crb_win_unlock(struct qla_hw_data *); | 544 | extern void qla82xx_crb_win_unlock(struct qla_hw_data *); |
543 | extern int qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *, ulong *); | 545 | extern int qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *, ulong *); |
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 915b77a6e193..2ad91100a7e4 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c | |||
@@ -2257,7 +2257,7 @@ void qla82xx_init_flags(struct qla_hw_data *ha) | |||
2257 | ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg; | 2257 | ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg; |
2258 | } | 2258 | } |
2259 | 2259 | ||
2260 | static inline void | 2260 | inline void |
2261 | qla82xx_set_drv_active(scsi_qla_host_t *vha) | 2261 | qla82xx_set_drv_active(scsi_qla_host_t *vha) |
2262 | { | 2262 | { |
2263 | uint32_t drv_active; | 2263 | uint32_t drv_active; |
@@ -2411,7 +2411,7 @@ fw_load_failed: | |||
2411 | return QLA_FUNCTION_FAILED; | 2411 | return QLA_FUNCTION_FAILED; |
2412 | } | 2412 | } |
2413 | 2413 | ||
2414 | static int | 2414 | int |
2415 | qla82xx_start_firmware(scsi_qla_host_t *vha) | 2415 | qla82xx_start_firmware(scsi_qla_host_t *vha) |
2416 | { | 2416 | { |
2417 | int pcie_cap; | 2417 | int pcie_cap; |
@@ -3291,6 +3291,9 @@ qla82xx_check_fw_alive(scsi_qla_host_t *vha) | |||
3291 | struct qla_hw_data *ha = vha->hw; | 3291 | struct qla_hw_data *ha = vha->hw; |
3292 | 3292 | ||
3293 | fw_heartbeat_counter = qla82xx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); | 3293 | fw_heartbeat_counter = qla82xx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); |
3294 | /* all 0xff, assume AER/EEH in progress, ignore */ | ||
3295 | if (fw_heartbeat_counter == 0xffffffff) | ||
3296 | return; | ||
3294 | if (vha->fw_heartbeat_counter == fw_heartbeat_counter) { | 3297 | if (vha->fw_heartbeat_counter == fw_heartbeat_counter) { |
3295 | vha->seconds_since_last_heartbeat++; | 3298 | vha->seconds_since_last_heartbeat++; |
3296 | /* FW not alive after 2 seconds */ | 3299 | /* FW not alive after 2 seconds */ |
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 30b05229af26..cfa55827a101 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c | |||
@@ -3526,6 +3526,11 @@ qla2x00_timer(scsi_qla_host_t *vha) | |||
3526 | struct qla_hw_data *ha = vha->hw; | 3526 | struct qla_hw_data *ha = vha->hw; |
3527 | struct req_que *req; | 3527 | struct req_que *req; |
3528 | 3528 | ||
3529 | if (ha->flags.eeh_busy) { | ||
3530 | qla2x00_restart_timer(vha, WATCH_INTERVAL); | ||
3531 | return; | ||
3532 | } | ||
3533 | |||
3529 | if (IS_QLA82XX(ha)) | 3534 | if (IS_QLA82XX(ha)) |
3530 | qla82xx_watchdog(vha); | 3535 | qla82xx_watchdog(vha); |
3531 | 3536 | ||
@@ -3755,6 +3760,17 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) | |||
3755 | return PCI_ERS_RESULT_CAN_RECOVER; | 3760 | return PCI_ERS_RESULT_CAN_RECOVER; |
3756 | case pci_channel_io_frozen: | 3761 | case pci_channel_io_frozen: |
3757 | ha->flags.eeh_busy = 1; | 3762 | ha->flags.eeh_busy = 1; |
3763 | /* For ISP82XX complete any pending mailbox cmd */ | ||
3764 | if (IS_QLA82XX(ha)) { | ||
3765 | ha->flags.fw_hung = 1; | ||
3766 | if (ha->flags.mbox_busy) { | ||
3767 | ha->flags.mbox_int = 1; | ||
3768 | DEBUG2(qla_printk(KERN_ERR, ha, | ||
3769 | "Due to pci channel io frozen, doing premature " | ||
3770 | "completion of mbx command\n")); | ||
3771 | complete(&ha->mbx_intr_comp); | ||
3772 | } | ||
3773 | } | ||
3758 | qla2x00_free_irqs(vha); | 3774 | qla2x00_free_irqs(vha); |
3759 | pci_disable_device(pdev); | 3775 | pci_disable_device(pdev); |
3760 | return PCI_ERS_RESULT_NEED_RESET; | 3776 | return PCI_ERS_RESULT_NEED_RESET; |
@@ -3803,6 +3819,109 @@ qla2xxx_pci_mmio_enabled(struct pci_dev *pdev) | |||
3803 | return PCI_ERS_RESULT_RECOVERED; | 3819 | return PCI_ERS_RESULT_RECOVERED; |
3804 | } | 3820 | } |
3805 | 3821 | ||
3822 | uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha) | ||
3823 | { | ||
3824 | uint32_t rval = QLA_FUNCTION_FAILED; | ||
3825 | uint32_t drv_active = 0; | ||
3826 | struct qla_hw_data *ha = base_vha->hw; | ||
3827 | int fn; | ||
3828 | struct pci_dev *other_pdev = NULL; | ||
3829 | |||
3830 | DEBUG17(qla_printk(KERN_INFO, ha, | ||
3831 | "scsi(%ld): In qla82xx_error_recovery\n", base_vha->host_no)); | ||
3832 | |||
3833 | set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); | ||
3834 | |||
3835 | if (base_vha->flags.online) { | ||
3836 | /* Abort all outstanding commands, | ||
3837 | * so as to be requeued later */ | ||
3838 | qla2x00_abort_isp_cleanup(base_vha); | ||
3839 | } | ||
3840 | |||
3841 | |||
3842 | fn = PCI_FUNC(ha->pdev->devfn); | ||
3843 | while (fn > 0) { | ||
3844 | fn--; | ||
3845 | DEBUG17(qla_printk(KERN_INFO, ha, | ||
3846 | "Finding pci device at function = 0x%x\n", fn)); | ||
3847 | other_pdev = | ||
3848 | pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus), | ||
3849 | ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn), | ||
3850 | fn)); | ||
3851 | |||
3852 | if (!other_pdev) | ||
3853 | continue; | ||
3854 | if (atomic_read(&other_pdev->enable_cnt)) { | ||
3855 | DEBUG17(qla_printk(KERN_INFO, ha, | ||
3856 | "Found PCI func availabe and enabled at 0x%x\n", | ||
3857 | fn)); | ||
3858 | pci_dev_put(other_pdev); | ||
3859 | break; | ||
3860 | } | ||
3861 | pci_dev_put(other_pdev); | ||
3862 | } | ||
3863 | |||
3864 | if (!fn) { | ||
3865 | /* Reset owner */ | ||
3866 | DEBUG17(qla_printk(KERN_INFO, ha, | ||
3867 | "This devfn is reset owner = 0x%x\n", ha->pdev->devfn)); | ||
3868 | qla82xx_idc_lock(ha); | ||
3869 | |||
3870 | qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, | ||
3871 | QLA82XX_DEV_INITIALIZING); | ||
3872 | |||
3873 | qla82xx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION, | ||
3874 | QLA82XX_IDC_VERSION); | ||
3875 | |||
3876 | drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); | ||
3877 | DEBUG17(qla_printk(KERN_INFO, ha, | ||
3878 | "drv_active = 0x%x\n", drv_active)); | ||
3879 | |||
3880 | qla82xx_idc_unlock(ha); | ||
3881 | /* Reset if device is not already reset | ||
3882 | * drv_active would be 0 if a reset has already been done | ||
3883 | */ | ||
3884 | if (drv_active) | ||
3885 | rval = qla82xx_start_firmware(base_vha); | ||
3886 | else | ||
3887 | rval = QLA_SUCCESS; | ||
3888 | qla82xx_idc_lock(ha); | ||
3889 | |||
3890 | if (rval != QLA_SUCCESS) { | ||
3891 | qla_printk(KERN_INFO, ha, "HW State: FAILED\n"); | ||
3892 | qla82xx_clear_drv_active(ha); | ||
3893 | qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, | ||
3894 | QLA82XX_DEV_FAILED); | ||
3895 | } else { | ||
3896 | qla_printk(KERN_INFO, ha, "HW State: READY\n"); | ||
3897 | qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, | ||
3898 | QLA82XX_DEV_READY); | ||
3899 | qla82xx_idc_unlock(ha); | ||
3900 | ha->flags.fw_hung = 0; | ||
3901 | rval = qla82xx_restart_isp(base_vha); | ||
3902 | qla82xx_idc_lock(ha); | ||
3903 | /* Clear driver state register */ | ||
3904 | qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0); | ||
3905 | qla82xx_set_drv_active(base_vha); | ||
3906 | } | ||
3907 | qla82xx_idc_unlock(ha); | ||
3908 | } else { | ||
3909 | DEBUG17(qla_printk(KERN_INFO, ha, | ||
3910 | "This devfn is not reset owner = 0x%x\n", ha->pdev->devfn)); | ||
3911 | if ((qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE) == | ||
3912 | QLA82XX_DEV_READY)) { | ||
3913 | ha->flags.fw_hung = 0; | ||
3914 | rval = qla82xx_restart_isp(base_vha); | ||
3915 | qla82xx_idc_lock(ha); | ||
3916 | qla82xx_set_drv_active(base_vha); | ||
3917 | qla82xx_idc_unlock(ha); | ||
3918 | } | ||
3919 | } | ||
3920 | clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); | ||
3921 | |||
3922 | return rval; | ||
3923 | } | ||
3924 | |||
3806 | static pci_ers_result_t | 3925 | static pci_ers_result_t |
3807 | qla2xxx_pci_slot_reset(struct pci_dev *pdev) | 3926 | qla2xxx_pci_slot_reset(struct pci_dev *pdev) |
3808 | { | 3927 | { |
@@ -3835,15 +3954,23 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev) | |||
3835 | if (rc) { | 3954 | if (rc) { |
3836 | qla_printk(KERN_WARNING, ha, | 3955 | qla_printk(KERN_WARNING, ha, |
3837 | "Can't re-enable PCI device after reset.\n"); | 3956 | "Can't re-enable PCI device after reset.\n"); |
3838 | return ret; | 3957 | goto exit_slot_reset; |
3839 | } | 3958 | } |
3840 | 3959 | ||
3841 | rsp = ha->rsp_q_map[0]; | 3960 | rsp = ha->rsp_q_map[0]; |
3842 | if (qla2x00_request_irqs(ha, rsp)) | 3961 | if (qla2x00_request_irqs(ha, rsp)) |
3843 | return ret; | 3962 | goto exit_slot_reset; |
3844 | 3963 | ||
3845 | if (ha->isp_ops->pci_config(base_vha)) | 3964 | if (ha->isp_ops->pci_config(base_vha)) |
3846 | return ret; | 3965 | goto exit_slot_reset; |
3966 | |||
3967 | if (IS_QLA82XX(ha)) { | ||
3968 | if (qla82xx_error_recovery(base_vha) == QLA_SUCCESS) { | ||
3969 | ret = PCI_ERS_RESULT_RECOVERED; | ||
3970 | goto exit_slot_reset; | ||
3971 | } else | ||
3972 | goto exit_slot_reset; | ||
3973 | } | ||
3847 | 3974 | ||
3848 | while (ha->flags.mbox_busy && retries--) | 3975 | while (ha->flags.mbox_busy && retries--) |
3849 | msleep(1000); | 3976 | msleep(1000); |
@@ -3854,6 +3981,7 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev) | |||
3854 | clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); | 3981 | clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); |
3855 | 3982 | ||
3856 | 3983 | ||
3984 | exit_slot_reset: | ||
3857 | DEBUG17(qla_printk(KERN_WARNING, ha, | 3985 | DEBUG17(qla_printk(KERN_WARNING, ha, |
3858 | "slot_reset-return:ret=%x\n", ret)); | 3986 | "slot_reset-return:ret=%x\n", ret)); |
3859 | 3987 | ||