aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/lpfc/lpfc_els.c
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/scsi/lpfc/lpfc_els.c
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/scsi/lpfc/lpfc_els.c')
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c186
1 files changed, 97 insertions, 89 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;