aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJames Smart <James.Smart@Emulex.Com>2008-08-24 21:49:45 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-10-13 09:28:53 -0400
commit90160e010b6f3a91a9bb044bbe6723731e6f366c (patch)
tree8320400d5bed96f1976cef88adcad647fcb48f9e /drivers
parente59058c44025d71c9b7f260076a932935d3bba95 (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')
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c186
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c8
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c14
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.c74
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 **/
1570static void
1571lpfc_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 **/
1594static void
1595lpfc_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 **/
1601static void
1602lpfc_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 }
1741out: 1751out:
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
4526reject_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 **/
222static 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
207int 278int
208lpfc_vport_create(struct fc_vport *fc_vport, bool disable) 279lpfc_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
605skip_logo: 679skip_logo:
606 lpfc_cleanup(vport); 680 lpfc_cleanup(vport);
607 lpfc_sli_host_down(vport); 681 lpfc_sli_host_down(vport);