Commit 14e660e6 authored by Seokmann Ju's avatar Seokmann Ju Committed by James Bottomley

[SCSI] qla2xxx: Add PCI error recovery support.

Additional cleanups and
Signed-off-by: default avatarAndrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent b7cc176c
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/aer.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include <scsi/scsi.h> #include <scsi/scsi.h>
......
...@@ -34,6 +34,7 @@ qla2100_intr_handler(int irq, void *dev_id) ...@@ -34,6 +34,7 @@ qla2100_intr_handler(int irq, void *dev_id)
int status; int status;
unsigned long flags; unsigned long flags;
unsigned long iter; unsigned long iter;
uint16_t hccr;
uint16_t mb[4]; uint16_t mb[4];
ha = (scsi_qla_host_t *) dev_id; ha = (scsi_qla_host_t *) dev_id;
...@@ -48,7 +49,23 @@ qla2100_intr_handler(int irq, void *dev_id) ...@@ -48,7 +49,23 @@ qla2100_intr_handler(int irq, void *dev_id)
spin_lock_irqsave(&ha->hardware_lock, flags); spin_lock_irqsave(&ha->hardware_lock, flags);
for (iter = 50; iter--; ) { for (iter = 50; iter--; ) {
if ((RD_REG_WORD(&reg->istatus) & ISR_RISC_INT) == 0) hccr = RD_REG_WORD(&reg->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(&reg->hccr, HCCR_RESET_RISC);
RD_REG_WORD(&reg->hccr);
ha->isp_ops->fw_dump(ha, 1);
set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
break;
} else if ((RD_REG_WORD(&reg->istatus) & ISR_RISC_INT) == 0)
break; break;
if (RD_REG_WORD(&reg->semaphore) & BIT_0) { if (RD_REG_WORD(&reg->semaphore) & BIT_0) {
...@@ -127,6 +144,9 @@ qla2300_intr_handler(int irq, void *dev_id) ...@@ -127,6 +144,9 @@ qla2300_intr_handler(int irq, void *dev_id)
for (iter = 50; iter--; ) { for (iter = 50; iter--; ) {
stat = RD_REG_DWORD(&reg->u.isp2300.host_status); stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
if (stat & HSR_RISC_PAUSED) { if (stat & HSR_RISC_PAUSED) {
if (pci_channel_offline(ha->pdev))
break;
hccr = RD_REG_WORD(&reg->hccr); hccr = RD_REG_WORD(&reg->hccr);
if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8)) if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8))
qla_printk(KERN_INFO, ha, "Parity error -- " qla_printk(KERN_INFO, ha, "Parity error -- "
...@@ -1499,6 +1519,9 @@ qla24xx_intr_handler(int irq, void *dev_id) ...@@ -1499,6 +1519,9 @@ qla24xx_intr_handler(int irq, void *dev_id)
for (iter = 50; iter--; ) { for (iter = 50; iter--; ) {
stat = RD_REG_DWORD(&reg->host_status); stat = RD_REG_DWORD(&reg->host_status);
if (stat & HSRX_RISC_PAUSED) { if (stat & HSRX_RISC_PAUSED) {
if (pci_channel_offline(ha->pdev))
break;
hccr = RD_REG_DWORD(&reg->hccr); hccr = RD_REG_DWORD(&reg->hccr);
qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, " qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
...@@ -1633,6 +1656,9 @@ qla24xx_msix_default(int irq, void *dev_id) ...@@ -1633,6 +1656,9 @@ qla24xx_msix_default(int irq, void *dev_id)
for (iter = 50; iter--; ) { for (iter = 50; iter--; ) {
stat = RD_REG_DWORD(&reg->host_status); stat = RD_REG_DWORD(&reg->host_status);
if (stat & HSRX_RISC_PAUSED) { if (stat & HSRX_RISC_PAUSED) {
if (pci_channel_offline(ha->pdev))
break;
hccr = RD_REG_DWORD(&reg->hccr); hccr = RD_REG_DWORD(&reg->hccr);
qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, " qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
......
...@@ -385,6 +385,11 @@ qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) ...@@ -385,6 +385,11 @@ qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
srb_t *sp; srb_t *sp;
int rval; int rval;
if (unlikely(pci_channel_offline(ha->pdev))) {
cmd->result = DID_REQUEUE << 16;
goto qc_fail_command;
}
rval = fc_remote_port_chkready(rport); rval = fc_remote_port_chkready(rport);
if (rval) { if (rval) {
cmd->result = rval; cmd->result = rval;
...@@ -447,6 +452,11 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) ...@@ -447,6 +452,11 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
int rval; int rval;
scsi_qla_host_t *pha = to_qla_parent(ha); 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); rval = fc_remote_port_chkready(rport);
if (rval) { if (rval) {
cmd->result = rval; cmd->result = rval;
...@@ -1571,6 +1581,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -1571,6 +1581,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (pci_enable_device(pdev)) if (pci_enable_device(pdev))
goto probe_out; goto probe_out;
if (pci_find_aer_capability(pdev))
if (pci_enable_pcie_error_reporting(pdev))
goto probe_out;
sht = &qla2x00_driver_template; sht = &qla2x00_driver_template;
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 || if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 ||
...@@ -2814,6 +2828,105 @@ qla2x00_release_firmware(void) ...@@ -2814,6 +2828,105 @@ qla2x00_release_firmware(void)
up(&qla_fw_lock); 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(&reg->hccr);
if (stat & HCCR_RISC_PAUSE)
risc_paused = 1;
} else if (IS_QLA23XX(ha)) {
stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
if (stat & HSR_RISC_PAUSED)
risc_paused = 1;
} else if (IS_FWI2_CAPABLE(ha)) {
stat = RD_REG_DWORD(&reg24->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[] = { 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_ISP2100) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2200) }, { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2200) },
...@@ -2839,6 +2952,7 @@ static struct pci_driver qla2xxx_pci_driver = { ...@@ -2839,6 +2952,7 @@ static struct pci_driver qla2xxx_pci_driver = {
.id_table = qla2xxx_pci_tbl, .id_table = qla2xxx_pci_tbl,
.probe = qla2x00_probe_one, .probe = qla2x00_probe_one,
.remove = __devexit_p(qla2x00_remove_one), .remove = __devexit_p(qla2x00_remove_one),
.err_handler = &qla2xxx_err_handler,
}; };
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment