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/lpfc/lpfc_els.c | |
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/lpfc/lpfc_els.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 186 |
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 | **/ | ||
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; |