int status;
unsigned long flags;
unsigned long iter;
+ uint16_t hccr;
uint16_t mb[4];
ha = (scsi_qla_host_t *) dev_id;
spin_lock_irqsave(&ha->hardware_lock, flags);
for (iter = 50; iter--; ) {
- if ((RD_REG_WORD(®->istatus) & ISR_RISC_INT) == 0)
+ hccr = RD_REG_WORD(®->hccr);
+ if (hccr & HCCR_RISC_PAUSE) {
+ if (pci_channel_offline(ha->pdev))
+ break;
+
+ /*
+ * Issue a "HARD" reset in order for the RISC interrupt
+ * bit to be cleared. Schedule a big hammmer to get
+ * out of the RISC PAUSED state.
+ */
+ WRT_REG_WORD(®->hccr, HCCR_RESET_RISC);
+ RD_REG_WORD(®->hccr);
+
+ ha->isp_ops->fw_dump(ha, 1);
+ set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+ break;
+ } else if ((RD_REG_WORD(®->istatus) & ISR_RISC_INT) == 0)
break;
if (RD_REG_WORD(®->semaphore) & BIT_0) {
for (iter = 50; iter--; ) {
stat = RD_REG_DWORD(®->u.isp2300.host_status);
if (stat & HSR_RISC_PAUSED) {
+ if (pci_channel_offline(ha->pdev))
+ break;
+
hccr = RD_REG_WORD(®->hccr);
if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8))
qla_printk(KERN_INFO, ha, "Parity error -- "
for (iter = 50; iter--; ) {
stat = RD_REG_DWORD(®->host_status);
if (stat & HSRX_RISC_PAUSED) {
+ if (pci_channel_offline(ha->pdev))
+ break;
+
hccr = RD_REG_DWORD(®->hccr);
qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
for (iter = 50; iter--; ) {
stat = RD_REG_DWORD(®->host_status);
if (stat & HSRX_RISC_PAUSED) {
+ if (pci_channel_offline(ha->pdev))
+ break;
+
hccr = RD_REG_DWORD(®->hccr);
qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
srb_t *sp;
int rval;
+ if (unlikely(pci_channel_offline(ha->pdev))) {
+ cmd->result = DID_REQUEUE << 16;
+ goto qc_fail_command;
+ }
+
rval = fc_remote_port_chkready(rport);
if (rval) {
cmd->result = rval;
int rval;
scsi_qla_host_t *pha = to_qla_parent(ha);
+ if (unlikely(pci_channel_offline(ha->pdev))) {
+ cmd->result = DID_REQUEUE << 16;
+ goto qc24_fail_command;
+ }
+
rval = fc_remote_port_chkready(rport);
if (rval) {
cmd->result = rval;
if (pci_enable_device(pdev))
goto probe_out;
+ if (pci_find_aer_capability(pdev))
+ if (pci_enable_pcie_error_reporting(pdev))
+ goto probe_out;
+
sht = &qla2x00_driver_template;
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 ||
up(&qla_fw_lock);
}
+static pci_ers_result_t
+qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
+{
+ switch (state) {
+ case pci_channel_io_normal:
+ return PCI_ERS_RESULT_CAN_RECOVER;
+ case pci_channel_io_frozen:
+ pci_disable_device(pdev);
+ return PCI_ERS_RESULT_NEED_RESET;
+ case pci_channel_io_perm_failure:
+ qla2x00_remove_one(pdev);
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t
+qla2xxx_pci_mmio_enabled(struct pci_dev *pdev)
+{
+ int risc_paused = 0;
+ uint32_t stat;
+ unsigned long flags;
+ scsi_qla_host_t *ha = pci_get_drvdata(pdev);
+ struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+ struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ if (IS_QLA2100(ha) || IS_QLA2200(ha)){
+ stat = RD_REG_DWORD(®->hccr);
+ if (stat & HCCR_RISC_PAUSE)
+ risc_paused = 1;
+ } else if (IS_QLA23XX(ha)) {
+ stat = RD_REG_DWORD(®->u.isp2300.host_status);
+ if (stat & HSR_RISC_PAUSED)
+ risc_paused = 1;
+ } else if (IS_FWI2_CAPABLE(ha)) {
+ stat = RD_REG_DWORD(®24->host_status);
+ if (stat & HSRX_RISC_PAUSED)
+ risc_paused = 1;
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ if (risc_paused) {
+ qla_printk(KERN_INFO, ha, "RISC paused -- mmio_enabled, "
+ "Dumping firmware!\n");
+ ha->isp_ops->fw_dump(ha, 0);
+
+ return PCI_ERS_RESULT_NEED_RESET;
+ } else
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+static pci_ers_result_t
+qla2xxx_pci_slot_reset(struct pci_dev *pdev)
+{
+ pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT;
+ scsi_qla_host_t *ha = pci_get_drvdata(pdev);
+
+ if (pci_enable_device(pdev)) {
+ qla_printk(KERN_WARNING, ha,
+ "Can't re-enable PCI device after reset.\n");
+
+ return ret;
+ }
+ pci_set_master(pdev);
+
+ if (ha->isp_ops->pci_config(ha))
+ return ret;
+
+ set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+ if (qla2x00_abort_isp(ha)== QLA_SUCCESS)
+ ret = PCI_ERS_RESULT_RECOVERED;
+ clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+
+ return ret;
+}
+
+static void
+qla2xxx_pci_resume(struct pci_dev *pdev)
+{
+ scsi_qla_host_t *ha = pci_get_drvdata(pdev);
+ int ret;
+
+ ret = qla2x00_wait_for_hba_online(ha);
+ if (ret != QLA_SUCCESS) {
+ qla_printk(KERN_ERR, ha,
+ "the device failed to resume I/O "
+ "from slot/link_reset");
+ }
+ pci_cleanup_aer_uncorrect_error_status(pdev);
+}
+
+static struct pci_error_handlers qla2xxx_err_handler = {
+ .error_detected = qla2xxx_pci_error_detected,
+ .mmio_enabled = qla2xxx_pci_mmio_enabled,
+ .slot_reset = qla2xxx_pci_slot_reset,
+ .resume = qla2xxx_pci_resume,
+};
+
static struct pci_device_id qla2xxx_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2100) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2200) },
.id_table = qla2xxx_pci_tbl,
.probe = qla2x00_probe_one,
.remove = __devexit_p(qla2x00_remove_one),
+ .err_handler = &qla2xxx_err_handler,
};
/**