diff options
| -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 | ||
