|
@@ -2274,8 +2274,7 @@ lpfc_enable_msix(struct lpfc_hba *phba)
|
|
ARRAY_SIZE(phba->msix_entries));
|
|
ARRAY_SIZE(phba->msix_entries));
|
|
if (rc) {
|
|
if (rc) {
|
|
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
|
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
|
- "0420 Enable MSI-X failed (%d), continuing "
|
|
|
|
- "with MSI\n", rc);
|
|
|
|
|
|
+ "0420 PCI enable MSI-X failed (%d)\n", rc);
|
|
goto msi_fail_out;
|
|
goto msi_fail_out;
|
|
} else
|
|
} else
|
|
for (i = 0; i < LPFC_MSIX_VECTORS; i++)
|
|
for (i = 0; i < LPFC_MSIX_VECTORS; i++)
|
|
@@ -2292,9 +2291,9 @@ lpfc_enable_msix(struct lpfc_hba *phba)
|
|
rc = request_irq(phba->msix_entries[0].vector, &lpfc_sp_intr_handler,
|
|
rc = request_irq(phba->msix_entries[0].vector, &lpfc_sp_intr_handler,
|
|
IRQF_SHARED, LPFC_SP_DRIVER_HANDLER_NAME, phba);
|
|
IRQF_SHARED, LPFC_SP_DRIVER_HANDLER_NAME, phba);
|
|
if (rc) {
|
|
if (rc) {
|
|
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
|
|
|
|
|
+ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
|
|
"0421 MSI-X slow-path request_irq failed "
|
|
"0421 MSI-X slow-path request_irq failed "
|
|
- "(%d), continuing with MSI\n", rc);
|
|
|
|
|
|
+ "(%d)\n", rc);
|
|
goto msi_fail_out;
|
|
goto msi_fail_out;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2303,9 +2302,9 @@ lpfc_enable_msix(struct lpfc_hba *phba)
|
|
IRQF_SHARED, LPFC_FP_DRIVER_HANDLER_NAME, phba);
|
|
IRQF_SHARED, LPFC_FP_DRIVER_HANDLER_NAME, phba);
|
|
|
|
|
|
if (rc) {
|
|
if (rc) {
|
|
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
|
|
|
|
|
+ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
|
|
"0429 MSI-X fast-path request_irq failed "
|
|
"0429 MSI-X fast-path request_irq failed "
|
|
- "(%d), continuing with MSI\n", rc);
|
|
|
|
|
|
+ "(%d)\n", rc);
|
|
goto irq_fail_out;
|
|
goto irq_fail_out;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2326,7 +2325,7 @@ lpfc_enable_msix(struct lpfc_hba *phba)
|
|
goto mbx_fail_out;
|
|
goto mbx_fail_out;
|
|
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
|
|
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
|
|
if (rc != MBX_SUCCESS) {
|
|
if (rc != MBX_SUCCESS) {
|
|
- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
|
|
|
|
|
|
+ lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
|
|
"0351 Config MSI mailbox command failed, "
|
|
"0351 Config MSI mailbox command failed, "
|
|
"mbxCmd x%x, mbxStatus x%x\n",
|
|
"mbxCmd x%x, mbxStatus x%x\n",
|
|
pmb->mb.mbxCommand, pmb->mb.mbxStatus);
|
|
pmb->mb.mbxCommand, pmb->mb.mbxStatus);
|
|
@@ -2374,6 +2373,195 @@ lpfc_disable_msix(struct lpfc_hba *phba)
|
|
pci_disable_msix(phba->pcidev);
|
|
pci_disable_msix(phba->pcidev);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * lpfc_enable_msi: Enable MSI interrupt mode.
|
|
|
|
+ * @phba: pointer to lpfc hba data structure.
|
|
|
|
+ *
|
|
|
|
+ * This routine is invoked to enable the MSI interrupt mode. The kernel
|
|
|
|
+ * function pci_enable_msi() is called to enable the MSI vector. The
|
|
|
|
+ * device driver is responsible for calling the request_irq() to register
|
|
|
|
+ * MSI vector with a interrupt the handler, which is done in this function.
|
|
|
|
+ *
|
|
|
|
+ * Return codes
|
|
|
|
+ * 0 - sucessful
|
|
|
|
+ * other values - error
|
|
|
|
+ */
|
|
|
|
+static int
|
|
|
|
+lpfc_enable_msi(struct lpfc_hba *phba)
|
|
|
|
+{
|
|
|
|
+ int rc;
|
|
|
|
+
|
|
|
|
+ rc = pci_enable_msi(phba->pcidev);
|
|
|
|
+ if (!rc)
|
|
|
|
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
|
|
|
+ "0462 PCI enable MSI mode success.\n");
|
|
|
|
+ else {
|
|
|
|
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
|
|
|
+ "0471 PCI enable MSI mode failed (%d)\n", rc);
|
|
|
|
+ return rc;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ rc = request_irq(phba->pcidev->irq, lpfc_intr_handler,
|
|
|
|
+ IRQF_SHARED, LPFC_DRIVER_NAME, phba);
|
|
|
|
+ if (rc) {
|
|
|
|
+ pci_disable_msi(phba->pcidev);
|
|
|
|
+ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
|
|
|
|
+ "0478 MSI request_irq failed (%d)\n", rc);
|
|
|
|
+ }
|
|
|
|
+ return rc;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * lpfc_disable_msi: Disable MSI interrupt mode.
|
|
|
|
+ * @phba: pointer to lpfc hba data structure.
|
|
|
|
+ *
|
|
|
|
+ * This routine is invoked to disable the MSI interrupt mode. The driver
|
|
|
|
+ * calls free_irq() on MSI vector it has done request_irq() on before
|
|
|
|
+ * calling pci_disable_msi(). Failure to do so results in a BUG_ON() and
|
|
|
|
+ * a device will be left with MSI enabled and leaks its vector.
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+static void
|
|
|
|
+lpfc_disable_msi(struct lpfc_hba *phba)
|
|
|
|
+{
|
|
|
|
+ free_irq(phba->pcidev->irq, phba);
|
|
|
|
+ pci_disable_msi(phba->pcidev);
|
|
|
|
+ return;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * lpfc_log_intr_mode: Log the active interrupt mode
|
|
|
|
+ * @phba: pointer to lpfc hba data structure.
|
|
|
|
+ * @intr_mode: active interrupt mode adopted.
|
|
|
|
+ *
|
|
|
|
+ * This routine it invoked to log the currently used active interrupt mode
|
|
|
|
+ * to the device.
|
|
|
|
+ */
|
|
|
|
+static void
|
|
|
|
+lpfc_log_intr_mode(struct lpfc_hba *phba, uint32_t intr_mode)
|
|
|
|
+{
|
|
|
|
+ switch (intr_mode) {
|
|
|
|
+ case 0:
|
|
|
|
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
|
|
|
+ "0470 Enable INTx interrupt mode.\n");
|
|
|
|
+ break;
|
|
|
|
+ case 1:
|
|
|
|
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
|
|
|
+ "0481 Enabled MSI interrupt mode.\n");
|
|
|
|
+ break;
|
|
|
|
+ case 2:
|
|
|
|
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
|
|
|
+ "0480 Enabled MSI-X interrupt mode.\n");
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
|
|
|
+ "0482 Illegal interrupt mode.\n");
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ return;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void
|
|
|
|
+lpfc_stop_port(struct lpfc_hba *phba)
|
|
|
|
+{
|
|
|
|
+ /* Clear all interrupt enable conditions */
|
|
|
|
+ writel(0, phba->HCregaddr);
|
|
|
|
+ readl(phba->HCregaddr); /* flush */
|
|
|
|
+ /* Clear all pending interrupts */
|
|
|
|
+ writel(0xffffffff, phba->HAregaddr);
|
|
|
|
+ readl(phba->HAregaddr); /* flush */
|
|
|
|
+
|
|
|
|
+ /* Reset some HBA SLI setup states */
|
|
|
|
+ lpfc_stop_phba_timers(phba);
|
|
|
|
+ phba->pport->work_port_events = 0;
|
|
|
|
+
|
|
|
|
+ return;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * lpfc_enable_intr: Enable device interrupt.
|
|
|
|
+ * @phba: pointer to lpfc hba data structure.
|
|
|
|
+ *
|
|
|
|
+ * This routine is invoked to enable device interrupt and associate driver's
|
|
|
|
+ * interrupt handler(s) to interrupt vector(s). Depends on the interrupt
|
|
|
|
+ * mode configured to the driver, the driver will try to fallback from the
|
|
|
|
+ * configured interrupt mode to an interrupt mode which is supported by the
|
|
|
|
+ * platform, kernel, and device in the order of: MSI-X -> MSI -> IRQ.
|
|
|
|
+ *
|
|
|
|
+ * Return codes
|
|
|
|
+ * 0 - sucessful
|
|
|
|
+ * other values - error
|
|
|
|
+ **/
|
|
|
|
+static uint32_t
|
|
|
|
+lpfc_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode)
|
|
|
|
+{
|
|
|
|
+ uint32_t intr_mode = LPFC_INTR_ERROR;
|
|
|
|
+ int retval;
|
|
|
|
+
|
|
|
|
+ if (cfg_mode == 2) {
|
|
|
|
+ /* Need to issue conf_port mbox cmd before conf_msi mbox cmd */
|
|
|
|
+ retval = lpfc_sli_config_port(phba, 3);
|
|
|
|
+ if (!retval) {
|
|
|
|
+ /* Now, try to enable MSI-X interrupt mode */
|
|
|
|
+ retval = lpfc_enable_msix(phba);
|
|
|
|
+ if (!retval) {
|
|
|
|
+ /* Indicate initialization to MSI-X mode */
|
|
|
|
+ phba->intr_type = MSIX;
|
|
|
|
+ intr_mode = 2;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Fallback to MSI if MSI-X initialization failed */
|
|
|
|
+ if (cfg_mode >= 1 && phba->intr_type == NONE) {
|
|
|
|
+ retval = lpfc_enable_msi(phba);
|
|
|
|
+ if (!retval) {
|
|
|
|
+ /* Indicate initialization to MSI mode */
|
|
|
|
+ phba->intr_type = MSI;
|
|
|
|
+ intr_mode = 1;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Fallback to INTx if both MSI-X/MSI initalization failed */
|
|
|
|
+ if (phba->intr_type == NONE) {
|
|
|
|
+ retval = request_irq(phba->pcidev->irq, lpfc_intr_handler,
|
|
|
|
+ IRQF_SHARED, LPFC_DRIVER_NAME, phba);
|
|
|
|
+ if (!retval) {
|
|
|
|
+ /* Indicate initialization to INTx mode */
|
|
|
|
+ phba->intr_type = INTx;
|
|
|
|
+ intr_mode = 0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return intr_mode;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * lpfc_disable_intr: Disable device interrupt.
|
|
|
|
+ * @phba: pointer to lpfc hba data structure.
|
|
|
|
+ *
|
|
|
|
+ * This routine is invoked to disable device interrupt and disassociate the
|
|
|
|
+ * driver's interrupt handler(s) from interrupt vector(s). Depending on the
|
|
|
|
+ * interrupt mode, the driver will release the interrupt vector(s) for the
|
|
|
|
+ * message signaled interrupt.
|
|
|
|
+ **/
|
|
|
|
+static void
|
|
|
|
+lpfc_disable_intr(struct lpfc_hba *phba)
|
|
|
|
+{
|
|
|
|
+ /* Disable the currently initialized interrupt mode */
|
|
|
|
+ if (phba->intr_type == MSIX)
|
|
|
|
+ lpfc_disable_msix(phba);
|
|
|
|
+ else if (phba->intr_type == MSI)
|
|
|
|
+ lpfc_disable_msi(phba);
|
|
|
|
+ else if (phba->intr_type == INTx)
|
|
|
|
+ free_irq(phba->pcidev->irq, phba);
|
|
|
|
+
|
|
|
|
+ /* Reset interrupt management states */
|
|
|
|
+ phba->intr_type = NONE;
|
|
|
|
+ phba->sli.slistat.sli_intr = 0;
|
|
|
|
+
|
|
|
|
+ return;
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* lpfc_pci_probe_one: lpfc PCI probe func to register device to PCI subsystem.
|
|
* lpfc_pci_probe_one: lpfc PCI probe func to register device to PCI subsystem.
|
|
* @pdev: pointer to PCI device
|
|
* @pdev: pointer to PCI device
|
|
@@ -2404,6 +2592,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
|
|
int error = -ENODEV, retval;
|
|
int error = -ENODEV, retval;
|
|
int i, hbq_count;
|
|
int i, hbq_count;
|
|
uint16_t iotag;
|
|
uint16_t iotag;
|
|
|
|
+ uint32_t cfg_mode, intr_mode;
|
|
int bars = pci_select_bars(pdev, IORESOURCE_MEM);
|
|
int bars = pci_select_bars(pdev, IORESOURCE_MEM);
|
|
struct lpfc_adapter_event_header adapter_event;
|
|
struct lpfc_adapter_event_header adapter_event;
|
|
|
|
|
|
@@ -2606,7 +2795,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
|
|
lpfc_debugfs_initialize(vport);
|
|
lpfc_debugfs_initialize(vport);
|
|
|
|
|
|
pci_set_drvdata(pdev, shost);
|
|
pci_set_drvdata(pdev, shost);
|
|
- phba->intr_type = NONE;
|
|
|
|
|
|
|
|
phba->MBslimaddr = phba->slim_memmap_p;
|
|
phba->MBslimaddr = phba->slim_memmap_p;
|
|
phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET;
|
|
phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET;
|
|
@@ -2614,63 +2802,58 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
|
|
phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
|
|
phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
|
|
phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
|
|
phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
|
|
|
|
|
|
- /* Configure and enable interrupt */
|
|
|
|
- if (phba->cfg_use_msi == 2) {
|
|
|
|
- /* Need to issue conf_port mbox cmd before conf_msi mbox cmd */
|
|
|
|
- error = lpfc_sli_config_port(phba, 3);
|
|
|
|
- if (error)
|
|
|
|
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
|
|
|
- "0427 Firmware not capable of SLI 3 mode.\n");
|
|
|
|
- else {
|
|
|
|
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
|
|
|
- "0426 Firmware capable of SLI 3 mode.\n");
|
|
|
|
- /* Now, try to enable MSI-X interrupt mode */
|
|
|
|
- error = lpfc_enable_msix(phba);
|
|
|
|
- if (!error) {
|
|
|
|
- phba->intr_type = MSIX;
|
|
|
|
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
|
|
|
- "0430 enable MSI-X mode.\n");
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* Fallback to MSI if MSI-X initialization failed */
|
|
|
|
- if (phba->cfg_use_msi >= 1 && phba->intr_type == NONE) {
|
|
|
|
- retval = pci_enable_msi(phba->pcidev);
|
|
|
|
- if (!retval) {
|
|
|
|
- phba->intr_type = MSI;
|
|
|
|
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
|
|
|
- "0473 enable MSI mode.\n");
|
|
|
|
- } else
|
|
|
|
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
|
|
|
- "0452 enable IRQ mode.\n");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* MSI-X is the only case the doesn't need to call request_irq */
|
|
|
|
- if (phba->intr_type != MSIX) {
|
|
|
|
- retval = request_irq(phba->pcidev->irq, lpfc_intr_handler,
|
|
|
|
- IRQF_SHARED, LPFC_DRIVER_NAME, phba);
|
|
|
|
- if (retval) {
|
|
|
|
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0451 Enable "
|
|
|
|
- "interrupt handler failed\n");
|
|
|
|
- error = retval;
|
|
|
|
- goto out_disable_msi;
|
|
|
|
- } else if (phba->intr_type != MSI)
|
|
|
|
- phba->intr_type = INTx;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+ /* Configure sysfs attributes */
|
|
if (lpfc_alloc_sysfs_attr(vport)) {
|
|
if (lpfc_alloc_sysfs_attr(vport)) {
|
|
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
|
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
|
"1476 Failed to allocate sysfs attr\n");
|
|
"1476 Failed to allocate sysfs attr\n");
|
|
error = -ENOMEM;
|
|
error = -ENOMEM;
|
|
- goto out_free_irq;
|
|
|
|
|
|
+ goto out_destroy_port;
|
|
}
|
|
}
|
|
|
|
|
|
- if (lpfc_sli_hba_setup(phba)) {
|
|
|
|
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
|
|
|
- "1477 Failed to set up hba\n");
|
|
|
|
- error = -ENODEV;
|
|
|
|
- goto out_remove_device;
|
|
|
|
|
|
+ cfg_mode = phba->cfg_use_msi;
|
|
|
|
+ while (true) {
|
|
|
|
+ /* Configure and enable interrupt */
|
|
|
|
+ intr_mode = lpfc_enable_intr(phba, cfg_mode);
|
|
|
|
+ if (intr_mode == LPFC_INTR_ERROR) {
|
|
|
|
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
|
|
|
+ "0426 Failed to enable interrupt.\n");
|
|
|
|
+ goto out_free_sysfs_attr;
|
|
|
|
+ }
|
|
|
|
+ /* HBA SLI setup */
|
|
|
|
+ if (lpfc_sli_hba_setup(phba)) {
|
|
|
|
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
|
|
|
+ "1477 Failed to set up hba\n");
|
|
|
|
+ error = -ENODEV;
|
|
|
|
+ goto out_remove_device;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Wait 50ms for the interrupts of previous mailbox commands */
|
|
|
|
+ msleep(50);
|
|
|
|
+ /* Check active interrupts received */
|
|
|
|
+ if (phba->sli.slistat.sli_intr > LPFC_MSIX_VECTORS) {
|
|
|
|
+ /* Log the current active interrupt mode */
|
|
|
|
+ phba->intr_mode = intr_mode;
|
|
|
|
+ lpfc_log_intr_mode(phba, intr_mode);
|
|
|
|
+ break;
|
|
|
|
+ } else {
|
|
|
|
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
|
|
|
+ "0451 Configure interrupt mode (%d) "
|
|
|
|
+ "failed active interrupt test.\n",
|
|
|
|
+ intr_mode);
|
|
|
|
+ if (intr_mode == 0) {
|
|
|
|
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
|
|
|
+ "0479 Failed to enable "
|
|
|
|
+ "interrupt.\n");
|
|
|
|
+ error = -ENODEV;
|
|
|
|
+ goto out_remove_device;
|
|
|
|
+ }
|
|
|
|
+ /* Stop HBA SLI setups */
|
|
|
|
+ lpfc_stop_port(phba);
|
|
|
|
+ /* Disable the current interrupt mode */
|
|
|
|
+ lpfc_disable_intr(phba);
|
|
|
|
+ /* Try next level of interrupt mode */
|
|
|
|
+ cfg_mode = --intr_mode;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -2700,22 +2883,15 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
out_remove_device:
|
|
out_remove_device:
|
|
- lpfc_free_sysfs_attr(vport);
|
|
|
|
spin_lock_irq(shost->host_lock);
|
|
spin_lock_irq(shost->host_lock);
|
|
vport->load_flag |= FC_UNLOADING;
|
|
vport->load_flag |= FC_UNLOADING;
|
|
spin_unlock_irq(shost->host_lock);
|
|
spin_unlock_irq(shost->host_lock);
|
|
-out_free_irq:
|
|
|
|
lpfc_stop_phba_timers(phba);
|
|
lpfc_stop_phba_timers(phba);
|
|
phba->pport->work_port_events = 0;
|
|
phba->pport->work_port_events = 0;
|
|
-
|
|
|
|
- if (phba->intr_type == MSIX)
|
|
|
|
- lpfc_disable_msix(phba);
|
|
|
|
- else
|
|
|
|
- free_irq(phba->pcidev->irq, phba);
|
|
|
|
-
|
|
|
|
-out_disable_msi:
|
|
|
|
- if (phba->intr_type == MSI)
|
|
|
|
- pci_disable_msi(phba->pcidev);
|
|
|
|
|
|
+ lpfc_disable_intr(phba);
|
|
|
|
+out_free_sysfs_attr:
|
|
|
|
+ lpfc_free_sysfs_attr(vport);
|
|
|
|
+out_destroy_port:
|
|
destroy_port(vport);
|
|
destroy_port(vport);
|
|
out_kthread_stop:
|
|
out_kthread_stop:
|
|
kthread_stop(phba->worker_thread);
|
|
kthread_stop(phba->worker_thread);
|
|
@@ -2804,13 +2980,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
|
|
|
|
|
|
lpfc_debugfs_terminate(vport);
|
|
lpfc_debugfs_terminate(vport);
|
|
|
|
|
|
- if (phba->intr_type == MSIX)
|
|
|
|
- lpfc_disable_msix(phba);
|
|
|
|
- else {
|
|
|
|
- free_irq(phba->pcidev->irq, phba);
|
|
|
|
- if (phba->intr_type == MSI)
|
|
|
|
- pci_disable_msi(phba->pcidev);
|
|
|
|
- }
|
|
|
|
|
|
+ /* Disable interrupt */
|
|
|
|
+ lpfc_disable_intr(phba);
|
|
|
|
|
|
pci_set_drvdata(pdev, NULL);
|
|
pci_set_drvdata(pdev, NULL);
|
|
scsi_host_put(shost);
|
|
scsi_host_put(shost);
|
|
@@ -2908,6 +3079,7 @@ lpfc_pci_resume_one(struct pci_dev *pdev)
|
|
{
|
|
{
|
|
struct Scsi_Host *shost = pci_get_drvdata(pdev);
|
|
struct Scsi_Host *shost = pci_get_drvdata(pdev);
|
|
struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
|
|
struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
|
|
|
|
+ uint32_t intr_mode;
|
|
int error;
|
|
int error;
|
|
|
|
|
|
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
|
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
|
@@ -2930,19 +3102,22 @@ lpfc_pci_resume_one(struct pci_dev *pdev)
|
|
return error;
|
|
return error;
|
|
}
|
|
}
|
|
|
|
|
|
- /* Enable interrupt from device */
|
|
|
|
- error = lpfc_enable_intr(phba);
|
|
|
|
- if (error) {
|
|
|
|
|
|
+ /* Configure and enable interrupt */
|
|
|
|
+ intr_mode = lpfc_enable_intr(phba, phba->intr_mode);
|
|
|
|
+ if (intr_mode == LPFC_INTR_ERROR) {
|
|
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
|
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
|
- "0430 PM resume Failed to enable interrupt: "
|
|
|
|
- "error=x%x.\n", error);
|
|
|
|
- return error;
|
|
|
|
- }
|
|
|
|
|
|
+ "0430 PM resume Failed to enable interrupt\n");
|
|
|
|
+ return -EIO;
|
|
|
|
+ } else
|
|
|
|
+ phba->intr_mode = intr_mode;
|
|
|
|
|
|
/* Restart HBA and bring it online */
|
|
/* Restart HBA and bring it online */
|
|
lpfc_sli_brdrestart(phba);
|
|
lpfc_sli_brdrestart(phba);
|
|
lpfc_online(phba);
|
|
lpfc_online(phba);
|
|
|
|
|
|
|
|
+ /* Log the current active interrupt mode */
|
|
|
|
+ lpfc_log_intr_mode(phba, phba->intr_mode);
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2989,13 +3164,8 @@ static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev,
|
|
pring = &psli->ring[psli->fcp_ring];
|
|
pring = &psli->ring[psli->fcp_ring];
|
|
lpfc_sli_abort_iocb_ring(phba, pring);
|
|
lpfc_sli_abort_iocb_ring(phba, pring);
|
|
|
|
|
|
- if (phba->intr_type == MSIX)
|
|
|
|
- lpfc_disable_msix(phba);
|
|
|
|
- else {
|
|
|
|
- free_irq(phba->pcidev->irq, phba);
|
|
|
|
- if (phba->intr_type == MSI)
|
|
|
|
- pci_disable_msi(phba->pcidev);
|
|
|
|
- }
|
|
|
|
|
|
+ /* Disable interrupt */
|
|
|
|
+ lpfc_disable_intr(phba);
|
|
|
|
|
|
/* Request a slot reset. */
|
|
/* Request a slot reset. */
|
|
return PCI_ERS_RESULT_NEED_RESET;
|
|
return PCI_ERS_RESULT_NEED_RESET;
|
|
@@ -3023,7 +3193,7 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev)
|
|
struct Scsi_Host *shost = pci_get_drvdata(pdev);
|
|
struct Scsi_Host *shost = pci_get_drvdata(pdev);
|
|
struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
|
|
struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
|
|
struct lpfc_sli *psli = &phba->sli;
|
|
struct lpfc_sli *psli = &phba->sli;
|
|
- int error, retval;
|
|
|
|
|
|
+ uint32_t intr_mode;
|
|
|
|
|
|
dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n");
|
|
dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n");
|
|
if (pci_enable_device_mem(pdev)) {
|
|
if (pci_enable_device_mem(pdev)) {
|
|
@@ -3040,55 +3210,23 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev)
|
|
psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
|
|
psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
|
|
spin_unlock_irq(&phba->hbalock);
|
|
spin_unlock_irq(&phba->hbalock);
|
|
|
|
|
|
- /* Enable configured interrupt method */
|
|
|
|
- phba->intr_type = NONE;
|
|
|
|
- if (phba->cfg_use_msi == 2) {
|
|
|
|
- /* Need to issue conf_port mbox cmd before conf_msi mbox cmd */
|
|
|
|
- error = lpfc_sli_config_port(phba, 3);
|
|
|
|
- if (error)
|
|
|
|
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
|
|
|
- "0478 Firmware not capable of SLI 3 mode.\n");
|
|
|
|
- else {
|
|
|
|
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
|
|
|
- "0479 Firmware capable of SLI 3 mode.\n");
|
|
|
|
- /* Now, try to enable MSI-X interrupt mode */
|
|
|
|
- error = lpfc_enable_msix(phba);
|
|
|
|
- if (!error) {
|
|
|
|
- phba->intr_type = MSIX;
|
|
|
|
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
|
|
|
- "0480 enable MSI-X mode.\n");
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* Fallback to MSI if MSI-X initialization failed */
|
|
|
|
- if (phba->cfg_use_msi >= 1 && phba->intr_type == NONE) {
|
|
|
|
- retval = pci_enable_msi(phba->pcidev);
|
|
|
|
- if (!retval) {
|
|
|
|
- phba->intr_type = MSI;
|
|
|
|
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
|
|
|
- "0481 enable MSI mode.\n");
|
|
|
|
- } else
|
|
|
|
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
|
|
|
|
- "0470 enable IRQ mode.\n");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* MSI-X is the only case the doesn't need to call request_irq */
|
|
|
|
- if (phba->intr_type != MSIX) {
|
|
|
|
- retval = request_irq(phba->pcidev->irq, lpfc_intr_handler,
|
|
|
|
- IRQF_SHARED, LPFC_DRIVER_NAME, phba);
|
|
|
|
- if (retval) {
|
|
|
|
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
|
|
|
- "0471 Enable interrupt handler "
|
|
|
|
- "failed\n");
|
|
|
|
- } else if (phba->intr_type != MSI)
|
|
|
|
- phba->intr_type = INTx;
|
|
|
|
- }
|
|
|
|
|
|
+ /* Configure and enable interrupt */
|
|
|
|
+ intr_mode = lpfc_enable_intr(phba, phba->intr_mode);
|
|
|
|
+ if (intr_mode == LPFC_INTR_ERROR) {
|
|
|
|
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
|
|
|
|
+ "0427 Cannot re-enable interrupt after "
|
|
|
|
+ "slot reset.\n");
|
|
|
|
+ return PCI_ERS_RESULT_DISCONNECT;
|
|
|
|
+ } else
|
|
|
|
+ phba->intr_mode = intr_mode;
|
|
|
|
|
|
/* Take device offline; this will perform cleanup */
|
|
/* Take device offline; this will perform cleanup */
|
|
lpfc_offline(phba);
|
|
lpfc_offline(phba);
|
|
lpfc_sli_brdrestart(phba);
|
|
lpfc_sli_brdrestart(phba);
|
|
|
|
|
|
|
|
+ /* Log the current active interrupt mode */
|
|
|
|
+ lpfc_log_intr_mode(phba, phba->intr_mode);
|
|
|
|
+
|
|
return PCI_ERS_RESULT_RECOVERED;
|
|
return PCI_ERS_RESULT_RECOVERED;
|
|
}
|
|
}
|
|
|
|
|