|
@@ -475,11 +475,11 @@ qla2xxx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
|
|
|
srb_t *sp;
|
|
|
int rval;
|
|
|
|
|
|
- if (unlikely(pci_channel_offline(ha->pdev))) {
|
|
|
- if (ha->pdev->error_state == pci_channel_io_frozen)
|
|
|
- cmd->result = DID_REQUEUE << 16;
|
|
|
- else
|
|
|
+ if (ha->flags.eeh_busy) {
|
|
|
+ if (ha->flags.pci_channel_io_perm_failure)
|
|
|
cmd->result = DID_NO_CONNECT << 16;
|
|
|
+ else
|
|
|
+ cmd->result = DID_REQUEUE << 16;
|
|
|
goto qc24_fail_command;
|
|
|
}
|
|
|
|
|
@@ -552,8 +552,15 @@ qla2x00_eh_wait_on_command(struct scsi_cmnd *cmd)
|
|
|
#define ABORT_POLLING_PERIOD 1000
|
|
|
#define ABORT_WAIT_ITER ((10 * 1000) / (ABORT_POLLING_PERIOD))
|
|
|
unsigned long wait_iter = ABORT_WAIT_ITER;
|
|
|
+ scsi_qla_host_t *vha = shost_priv(cmd->device->host);
|
|
|
+ struct qla_hw_data *ha = vha->hw;
|
|
|
int ret = QLA_SUCCESS;
|
|
|
|
|
|
+ if (unlikely(pci_channel_offline(ha->pdev)) || ha->flags.eeh_busy) {
|
|
|
+ DEBUG17(qla_printk(KERN_WARNING, ha, "return:eh_wait\n"));
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
while (CMD_SP(cmd) && wait_iter--) {
|
|
|
msleep(ABORT_POLLING_PERIOD);
|
|
|
}
|
|
@@ -1810,6 +1817,13 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
|
|
|
|
|
/* Set ISP-type information. */
|
|
|
qla2x00_set_isp_flags(ha);
|
|
|
+
|
|
|
+ /* Set EEH reset type to fundamental if required by hba */
|
|
|
+ if ( IS_QLA24XX(ha) || IS_QLA25XX(ha) || IS_QLA81XX(ha)) {
|
|
|
+ pdev->needs_freset = 1;
|
|
|
+ pci_save_state(pdev);
|
|
|
+ }
|
|
|
+
|
|
|
/* Configure PCI I/O space */
|
|
|
ret = qla2x00_iospace_config(ha);
|
|
|
if (ret)
|
|
@@ -2174,6 +2188,24 @@ qla2x00_free_device(scsi_qla_host_t *vha)
|
|
|
{
|
|
|
struct qla_hw_data *ha = vha->hw;
|
|
|
|
|
|
+ qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16);
|
|
|
+
|
|
|
+ /* Disable timer */
|
|
|
+ if (vha->timer_active)
|
|
|
+ qla2x00_stop_timer(vha);
|
|
|
+
|
|
|
+ /* Kill the kernel thread for this host */
|
|
|
+ if (ha->dpc_thread) {
|
|
|
+ struct task_struct *t = ha->dpc_thread;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * qla2xxx_wake_dpc checks for ->dpc_thread
|
|
|
+ * so we need to zero it out.
|
|
|
+ */
|
|
|
+ ha->dpc_thread = NULL;
|
|
|
+ kthread_stop(t);
|
|
|
+ }
|
|
|
+
|
|
|
qla25xx_delete_queues(vha);
|
|
|
|
|
|
if (ha->flags.fce_enabled)
|
|
@@ -2185,6 +2217,8 @@ qla2x00_free_device(scsi_qla_host_t *vha)
|
|
|
/* Stop currently executing firmware. */
|
|
|
qla2x00_try_to_stop_firmware(vha);
|
|
|
|
|
|
+ vha->flags.online = 0;
|
|
|
+
|
|
|
/* turn-off interrupts on the card */
|
|
|
if (ha->interrupts_on)
|
|
|
ha->isp_ops->disable_intrs(ha);
|
|
@@ -2859,6 +2893,13 @@ qla2x00_do_dpc(void *data)
|
|
|
if (!base_vha->flags.init_done)
|
|
|
continue;
|
|
|
|
|
|
+ if (ha->flags.eeh_busy) {
|
|
|
+ DEBUG17(qla_printk(KERN_WARNING, ha,
|
|
|
+ "qla2x00_do_dpc: dpc_flags: %lx\n",
|
|
|
+ base_vha->dpc_flags));
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
DEBUG3(printk("scsi(%ld): DPC handler\n", base_vha->host_no));
|
|
|
|
|
|
ha->dpc_active = 1;
|
|
@@ -3049,8 +3090,13 @@ qla2x00_timer(scsi_qla_host_t *vha)
|
|
|
int index;
|
|
|
srb_t *sp;
|
|
|
int t;
|
|
|
+ uint16_t w;
|
|
|
struct qla_hw_data *ha = vha->hw;
|
|
|
struct req_que *req;
|
|
|
+
|
|
|
+ /* Hardware read to raise pending EEH errors during mailbox waits. */
|
|
|
+ if (!pci_channel_offline(ha->pdev))
|
|
|
+ pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w);
|
|
|
/*
|
|
|
* Ports - Port down timer.
|
|
|
*
|
|
@@ -3252,16 +3298,23 @@ qla2x00_release_firmware(void)
|
|
|
static pci_ers_result_t
|
|
|
qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
|
|
|
{
|
|
|
- scsi_qla_host_t *base_vha = pci_get_drvdata(pdev);
|
|
|
+ scsi_qla_host_t *vha = pci_get_drvdata(pdev);
|
|
|
+ struct qla_hw_data *ha = vha->hw;
|
|
|
+
|
|
|
+ DEBUG2(qla_printk(KERN_WARNING, ha, "error_detected:state %x\n",
|
|
|
+ state));
|
|
|
|
|
|
switch (state) {
|
|
|
case pci_channel_io_normal:
|
|
|
+ ha->flags.eeh_busy = 0;
|
|
|
return PCI_ERS_RESULT_CAN_RECOVER;
|
|
|
case pci_channel_io_frozen:
|
|
|
+ ha->flags.eeh_busy = 1;
|
|
|
pci_disable_device(pdev);
|
|
|
return PCI_ERS_RESULT_NEED_RESET;
|
|
|
case pci_channel_io_perm_failure:
|
|
|
- qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16);
|
|
|
+ ha->flags.pci_channel_io_perm_failure = 1;
|
|
|
+ qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16);
|
|
|
return PCI_ERS_RESULT_DISCONNECT;
|
|
|
}
|
|
|
return PCI_ERS_RESULT_NEED_RESET;
|
|
@@ -3312,6 +3365,8 @@ qla2xxx_pci_slot_reset(struct pci_dev *pdev)
|
|
|
struct qla_hw_data *ha = base_vha->hw;
|
|
|
int rc;
|
|
|
|
|
|
+ DEBUG17(qla_printk(KERN_WARNING, ha, "slot_reset\n"));
|
|
|
+
|
|
|
if (ha->mem_only)
|
|
|
rc = pci_enable_device_mem(pdev);
|
|
|
else
|
|
@@ -3320,19 +3375,33 @@ 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;
|
|
|
}
|
|
|
- pci_set_master(pdev);
|
|
|
|
|
|
if (ha->isp_ops->pci_config(base_vha))
|
|
|
return ret;
|
|
|
|
|
|
+#ifdef QL_DEBUG_LEVEL_17
|
|
|
+ {
|
|
|
+ uint8_t b;
|
|
|
+ uint32_t i;
|
|
|
+
|
|
|
+ printk("slot_reset_1: ");
|
|
|
+ for (i = 0; i < 256; i++) {
|
|
|
+ pci_read_config_byte(ha->pdev, i, &b);
|
|
|
+ printk("%s%02x", (i%16) ? " " : "\n", b);
|
|
|
+ }
|
|
|
+ printk("\n");
|
|
|
+ }
|
|
|
+#endif
|
|
|
set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
|
|
|
if (qla2x00_abort_isp(base_vha) == QLA_SUCCESS)
|
|
|
ret = PCI_ERS_RESULT_RECOVERED;
|
|
|
clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
|
|
|
|
|
|
+ DEBUG17(qla_printk(KERN_WARNING, ha,
|
|
|
+ "slot_reset-return:ret=%x\n", ret));
|
|
|
+
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -3343,12 +3412,17 @@ qla2xxx_pci_resume(struct pci_dev *pdev)
|
|
|
struct qla_hw_data *ha = base_vha->hw;
|
|
|
int ret;
|
|
|
|
|
|
+ DEBUG17(qla_printk(KERN_WARNING, ha, "pci_resume\n"));
|
|
|
+
|
|
|
ret = qla2x00_wait_for_hba_online(base_vha);
|
|
|
if (ret != QLA_SUCCESS) {
|
|
|
qla_printk(KERN_ERR, ha,
|
|
|
"the device failed to resume I/O "
|
|
|
"from slot/link_reset");
|
|
|
}
|
|
|
+
|
|
|
+ ha->flags.eeh_busy = 0;
|
|
|
+
|
|
|
pci_cleanup_aer_uncorrect_error_status(pdev);
|
|
|
}
|
|
|
|