diff options
author | James Smart <James.Smart@Emulex.Com> | 2008-08-24 21:49:45 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-10-13 09:28:53 -0400 |
commit | 90160e010b6f3a91a9bb044bbe6723731e6f366c (patch) | |
tree | 8320400d5bed96f1976cef88adcad647fcb48f9e /drivers/scsi | |
parent | e59058c44025d71c9b7f260076a932935d3bba95 (diff) |
[SCSI] lpfc 8.2.8 : Miscellaneous Discovery Fixes
Miscellaneous Discovery fixes:
- Fix rejection followed by acceptance in handling RPL and RPS
unsolicited events
- Fix for vport delete crash
- Fix PLOGI vs ADISC race condition
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 186 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 8 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nportdisc.c | 14 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_vport.c | 74 |
4 files changed, 172 insertions, 110 deletions
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 43049b9d64c9..2e24b4fe2be5 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c | |||
@@ -1556,6 +1556,83 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
1556 | } | 1556 | } |
1557 | 1557 | ||
1558 | /** | 1558 | /** |
1559 | * lpfc_rscn_disc: Perform rscn discovery for a vport. | ||
1560 | * @vport: pointer to a host virtual N_Port data structure. | ||
1561 | * | ||
1562 | * This routine performs Registration State Change Notification (RSCN) | ||
1563 | * discovery for a @vport. If the @vport's node port recovery count is not | ||
1564 | * zero, it will invoke the lpfc_els_disc_plogi() to perform PLOGI for all | ||
1565 | * the nodes that need recovery. If none of the PLOGI were needed through | ||
1566 | * the lpfc_els_disc_plogi() routine, the lpfc_end_rscn() routine shall be | ||
1567 | * invoked to check and handle possible more RSCN came in during the period | ||
1568 | * of processing the current ones. | ||
1569 | **/ | ||
1570 | static void | ||
1571 | lpfc_rscn_disc(struct lpfc_vport *vport) | ||
1572 | { | ||
1573 | lpfc_can_disctmo(vport); | ||
1574 | |||
1575 | /* RSCN discovery */ | ||
1576 | /* go thru NPR nodes and issue ELS PLOGIs */ | ||
1577 | if (vport->fc_npr_cnt) | ||
1578 | if (lpfc_els_disc_plogi(vport)) | ||
1579 | return; | ||
1580 | |||
1581 | lpfc_end_rscn(vport); | ||
1582 | } | ||
1583 | |||
1584 | /** | ||
1585 | * lpfc_adisc_done: Complete the adisc phase of discovery. | ||
1586 | * @vport: pointer to lpfc_vport hba data structure that finished all ADISCs. | ||
1587 | * | ||
1588 | * This function is called when the final ADISC is completed during discovery. | ||
1589 | * This function handles clearing link attention or issuing reg_vpi depending | ||
1590 | * on whether npiv is enabled. This function also kicks off the PLOGI phase of | ||
1591 | * discovery. | ||
1592 | * This function is called with no locks held. | ||
1593 | **/ | ||
1594 | static void | ||
1595 | lpfc_adisc_done(struct lpfc_vport *vport) | ||
1596 | { | ||
1597 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||
1598 | struct lpfc_hba *phba = vport->phba; | ||
1599 | |||
1600 | /* | ||
1601 | * For NPIV, cmpl_reg_vpi will set port_state to READY, | ||
1602 | * and continue discovery. | ||
1603 | */ | ||
1604 | if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && | ||
1605 | !(vport->fc_flag & FC_RSCN_MODE)) { | ||
1606 | lpfc_issue_reg_vpi(phba, vport); | ||
1607 | return; | ||
1608 | } | ||
1609 | /* | ||
1610 | * For SLI2, we need to set port_state to READY | ||
1611 | * and continue discovery. | ||
1612 | */ | ||
1613 | if (vport->port_state < LPFC_VPORT_READY) { | ||
1614 | /* If we get here, there is nothing to ADISC */ | ||
1615 | if (vport->port_type == LPFC_PHYSICAL_PORT) | ||
1616 | lpfc_issue_clear_la(phba, vport); | ||
1617 | if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) { | ||
1618 | vport->num_disc_nodes = 0; | ||
1619 | /* go thru NPR list, issue ELS PLOGIs */ | ||
1620 | if (vport->fc_npr_cnt) | ||
1621 | lpfc_els_disc_plogi(vport); | ||
1622 | if (!vport->num_disc_nodes) { | ||
1623 | spin_lock_irq(shost->host_lock); | ||
1624 | vport->fc_flag &= ~FC_NDISC_ACTIVE; | ||
1625 | spin_unlock_irq(shost->host_lock); | ||
1626 | lpfc_can_disctmo(vport); | ||
1627 | lpfc_end_rscn(vport); | ||
1628 | } | ||
1629 | } | ||
1630 | vport->port_state = LPFC_VPORT_READY; | ||
1631 | } else | ||
1632 | lpfc_rscn_disc(vport); | ||
1633 | } | ||
1634 | |||
1635 | /** | ||
1559 | * lpfc_more_adisc: Issue more adisc as needed. | 1636 | * lpfc_more_adisc: Issue more adisc as needed. |
1560 | * @vport: pointer to a host virtual N_Port data structure. | 1637 | * @vport: pointer to a host virtual N_Port data structure. |
1561 | * | 1638 | * |
@@ -1583,36 +1660,12 @@ lpfc_more_adisc(struct lpfc_vport *vport) | |||
1583 | /* go thru NPR nodes and issue any remaining ELS ADISCs */ | 1660 | /* go thru NPR nodes and issue any remaining ELS ADISCs */ |
1584 | sentadisc = lpfc_els_disc_adisc(vport); | 1661 | sentadisc = lpfc_els_disc_adisc(vport); |
1585 | } | 1662 | } |
1663 | if (!vport->num_disc_nodes) | ||
1664 | lpfc_adisc_done(vport); | ||
1586 | return; | 1665 | return; |
1587 | } | 1666 | } |
1588 | 1667 | ||
1589 | /** | 1668 | /** |
1590 | * lpfc_rscn_disc: Perform rscn discovery for a vport. | ||
1591 | * @vport: pointer to a host virtual N_Port data structure. | ||
1592 | * | ||
1593 | * This routine performs Registration State Change Notification (RSCN) | ||
1594 | * discovery for a @vport. If the @vport's node port recovery count is not | ||
1595 | * zero, it will invoke the lpfc_els_disc_plogi() to perform PLOGI for all | ||
1596 | * the nodes that need recovery. If none of the PLOGI were needed through | ||
1597 | * the lpfc_els_disc_plogi() routine, the lpfc_end_rscn() routine shall be | ||
1598 | * invoked to check and handle possible more RSCN came in during the period | ||
1599 | * of processing the current ones. | ||
1600 | **/ | ||
1601 | static void | ||
1602 | lpfc_rscn_disc(struct lpfc_vport *vport) | ||
1603 | { | ||
1604 | lpfc_can_disctmo(vport); | ||
1605 | |||
1606 | /* RSCN discovery */ | ||
1607 | /* go thru NPR nodes and issue ELS PLOGIs */ | ||
1608 | if (vport->fc_npr_cnt) | ||
1609 | if (lpfc_els_disc_plogi(vport)) | ||
1610 | return; | ||
1611 | |||
1612 | lpfc_end_rscn(vport); | ||
1613 | } | ||
1614 | |||
1615 | /** | ||
1616 | * lpfc_cmpl_els_adisc: Completion callback function for adisc. | 1669 | * lpfc_cmpl_els_adisc: Completion callback function for adisc. |
1617 | * @phba: pointer to lpfc hba data structure. | 1670 | * @phba: pointer to lpfc hba data structure. |
1618 | * @cmdiocb: pointer to lpfc command iocb data structure. | 1671 | * @cmdiocb: pointer to lpfc command iocb data structure. |
@@ -1692,52 +1745,9 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
1692 | lpfc_disc_state_machine(vport, ndlp, cmdiocb, | 1745 | lpfc_disc_state_machine(vport, ndlp, cmdiocb, |
1693 | NLP_EVT_CMPL_ADISC); | 1746 | NLP_EVT_CMPL_ADISC); |
1694 | 1747 | ||
1695 | if (disc && vport->num_disc_nodes) { | 1748 | /* Check to see if there are more ADISCs to be sent */ |
1696 | /* Check to see if there are more ADISCs to be sent */ | 1749 | if (disc && vport->num_disc_nodes) |
1697 | lpfc_more_adisc(vport); | 1750 | lpfc_more_adisc(vport); |
1698 | |||
1699 | /* Check to see if we are done with ADISC authentication */ | ||
1700 | if (vport->num_disc_nodes == 0) { | ||
1701 | /* If we get here, there is nothing left to ADISC */ | ||
1702 | /* | ||
1703 | * For NPIV, cmpl_reg_vpi will set port_state to READY, | ||
1704 | * and continue discovery. | ||
1705 | */ | ||
1706 | if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && | ||
1707 | !(vport->fc_flag & FC_RSCN_MODE)) { | ||
1708 | lpfc_issue_reg_vpi(phba, vport); | ||
1709 | goto out; | ||
1710 | } | ||
1711 | /* | ||
1712 | * For SLI2, we need to set port_state to READY | ||
1713 | * and continue discovery. | ||
1714 | */ | ||
1715 | if (vport->port_state < LPFC_VPORT_READY) { | ||
1716 | /* If we get here, there is nothing to ADISC */ | ||
1717 | if (vport->port_type == LPFC_PHYSICAL_PORT) | ||
1718 | lpfc_issue_clear_la(phba, vport); | ||
1719 | |||
1720 | if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) { | ||
1721 | vport->num_disc_nodes = 0; | ||
1722 | /* go thru NPR list, issue ELS PLOGIs */ | ||
1723 | if (vport->fc_npr_cnt) | ||
1724 | lpfc_els_disc_plogi(vport); | ||
1725 | |||
1726 | if (!vport->num_disc_nodes) { | ||
1727 | spin_lock_irq(shost->host_lock); | ||
1728 | vport->fc_flag &= | ||
1729 | ~FC_NDISC_ACTIVE; | ||
1730 | spin_unlock_irq( | ||
1731 | shost->host_lock); | ||
1732 | lpfc_can_disctmo(vport); | ||
1733 | } | ||
1734 | } | ||
1735 | vport->port_state = LPFC_VPORT_READY; | ||
1736 | } else { | ||
1737 | lpfc_rscn_disc(vport); | ||
1738 | } | ||
1739 | } | ||
1740 | } | ||
1741 | out: | 1751 | out: |
1742 | lpfc_els_free_iocb(phba, cmdiocb); | 1752 | lpfc_els_free_iocb(phba, cmdiocb); |
1743 | return; | 1753 | return; |
@@ -2258,19 +2268,16 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) | |||
2258 | if (vport->port_state < LPFC_VPORT_READY) { | 2268 | if (vport->port_state < LPFC_VPORT_READY) { |
2259 | /* Check if there are more ADISCs to be sent */ | 2269 | /* Check if there are more ADISCs to be sent */ |
2260 | lpfc_more_adisc(vport); | 2270 | lpfc_more_adisc(vport); |
2261 | if ((vport->num_disc_nodes == 0) && | ||
2262 | (vport->fc_npr_cnt)) | ||
2263 | lpfc_els_disc_plogi(vport); | ||
2264 | } else { | 2271 | } else { |
2265 | /* Check if there are more PLOGIs to be sent */ | 2272 | /* Check if there are more PLOGIs to be sent */ |
2266 | lpfc_more_plogi(vport); | 2273 | lpfc_more_plogi(vport); |
2267 | } | 2274 | if (vport->num_disc_nodes == 0) { |
2268 | if (vport->num_disc_nodes == 0) { | 2275 | spin_lock_irq(shost->host_lock); |
2269 | spin_lock_irq(shost->host_lock); | 2276 | vport->fc_flag &= ~FC_NDISC_ACTIVE; |
2270 | vport->fc_flag &= ~FC_NDISC_ACTIVE; | 2277 | spin_unlock_irq(shost->host_lock); |
2271 | spin_unlock_irq(shost->host_lock); | 2278 | lpfc_can_disctmo(vport); |
2272 | lpfc_can_disctmo(vport); | 2279 | lpfc_end_rscn(vport); |
2273 | lpfc_end_rscn(vport); | 2280 | } |
2274 | } | 2281 | } |
2275 | } | 2282 | } |
2276 | } | 2283 | } |
@@ -4480,14 +4487,9 @@ lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | |||
4480 | struct ls_rjt stat; | 4487 | struct ls_rjt stat; |
4481 | 4488 | ||
4482 | if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && | 4489 | if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && |
4483 | (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) { | 4490 | (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) |
4484 | stat.un.b.lsRjtRsvd0 = 0; | 4491 | /* reject the unsolicited RPS request and done with it */ |
4485 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; | 4492 | goto reject_out; |
4486 | stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; | ||
4487 | stat.un.b.vendorUnique = 0; | ||
4488 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, | ||
4489 | NULL); | ||
4490 | } | ||
4491 | 4493 | ||
4492 | pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; | 4494 | pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; |
4493 | lp = (uint32_t *) pcmd->virt; | 4495 | lp = (uint32_t *) pcmd->virt; |
@@ -4520,6 +4522,9 @@ lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | |||
4520 | mempool_free(mbox, phba->mbox_mem_pool); | 4522 | mempool_free(mbox, phba->mbox_mem_pool); |
4521 | } | 4523 | } |
4522 | } | 4524 | } |
4525 | |||
4526 | reject_out: | ||
4527 | /* issue rejection response */ | ||
4523 | stat.un.b.lsRjtRsvd0 = 0; | 4528 | stat.un.b.lsRjtRsvd0 = 0; |
4524 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; | 4529 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; |
4525 | stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; | 4530 | stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; |
@@ -4629,12 +4634,15 @@ lpfc_els_rcv_rpl(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | |||
4629 | 4634 | ||
4630 | if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && | 4635 | if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && |
4631 | (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) { | 4636 | (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) { |
4637 | /* issue rejection response */ | ||
4632 | stat.un.b.lsRjtRsvd0 = 0; | 4638 | stat.un.b.lsRjtRsvd0 = 0; |
4633 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; | 4639 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; |
4634 | stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; | 4640 | stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; |
4635 | stat.un.b.vendorUnique = 0; | 4641 | stat.un.b.vendorUnique = 0; |
4636 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, | 4642 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, |
4637 | NULL); | 4643 | NULL); |
4644 | /* rejected the unsolicited RPL request and done with it */ | ||
4645 | return 0; | ||
4638 | } | 4646 | } |
4639 | 4647 | ||
4640 | pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; | 4648 | pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; |
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index b9d553c2ac4d..93fd09daca87 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
@@ -1580,14 +1580,6 @@ lpfc_cleanup(struct lpfc_vport *vport) | |||
1580 | lpfc_disc_state_machine(vport, ndlp, NULL, | 1580 | lpfc_disc_state_machine(vport, ndlp, NULL, |
1581 | NLP_EVT_DEVICE_RM); | 1581 | NLP_EVT_DEVICE_RM); |
1582 | 1582 | ||
1583 | /* nlp_type zero is not defined, nlp_flag zero also not defined, | ||
1584 | * nlp_state is unused, this happens when | ||
1585 | * an initiator has logged | ||
1586 | * into us so cleanup this ndlp. | ||
1587 | */ | ||
1588 | if ((ndlp->nlp_type == 0) && (ndlp->nlp_flag == 0) && | ||
1589 | (ndlp->nlp_state == 0)) | ||
1590 | lpfc_nlp_put(ndlp); | ||
1591 | } | 1583 | } |
1592 | 1584 | ||
1593 | /* At this point, ALL ndlp's should be gone | 1585 | /* At this point, ALL ndlp's should be gone |
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 6688a8689b56..705c4ae1bdc3 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c | |||
@@ -1003,20 +1003,8 @@ lpfc_rcv_plogi_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
1003 | spin_lock_irq(shost->host_lock); | 1003 | spin_lock_irq(shost->host_lock); |
1004 | ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; | 1004 | ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; |
1005 | spin_unlock_irq(shost->host_lock); | 1005 | spin_unlock_irq(shost->host_lock); |
1006 | 1006 | if (vport->num_disc_nodes) | |
1007 | if (vport->num_disc_nodes) { | ||
1008 | lpfc_more_adisc(vport); | 1007 | lpfc_more_adisc(vport); |
1009 | if ((vport->num_disc_nodes == 0) && | ||
1010 | (vport->fc_npr_cnt)) | ||
1011 | lpfc_els_disc_plogi(vport); | ||
1012 | if (vport->num_disc_nodes == 0) { | ||
1013 | spin_lock_irq(shost->host_lock); | ||
1014 | vport->fc_flag &= ~FC_NDISC_ACTIVE; | ||
1015 | spin_unlock_irq(shost->host_lock); | ||
1016 | lpfc_can_disctmo(vport); | ||
1017 | lpfc_end_rscn(vport); | ||
1018 | } | ||
1019 | } | ||
1020 | } | 1008 | } |
1021 | return ndlp->nlp_state; | 1009 | return ndlp->nlp_state; |
1022 | } | 1010 | } |
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index 109f89d98830..ad0f65313878 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c | |||
@@ -204,6 +204,77 @@ lpfc_unique_wwpn(struct lpfc_hba *phba, struct lpfc_vport *new_vport) | |||
204 | return 1; | 204 | return 1; |
205 | } | 205 | } |
206 | 206 | ||
207 | /** | ||
208 | * lpfc_discovery_wait: Wait for driver discovery to quiesce. | ||
209 | * @vport: The virtual port for which this call is being executed. | ||
210 | * | ||
211 | * This driver calls this routine specifically from lpfc_vport_delete | ||
212 | * to enforce a synchronous execution of vport | ||
213 | * delete relative to discovery activities. The | ||
214 | * lpfc_vport_delete routine should not return until it | ||
215 | * can reasonably guarantee that discovery has quiesced. | ||
216 | * Post FDISC LOGO, the driver must wait until its SAN teardown is | ||
217 | * complete and all resources recovered before allowing | ||
218 | * cleanup. | ||
219 | * | ||
220 | * This routine does not require any locks held. | ||
221 | **/ | ||
222 | static void lpfc_discovery_wait(struct lpfc_vport *vport) | ||
223 | { | ||
224 | struct lpfc_hba *phba = vport->phba; | ||
225 | uint32_t wait_flags = 0; | ||
226 | unsigned long wait_time_max; | ||
227 | unsigned long start_time; | ||
228 | |||
229 | wait_flags = FC_RSCN_MODE | FC_RSCN_DISCOVERY | FC_NLP_MORE | | ||
230 | FC_RSCN_DEFERRED | FC_NDISC_ACTIVE | FC_DISC_TMO; | ||
231 | |||
232 | /* | ||
233 | * The time constraint on this loop is a balance between the | ||
234 | * fabric RA_TOV value and dev_loss tmo. The driver's | ||
235 | * devloss_tmo is 10 giving this loop a 3x multiplier minimally. | ||
236 | */ | ||
237 | wait_time_max = msecs_to_jiffies(((phba->fc_ratov * 3) + 3) * 1000); | ||
238 | wait_time_max += jiffies; | ||
239 | start_time = jiffies; | ||
240 | while (time_before(jiffies, wait_time_max)) { | ||
241 | if ((vport->num_disc_nodes > 0) || | ||
242 | (vport->fc_flag & wait_flags) || | ||
243 | ((vport->port_state > LPFC_VPORT_FAILED) && | ||
244 | (vport->port_state < LPFC_VPORT_READY))) { | ||
245 | lpfc_printf_log(phba, KERN_INFO, LOG_VPORT, | ||
246 | "1833 Vport discovery quiesce Wait:" | ||
247 | " vpi x%x state x%x fc_flags x%x" | ||
248 | " num_nodes x%x, waiting 1000 msecs" | ||
249 | " total wait msecs x%x\n", | ||
250 | vport->vpi, vport->port_state, | ||
251 | vport->fc_flag, vport->num_disc_nodes, | ||
252 | jiffies_to_msecs(jiffies - start_time)); | ||
253 | msleep(1000); | ||
254 | } else { | ||
255 | /* Base case. Wait variants satisfied. Break out */ | ||
256 | lpfc_printf_log(phba, KERN_INFO, LOG_VPORT, | ||
257 | "1834 Vport discovery quiesced:" | ||
258 | " vpi x%x state x%x fc_flags x%x" | ||
259 | " wait msecs x%x\n", | ||
260 | vport->vpi, vport->port_state, | ||
261 | vport->fc_flag, | ||
262 | jiffies_to_msecs(jiffies | ||
263 | - start_time)); | ||
264 | break; | ||
265 | } | ||
266 | } | ||
267 | |||
268 | if (time_after(jiffies, wait_time_max)) | ||
269 | lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, | ||
270 | "1835 Vport discovery quiesce failed:" | ||
271 | " vpi x%x state x%x fc_flags x%x" | ||
272 | " wait msecs x%x\n", | ||
273 | vport->vpi, vport->port_state, | ||
274 | vport->fc_flag, | ||
275 | jiffies_to_msecs(jiffies - start_time)); | ||
276 | } | ||
277 | |||
207 | int | 278 | int |
208 | lpfc_vport_create(struct fc_vport *fc_vport, bool disable) | 279 | lpfc_vport_create(struct fc_vport *fc_vport, bool disable) |
209 | { | 280 | { |
@@ -602,6 +673,9 @@ lpfc_vport_delete(struct fc_vport *fc_vport) | |||
602 | timeout = schedule_timeout(timeout); | 673 | timeout = schedule_timeout(timeout); |
603 | } | 674 | } |
604 | 675 | ||
676 | if (!(phba->pport->load_flag & FC_UNLOADING)) | ||
677 | lpfc_discovery_wait(vport); | ||
678 | |||
605 | skip_logo: | 679 | skip_logo: |
606 | lpfc_cleanup(vport); | 680 | lpfc_cleanup(vport); |
607 | lpfc_sli_host_down(vport); | 681 | lpfc_sli_host_down(vport); |