|
@@ -5830,6 +5830,109 @@ static void ipr_initiate_ioa_reset(struct ipr_ioa_cfg *ioa_cfg,
|
|
|
shutdown_type);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * ipr_reset_freeze - Hold off all I/O activity
|
|
|
+ * @ipr_cmd: ipr command struct
|
|
|
+ *
|
|
|
+ * Description: If the PCI slot is frozen, hold off all I/O
|
|
|
+ * activity; then, as soon as the slot is available again,
|
|
|
+ * initiate an adapter reset.
|
|
|
+ */
|
|
|
+static int ipr_reset_freeze(struct ipr_cmnd *ipr_cmd)
|
|
|
+{
|
|
|
+ /* Disallow new interrupts, avoid loop */
|
|
|
+ ipr_cmd->ioa_cfg->allow_interrupts = 0;
|
|
|
+ list_add_tail(&ipr_cmd->queue, &ipr_cmd->ioa_cfg->pending_q);
|
|
|
+ ipr_cmd->done = ipr_reset_ioa_job;
|
|
|
+ return IPR_RC_JOB_RETURN;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * ipr_pci_frozen - Called when slot has experienced a PCI bus error.
|
|
|
+ * @pdev: PCI device struct
|
|
|
+ *
|
|
|
+ * Description: This routine is called to tell us that the PCI bus
|
|
|
+ * is down. Can't do anything here, except put the device driver
|
|
|
+ * into a holding pattern, waiting for the PCI bus to come back.
|
|
|
+ */
|
|
|
+static void ipr_pci_frozen(struct pci_dev *pdev)
|
|
|
+{
|
|
|
+ unsigned long flags = 0;
|
|
|
+ struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
|
|
|
+
|
|
|
+ spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
|
|
|
+ _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_freeze, IPR_SHUTDOWN_NONE);
|
|
|
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * ipr_pci_slot_reset - Called when PCI slot has been reset.
|
|
|
+ * @pdev: PCI device struct
|
|
|
+ *
|
|
|
+ * Description: This routine is called by the pci error recovery
|
|
|
+ * code after the PCI slot has been reset, just before we
|
|
|
+ * should resume normal operations.
|
|
|
+ */
|
|
|
+static pci_ers_result_t ipr_pci_slot_reset(struct pci_dev *pdev)
|
|
|
+{
|
|
|
+ unsigned long flags = 0;
|
|
|
+ struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
|
|
|
+
|
|
|
+ spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
|
|
|
+ _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_restore_cfg_space,
|
|
|
+ IPR_SHUTDOWN_NONE);
|
|
|
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
|
|
|
+ return PCI_ERS_RESULT_RECOVERED;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * ipr_pci_perm_failure - Called when PCI slot is dead for good.
|
|
|
+ * @pdev: PCI device struct
|
|
|
+ *
|
|
|
+ * Description: This routine is called when the PCI bus has
|
|
|
+ * permanently failed.
|
|
|
+ */
|
|
|
+static void ipr_pci_perm_failure(struct pci_dev *pdev)
|
|
|
+{
|
|
|
+ unsigned long flags = 0;
|
|
|
+ struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
|
|
|
+
|
|
|
+ spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
|
|
|
+ if (ioa_cfg->sdt_state == WAIT_FOR_DUMP)
|
|
|
+ ioa_cfg->sdt_state = ABORT_DUMP;
|
|
|
+ ioa_cfg->reset_retries = IPR_NUM_RESET_RELOAD_RETRIES;
|
|
|
+ ioa_cfg->in_ioa_bringdown = 1;
|
|
|
+ ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
|
|
|
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * ipr_pci_error_detected - Called when a PCI error is detected.
|
|
|
+ * @pdev: PCI device struct
|
|
|
+ * @state: PCI channel state
|
|
|
+ *
|
|
|
+ * Description: Called when a PCI error is detected.
|
|
|
+ *
|
|
|
+ * Return value:
|
|
|
+ * PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT
|
|
|
+ */
|
|
|
+static pci_ers_result_t ipr_pci_error_detected(struct pci_dev *pdev,
|
|
|
+ pci_channel_state_t state)
|
|
|
+{
|
|
|
+ switch (state) {
|
|
|
+ case pci_channel_io_frozen:
|
|
|
+ ipr_pci_frozen(pdev);
|
|
|
+ return PCI_ERS_RESULT_NEED_RESET;
|
|
|
+ case pci_channel_io_perm_failure:
|
|
|
+ ipr_pci_perm_failure(pdev);
|
|
|
+ return PCI_ERS_RESULT_DISCONNECT;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return PCI_ERS_RESULT_NEED_RESET;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* ipr_probe_ioa_part2 - Initializes IOAs found in ipr_probe_ioa(..)
|
|
|
* @ioa_cfg: ioa cfg struct
|
|
@@ -6601,12 +6704,18 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = {
|
|
|
};
|
|
|
MODULE_DEVICE_TABLE(pci, ipr_pci_table);
|
|
|
|
|
|
+static struct pci_error_handlers ipr_err_handler = {
|
|
|
+ .error_detected = ipr_pci_error_detected,
|
|
|
+ .slot_reset = ipr_pci_slot_reset,
|
|
|
+};
|
|
|
+
|
|
|
static struct pci_driver ipr_driver = {
|
|
|
.name = IPR_NAME,
|
|
|
.id_table = ipr_pci_table,
|
|
|
.probe = ipr_probe,
|
|
|
.remove = ipr_remove,
|
|
|
.shutdown = ipr_shutdown,
|
|
|
+ .err_handler = &ipr_err_handler,
|
|
|
};
|
|
|
|
|
|
/**
|