aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/lpfc/lpfc_init.c
diff options
context:
space:
mode:
authorJames Smart <James.Smart@Emulex.Com>2008-12-04 22:39:35 -0500
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-12-29 12:24:27 -0500
commit5b75da2fa2c9570c3c3dbb2f63cae5b4183e0ca3 (patch)
tree618f67c4fd9cda1d60aa24d04262e4fb3ee2911f /drivers/scsi/lpfc/lpfc_init.c
parenteaf15d5b5605e1a403f631489de30a49fd66905d (diff)
[SCSI] lpfc 8.3.0 : Add active interrupt test for enabling MSI/MSI-X/INTx
Per the recent discussions at the Linux Plumbers Conference, when enabling MSI or MSI-X, generate a test interrupt to verify the interrupt routing is working properly. If the test interrupt fails, fall back to MSI first, and if that fails as well, to INTx. If the interrupt test fails with INTx, log an error and fail the PCI probe. Also changed the use of spin_(lock|unlock) to the _irq(save|restore) variants in the interrupt handlers because with multi-message MSI-X, both interrupt handlers can now run in parallel. Signed-off-by: James Smart <James.Smart@emulex.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_init.c')
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c410
1 files changed, 274 insertions, 136 deletions
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 4516d627deb9..e07f12a0871b 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -2274,8 +2274,7 @@ lpfc_enable_msix(struct lpfc_hba *phba)
2274 ARRAY_SIZE(phba->msix_entries)); 2274 ARRAY_SIZE(phba->msix_entries));
2275 if (rc) { 2275 if (rc) {
2276 lpfc_printf_log(phba, KERN_INFO, LOG_INIT, 2276 lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
2277 "0420 Enable MSI-X failed (%d), continuing " 2277 "0420 PCI enable MSI-X failed (%d)\n", rc);
2278 "with MSI\n", rc);
2279 goto msi_fail_out; 2278 goto msi_fail_out;
2280 } else 2279 } else
2281 for (i = 0; i < LPFC_MSIX_VECTORS; i++) 2280 for (i = 0; i < LPFC_MSIX_VECTORS; i++)
@@ -2292,9 +2291,9 @@ lpfc_enable_msix(struct lpfc_hba *phba)
2292 rc = request_irq(phba->msix_entries[0].vector, &lpfc_sp_intr_handler, 2291 rc = request_irq(phba->msix_entries[0].vector, &lpfc_sp_intr_handler,
2293 IRQF_SHARED, LPFC_SP_DRIVER_HANDLER_NAME, phba); 2292 IRQF_SHARED, LPFC_SP_DRIVER_HANDLER_NAME, phba);
2294 if (rc) { 2293 if (rc) {
2295 lpfc_printf_log(phba, KERN_ERR, LOG_INIT, 2294 lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
2296 "0421 MSI-X slow-path request_irq failed " 2295 "0421 MSI-X slow-path request_irq failed "
2297 "(%d), continuing with MSI\n", rc); 2296 "(%d)\n", rc);
2298 goto msi_fail_out; 2297 goto msi_fail_out;
2299 } 2298 }
2300 2299
@@ -2303,9 +2302,9 @@ lpfc_enable_msix(struct lpfc_hba *phba)
2303 IRQF_SHARED, LPFC_FP_DRIVER_HANDLER_NAME, phba); 2302 IRQF_SHARED, LPFC_FP_DRIVER_HANDLER_NAME, phba);
2304 2303
2305 if (rc) { 2304 if (rc) {
2306 lpfc_printf_log(phba, KERN_ERR, LOG_INIT, 2305 lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
2307 "0429 MSI-X fast-path request_irq failed " 2306 "0429 MSI-X fast-path request_irq failed "
2308 "(%d), continuing with MSI\n", rc); 2307 "(%d)\n", rc);
2309 goto irq_fail_out; 2308 goto irq_fail_out;
2310 } 2309 }
2311 2310
@@ -2326,7 +2325,7 @@ lpfc_enable_msix(struct lpfc_hba *phba)
2326 goto mbx_fail_out; 2325 goto mbx_fail_out;
2327 rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); 2326 rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
2328 if (rc != MBX_SUCCESS) { 2327 if (rc != MBX_SUCCESS) {
2329 lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, 2328 lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
2330 "0351 Config MSI mailbox command failed, " 2329 "0351 Config MSI mailbox command failed, "
2331 "mbxCmd x%x, mbxStatus x%x\n", 2330 "mbxCmd x%x, mbxStatus x%x\n",
2332 pmb->mb.mbxCommand, pmb->mb.mbxStatus); 2331 pmb->mb.mbxCommand, pmb->mb.mbxStatus);
@@ -2375,6 +2374,195 @@ lpfc_disable_msix(struct lpfc_hba *phba)
2375} 2374}
2376 2375
2377/** 2376/**
2377 * lpfc_enable_msi: Enable MSI interrupt mode.
2378 * @phba: pointer to lpfc hba data structure.
2379 *
2380 * This routine is invoked to enable the MSI interrupt mode. The kernel
2381 * function pci_enable_msi() is called to enable the MSI vector. The
2382 * device driver is responsible for calling the request_irq() to register
2383 * MSI vector with a interrupt the handler, which is done in this function.
2384 *
2385 * Return codes
2386 * 0 - sucessful
2387 * other values - error
2388 */
2389static int
2390lpfc_enable_msi(struct lpfc_hba *phba)
2391{
2392 int rc;
2393
2394 rc = pci_enable_msi(phba->pcidev);
2395 if (!rc)
2396 lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
2397 "0462 PCI enable MSI mode success.\n");
2398 else {
2399 lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
2400 "0471 PCI enable MSI mode failed (%d)\n", rc);
2401 return rc;
2402 }
2403
2404 rc = request_irq(phba->pcidev->irq, lpfc_intr_handler,
2405 IRQF_SHARED, LPFC_DRIVER_NAME, phba);
2406 if (rc) {
2407 pci_disable_msi(phba->pcidev);
2408 lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
2409 "0478 MSI request_irq failed (%d)\n", rc);
2410 }
2411 return rc;
2412}
2413
2414/**
2415 * lpfc_disable_msi: Disable MSI interrupt mode.
2416 * @phba: pointer to lpfc hba data structure.
2417 *
2418 * This routine is invoked to disable the MSI interrupt mode. The driver
2419 * calls free_irq() on MSI vector it has done request_irq() on before
2420 * calling pci_disable_msi(). Failure to do so results in a BUG_ON() and
2421 * a device will be left with MSI enabled and leaks its vector.
2422 */
2423
2424static void
2425lpfc_disable_msi(struct lpfc_hba *phba)
2426{
2427 free_irq(phba->pcidev->irq, phba);
2428 pci_disable_msi(phba->pcidev);
2429 return;
2430}
2431
2432/**
2433 * lpfc_log_intr_mode: Log the active interrupt mode
2434 * @phba: pointer to lpfc hba data structure.
2435 * @intr_mode: active interrupt mode adopted.
2436 *
2437 * This routine it invoked to log the currently used active interrupt mode
2438 * to the device.
2439 */
2440static void
2441lpfc_log_intr_mode(struct lpfc_hba *phba, uint32_t intr_mode)
2442{
2443 switch (intr_mode) {
2444 case 0:
2445 lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
2446 "0470 Enable INTx interrupt mode.\n");
2447 break;
2448 case 1:
2449 lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
2450 "0481 Enabled MSI interrupt mode.\n");
2451 break;
2452 case 2:
2453 lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
2454 "0480 Enabled MSI-X interrupt mode.\n");
2455 break;
2456 default:
2457 lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
2458 "0482 Illegal interrupt mode.\n");
2459 break;
2460 }
2461 return;
2462}
2463
2464static void
2465lpfc_stop_port(struct lpfc_hba *phba)
2466{
2467 /* Clear all interrupt enable conditions */
2468 writel(0, phba->HCregaddr);
2469 readl(phba->HCregaddr); /* flush */
2470 /* Clear all pending interrupts */
2471 writel(0xffffffff, phba->HAregaddr);
2472 readl(phba->HAregaddr); /* flush */
2473
2474 /* Reset some HBA SLI setup states */
2475 lpfc_stop_phba_timers(phba);
2476 phba->pport->work_port_events = 0;
2477
2478 return;
2479}
2480
2481/**
2482 * lpfc_enable_intr: Enable device interrupt.
2483 * @phba: pointer to lpfc hba data structure.
2484 *
2485 * This routine is invoked to enable device interrupt and associate driver's
2486 * interrupt handler(s) to interrupt vector(s). Depends on the interrupt
2487 * mode configured to the driver, the driver will try to fallback from the
2488 * configured interrupt mode to an interrupt mode which is supported by the
2489 * platform, kernel, and device in the order of: MSI-X -> MSI -> IRQ.
2490 *
2491 * Return codes
2492 * 0 - sucessful
2493 * other values - error
2494 **/
2495static uint32_t
2496lpfc_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode)
2497{
2498 uint32_t intr_mode = LPFC_INTR_ERROR;
2499 int retval;
2500
2501 if (cfg_mode == 2) {
2502 /* Need to issue conf_port mbox cmd before conf_msi mbox cmd */
2503 retval = lpfc_sli_config_port(phba, 3);
2504 if (!retval) {
2505 /* Now, try to enable MSI-X interrupt mode */
2506 retval = lpfc_enable_msix(phba);
2507 if (!retval) {
2508 /* Indicate initialization to MSI-X mode */
2509 phba->intr_type = MSIX;
2510 intr_mode = 2;
2511 }
2512 }
2513 }
2514
2515 /* Fallback to MSI if MSI-X initialization failed */
2516 if (cfg_mode >= 1 && phba->intr_type == NONE) {
2517 retval = lpfc_enable_msi(phba);
2518 if (!retval) {
2519 /* Indicate initialization to MSI mode */
2520 phba->intr_type = MSI;
2521 intr_mode = 1;
2522 }
2523 }
2524
2525 /* Fallback to INTx if both MSI-X/MSI initalization failed */
2526 if (phba->intr_type == NONE) {
2527 retval = request_irq(phba->pcidev->irq, lpfc_intr_handler,
2528 IRQF_SHARED, LPFC_DRIVER_NAME, phba);
2529 if (!retval) {
2530 /* Indicate initialization to INTx mode */
2531 phba->intr_type = INTx;
2532 intr_mode = 0;
2533 }
2534 }
2535 return intr_mode;
2536}
2537
2538/**
2539 * lpfc_disable_intr: Disable device interrupt.
2540 * @phba: pointer to lpfc hba data structure.
2541 *
2542 * This routine is invoked to disable device interrupt and disassociate the
2543 * driver's interrupt handler(s) from interrupt vector(s). Depending on the
2544 * interrupt mode, the driver will release the interrupt vector(s) for the
2545 * message signaled interrupt.
2546 **/
2547static void
2548lpfc_disable_intr(struct lpfc_hba *phba)
2549{
2550 /* Disable the currently initialized interrupt mode */
2551 if (phba->intr_type == MSIX)
2552 lpfc_disable_msix(phba);
2553 else if (phba->intr_type == MSI)
2554 lpfc_disable_msi(phba);
2555 else if (phba->intr_type == INTx)
2556 free_irq(phba->pcidev->irq, phba);
2557
2558 /* Reset interrupt management states */
2559 phba->intr_type = NONE;
2560 phba->sli.slistat.sli_intr = 0;
2561
2562 return;
2563}
2564
2565/**
2378 * lpfc_pci_probe_one: lpfc PCI probe func to register device to PCI subsystem. 2566 * lpfc_pci_probe_one: lpfc PCI probe func to register device to PCI subsystem.
2379 * @pdev: pointer to PCI device 2567 * @pdev: pointer to PCI device
2380 * @pid: pointer to PCI device identifier 2568 * @pid: pointer to PCI device identifier
@@ -2404,6 +2592,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
2404 int error = -ENODEV, retval; 2592 int error = -ENODEV, retval;
2405 int i, hbq_count; 2593 int i, hbq_count;
2406 uint16_t iotag; 2594 uint16_t iotag;
2595 uint32_t cfg_mode, intr_mode;
2407 int bars = pci_select_bars(pdev, IORESOURCE_MEM); 2596 int bars = pci_select_bars(pdev, IORESOURCE_MEM);
2408 struct lpfc_adapter_event_header adapter_event; 2597 struct lpfc_adapter_event_header adapter_event;
2409 2598
@@ -2606,7 +2795,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
2606 lpfc_debugfs_initialize(vport); 2795 lpfc_debugfs_initialize(vport);
2607 2796
2608 pci_set_drvdata(pdev, shost); 2797 pci_set_drvdata(pdev, shost);
2609 phba->intr_type = NONE;
2610 2798
2611 phba->MBslimaddr = phba->slim_memmap_p; 2799 phba->MBslimaddr = phba->slim_memmap_p;
2612 phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET; 2800 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)
2614 phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET; 2802 phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
2615 phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET; 2803 phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
2616 2804
2617 /* Configure and enable interrupt */ 2805 /* Configure sysfs attributes */
2618 if (phba->cfg_use_msi == 2) {
2619 /* Need to issue conf_port mbox cmd before conf_msi mbox cmd */
2620 error = lpfc_sli_config_port(phba, 3);
2621 if (error)
2622 lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
2623 "0427 Firmware not capable of SLI 3 mode.\n");
2624 else {
2625 lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
2626 "0426 Firmware capable of SLI 3 mode.\n");
2627 /* Now, try to enable MSI-X interrupt mode */
2628 error = lpfc_enable_msix(phba);
2629 if (!error) {
2630 phba->intr_type = MSIX;
2631 lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
2632 "0430 enable MSI-X mode.\n");
2633 }
2634 }
2635 }
2636
2637 /* Fallback to MSI if MSI-X initialization failed */
2638 if (phba->cfg_use_msi >= 1 && phba->intr_type == NONE) {
2639 retval = pci_enable_msi(phba->pcidev);
2640 if (!retval) {
2641 phba->intr_type = MSI;
2642 lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
2643 "0473 enable MSI mode.\n");
2644 } else
2645 lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
2646 "0452 enable IRQ mode.\n");
2647 }
2648
2649 /* MSI-X is the only case the doesn't need to call request_irq */
2650 if (phba->intr_type != MSIX) {
2651 retval = request_irq(phba->pcidev->irq, lpfc_intr_handler,
2652 IRQF_SHARED, LPFC_DRIVER_NAME, phba);
2653 if (retval) {
2654 lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0451 Enable "
2655 "interrupt handler failed\n");
2656 error = retval;
2657 goto out_disable_msi;
2658 } else if (phba->intr_type != MSI)
2659 phba->intr_type = INTx;
2660 }
2661
2662 if (lpfc_alloc_sysfs_attr(vport)) { 2806 if (lpfc_alloc_sysfs_attr(vport)) {
2663 lpfc_printf_log(phba, KERN_ERR, LOG_INIT, 2807 lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
2664 "1476 Failed to allocate sysfs attr\n"); 2808 "1476 Failed to allocate sysfs attr\n");
2665 error = -ENOMEM; 2809 error = -ENOMEM;
2666 goto out_free_irq; 2810 goto out_destroy_port;
2667 } 2811 }
2668 2812
2669 if (lpfc_sli_hba_setup(phba)) { 2813 cfg_mode = phba->cfg_use_msi;
2670 lpfc_printf_log(phba, KERN_ERR, LOG_INIT, 2814 while (true) {
2671 "1477 Failed to set up hba\n"); 2815 /* Configure and enable interrupt */
2672 error = -ENODEV; 2816 intr_mode = lpfc_enable_intr(phba, cfg_mode);
2673 goto out_remove_device; 2817 if (intr_mode == LPFC_INTR_ERROR) {
2818 lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
2819 "0426 Failed to enable interrupt.\n");
2820 goto out_free_sysfs_attr;
2821 }
2822 /* HBA SLI setup */
2823 if (lpfc_sli_hba_setup(phba)) {
2824 lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
2825 "1477 Failed to set up hba\n");
2826 error = -ENODEV;
2827 goto out_remove_device;
2828 }
2829
2830 /* Wait 50ms for the interrupts of previous mailbox commands */
2831 msleep(50);
2832 /* Check active interrupts received */
2833 if (phba->sli.slistat.sli_intr > LPFC_MSIX_VECTORS) {
2834 /* Log the current active interrupt mode */
2835 phba->intr_mode = intr_mode;
2836 lpfc_log_intr_mode(phba, intr_mode);
2837 break;
2838 } else {
2839 lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
2840 "0451 Configure interrupt mode (%d) "
2841 "failed active interrupt test.\n",
2842 intr_mode);
2843 if (intr_mode == 0) {
2844 lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
2845 "0479 Failed to enable "
2846 "interrupt.\n");
2847 error = -ENODEV;
2848 goto out_remove_device;
2849 }
2850 /* Stop HBA SLI setups */
2851 lpfc_stop_port(phba);
2852 /* Disable the current interrupt mode */
2853 lpfc_disable_intr(phba);
2854 /* Try next level of interrupt mode */
2855 cfg_mode = --intr_mode;
2856 }
2674 } 2857 }
2675 2858
2676 /* 2859 /*
@@ -2700,22 +2883,15 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
2700 return 0; 2883 return 0;
2701 2884
2702out_remove_device: 2885out_remove_device:
2703 lpfc_free_sysfs_attr(vport);
2704 spin_lock_irq(shost->host_lock); 2886 spin_lock_irq(shost->host_lock);
2705 vport->load_flag |= FC_UNLOADING; 2887 vport->load_flag |= FC_UNLOADING;
2706 spin_unlock_irq(shost->host_lock); 2888 spin_unlock_irq(shost->host_lock);
2707out_free_irq:
2708 lpfc_stop_phba_timers(phba); 2889 lpfc_stop_phba_timers(phba);
2709 phba->pport->work_port_events = 0; 2890 phba->pport->work_port_events = 0;
2710 2891 lpfc_disable_intr(phba);
2711 if (phba->intr_type == MSIX) 2892out_free_sysfs_attr:
2712 lpfc_disable_msix(phba); 2893 lpfc_free_sysfs_attr(vport);
2713 else 2894out_destroy_port:
2714 free_irq(phba->pcidev->irq, phba);
2715
2716out_disable_msi:
2717 if (phba->intr_type == MSI)
2718 pci_disable_msi(phba->pcidev);
2719 destroy_port(vport); 2895 destroy_port(vport);
2720out_kthread_stop: 2896out_kthread_stop:
2721 kthread_stop(phba->worker_thread); 2897 kthread_stop(phba->worker_thread);
@@ -2804,13 +2980,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
2804 2980
2805 lpfc_debugfs_terminate(vport); 2981 lpfc_debugfs_terminate(vport);
2806 2982
2807 if (phba->intr_type == MSIX) 2983 /* Disable interrupt */
2808 lpfc_disable_msix(phba); 2984 lpfc_disable_intr(phba);
2809 else {
2810 free_irq(phba->pcidev->irq, phba);
2811 if (phba->intr_type == MSI)
2812 pci_disable_msi(phba->pcidev);
2813 }
2814 2985
2815 pci_set_drvdata(pdev, NULL); 2986 pci_set_drvdata(pdev, NULL);
2816 scsi_host_put(shost); 2987 scsi_host_put(shost);
@@ -2908,6 +3079,7 @@ lpfc_pci_resume_one(struct pci_dev *pdev)
2908{ 3079{
2909 struct Scsi_Host *shost = pci_get_drvdata(pdev); 3080 struct Scsi_Host *shost = pci_get_drvdata(pdev);
2910 struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; 3081 struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
3082 uint32_t intr_mode;
2911 int error; 3083 int error;
2912 3084
2913 lpfc_printf_log(phba, KERN_INFO, LOG_INIT, 3085 lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
@@ -2930,19 +3102,22 @@ lpfc_pci_resume_one(struct pci_dev *pdev)
2930 return error; 3102 return error;
2931 } 3103 }
2932 3104
2933 /* Enable interrupt from device */ 3105 /* Configure and enable interrupt */
2934 error = lpfc_enable_intr(phba); 3106 intr_mode = lpfc_enable_intr(phba, phba->intr_mode);
2935 if (error) { 3107 if (intr_mode == LPFC_INTR_ERROR) {
2936 lpfc_printf_log(phba, KERN_ERR, LOG_INIT, 3108 lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
2937 "0430 PM resume Failed to enable interrupt: " 3109 "0430 PM resume Failed to enable interrupt\n");
2938 "error=x%x.\n", error); 3110 return -EIO;
2939 return error; 3111 } else
2940 } 3112 phba->intr_mode = intr_mode;
2941 3113
2942 /* Restart HBA and bring it online */ 3114 /* Restart HBA and bring it online */
2943 lpfc_sli_brdrestart(phba); 3115 lpfc_sli_brdrestart(phba);
2944 lpfc_online(phba); 3116 lpfc_online(phba);
2945 3117
3118 /* Log the current active interrupt mode */
3119 lpfc_log_intr_mode(phba, phba->intr_mode);
3120
2946 return 0; 3121 return 0;
2947} 3122}
2948 3123
@@ -2989,13 +3164,8 @@ static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev,
2989 pring = &psli->ring[psli->fcp_ring]; 3164 pring = &psli->ring[psli->fcp_ring];
2990 lpfc_sli_abort_iocb_ring(phba, pring); 3165 lpfc_sli_abort_iocb_ring(phba, pring);
2991 3166
2992 if (phba->intr_type == MSIX) 3167 /* Disable interrupt */
2993 lpfc_disable_msix(phba); 3168 lpfc_disable_intr(phba);
2994 else {
2995 free_irq(phba->pcidev->irq, phba);
2996 if (phba->intr_type == MSI)
2997 pci_disable_msi(phba->pcidev);
2998 }
2999 3169
3000 /* Request a slot reset. */ 3170 /* Request a slot reset. */
3001 return PCI_ERS_RESULT_NEED_RESET; 3171 return PCI_ERS_RESULT_NEED_RESET;
@@ -3023,7 +3193,7 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev)
3023 struct Scsi_Host *shost = pci_get_drvdata(pdev); 3193 struct Scsi_Host *shost = pci_get_drvdata(pdev);
3024 struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; 3194 struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
3025 struct lpfc_sli *psli = &phba->sli; 3195 struct lpfc_sli *psli = &phba->sli;
3026 int error, retval; 3196 uint32_t intr_mode;
3027 3197
3028 dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n"); 3198 dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n");
3029 if (pci_enable_device_mem(pdev)) { 3199 if (pci_enable_device_mem(pdev)) {
@@ -3040,55 +3210,23 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev)
3040 psli->sli_flag &= ~LPFC_SLI2_ACTIVE; 3210 psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
3041 spin_unlock_irq(&phba->hbalock); 3211 spin_unlock_irq(&phba->hbalock);
3042 3212
3043 /* Enable configured interrupt method */ 3213 /* Configure and enable interrupt */
3044 phba->intr_type = NONE; 3214 intr_mode = lpfc_enable_intr(phba, phba->intr_mode);
3045 if (phba->cfg_use_msi == 2) { 3215 if (intr_mode == LPFC_INTR_ERROR) {
3046 /* Need to issue conf_port mbox cmd before conf_msi mbox cmd */ 3216 lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
3047 error = lpfc_sli_config_port(phba, 3); 3217 "0427 Cannot re-enable interrupt after "
3048 if (error) 3218 "slot reset.\n");
3049 lpfc_printf_log(phba, KERN_INFO, LOG_INIT, 3219 return PCI_ERS_RESULT_DISCONNECT;
3050 "0478 Firmware not capable of SLI 3 mode.\n"); 3220 } else
3051 else { 3221 phba->intr_mode = intr_mode;
3052 lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
3053 "0479 Firmware capable of SLI 3 mode.\n");
3054 /* Now, try to enable MSI-X interrupt mode */
3055 error = lpfc_enable_msix(phba);
3056 if (!error) {
3057 phba->intr_type = MSIX;
3058 lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
3059 "0480 enable MSI-X mode.\n");
3060 }
3061 }
3062 }
3063
3064 /* Fallback to MSI if MSI-X initialization failed */
3065 if (phba->cfg_use_msi >= 1 && phba->intr_type == NONE) {
3066 retval = pci_enable_msi(phba->pcidev);
3067 if (!retval) {
3068 phba->intr_type = MSI;
3069 lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
3070 "0481 enable MSI mode.\n");
3071 } else
3072 lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
3073 "0470 enable IRQ mode.\n");
3074 }
3075
3076 /* MSI-X is the only case the doesn't need to call request_irq */
3077 if (phba->intr_type != MSIX) {
3078 retval = request_irq(phba->pcidev->irq, lpfc_intr_handler,
3079 IRQF_SHARED, LPFC_DRIVER_NAME, phba);
3080 if (retval) {
3081 lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
3082 "0471 Enable interrupt handler "
3083 "failed\n");
3084 } else if (phba->intr_type != MSI)
3085 phba->intr_type = INTx;
3086 }
3087 3222
3088 /* Take device offline; this will perform cleanup */ 3223 /* Take device offline; this will perform cleanup */
3089 lpfc_offline(phba); 3224 lpfc_offline(phba);
3090 lpfc_sli_brdrestart(phba); 3225 lpfc_sli_brdrestart(phba);
3091 3226
3227 /* Log the current active interrupt mode */
3228 lpfc_log_intr_mode(phba, phba->intr_mode);
3229
3092 return PCI_ERS_RESULT_RECOVERED; 3230 return PCI_ERS_RESULT_RECOVERED;
3093} 3231}
3094 3232