diff options
author | James Smart <James.Smart@Emulex.Com> | 2007-08-02 11:10:31 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.localdomain> | 2007-08-01 13:24:10 -0400 |
commit | 51ef4c26891a734bc8416b639ad460a8162926bc (patch) | |
tree | 8279e11bf1a0a3200e8aa9bb3d956345ef73533c /drivers/scsi/lpfc/lpfc_init.c | |
parent | 78b2d852a88cd2a55e3ab632109de045d58b83e3 (diff) |
[SCSI] lpfc 8.2.2 : Miscellaneous Bug Fixes
- Fix vport ndlp ref counting errors
- Fix use after free of ndlp structure
- Use the correct flag to check for LOADING setting.
- Fix driver unload bugs (related to shost references) after link down or rscn
- Fix up HBQ initialization
- Fix port_list locking around driver unload.
- Fix references to hostdata as a phba
- Fix GFFID type offset to work correctly with big endian structure.
- Only call pci_disable_msi if the pci_enable_msi succeeded
- Fix vport_delete wait/fail if in discovery
- Put a reference on the nameservers ndlp when performing CT traffic.
- Remove unbalanced hba unlock.
- Fix up HBQ processing
- Fix lpfc debugfs discovery trace output for ELS rsp cmpl
- Send ADISC when rpi is 0
- Stop FDISC retrying forever
- Unable to retrieve correct config parameter for vport
- Fix sli_validate_fcp_iocb, sli_sum_iocb, sli_abort_iocb to be vport-aware.
- Fix index-out-of-range error in iocb. Spotted by Coverity.
Signed-off-by: James Smart <James.Smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_init.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 86 |
1 files changed, 48 insertions, 38 deletions
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 7e5ea0774e58..21f8f7a56e23 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
@@ -55,6 +55,8 @@ static DEFINE_IDR(lpfc_hba_index); | |||
55 | 55 | ||
56 | 56 | ||
57 | 57 | ||
58 | extern struct lpfc_hbq_init *lpfc_hbq_defs[]; | ||
59 | |||
58 | /************************************************************************/ | 60 | /************************************************************************/ |
59 | /* */ | 61 | /* */ |
60 | /* lpfc_config_port_prep */ | 62 | /* lpfc_config_port_prep */ |
@@ -429,18 +431,11 @@ lpfc_config_port_post(struct lpfc_hba *phba) | |||
429 | int | 431 | int |
430 | lpfc_hba_down_prep(struct lpfc_hba *phba) | 432 | lpfc_hba_down_prep(struct lpfc_hba *phba) |
431 | { | 433 | { |
432 | struct lpfc_vport **vports; | ||
433 | int i; | ||
434 | |||
435 | /* Disable interrupts */ | 434 | /* Disable interrupts */ |
436 | writel(0, phba->HCregaddr); | 435 | writel(0, phba->HCregaddr); |
437 | readl(phba->HCregaddr); /* flush */ | 436 | readl(phba->HCregaddr); /* flush */ |
438 | 437 | ||
439 | vports = lpfc_create_vport_work_array(phba); | 438 | lpfc_cleanup_discovery_resources(phba->pport); |
440 | if (vports != NULL) | ||
441 | for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) | ||
442 | lpfc_cleanup_discovery_resources(vports[i]); | ||
443 | lpfc_destroy_vport_work_array(vports); | ||
444 | return 0; | 439 | return 0; |
445 | } | 440 | } |
446 | 441 | ||
@@ -512,7 +507,7 @@ lpfc_hb_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq) | |||
512 | mempool_free(pmboxq, phba->mbox_mem_pool); | 507 | mempool_free(pmboxq, phba->mbox_mem_pool); |
513 | if (!(phba->pport->fc_flag & FC_OFFLINE_MODE) && | 508 | if (!(phba->pport->fc_flag & FC_OFFLINE_MODE) && |
514 | !(phba->link_state == LPFC_HBA_ERROR) && | 509 | !(phba->link_state == LPFC_HBA_ERROR) && |
515 | !(phba->pport->fc_flag & FC_UNLOADING)) | 510 | !(phba->pport->load_flag & FC_UNLOADING)) |
516 | mod_timer(&phba->hb_tmofunc, | 511 | mod_timer(&phba->hb_tmofunc, |
517 | jiffies + HZ * LPFC_HB_MBOX_INTERVAL); | 512 | jiffies + HZ * LPFC_HB_MBOX_INTERVAL); |
518 | return; | 513 | return; |
@@ -526,7 +521,7 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba) | |||
526 | struct lpfc_sli *psli = &phba->sli; | 521 | struct lpfc_sli *psli = &phba->sli; |
527 | 522 | ||
528 | if ((phba->link_state == LPFC_HBA_ERROR) || | 523 | if ((phba->link_state == LPFC_HBA_ERROR) || |
529 | (phba->pport->fc_flag & FC_UNLOADING) || | 524 | (phba->pport->load_flag & FC_UNLOADING) || |
530 | (phba->pport->fc_flag & FC_OFFLINE_MODE)) | 525 | (phba->pport->fc_flag & FC_OFFLINE_MODE)) |
531 | return; | 526 | return; |
532 | 527 | ||
@@ -1340,16 +1335,9 @@ lpfc_stop_vport_timers(struct lpfc_vport *vport) | |||
1340 | static void | 1335 | static void |
1341 | lpfc_stop_phba_timers(struct lpfc_hba *phba) | 1336 | lpfc_stop_phba_timers(struct lpfc_hba *phba) |
1342 | { | 1337 | { |
1343 | struct lpfc_vport **vports; | ||
1344 | int i; | ||
1345 | |||
1346 | del_timer_sync(&phba->fcp_poll_timer); | 1338 | del_timer_sync(&phba->fcp_poll_timer); |
1347 | del_timer_sync(&phba->fc_estabtmo); | 1339 | del_timer_sync(&phba->fc_estabtmo); |
1348 | vports = lpfc_create_vport_work_array(phba); | 1340 | lpfc_stop_vport_timers(phba->pport); |
1349 | if (vports != NULL) | ||
1350 | for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) | ||
1351 | lpfc_stop_vport_timers(vports[i]); | ||
1352 | lpfc_destroy_vport_work_array(vports); | ||
1353 | del_timer_sync(&phba->sli.mbox_tmo); | 1341 | del_timer_sync(&phba->sli.mbox_tmo); |
1354 | del_timer_sync(&phba->fabric_block_timer); | 1342 | del_timer_sync(&phba->fabric_block_timer); |
1355 | phba->hb_outstanding = 0; | 1343 | phba->hb_outstanding = 0; |
@@ -1455,6 +1443,11 @@ lpfc_offline(struct lpfc_hba *phba) | |||
1455 | 1443 | ||
1456 | /* stop all timers associated with this hba */ | 1444 | /* stop all timers associated with this hba */ |
1457 | lpfc_stop_phba_timers(phba); | 1445 | lpfc_stop_phba_timers(phba); |
1446 | vports = lpfc_create_vport_work_array(phba); | ||
1447 | if (vports != NULL) | ||
1448 | for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) | ||
1449 | lpfc_stop_vport_timers(vports[i]); | ||
1450 | lpfc_destroy_vport_work_array(vports); | ||
1458 | lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, | 1451 | lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, |
1459 | "0460 Bring Adapter offline\n"); | 1452 | "0460 Bring Adapter offline\n"); |
1460 | /* Bring down the SLI Layer and cleanup. The HBA is offline | 1453 | /* Bring down the SLI Layer and cleanup. The HBA is offline |
@@ -1629,7 +1622,7 @@ int lpfc_scan_finished(struct Scsi_Host *shost, unsigned long time) | |||
1629 | 1622 | ||
1630 | spin_lock_irq(shost->host_lock); | 1623 | spin_lock_irq(shost->host_lock); |
1631 | 1624 | ||
1632 | if (vport->fc_flag & FC_UNLOADING) { | 1625 | if (vport->load_flag & FC_UNLOADING) { |
1633 | stat = 1; | 1626 | stat = 1; |
1634 | goto finished; | 1627 | goto finished; |
1635 | } | 1628 | } |
@@ -1706,7 +1699,7 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost) | |||
1706 | 1699 | ||
1707 | fc_host_max_npiv_vports(shost) = phba->max_vpi; | 1700 | fc_host_max_npiv_vports(shost) = phba->max_vpi; |
1708 | spin_lock_irq(shost->host_lock); | 1701 | spin_lock_irq(shost->host_lock); |
1709 | vport->fc_flag &= ~FC_LOADING; | 1702 | vport->load_flag &= ~FC_LOADING; |
1710 | spin_unlock_irq(shost->host_lock); | 1703 | spin_unlock_irq(shost->host_lock); |
1711 | } | 1704 | } |
1712 | 1705 | ||
@@ -1718,9 +1711,10 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
1718 | struct lpfc_sli *psli; | 1711 | struct lpfc_sli *psli; |
1719 | struct lpfc_iocbq *iocbq_entry = NULL, *iocbq_next = NULL; | 1712 | struct lpfc_iocbq *iocbq_entry = NULL, *iocbq_next = NULL; |
1720 | struct Scsi_Host *shost = NULL; | 1713 | struct Scsi_Host *shost = NULL; |
1714 | void *ptr; | ||
1721 | unsigned long bar0map_len, bar2map_len; | 1715 | unsigned long bar0map_len, bar2map_len; |
1722 | int error = -ENODEV; | 1716 | int error = -ENODEV; |
1723 | int i; | 1717 | int i, hbq_count; |
1724 | uint16_t iotag; | 1718 | uint16_t iotag; |
1725 | 1719 | ||
1726 | if (pci_enable_device(pdev)) | 1720 | if (pci_enable_device(pdev)) |
@@ -1741,7 +1735,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
1741 | goto out_free_phba; | 1735 | goto out_free_phba; |
1742 | 1736 | ||
1743 | INIT_LIST_HEAD(&phba->port_list); | 1737 | INIT_LIST_HEAD(&phba->port_list); |
1744 | INIT_LIST_HEAD(&phba->hbq_buffer_list); | ||
1745 | /* | 1738 | /* |
1746 | * Get all the module params for configuring this host and then | 1739 | * Get all the module params for configuring this host and then |
1747 | * establish the host. | 1740 | * establish the host. |
@@ -1819,6 +1812,17 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
1819 | if (!phba->hbqslimp.virt) | 1812 | if (!phba->hbqslimp.virt) |
1820 | goto out_free_slim; | 1813 | goto out_free_slim; |
1821 | 1814 | ||
1815 | hbq_count = lpfc_sli_hbq_count(); | ||
1816 | ptr = phba->hbqslimp.virt; | ||
1817 | for (i = 0; i < hbq_count; ++i) { | ||
1818 | phba->hbqs[i].hbq_virt = ptr; | ||
1819 | INIT_LIST_HEAD(&phba->hbqs[i].hbq_buffer_list); | ||
1820 | ptr += (lpfc_hbq_defs[i]->entry_count * | ||
1821 | sizeof(struct lpfc_hbq_entry)); | ||
1822 | } | ||
1823 | phba->hbqs[LPFC_ELS_HBQ].hbq_alloc_buffer = lpfc_els_hbq_alloc; | ||
1824 | phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer = lpfc_els_hbq_free; | ||
1825 | |||
1822 | memset(phba->hbqslimp.virt, 0, lpfc_sli_hbq_size()); | 1826 | memset(phba->hbqslimp.virt, 0, lpfc_sli_hbq_size()); |
1823 | 1827 | ||
1824 | /* Initialize the SLI Layer to run with lpfc HBAs. */ | 1828 | /* Initialize the SLI Layer to run with lpfc HBAs. */ |
@@ -1894,7 +1898,9 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
1894 | 1898 | ||
1895 | if (phba->cfg_use_msi) { | 1899 | if (phba->cfg_use_msi) { |
1896 | error = pci_enable_msi(phba->pcidev); | 1900 | error = pci_enable_msi(phba->pcidev); |
1897 | if (error) | 1901 | if (!error) |
1902 | phba->using_msi = 1; | ||
1903 | else | ||
1898 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | 1904 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, |
1899 | "0452 Enable MSI failed, continuing " | 1905 | "0452 Enable MSI failed, continuing " |
1900 | "with IRQ\n"); | 1906 | "with IRQ\n"); |
@@ -1941,14 +1947,15 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
1941 | out_remove_device: | 1947 | out_remove_device: |
1942 | lpfc_free_sysfs_attr(vport); | 1948 | lpfc_free_sysfs_attr(vport); |
1943 | spin_lock_irq(shost->host_lock); | 1949 | spin_lock_irq(shost->host_lock); |
1944 | vport->fc_flag |= FC_UNLOADING; | 1950 | vport->load_flag |= FC_UNLOADING; |
1945 | spin_unlock_irq(shost->host_lock); | 1951 | spin_unlock_irq(shost->host_lock); |
1946 | out_free_irq: | 1952 | out_free_irq: |
1947 | lpfc_stop_phba_timers(phba); | 1953 | lpfc_stop_phba_timers(phba); |
1948 | phba->pport->work_port_events = 0; | 1954 | phba->pport->work_port_events = 0; |
1949 | free_irq(phba->pcidev->irq, phba); | 1955 | free_irq(phba->pcidev->irq, phba); |
1950 | out_disable_msi: | 1956 | out_disable_msi: |
1951 | pci_disable_msi(phba->pcidev); | 1957 | if (phba->using_msi) |
1958 | pci_disable_msi(phba->pcidev); | ||
1952 | destroy_port(vport); | 1959 | destroy_port(vport); |
1953 | out_kthread_stop: | 1960 | out_kthread_stop: |
1954 | kthread_stop(phba->worker_thread); | 1961 | kthread_stop(phba->worker_thread); |
@@ -1990,10 +1997,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev) | |||
1990 | struct Scsi_Host *shost = pci_get_drvdata(pdev); | 1997 | struct Scsi_Host *shost = pci_get_drvdata(pdev); |
1991 | struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; | 1998 | struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; |
1992 | struct lpfc_hba *phba = vport->phba; | 1999 | struct lpfc_hba *phba = vport->phba; |
1993 | struct lpfc_vport *port_iterator; | ||
1994 | spin_lock_irq(&phba->hbalock); | 2000 | spin_lock_irq(&phba->hbalock); |
1995 | list_for_each_entry(port_iterator, &phba->port_list, listentry) | 2001 | vport->load_flag |= FC_UNLOADING; |
1996 | port_iterator->load_flag |= FC_UNLOADING; | ||
1997 | spin_unlock_irq(&phba->hbalock); | 2002 | spin_unlock_irq(&phba->hbalock); |
1998 | 2003 | ||
1999 | kfree(vport->vname); | 2004 | kfree(vport->vname); |
@@ -2001,7 +2006,6 @@ lpfc_pci_remove_one(struct pci_dev *pdev) | |||
2001 | 2006 | ||
2002 | fc_remove_host(shost); | 2007 | fc_remove_host(shost); |
2003 | scsi_remove_host(shost); | 2008 | scsi_remove_host(shost); |
2004 | |||
2005 | /* | 2009 | /* |
2006 | * Bring down the SLI Layer. This step disable all interrupts, | 2010 | * Bring down the SLI Layer. This step disable all interrupts, |
2007 | * clears the rings, discards all mailbox commands, and resets | 2011 | * clears the rings, discards all mailbox commands, and resets |
@@ -2022,7 +2026,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev) | |||
2022 | 2026 | ||
2023 | /* Release the irq reservation */ | 2027 | /* Release the irq reservation */ |
2024 | free_irq(phba->pcidev->irq, phba); | 2028 | free_irq(phba->pcidev->irq, phba); |
2025 | pci_disable_msi(phba->pcidev); | 2029 | if (phba->using_msi) |
2030 | pci_disable_msi(phba->pcidev); | ||
2026 | 2031 | ||
2027 | pci_set_drvdata(pdev, NULL); | 2032 | pci_set_drvdata(pdev, NULL); |
2028 | scsi_host_put(shost); | 2033 | scsi_host_put(shost); |
@@ -2064,8 +2069,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev) | |||
2064 | static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev, | 2069 | static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev, |
2065 | pci_channel_state_t state) | 2070 | pci_channel_state_t state) |
2066 | { | 2071 | { |
2067 | struct Scsi_Host *host = pci_get_drvdata(pdev); | 2072 | struct Scsi_Host *shost = pci_get_drvdata(pdev); |
2068 | struct lpfc_hba *phba = (struct lpfc_hba *)host->hostdata; | 2073 | struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; |
2069 | struct lpfc_sli *psli = &phba->sli; | 2074 | struct lpfc_sli *psli = &phba->sli; |
2070 | struct lpfc_sli_ring *pring; | 2075 | struct lpfc_sli_ring *pring; |
2071 | 2076 | ||
@@ -2081,6 +2086,11 @@ static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev, | |||
2081 | pring = &psli->ring[psli->fcp_ring]; | 2086 | pring = &psli->ring[psli->fcp_ring]; |
2082 | lpfc_sli_abort_iocb_ring(phba, pring); | 2087 | lpfc_sli_abort_iocb_ring(phba, pring); |
2083 | 2088 | ||
2089 | /* Release the irq reservation */ | ||
2090 | free_irq(phba->pcidev->irq, phba); | ||
2091 | if (phba->using_msi) | ||
2092 | pci_disable_msi(phba->pcidev); | ||
2093 | |||
2084 | /* Request a slot reset. */ | 2094 | /* Request a slot reset. */ |
2085 | return PCI_ERS_RESULT_NEED_RESET; | 2095 | return PCI_ERS_RESULT_NEED_RESET; |
2086 | } | 2096 | } |
@@ -2093,8 +2103,8 @@ static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev, | |||
2093 | */ | 2103 | */ |
2094 | static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev) | 2104 | static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev) |
2095 | { | 2105 | { |
2096 | struct Scsi_Host *host = pci_get_drvdata(pdev); | 2106 | struct Scsi_Host *shost = pci_get_drvdata(pdev); |
2097 | struct lpfc_hba *phba = (struct lpfc_hba *)host->hostdata; | 2107 | struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; |
2098 | struct lpfc_sli *psli = &phba->sli; | 2108 | struct lpfc_sli *psli = &phba->sli; |
2099 | int bars = pci_select_bars(pdev, IORESOURCE_MEM); | 2109 | int bars = pci_select_bars(pdev, IORESOURCE_MEM); |
2100 | 2110 | ||
@@ -2108,9 +2118,9 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev) | |||
2108 | pci_set_master(pdev); | 2118 | pci_set_master(pdev); |
2109 | 2119 | ||
2110 | /* Re-establishing Link */ | 2120 | /* Re-establishing Link */ |
2111 | spin_lock_irq(host->host_lock); | 2121 | spin_lock_irq(shost->host_lock); |
2112 | phba->pport->fc_flag |= FC_ESTABLISH_LINK; | 2122 | phba->pport->fc_flag |= FC_ESTABLISH_LINK; |
2113 | spin_unlock_irq(host->host_lock); | 2123 | spin_unlock_irq(shost->host_lock); |
2114 | 2124 | ||
2115 | spin_lock_irq(&phba->hbalock); | 2125 | spin_lock_irq(&phba->hbalock); |
2116 | psli->sli_flag &= ~LPFC_SLI2_ACTIVE; | 2126 | psli->sli_flag &= ~LPFC_SLI2_ACTIVE; |
@@ -2133,8 +2143,8 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev) | |||
2133 | */ | 2143 | */ |
2134 | static void lpfc_io_resume(struct pci_dev *pdev) | 2144 | static void lpfc_io_resume(struct pci_dev *pdev) |
2135 | { | 2145 | { |
2136 | struct Scsi_Host *host = pci_get_drvdata(pdev); | 2146 | struct Scsi_Host *shost = pci_get_drvdata(pdev); |
2137 | struct lpfc_hba *phba = (struct lpfc_hba *)host->hostdata; | 2147 | struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; |
2138 | 2148 | ||
2139 | if (lpfc_online(phba) == 0) { | 2149 | if (lpfc_online(phba) == 0) { |
2140 | mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60); | 2150 | mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60); |