|
@@ -385,6 +385,11 @@ qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
|
|
|
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;
|
|
@@ -447,6 +452,11 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
|
|
|
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;
|
|
@@ -1571,6 +1581,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
|
|
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 ||
|
|
@@ -2814,6 +2828,105 @@ qla2x00_release_firmware(void)
|
|
|
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) },
|
|
@@ -2839,6 +2952,7 @@ static struct pci_driver qla2xxx_pci_driver = {
|
|
|
.id_table = qla2xxx_pci_tbl,
|
|
|
.probe = qla2x00_probe_one,
|
|
|
.remove = __devexit_p(qla2x00_remove_one),
|
|
|
+ .err_handler = &qla2xxx_err_handler,
|
|
|
};
|
|
|
|
|
|
/**
|