diff options
author | James Smart <James.Smart@Emulex.Com> | 2007-10-27 13:37:43 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-01-11 19:22:33 -0500 |
commit | 87af33fe5f78c27cf9e43c6e586dd6efd4be3e40 (patch) | |
tree | e9960c6e95ed599672d5dcec0d3c4e428ae42799 /drivers/scsi/lpfc/lpfc_els.c | |
parent | 98c9ea5c026ee47efe2a0f595078dbf199d08f50 (diff) |
[SCSI] lpfc 8.2.3 : FC Discovery Fixes
FC Discovery Fixes:
- Fix up lpfc_drop_node() vs lpfc_nlp_not_used() usage
- Clear ADISC flag when unregistering RPI and REMOVE ndlps if in recovery.
- Fix usage of UNUSED list and ndlps
- Fix PLOGI race conditions
- Reset link if NameServer PLOGI errors occur
- Synchronize GID_FT queries with PLOGI receptions
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 | 231 |
1 files changed, 123 insertions, 108 deletions
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 813eeca7ce1e..0a5006ea9909 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c | |||
@@ -575,8 +575,13 @@ flogifail: | |||
575 | 575 | ||
576 | /* Start discovery */ | 576 | /* Start discovery */ |
577 | lpfc_disc_start(vport); | 577 | lpfc_disc_start(vport); |
578 | } else if (((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) || | ||
579 | ((irsp->un.ulpWord[4] != IOERR_SLI_ABORTED) && | ||
580 | (irsp->un.ulpWord[4] != IOERR_SLI_DOWN))) && | ||
581 | (phba->link_state != LPFC_CLEAR_LA)) { | ||
582 | /* If FLOGI failed enable link interrupt. */ | ||
583 | lpfc_issue_clear_la(phba, vport); | ||
578 | } | 584 | } |
579 | |||
580 | out: | 585 | out: |
581 | lpfc_els_free_iocb(phba, cmdiocb); | 586 | lpfc_els_free_iocb(phba, cmdiocb); |
582 | } | 587 | } |
@@ -711,13 +716,8 @@ lpfc_initial_flogi(struct lpfc_vport *vport) | |||
711 | lpfc_nlp_init(vport, ndlp, Fabric_DID); | 716 | lpfc_nlp_init(vport, ndlp, Fabric_DID); |
712 | } else { | 717 | } else { |
713 | lpfc_dequeue_node(vport, ndlp); | 718 | lpfc_dequeue_node(vport, ndlp); |
714 | |||
715 | /* If we go thru this path, Fabric_DID ndlp is in the process | ||
716 | * of being removed. We need to bump the reference count by 1 | ||
717 | * so it stays around all through this link up period. | ||
718 | */ | ||
719 | lpfc_nlp_get(ndlp); | ||
720 | } | 719 | } |
720 | |||
721 | if (lpfc_issue_els_flogi(vport, ndlp, 0)) { | 721 | if (lpfc_issue_els_flogi(vport, ndlp, 0)) { |
722 | lpfc_nlp_put(ndlp); | 722 | lpfc_nlp_put(ndlp); |
723 | } | 723 | } |
@@ -746,7 +746,8 @@ lpfc_initial_fdisc(struct lpfc_vport *vport) | |||
746 | } | 746 | } |
747 | return 1; | 747 | return 1; |
748 | } | 748 | } |
749 | static void | 749 | |
750 | void | ||
750 | lpfc_more_plogi(struct lpfc_vport *vport) | 751 | lpfc_more_plogi(struct lpfc_vport *vport) |
751 | { | 752 | { |
752 | int sentplogi; | 753 | int sentplogi; |
@@ -813,8 +814,12 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, | |||
813 | lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state); | 814 | lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state); |
814 | 815 | ||
815 | /* Move this back to NPR state */ | 816 | /* Move this back to NPR state */ |
816 | if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) | 817 | if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) { |
818 | /* The new_ndlp is replacing ndlp totally, so we need | ||
819 | * to put ndlp on UNUSED list and try to free it. | ||
820 | */ | ||
817 | lpfc_drop_node(vport, ndlp); | 821 | lpfc_drop_node(vport, ndlp); |
822 | } | ||
818 | else { | 823 | else { |
819 | lpfc_unreg_rpi(vport, ndlp); | 824 | lpfc_unreg_rpi(vport, ndlp); |
820 | ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */ | 825 | ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */ |
@@ -823,6 +828,27 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, | |||
823 | return new_ndlp; | 828 | return new_ndlp; |
824 | } | 829 | } |
825 | 830 | ||
831 | void | ||
832 | lpfc_end_rscn(struct lpfc_vport *vport) | ||
833 | { | ||
834 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||
835 | |||
836 | if (vport->fc_flag & FC_RSCN_MODE) { | ||
837 | /* | ||
838 | * Check to see if more RSCNs came in while we were | ||
839 | * processing this one. | ||
840 | */ | ||
841 | if (vport->fc_rscn_id_cnt || | ||
842 | (vport->fc_flag & FC_RSCN_DISCOVERY) != 0) | ||
843 | lpfc_els_handle_rscn(vport); | ||
844 | else { | ||
845 | spin_lock_irq(shost->host_lock); | ||
846 | vport->fc_flag &= ~FC_RSCN_MODE; | ||
847 | spin_unlock_irq(shost->host_lock); | ||
848 | } | ||
849 | } | ||
850 | } | ||
851 | |||
826 | static void | 852 | static void |
827 | lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | 853 | lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, |
828 | struct lpfc_iocbq *rspiocb) | 854 | struct lpfc_iocbq *rspiocb) |
@@ -893,13 +919,6 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
893 | goto out; | 919 | goto out; |
894 | } | 920 | } |
895 | /* PLOGI failed */ | 921 | /* PLOGI failed */ |
896 | if (ndlp->nlp_DID == NameServer_DID) { | ||
897 | lpfc_vport_set_state(vport, FC_VPORT_FAILED); | ||
898 | lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, | ||
899 | "0250 Nameserver login error: " | ||
900 | "0x%x / 0x%x\n", | ||
901 | irsp->ulpStatus, irsp->un.ulpWord[4]); | ||
902 | } | ||
903 | /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ | 922 | /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ |
904 | if (lpfc_error_lost_link(irsp)) { | 923 | if (lpfc_error_lost_link(irsp)) { |
905 | rc = NLP_STE_FREED_NODE; | 924 | rc = NLP_STE_FREED_NODE; |
@@ -927,20 +946,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
927 | spin_unlock_irq(shost->host_lock); | 946 | spin_unlock_irq(shost->host_lock); |
928 | 947 | ||
929 | lpfc_can_disctmo(vport); | 948 | lpfc_can_disctmo(vport); |
930 | if (vport->fc_flag & FC_RSCN_MODE) { | 949 | lpfc_end_rscn(vport); |
931 | /* | ||
932 | * Check to see if more RSCNs came in while | ||
933 | * we were processing this one. | ||
934 | */ | ||
935 | if ((vport->fc_rscn_id_cnt == 0) && | ||
936 | (!(vport->fc_flag & FC_RSCN_DISCOVERY))) { | ||
937 | spin_lock_irq(shost->host_lock); | ||
938 | vport->fc_flag &= ~FC_RSCN_MODE; | ||
939 | spin_unlock_irq(shost->host_lock); | ||
940 | } else { | ||
941 | lpfc_els_handle_rscn(vport); | ||
942 | } | ||
943 | } | ||
944 | } | 950 | } |
945 | } | 951 | } |
946 | 952 | ||
@@ -1160,8 +1166,6 @@ lpfc_more_adisc(struct lpfc_vport *vport) | |||
1160 | static void | 1166 | static void |
1161 | lpfc_rscn_disc(struct lpfc_vport *vport) | 1167 | lpfc_rscn_disc(struct lpfc_vport *vport) |
1162 | { | 1168 | { |
1163 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||
1164 | |||
1165 | lpfc_can_disctmo(vport); | 1169 | lpfc_can_disctmo(vport); |
1166 | 1170 | ||
1167 | /* RSCN discovery */ | 1171 | /* RSCN discovery */ |
@@ -1170,19 +1174,7 @@ lpfc_rscn_disc(struct lpfc_vport *vport) | |||
1170 | if (lpfc_els_disc_plogi(vport)) | 1174 | if (lpfc_els_disc_plogi(vport)) |
1171 | return; | 1175 | return; |
1172 | 1176 | ||
1173 | if (vport->fc_flag & FC_RSCN_MODE) { | 1177 | lpfc_end_rscn(vport); |
1174 | /* Check to see if more RSCNs came in while we were | ||
1175 | * processing this one. | ||
1176 | */ | ||
1177 | if ((vport->fc_rscn_id_cnt == 0) && | ||
1178 | (!(vport->fc_flag & FC_RSCN_DISCOVERY))) { | ||
1179 | spin_lock_irq(shost->host_lock); | ||
1180 | vport->fc_flag &= ~FC_RSCN_MODE; | ||
1181 | spin_unlock_irq(shost->host_lock); | ||
1182 | } else { | ||
1183 | lpfc_els_handle_rscn(vport); | ||
1184 | } | ||
1185 | } | ||
1186 | } | 1178 | } |
1187 | 1179 | ||
1188 | static void | 1180 | static void |
@@ -1632,27 +1624,6 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) | |||
1632 | return 0; | 1624 | return 0; |
1633 | } | 1625 | } |
1634 | 1626 | ||
1635 | static void | ||
1636 | lpfc_end_rscn(struct lpfc_vport *vport) | ||
1637 | { | ||
1638 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||
1639 | |||
1640 | if (vport->fc_flag & FC_RSCN_MODE) { | ||
1641 | /* | ||
1642 | * Check to see if more RSCNs came in while we were | ||
1643 | * processing this one. | ||
1644 | */ | ||
1645 | if (vport->fc_rscn_id_cnt || | ||
1646 | (vport->fc_flag & FC_RSCN_DISCOVERY) != 0) | ||
1647 | lpfc_els_handle_rscn(vport); | ||
1648 | else { | ||
1649 | spin_lock_irq(shost->host_lock); | ||
1650 | vport->fc_flag &= ~FC_RSCN_MODE; | ||
1651 | spin_unlock_irq(shost->host_lock); | ||
1652 | } | ||
1653 | } | ||
1654 | } | ||
1655 | |||
1656 | void | 1627 | void |
1657 | lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) | 1628 | lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) |
1658 | { | 1629 | { |
@@ -2069,6 +2040,32 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
2069 | } | 2040 | } |
2070 | 2041 | ||
2071 | int | 2042 | int |
2043 | lpfc_els_free_data(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr1) | ||
2044 | { | ||
2045 | struct lpfc_dmabuf *buf_ptr; | ||
2046 | |||
2047 | /* Free the response before processing the command. */ | ||
2048 | if (!list_empty(&buf_ptr1->list)) { | ||
2049 | list_remove_head(&buf_ptr1->list, buf_ptr, | ||
2050 | struct lpfc_dmabuf, | ||
2051 | list); | ||
2052 | lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); | ||
2053 | kfree(buf_ptr); | ||
2054 | } | ||
2055 | lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys); | ||
2056 | kfree(buf_ptr1); | ||
2057 | return 0; | ||
2058 | } | ||
2059 | |||
2060 | int | ||
2061 | lpfc_els_free_bpl(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr) | ||
2062 | { | ||
2063 | lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); | ||
2064 | kfree(buf_ptr); | ||
2065 | return 0; | ||
2066 | } | ||
2067 | |||
2068 | int | ||
2072 | lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb) | 2069 | lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb) |
2073 | { | 2070 | { |
2074 | struct lpfc_dmabuf *buf_ptr, *buf_ptr1; | 2071 | struct lpfc_dmabuf *buf_ptr, *buf_ptr1; |
@@ -2080,22 +2077,12 @@ lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb) | |||
2080 | /* context2 = cmd, context2->next = rsp, context3 = bpl */ | 2077 | /* context2 = cmd, context2->next = rsp, context3 = bpl */ |
2081 | if (elsiocb->context2) { | 2078 | if (elsiocb->context2) { |
2082 | buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2; | 2079 | buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2; |
2083 | /* Free the response before processing the command. */ | 2080 | lpfc_els_free_data(phba, buf_ptr1); |
2084 | if (!list_empty(&buf_ptr1->list)) { | ||
2085 | list_remove_head(&buf_ptr1->list, buf_ptr, | ||
2086 | struct lpfc_dmabuf, | ||
2087 | list); | ||
2088 | lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); | ||
2089 | kfree(buf_ptr); | ||
2090 | } | ||
2091 | lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys); | ||
2092 | kfree(buf_ptr1); | ||
2093 | } | 2081 | } |
2094 | 2082 | ||
2095 | if (elsiocb->context3) { | 2083 | if (elsiocb->context3) { |
2096 | buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3; | 2084 | buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3; |
2097 | lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); | 2085 | lpfc_els_free_bpl(phba, buf_ptr); |
2098 | kfree(buf_ptr); | ||
2099 | } | 2086 | } |
2100 | lpfc_sli_release_iocbq(phba, elsiocb); | 2087 | lpfc_sli_release_iocbq(phba, elsiocb); |
2101 | return 0; | 2088 | return 0; |
@@ -2119,15 +2106,15 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
2119 | "Data: x%x x%x x%x\n", | 2106 | "Data: x%x x%x x%x\n", |
2120 | ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, | 2107 | ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, |
2121 | ndlp->nlp_rpi); | 2108 | ndlp->nlp_rpi); |
2122 | switch (ndlp->nlp_state) { | 2109 | |
2123 | case NLP_STE_UNUSED_NODE: /* node is just allocated */ | 2110 | if (ndlp->nlp_state == NLP_STE_NPR_NODE) { |
2124 | lpfc_drop_node(vport, ndlp); | 2111 | /* NPort Recovery mode or node is just allocated */ |
2125 | break; | 2112 | if (!lpfc_nlp_not_used(ndlp)) { |
2126 | case NLP_STE_NPR_NODE: /* NPort Recovery mode */ | 2113 | /* If the ndlp is being used by another discovery |
2127 | lpfc_unreg_rpi(vport, ndlp); | 2114 | * thread, just unregister the RPI. |
2128 | break; | 2115 | */ |
2129 | default: | 2116 | lpfc_unreg_rpi(vport, ndlp); |
2130 | break; | 2117 | } |
2131 | } | 2118 | } |
2132 | lpfc_els_free_iocb(phba, cmdiocb); | 2119 | lpfc_els_free_iocb(phba, cmdiocb); |
2133 | return; | 2120 | return; |
@@ -2160,15 +2147,27 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
2160 | struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1; | 2147 | struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1; |
2161 | struct lpfc_vport *vport = ndlp ? ndlp->vport : NULL; | 2148 | struct lpfc_vport *vport = ndlp ? ndlp->vport : NULL; |
2162 | struct Scsi_Host *shost = vport ? lpfc_shost_from_vport(vport) : NULL; | 2149 | struct Scsi_Host *shost = vport ? lpfc_shost_from_vport(vport) : NULL; |
2163 | IOCB_t *irsp; | 2150 | IOCB_t *irsp; |
2151 | uint8_t *pcmd; | ||
2164 | LPFC_MBOXQ_t *mbox = NULL; | 2152 | LPFC_MBOXQ_t *mbox = NULL; |
2165 | struct lpfc_dmabuf *mp = NULL; | 2153 | struct lpfc_dmabuf *mp = NULL; |
2154 | uint32_t ls_rjt = 0; | ||
2166 | 2155 | ||
2167 | irsp = &rspiocb->iocb; | 2156 | irsp = &rspiocb->iocb; |
2168 | 2157 | ||
2169 | if (cmdiocb->context_un.mbox) | 2158 | if (cmdiocb->context_un.mbox) |
2170 | mbox = cmdiocb->context_un.mbox; | 2159 | mbox = cmdiocb->context_un.mbox; |
2171 | 2160 | ||
2161 | /* First determine if this is a LS_RJT cmpl */ | ||
2162 | pcmd = (uint8_t *) (((struct lpfc_dmabuf *) cmdiocb->context2)->virt); | ||
2163 | if (*((uint32_t *) (pcmd)) == ELS_CMD_LS_RJT) { | ||
2164 | /* A LS_RJT associated with Default RPI cleanup | ||
2165 | * has its own seperate code path. | ||
2166 | */ | ||
2167 | if (!(ndlp->nlp_flag & NLP_RM_DFLT_RPI)) | ||
2168 | ls_rjt = 1; | ||
2169 | } | ||
2170 | |||
2172 | /* Check to see if link went down during discovery */ | 2171 | /* Check to see if link went down during discovery */ |
2173 | if (!ndlp || lpfc_els_chk_latt(vport)) { | 2172 | if (!ndlp || lpfc_els_chk_latt(vport)) { |
2174 | if (mbox) { | 2173 | if (mbox) { |
@@ -2247,7 +2246,16 @@ out: | |||
2247 | spin_lock_irq(shost->host_lock); | 2246 | spin_lock_irq(shost->host_lock); |
2248 | ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI); | 2247 | ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI); |
2249 | spin_unlock_irq(shost->host_lock); | 2248 | spin_unlock_irq(shost->host_lock); |
2249 | |||
2250 | /* If the node is not being used by another discovery thread, | ||
2251 | * and we are sending a reject, we are done with it. | ||
2252 | * Release driver reference count here and free associated | ||
2253 | * resources. | ||
2254 | */ | ||
2255 | if (ls_rjt) | ||
2256 | lpfc_nlp_not_used(ndlp); | ||
2250 | } | 2257 | } |
2258 | |||
2251 | lpfc_els_free_iocb(phba, cmdiocb); | 2259 | lpfc_els_free_iocb(phba, cmdiocb); |
2252 | return; | 2260 | return; |
2253 | } | 2261 | } |
@@ -2418,18 +2426,6 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError, | |||
2418 | elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; | 2426 | elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; |
2419 | rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0); | 2427 | rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0); |
2420 | 2428 | ||
2421 | /* If the node is in the UNUSED state, and we are sending | ||
2422 | * a reject, we are done with it. Release driver reference | ||
2423 | * count here. The outstanding els will release its reference on | ||
2424 | * completion, as long as the ndlp stays in the UNUSED list, | ||
2425 | * and the node can be freed then. | ||
2426 | */ | ||
2427 | if ((ndlp->nlp_state == NLP_STE_UNUSED_NODE) && | ||
2428 | !(ndlp->nlp_flag & NLP_DELAYED_RM)) { | ||
2429 | ndlp->nlp_flag |= NLP_DELAYED_RM; | ||
2430 | lpfc_nlp_put(ndlp); | ||
2431 | } | ||
2432 | |||
2433 | if (rc == IOCB_ERROR) { | 2429 | if (rc == IOCB_ERROR) { |
2434 | lpfc_els_free_iocb(phba, elsiocb); | 2430 | lpfc_els_free_iocb(phba, elsiocb); |
2435 | return 1; | 2431 | return 1; |
@@ -2715,7 +2711,10 @@ lpfc_els_disc_plogi(struct lpfc_vport *vport) | |||
2715 | } | 2711 | } |
2716 | } | 2712 | } |
2717 | } | 2713 | } |
2718 | if (sentplogi == 0) { | 2714 | if (sentplogi) { |
2715 | lpfc_set_disctmo(vport); | ||
2716 | } | ||
2717 | else { | ||
2719 | spin_lock_irq(shost->host_lock); | 2718 | spin_lock_irq(shost->host_lock); |
2720 | vport->fc_flag &= ~FC_NLP_MORE; | 2719 | vport->fc_flag &= ~FC_NLP_MORE; |
2721 | spin_unlock_irq(shost->host_lock); | 2720 | spin_unlock_irq(shost->host_lock); |
@@ -3533,6 +3532,7 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | |||
3533 | * other NLP_FABRIC logins | 3532 | * other NLP_FABRIC logins |
3534 | */ | 3533 | */ |
3535 | lpfc_drop_node(vport, ndlp); | 3534 | lpfc_drop_node(vport, ndlp); |
3535 | |||
3536 | } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { | 3536 | } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { |
3537 | /* Fail outstanding I/O now since this | 3537 | /* Fail outstanding I/O now since this |
3538 | * device is marked for PLOGI | 3538 | * device is marked for PLOGI |
@@ -3781,6 +3781,7 @@ static void | |||
3781 | lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | 3781 | lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, |
3782 | struct lpfc_vport *vport, struct lpfc_iocbq *elsiocb) | 3782 | struct lpfc_vport *vport, struct lpfc_iocbq *elsiocb) |
3783 | { | 3783 | { |
3784 | struct Scsi_Host *shost; | ||
3784 | struct lpfc_nodelist *ndlp; | 3785 | struct lpfc_nodelist *ndlp; |
3785 | struct ls_rjt stat; | 3786 | struct ls_rjt stat; |
3786 | uint32_t *payload; | 3787 | uint32_t *payload; |
@@ -3826,6 +3827,14 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
3826 | ndlp->nlp_type |= NLP_FABRIC; | 3827 | ndlp->nlp_type |= NLP_FABRIC; |
3827 | } | 3828 | } |
3828 | } | 3829 | } |
3830 | else { | ||
3831 | if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) { | ||
3832 | /* This is simular to the new node path */ | ||
3833 | lpfc_nlp_get(ndlp); | ||
3834 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); | ||
3835 | newnode = 1; | ||
3836 | } | ||
3837 | } | ||
3829 | 3838 | ||
3830 | phba->fc_stat.elsRcvFrame++; | 3839 | phba->fc_stat.elsRcvFrame++; |
3831 | if (elsiocb->context1) | 3840 | if (elsiocb->context1) |
@@ -3853,6 +3862,12 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
3853 | rjt_err = LSRJT_UNABLE_TPC; | 3862 | rjt_err = LSRJT_UNABLE_TPC; |
3854 | break; | 3863 | break; |
3855 | } | 3864 | } |
3865 | |||
3866 | shost = lpfc_shost_from_vport(vport); | ||
3867 | spin_lock_irq(shost->host_lock); | ||
3868 | ndlp->nlp_flag &= ~NLP_TARGET_REMOVE; | ||
3869 | spin_unlock_irq(shost->host_lock); | ||
3870 | |||
3856 | lpfc_disc_state_machine(vport, ndlp, elsiocb, | 3871 | lpfc_disc_state_machine(vport, ndlp, elsiocb, |
3857 | NLP_EVT_RCV_PLOGI); | 3872 | NLP_EVT_RCV_PLOGI); |
3858 | 3873 | ||
@@ -3864,7 +3879,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
3864 | 3879 | ||
3865 | phba->fc_stat.elsRcvFLOGI++; | 3880 | phba->fc_stat.elsRcvFLOGI++; |
3866 | lpfc_els_rcv_flogi(vport, elsiocb, ndlp); | 3881 | lpfc_els_rcv_flogi(vport, elsiocb, ndlp); |
3867 | if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM))) | 3882 | if (newnode) |
3868 | lpfc_nlp_put(ndlp); | 3883 | lpfc_nlp_put(ndlp); |
3869 | break; | 3884 | break; |
3870 | case ELS_CMD_LOGO: | 3885 | case ELS_CMD_LOGO: |
@@ -3894,7 +3909,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
3894 | case ELS_CMD_RSCN: | 3909 | case ELS_CMD_RSCN: |
3895 | phba->fc_stat.elsRcvRSCN++; | 3910 | phba->fc_stat.elsRcvRSCN++; |
3896 | lpfc_els_rcv_rscn(vport, elsiocb, ndlp); | 3911 | lpfc_els_rcv_rscn(vport, elsiocb, ndlp); |
3897 | if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM))) | 3912 | if (newnode) |
3898 | lpfc_nlp_put(ndlp); | 3913 | lpfc_nlp_put(ndlp); |
3899 | break; | 3914 | break; |
3900 | case ELS_CMD_ADISC: | 3915 | case ELS_CMD_ADISC: |
@@ -3966,7 +3981,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
3966 | 3981 | ||
3967 | phba->fc_stat.elsRcvLIRR++; | 3982 | phba->fc_stat.elsRcvLIRR++; |
3968 | lpfc_els_rcv_lirr(vport, elsiocb, ndlp); | 3983 | lpfc_els_rcv_lirr(vport, elsiocb, ndlp); |
3969 | if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM))) | 3984 | if (newnode) |
3970 | lpfc_nlp_put(ndlp); | 3985 | lpfc_nlp_put(ndlp); |
3971 | break; | 3986 | break; |
3972 | case ELS_CMD_RPS: | 3987 | case ELS_CMD_RPS: |
@@ -3976,7 +3991,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
3976 | 3991 | ||
3977 | phba->fc_stat.elsRcvRPS++; | 3992 | phba->fc_stat.elsRcvRPS++; |
3978 | lpfc_els_rcv_rps(vport, elsiocb, ndlp); | 3993 | lpfc_els_rcv_rps(vport, elsiocb, ndlp); |
3979 | if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM))) | 3994 | if (newnode) |
3980 | lpfc_nlp_put(ndlp); | 3995 | lpfc_nlp_put(ndlp); |
3981 | break; | 3996 | break; |
3982 | case ELS_CMD_RPL: | 3997 | case ELS_CMD_RPL: |
@@ -3986,7 +4001,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
3986 | 4001 | ||
3987 | phba->fc_stat.elsRcvRPL++; | 4002 | phba->fc_stat.elsRcvRPL++; |
3988 | lpfc_els_rcv_rpl(vport, elsiocb, ndlp); | 4003 | lpfc_els_rcv_rpl(vport, elsiocb, ndlp); |
3989 | if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM))) | 4004 | if (newnode) |
3990 | lpfc_nlp_put(ndlp); | 4005 | lpfc_nlp_put(ndlp); |
3991 | break; | 4006 | break; |
3992 | case ELS_CMD_RNID: | 4007 | case ELS_CMD_RNID: |
@@ -3996,7 +4011,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
3996 | 4011 | ||
3997 | phba->fc_stat.elsRcvRNID++; | 4012 | phba->fc_stat.elsRcvRNID++; |
3998 | lpfc_els_rcv_rnid(vport, elsiocb, ndlp); | 4013 | lpfc_els_rcv_rnid(vport, elsiocb, ndlp); |
3999 | if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM))) | 4014 | if (newnode) |
4000 | lpfc_nlp_put(ndlp); | 4015 | lpfc_nlp_put(ndlp); |
4001 | break; | 4016 | break; |
4002 | default: | 4017 | default: |
@@ -4011,7 +4026,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
4011 | lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, | 4026 | lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, |
4012 | "0115 Unknown ELS command x%x " | 4027 | "0115 Unknown ELS command x%x " |
4013 | "received from NPORT x%x\n", cmd, did); | 4028 | "received from NPORT x%x\n", cmd, did); |
4014 | if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM))) | 4029 | if (newnode) |
4015 | lpfc_nlp_put(ndlp); | 4030 | lpfc_nlp_put(ndlp); |
4016 | break; | 4031 | break; |
4017 | } | 4032 | } |