From: Chad Dupuis <cdupuis@redhat.com> Date: Fri, 3 Sep 2010 21:43:46 -0400 Subject: [scsi] qla2xxx: add AER support for 82XX Message-id: <20100903214345.2831.78575.sendpatchset@localhost.localdomain> Patchwork-id: 28154 O-Subject: [RHEL 5.6 PATCH 1/2] qla2xxx: Add AER support for 82XX. Bugzilla: 613134 RH-Acked-by: Prarit Bhargava <prarit@redhat.com> Bugzilla -------- Bug 613134 (https://bugzilla.redhat.com/show_bug.cgi?id=613134) Upstream Status --------------- Will be submitted upstream as part of our next upstream submission. Description ----------- >From eea70792dc5206573182917eb32b2bbff248df91 Mon Sep 17 00:00:00 2001 From: root <root@labrat.lab.bos.redhat.com> Date: Fri, 3 Sep 2010 11:46:16 -0400 Subject: [PATCH] qla2xxx: Add AER support for 82XX. diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index cad79c0..cbfb647 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -456,6 +456,7 @@ extern void qla82xx_reset_chip(struct scsi_qla_host *); extern void qla82xx_config_rings(struct scsi_qla_host *); extern void qla82xx_reset_adapter(struct scsi_qla_host *); extern void qla82xx_watchdog(scsi_qla_host_t *); +extern int qla82xx_start_firmware(scsi_qla_host_t *); /* Firmware and flash related functions */ extern int qla82xx_load_risc(scsi_qla_host_t *, uint32_t *); @@ -487,6 +488,7 @@ extern void qla82xx_poll(int, void *, struct pt_regs *); extern void qla82xx_init_flags(struct scsi_qla_host *); /* ISP 8021 hardware related */ +extern void qla82xx_set_drv_active(scsi_qla_host_t *); extern int qla82xx_wr_32(scsi_qla_host_t *, ulong, u32); extern int qla82xx_rd_32(scsi_qla_host_t *, ulong); extern int qla82xx_rom_fast_read(scsi_qla_host_t *, int , int*); diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 1ab3b22..a22e451 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -2200,7 +2200,7 @@ void qla82xx_init_flags(struct scsi_qla_host *ha) ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg; } -static inline void +inline void qla82xx_set_drv_active(scsi_qla_host_t *ha) { uint32_t drv_active; @@ -2320,7 +2320,7 @@ int qla82xx_load_fw(scsi_qla_host_t *ha) return QLA_FUNCTION_FAILED; } -static int +int qla82xx_start_firmware(scsi_qla_host_t *ha) { int pcie_cap; @@ -2524,6 +2524,9 @@ qla82xx_check_fw_alive(scsi_qla_host_t *ha) uint32_t fw_heartbeat_counter, halt_status; fw_heartbeat_counter = qla82xx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); + /* all 0xff, assume AER/EEH in progress, ignore */ + if (fw_heartbeat_counter == 0xffffffff) + return; if (ha->fw_heartbeat_counter == fw_heartbeat_counter) { ha->seconds_since_last_heartbeat++; /* FW not alive after 2 seconds */ diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 22595ce..080bdf8 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -3475,6 +3475,11 @@ qla2x00_timer(scsi_qla_host_t *ha) int t; uint16_t w; + if (pha->flags.eeh_busy) { + qla2x00_restart_timer(ha, WATCH_INTERVAL); + return; + } + /* Hardware read to raise pending EEH errors during mailbox waits. */ if (!pci_channel_offline(pha->pdev)) pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); @@ -3656,6 +3661,17 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) return PCI_ERS_RESULT_CAN_RECOVER; case pci_channel_io_frozen: ha->flags.eeh_busy = 1; + /* For ISP82XX complete any pending mailbox cmd */ + if (IS_QLA82XX(ha)) { + ha->flags.fw_hung = 1; + if (ha->flags.mbox_busy) { + ha->flags.mbox_int = 1; + DEBUG2(qla_printk(KERN_ERR, ha, + "Due to pci channel io frozen, doing " + "premature completion of mbx command\n")); + complete(&ha->mbx_intr_comp); + } + } qla2x00_free_irqs(ha); pci_disable_device(pdev); /* Return back all IOs */ @@ -3705,6 +3721,108 @@ qla2xxx_pci_mmio_enabled(struct pci_dev *pdev) return PCI_ERS_RESULT_RECOVERED; } +uint32_t qla82xx_error_recovery(scsi_qla_host_t *ha) +{ + uint32_t rval = QLA_FUNCTION_FAILED; + uint32_t drv_active = 0; + int fn; + struct pci_dev *other_pdev = NULL; + + DEBUG17(qla_printk(KERN_INFO, ha, + "scsi(%ld): In qla82xx_error_recovery\n", ha->host_no)); + + set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); + + if (ha->flags.online) { + /* Abort all outstanding commands, + * so as to be requeued later */ + qla2x00_abort_isp_cleanup(ha); + } + + + fn = PCI_FUNC(ha->pdev->devfn); + while (fn > 0) { + fn--; + DEBUG17(qla_printk(KERN_INFO, ha, + "Finding pci device at function = 0x%x\n", fn)); + other_pdev = + pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus), + ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn), + fn)); + + if (!other_pdev) + continue; + if (other_pdev->is_enabled) { + DEBUG17(qla_printk(KERN_INFO, ha, + "Foudn PCI func availabe and enabled at 0x%x\n", + fn)); + pci_dev_put(other_pdev); + break; + } + pci_dev_put(other_pdev); + } + + if (!fn) { + /* Reset owner */ + DEBUG17(qla_printk(KERN_INFO, ha, + "This devfn is reset owner = 0x%x\n", ha->pdev->devfn)); + qla82xx_idc_lock(ha); + + qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, + QLA82XX_DEV_INITIALIZING); + + qla82xx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION, + QLA82XX_IDC_VERSION); + + drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); + DEBUG17(qla_printk(KERN_INFO, ha, + "drv_active = 0x%x\n", drv_active)); + + qla82xx_idc_unlock(ha); + /* Reset if device is not already reset + * drv_active would be 0 if a reset has already been done + */ + if (drv_active) + rval = qla82xx_start_firmware(ha); + else + rval = QLA_SUCCESS; + qla82xx_idc_lock(ha); + + if (rval != QLA_SUCCESS) { + qla_printk(KERN_INFO, ha, "HW State: FAILED\n"); + qla82xx_clear_drv_active(ha); + qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, + QLA82XX_DEV_FAILED); + } else { + qla_printk(KERN_INFO, ha, "HW State: READY\n"); + qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, + QLA82XX_DEV_READY); + qla82xx_idc_unlock(ha); + ha->flags.fw_hung = 0; + rval = qla82xx_restart_isp(ha); + qla82xx_idc_lock(ha); + qla82xx_set_drv_active(ha); + /* Clear driver state register */ + qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0); + } + qla82xx_idc_unlock(ha); + } else { + DEBUG17(qla_printk(KERN_INFO, ha, + "This devfn is not reset owner = 0x%x\n", ha->pdev->devfn)); + if ((qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE) == + QLA82XX_DEV_READY)) { + ha->flags.fw_hung = 0; + rval = qla82xx_restart_isp(ha); + qla82xx_idc_lock(ha); + qla82xx_set_drv_active(ha); + qla82xx_idc_unlock(ha); + } + } + clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); + return rval; +} + + static pci_ers_result_t qla2xxx_pci_slot_reset(struct pci_dev *pdev) { @@ -3741,15 +3859,22 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev) if (rc) { qla_printk(KERN_WARNING, ha, "Can't re-enable PCI device after reset.\n"); - - return ret; + goto exit_slot_reset; } if (qla2x00_request_irqs(ha)) - return ret; + goto exit_slot_reset; if (ha->isp_ops->pci_config(ha)) - return ret; + goto exit_slot_reset; + + if (IS_QLA82XX(ha)) { + if (qla82xx_error_recovery(ha) == QLA_SUCCESS) { + ret = PCI_ERS_RESULT_RECOVERED; + goto exit_slot_reset; + } else + goto exit_slot_reset; + } while (ha->flags.mbox_busy && retries--) msleep(1000); @@ -3775,6 +3900,7 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev) pci_cleanup_aer_uncorrect_error_status(pdev); +exit_slot_reset: qla_printk(KERN_WARNING, ha, "slot_reset-return:ret=%x\n",ret); return ret;