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 | |
| 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>
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_crtn.h | 4 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_disc.h | 1 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 231 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 96 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 66 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_nportdisc.c | 82 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_vport.c | 24 |
7 files changed, 300 insertions, 204 deletions
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 59164c6aa28f..338b5dd10a92 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h | |||
| @@ -45,6 +45,7 @@ void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t); | |||
| 45 | struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t); | 45 | struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t); |
| 46 | void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove); | 46 | void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove); |
| 47 | int lpfc_linkdown(struct lpfc_hba *); | 47 | int lpfc_linkdown(struct lpfc_hba *); |
| 48 | void lpfc_port_link_failure(struct lpfc_vport *); | ||
| 48 | void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *); | 49 | void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *); |
| 49 | 50 | ||
| 50 | void lpfc_mbx_cmpl_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *); | 51 | void lpfc_mbx_cmpl_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *); |
| @@ -74,6 +75,7 @@ void lpfc_disc_list_loopmap(struct lpfc_vport *); | |||
| 74 | void lpfc_disc_start(struct lpfc_vport *); | 75 | void lpfc_disc_start(struct lpfc_vport *); |
| 75 | void lpfc_disc_flush_list(struct lpfc_vport *); | 76 | void lpfc_disc_flush_list(struct lpfc_vport *); |
| 76 | void lpfc_cleanup_discovery_resources(struct lpfc_vport *); | 77 | void lpfc_cleanup_discovery_resources(struct lpfc_vport *); |
| 78 | void lpfc_cleanup(struct lpfc_vport *); | ||
| 77 | void lpfc_disc_timeout(unsigned long); | 79 | void lpfc_disc_timeout(unsigned long); |
| 78 | 80 | ||
| 79 | struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t); | 81 | struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t); |
| @@ -91,6 +93,8 @@ void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *); | |||
| 91 | int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *, | 93 | int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *, |
| 92 | struct serv_parm *, uint32_t); | 94 | struct serv_parm *, uint32_t); |
| 93 | int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *); | 95 | int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *); |
| 96 | void lpfc_more_plogi(struct lpfc_vport *); | ||
| 97 | void lpfc_end_rscn(struct lpfc_vport *); | ||
| 94 | int lpfc_els_chk_latt(struct lpfc_vport *); | 98 | int lpfc_els_chk_latt(struct lpfc_vport *); |
| 95 | int lpfc_els_abort_flogi(struct lpfc_hba *); | 99 | int lpfc_els_abort_flogi(struct lpfc_hba *); |
| 96 | int lpfc_initial_flogi(struct lpfc_vport *); | 100 | int lpfc_initial_flogi(struct lpfc_vport *); |
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index c9422a8423ca..99bc1a1ecac2 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h | |||
| @@ -103,7 +103,6 @@ struct lpfc_nodelist { | |||
| 103 | #define NLP_RM_DFLT_RPI 0x4000000 /* need to remove leftover dflt RPI */ | 103 | #define NLP_RM_DFLT_RPI 0x4000000 /* need to remove leftover dflt RPI */ |
| 104 | #define NLP_NODEV_REMOVE 0x8000000 /* Defer removal till discovery ends */ | 104 | #define NLP_NODEV_REMOVE 0x8000000 /* Defer removal till discovery ends */ |
| 105 | #define NLP_TARGET_REMOVE 0x10000000 /* Target remove in process */ | 105 | #define NLP_TARGET_REMOVE 0x10000000 /* Target remove in process */ |
| 106 | #define NLP_DELAYED_RM 0x20000000 /* Defer UNUSED List removal */ | ||
| 107 | 106 | ||
| 108 | /* There are 4 different double linked lists nodelist entries can reside on. | 107 | /* There are 4 different double linked lists nodelist entries can reside on. |
| 109 | * The Port Login (PLOGI) list and Address Discovery (ADISC) list are used | 108 | * The Port Login (PLOGI) list and Address Discovery (ADISC) list are used |
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 | } |
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index e181a98caf16..f64ce88e8a06 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c | |||
| @@ -157,6 +157,8 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) | |||
| 157 | struct lpfc_vport *vport; | 157 | struct lpfc_vport *vport; |
| 158 | struct lpfc_hba *phba; | 158 | struct lpfc_hba *phba; |
| 159 | uint8_t *name; | 159 | uint8_t *name; |
| 160 | int put_node; | ||
| 161 | int put_rport; | ||
| 160 | int warn_on = 0; | 162 | int warn_on = 0; |
| 161 | 163 | ||
| 162 | rport = ndlp->rport; | 164 | rport = ndlp->rport; |
| @@ -178,9 +180,6 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) | |||
| 178 | return; | 180 | return; |
| 179 | 181 | ||
| 180 | if (ndlp->nlp_type & NLP_FABRIC) { | 182 | if (ndlp->nlp_type & NLP_FABRIC) { |
| 181 | int put_node; | ||
| 182 | int put_rport; | ||
| 183 | |||
| 184 | /* We will clean up these Nodes in linkup */ | 183 | /* We will clean up these Nodes in linkup */ |
| 185 | put_node = rdata->pnode != NULL; | 184 | put_node = rdata->pnode != NULL; |
| 186 | put_rport = ndlp->rport != NULL; | 185 | put_rport = ndlp->rport != NULL; |
| @@ -222,23 +221,20 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) | |||
| 222 | ndlp->nlp_state, ndlp->nlp_rpi); | 221 | ndlp->nlp_state, ndlp->nlp_rpi); |
| 223 | } | 222 | } |
| 224 | 223 | ||
| 224 | put_node = rdata->pnode != NULL; | ||
| 225 | put_rport = ndlp->rport != NULL; | ||
| 226 | rdata->pnode = NULL; | ||
| 227 | ndlp->rport = NULL; | ||
| 228 | if (put_node) | ||
| 229 | lpfc_nlp_put(ndlp); | ||
| 230 | if (put_rport) | ||
| 231 | put_device(&rport->dev); | ||
| 232 | |||
| 225 | if (!(vport->load_flag & FC_UNLOADING) && | 233 | if (!(vport->load_flag & FC_UNLOADING) && |
| 226 | !(ndlp->nlp_flag & NLP_DELAY_TMO) && | 234 | !(ndlp->nlp_flag & NLP_DELAY_TMO) && |
| 227 | !(ndlp->nlp_flag & NLP_NPR_2B_DISC) && | 235 | !(ndlp->nlp_flag & NLP_NPR_2B_DISC) && |
| 228 | (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)) | 236 | (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)) { |
| 229 | lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); | 237 | lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); |
| 230 | else { | ||
| 231 | int put_node; | ||
| 232 | int put_rport; | ||
| 233 | |||
| 234 | put_node = rdata->pnode != NULL; | ||
| 235 | put_rport = ndlp->rport != NULL; | ||
| 236 | rdata->pnode = NULL; | ||
| 237 | ndlp->rport = NULL; | ||
| 238 | if (put_node) | ||
| 239 | lpfc_nlp_put(ndlp); | ||
| 240 | if (put_rport) | ||
| 241 | put_device(&rport->dev); | ||
| 242 | } | 238 | } |
| 243 | } | 239 | } |
| 244 | 240 | ||
| @@ -546,11 +542,9 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) | |||
| 546 | } | 542 | } |
| 547 | } | 543 | } |
| 548 | 544 | ||
| 549 | static void | 545 | void |
| 550 | lpfc_port_link_failure(struct lpfc_vport *vport) | 546 | lpfc_port_link_failure(struct lpfc_vport *vport) |
| 551 | { | 547 | { |
| 552 | struct lpfc_nodelist *ndlp, *next_ndlp; | ||
| 553 | |||
| 554 | /* Cleanup any outstanding RSCN activity */ | 548 | /* Cleanup any outstanding RSCN activity */ |
| 555 | lpfc_els_flush_rscn(vport); | 549 | lpfc_els_flush_rscn(vport); |
| 556 | 550 | ||
| @@ -559,11 +553,6 @@ lpfc_port_link_failure(struct lpfc_vport *vport) | |||
| 559 | 553 | ||
| 560 | lpfc_cleanup_rpis(vport, 0); | 554 | lpfc_cleanup_rpis(vport, 0); |
| 561 | 555 | ||
| 562 | /* free any ndlp's on unused list */ | ||
| 563 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) | ||
| 564 | if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) | ||
| 565 | lpfc_drop_node(vport, ndlp); | ||
| 566 | |||
| 567 | /* Turn off discovery timer if its running */ | 556 | /* Turn off discovery timer if its running */ |
| 568 | lpfc_can_disctmo(vport); | 557 | lpfc_can_disctmo(vport); |
| 569 | } | 558 | } |
| @@ -670,7 +659,6 @@ static void | |||
| 670 | lpfc_linkup_port(struct lpfc_vport *vport) | 659 | lpfc_linkup_port(struct lpfc_vport *vport) |
| 671 | { | 660 | { |
| 672 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | 661 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); |
| 673 | struct lpfc_nodelist *ndlp, *next_ndlp; | ||
| 674 | struct lpfc_hba *phba = vport->phba; | 662 | struct lpfc_hba *phba = vport->phba; |
| 675 | 663 | ||
| 676 | if ((vport->load_flag & FC_UNLOADING) != 0) | 664 | if ((vport->load_flag & FC_UNLOADING) != 0) |
| @@ -697,11 +685,6 @@ lpfc_linkup_port(struct lpfc_vport *vport) | |||
| 697 | if (vport->fc_flag & FC_LBIT) | 685 | if (vport->fc_flag & FC_LBIT) |
| 698 | lpfc_linkup_cleanup_nodes(vport); | 686 | lpfc_linkup_cleanup_nodes(vport); |
| 699 | 687 | ||
| 700 | /* free any ndlp's in unused state */ | ||
| 701 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, | ||
| 702 | nlp_listp) | ||
| 703 | if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) | ||
| 704 | lpfc_drop_node(vport, ndlp); | ||
| 705 | } | 688 | } |
| 706 | 689 | ||
| 707 | static int | 690 | static int |
| @@ -1345,7 +1328,9 @@ out: | |||
| 1345 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | 1328 | lpfc_mbuf_free(phba, mp->virt, mp->phys); |
| 1346 | kfree(mp); | 1329 | kfree(mp); |
| 1347 | mempool_free(pmb, phba->mbox_mem_pool); | 1330 | mempool_free(pmb, phba->mbox_mem_pool); |
| 1348 | lpfc_drop_node(vport, ndlp); | 1331 | |
| 1332 | /* If no other thread is using the ndlp, free it */ | ||
| 1333 | lpfc_nlp_not_used(ndlp); | ||
| 1349 | 1334 | ||
| 1350 | if (phba->fc_topology == TOPOLOGY_LOOP) { | 1335 | if (phba->fc_topology == TOPOLOGY_LOOP) { |
| 1351 | /* | 1336 | /* |
| @@ -1605,16 +1590,6 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
| 1605 | ndlp->nlp_type &= ~NLP_FC_NODE; | 1590 | ndlp->nlp_type &= ~NLP_FC_NODE; |
| 1606 | } | 1591 | } |
| 1607 | 1592 | ||
| 1608 | if ((old_state == NLP_STE_UNUSED_NODE) && | ||
| 1609 | (state != NLP_STE_UNUSED_NODE) && | ||
| 1610 | (ndlp->nlp_flag & NLP_DELAYED_RM)) { | ||
| 1611 | /* We are using the ndlp after all, so reverse | ||
| 1612 | * the delayed removal of it. | ||
| 1613 | */ | ||
| 1614 | ndlp->nlp_flag &= ~NLP_DELAYED_RM; | ||
| 1615 | lpfc_nlp_get(ndlp); | ||
| 1616 | } | ||
| 1617 | |||
| 1618 | if (list_empty(&ndlp->nlp_listp)) { | 1593 | if (list_empty(&ndlp->nlp_listp)) { |
| 1619 | spin_lock_irq(shost->host_lock); | 1594 | spin_lock_irq(shost->host_lock); |
| 1620 | list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes); | 1595 | list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes); |
| @@ -1646,9 +1621,16 @@ lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | |||
| 1646 | void | 1621 | void |
| 1647 | lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | 1622 | lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) |
| 1648 | { | 1623 | { |
| 1624 | /* | ||
| 1625 | * Use of lpfc_drop_node and UNUSED list. lpfc_drop_node should | ||
| 1626 | * be used if we wish to issue the "last" lpfc_nlp_put() to remove | ||
| 1627 | * the ndlp from the vport. The ndlp resides on the UNUSED list | ||
| 1628 | * until ALL other outstanding threads have completed. Thus, if a | ||
| 1629 | * ndlp is on the UNUSED list already, we should never do another | ||
| 1630 | * lpfc_drop_node() on it. | ||
| 1631 | */ | ||
| 1649 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); | 1632 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); |
| 1650 | if (!(ndlp->nlp_flag & NLP_DELAYED_RM)) | 1633 | lpfc_nlp_put(ndlp); |
| 1651 | lpfc_nlp_put(ndlp); | ||
| 1652 | return; | 1634 | return; |
| 1653 | } | 1635 | } |
| 1654 | 1636 | ||
| @@ -2116,6 +2098,12 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) | |||
| 2116 | } | 2098 | } |
| 2117 | if (vport->fc_flag & FC_RSCN_MODE) { | 2099 | if (vport->fc_flag & FC_RSCN_MODE) { |
| 2118 | if (lpfc_rscn_payload_check(vport, did)) { | 2100 | if (lpfc_rscn_payload_check(vport, did)) { |
| 2101 | /* If we've already recieved a PLOGI from this NPort | ||
| 2102 | * we don't need to try to discover it again. | ||
| 2103 | */ | ||
| 2104 | if (ndlp->nlp_flag & NLP_RCV_PLOGI) | ||
| 2105 | return NULL; | ||
| 2106 | |||
| 2119 | spin_lock_irq(shost->host_lock); | 2107 | spin_lock_irq(shost->host_lock); |
| 2120 | ndlp->nlp_flag |= NLP_NPR_2B_DISC; | 2108 | ndlp->nlp_flag |= NLP_NPR_2B_DISC; |
| 2121 | spin_unlock_irq(shost->host_lock); | 2109 | spin_unlock_irq(shost->host_lock); |
| @@ -2128,8 +2116,13 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) | |||
| 2128 | } else | 2116 | } else |
| 2129 | ndlp = NULL; | 2117 | ndlp = NULL; |
| 2130 | } else { | 2118 | } else { |
| 2119 | /* If we've already recieved a PLOGI from this NPort, | ||
| 2120 | * or we are already in the process of discovery on it, | ||
| 2121 | * we don't need to try to discover it again. | ||
| 2122 | */ | ||
| 2131 | if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE || | 2123 | if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE || |
| 2132 | ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) | 2124 | ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || |
| 2125 | ndlp->nlp_flag & NLP_RCV_PLOGI) | ||
| 2133 | return NULL; | 2126 | return NULL; |
| 2134 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); | 2127 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); |
| 2135 | spin_lock_irq(shost->host_lock); | 2128 | spin_lock_irq(shost->host_lock); |
| @@ -2497,6 +2490,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) | |||
| 2497 | if (ndlp->nlp_type & NLP_FABRIC) { | 2490 | if (ndlp->nlp_type & NLP_FABRIC) { |
| 2498 | /* Clean up the ndlp on Fabric connections */ | 2491 | /* Clean up the ndlp on Fabric connections */ |
| 2499 | lpfc_drop_node(vport, ndlp); | 2492 | lpfc_drop_node(vport, ndlp); |
| 2493 | |||
| 2500 | } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { | 2494 | } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { |
| 2501 | /* Fail outstanding IO now since device | 2495 | /* Fail outstanding IO now since device |
| 2502 | * is marked for PLOGI. | 2496 | * is marked for PLOGI. |
| @@ -2515,7 +2509,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) | |||
| 2515 | /* Initial FLOGI timeout */ | 2509 | /* Initial FLOGI timeout */ |
| 2516 | lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, | 2510 | lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, |
| 2517 | "0222 Initial %s timeout\n", | 2511 | "0222 Initial %s timeout\n", |
| 2518 | vport->vpi ? "FLOGI" : "FDISC"); | 2512 | vport->vpi ? "FDISC" : "FLOGI"); |
| 2519 | 2513 | ||
| 2520 | /* Assume no Fabric and go on with discovery. | 2514 | /* Assume no Fabric and go on with discovery. |
| 2521 | * Check for outstanding ELS FLOGI to abort. | 2515 | * Check for outstanding ELS FLOGI to abort. |
| @@ -2537,10 +2531,10 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) | |||
| 2537 | /* Next look for NameServer ndlp */ | 2531 | /* Next look for NameServer ndlp */ |
| 2538 | ndlp = lpfc_findnode_did(vport, NameServer_DID); | 2532 | ndlp = lpfc_findnode_did(vport, NameServer_DID); |
| 2539 | if (ndlp) | 2533 | if (ndlp) |
| 2540 | lpfc_nlp_put(ndlp); | 2534 | lpfc_els_abort(phba, ndlp); |
| 2541 | /* Start discovery */ | 2535 | |
| 2542 | lpfc_disc_start(vport); | 2536 | /* ReStart discovery */ |
| 2543 | break; | 2537 | goto restart_disc; |
| 2544 | 2538 | ||
| 2545 | case LPFC_NS_QRY: | 2539 | case LPFC_NS_QRY: |
| 2546 | /* Check for wait for NameServer Rsp timeout */ | 2540 | /* Check for wait for NameServer Rsp timeout */ |
| @@ -2559,6 +2553,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) | |||
| 2559 | } | 2553 | } |
| 2560 | vport->fc_ns_retry = 0; | 2554 | vport->fc_ns_retry = 0; |
| 2561 | 2555 | ||
| 2556 | restart_disc: | ||
| 2562 | /* | 2557 | /* |
| 2563 | * Discovery is over. | 2558 | * Discovery is over. |
| 2564 | * set port_state to PORT_READY if SLI2. | 2559 | * set port_state to PORT_READY if SLI2. |
| @@ -2731,8 +2726,7 @@ __lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param) | |||
| 2731 | struct lpfc_nodelist *ndlp; | 2726 | struct lpfc_nodelist *ndlp; |
| 2732 | 2727 | ||
| 2733 | list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { | 2728 | list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { |
| 2734 | if (ndlp->nlp_state != NLP_STE_UNUSED_NODE && | 2729 | if (filter(ndlp, param)) |
| 2735 | filter(ndlp, param)) | ||
| 2736 | return ndlp; | 2730 | return ndlp; |
| 2737 | } | 2731 | } |
| 2738 | return NULL; | 2732 | return NULL; |
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 729694d97597..ceb185fa3216 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
| @@ -1334,15 +1334,35 @@ lpfc_hba_init(struct lpfc_hba *phba, uint32_t *hbainit) | |||
| 1334 | kfree(HashWorking); | 1334 | kfree(HashWorking); |
| 1335 | } | 1335 | } |
| 1336 | 1336 | ||
| 1337 | static void | 1337 | void |
| 1338 | lpfc_cleanup(struct lpfc_vport *vport) | 1338 | lpfc_cleanup(struct lpfc_vport *vport) |
| 1339 | { | 1339 | { |
| 1340 | struct lpfc_hba *phba = vport->phba; | ||
| 1340 | struct lpfc_nodelist *ndlp, *next_ndlp; | 1341 | struct lpfc_nodelist *ndlp, *next_ndlp; |
| 1341 | 1342 | ||
| 1342 | /* clean up phba - lpfc specific */ | 1343 | if (phba->link_state > LPFC_LINK_DOWN) |
| 1343 | lpfc_can_disctmo(vport); | 1344 | lpfc_port_link_failure(vport); |
| 1344 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) | 1345 | |
| 1345 | lpfc_nlp_put(ndlp); | 1346 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { |
| 1347 | if (ndlp->nlp_type & NLP_FABRIC) | ||
| 1348 | lpfc_disc_state_machine(vport, ndlp, NULL, | ||
| 1349 | NLP_EVT_DEVICE_RECOVERY); | ||
| 1350 | lpfc_disc_state_machine(vport, ndlp, NULL, | ||
| 1351 | NLP_EVT_DEVICE_RM); | ||
| 1352 | } | ||
| 1353 | |||
| 1354 | /* At this point, ALL ndlp's should be gone */ | ||
| 1355 | while (!list_empty(&vport->fc_nodes)) { | ||
| 1356 | |||
| 1357 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, | ||
| 1358 | nlp_listp) { | ||
| 1359 | lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, | ||
| 1360 | "0233 Nodelist x%x not free: %d\n", | ||
| 1361 | ndlp->nlp_DID, | ||
| 1362 | atomic_read(&ndlp->kref.refcount)); | ||
| 1363 | lpfc_drop_node(vport, ndlp); | ||
| 1364 | } | ||
| 1365 | } | ||
| 1346 | return; | 1366 | return; |
| 1347 | } | 1367 | } |
| 1348 | 1368 | ||
| @@ -1463,6 +1483,8 @@ lpfc_offline_prep(struct lpfc_hba * phba) | |||
| 1463 | { | 1483 | { |
| 1464 | struct lpfc_vport *vport = phba->pport; | 1484 | struct lpfc_vport *vport = phba->pport; |
| 1465 | struct lpfc_nodelist *ndlp, *next_ndlp; | 1485 | struct lpfc_nodelist *ndlp, *next_ndlp; |
| 1486 | struct lpfc_vport **vports; | ||
| 1487 | int i; | ||
| 1466 | 1488 | ||
| 1467 | if (vport->fc_flag & FC_OFFLINE_MODE) | 1489 | if (vport->fc_flag & FC_OFFLINE_MODE) |
| 1468 | return; | 1490 | return; |
| @@ -1471,10 +1493,32 @@ lpfc_offline_prep(struct lpfc_hba * phba) | |||
| 1471 | 1493 | ||
| 1472 | lpfc_linkdown(phba); | 1494 | lpfc_linkdown(phba); |
| 1473 | 1495 | ||
| 1474 | /* Issue an unreg_login to all nodes */ | 1496 | /* Issue an unreg_login to all nodes on all vports */ |
| 1475 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) | 1497 | vports = lpfc_create_vport_work_array(phba); |
| 1476 | if (ndlp->nlp_state != NLP_STE_UNUSED_NODE) | 1498 | if (vports != NULL) { |
| 1477 | lpfc_unreg_rpi(vport, ndlp); | 1499 | for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { |
| 1500 | struct Scsi_Host *shost; | ||
| 1501 | |||
| 1502 | shost = lpfc_shost_from_vport(vports[i]); | ||
| 1503 | list_for_each_entry_safe(ndlp, next_ndlp, | ||
| 1504 | &vports[i]->fc_nodes, | ||
| 1505 | nlp_listp) { | ||
| 1506 | if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) | ||
| 1507 | continue; | ||
| 1508 | if (ndlp->nlp_type & NLP_FABRIC) { | ||
| 1509 | lpfc_disc_state_machine(vports[i], ndlp, | ||
| 1510 | NULL, NLP_EVT_DEVICE_RECOVERY); | ||
| 1511 | lpfc_disc_state_machine(vports[i], ndlp, | ||
| 1512 | NULL, NLP_EVT_DEVICE_RM); | ||
| 1513 | } | ||
| 1514 | spin_lock_irq(shost->host_lock); | ||
| 1515 | ndlp->nlp_flag &= ~NLP_NPR_ADISC; | ||
| 1516 | spin_unlock_irq(shost->host_lock); | ||
| 1517 | lpfc_unreg_rpi(vports[i], ndlp); | ||
| 1518 | } | ||
| 1519 | } | ||
| 1520 | } | ||
| 1521 | lpfc_destroy_vport_work_array(vports); | ||
| 1478 | 1522 | ||
| 1479 | lpfc_sli_flush_mbox_queue(phba); | 1523 | lpfc_sli_flush_mbox_queue(phba); |
| 1480 | } | 1524 | } |
| @@ -1508,7 +1552,6 @@ lpfc_offline(struct lpfc_hba *phba) | |||
| 1508 | if (vports != NULL) | 1552 | if (vports != NULL) |
| 1509 | for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { | 1553 | for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { |
| 1510 | shost = lpfc_shost_from_vport(vports[i]); | 1554 | shost = lpfc_shost_from_vport(vports[i]); |
| 1511 | lpfc_cleanup(vports[i]); | ||
| 1512 | spin_lock_irq(shost->host_lock); | 1555 | spin_lock_irq(shost->host_lock); |
| 1513 | vports[i]->work_port_events = 0; | 1556 | vports[i]->work_port_events = 0; |
| 1514 | vports[i]->fc_flag |= FC_OFFLINE_MODE; | 1557 | vports[i]->fc_flag |= FC_OFFLINE_MODE; |
| @@ -2061,6 +2104,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev) | |||
| 2061 | 2104 | ||
| 2062 | fc_remove_host(shost); | 2105 | fc_remove_host(shost); |
| 2063 | scsi_remove_host(shost); | 2106 | scsi_remove_host(shost); |
| 2107 | lpfc_cleanup(vport); | ||
| 2108 | |||
| 2064 | /* | 2109 | /* |
| 2065 | * Bring down the SLI Layer. This step disable all interrupts, | 2110 | * Bring down the SLI Layer. This step disable all interrupts, |
| 2066 | * clears the rings, discards all mailbox commands, and resets | 2111 | * clears the rings, discards all mailbox commands, and resets |
| @@ -2075,7 +2120,6 @@ lpfc_pci_remove_one(struct pci_dev *pdev) | |||
| 2075 | spin_unlock_irq(&phba->hbalock); | 2120 | spin_unlock_irq(&phba->hbalock); |
| 2076 | 2121 | ||
| 2077 | lpfc_debugfs_terminate(vport); | 2122 | lpfc_debugfs_terminate(vport); |
| 2078 | lpfc_cleanup(vport); | ||
| 2079 | 2123 | ||
| 2080 | kthread_stop(phba->worker_thread); | 2124 | kthread_stop(phba->worker_thread); |
| 2081 | 2125 | ||
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 1a16ee9b2e87..bba1fb6103f6 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c | |||
| @@ -406,6 +406,41 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
| 406 | ndlp, mbox); | 406 | ndlp, mbox); |
| 407 | return 1; | 407 | return 1; |
| 408 | } | 408 | } |
| 409 | |||
| 410 | /* If the remote NPort logs into us, before we can initiate | ||
| 411 | * discovery to them, cleanup the NPort from discovery accordingly. | ||
| 412 | */ | ||
| 413 | if (ndlp->nlp_state == NLP_STE_NPR_NODE) { | ||
| 414 | spin_lock_irq(shost->host_lock); | ||
| 415 | ndlp->nlp_flag &= ~NLP_DELAY_TMO; | ||
| 416 | spin_unlock_irq(shost->host_lock); | ||
| 417 | del_timer_sync(&ndlp->nlp_delayfunc); | ||
| 418 | ndlp->nlp_last_elscmd = 0; | ||
| 419 | |||
| 420 | if (!list_empty(&ndlp->els_retry_evt.evt_listp)) | ||
| 421 | list_del_init(&ndlp->els_retry_evt.evt_listp); | ||
| 422 | |||
| 423 | if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { | ||
| 424 | spin_lock_irq(shost->host_lock); | ||
| 425 | ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; | ||
| 426 | spin_unlock_irq(shost->host_lock); | ||
| 427 | if (vport->num_disc_nodes) { | ||
| 428 | /* Check to see if there are more | ||
| 429 | * PLOGIs to be sent | ||
| 430 | */ | ||
| 431 | lpfc_more_plogi(vport); | ||
| 432 | |||
| 433 | if (vport->num_disc_nodes == 0) { | ||
| 434 | spin_lock_irq(shost->host_lock); | ||
| 435 | vport->fc_flag &= ~FC_NDISC_ACTIVE; | ||
| 436 | spin_unlock_irq(shost->host_lock); | ||
| 437 | lpfc_can_disctmo(vport); | ||
| 438 | lpfc_end_rscn(vport); | ||
| 439 | } | ||
| 440 | } | ||
| 441 | } | ||
| 442 | } | ||
| 443 | |||
| 409 | lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox); | 444 | lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox); |
| 410 | return 1; | 445 | return 1; |
| 411 | 446 | ||
| @@ -500,12 +535,9 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
| 500 | spin_unlock_irq(shost->host_lock); | 535 | spin_unlock_irq(shost->host_lock); |
| 501 | 536 | ||
| 502 | ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; | 537 | ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; |
| 503 | ndlp->nlp_prev_state = ndlp->nlp_state; | ||
| 504 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); | ||
| 505 | } else { | ||
| 506 | ndlp->nlp_prev_state = ndlp->nlp_state; | ||
| 507 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); | ||
| 508 | } | 538 | } |
| 539 | ndlp->nlp_prev_state = ndlp->nlp_state; | ||
| 540 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); | ||
| 509 | 541 | ||
| 510 | spin_lock_irq(shost->host_lock); | 542 | spin_lock_irq(shost->host_lock); |
| 511 | ndlp->nlp_flag &= ~NLP_NPR_ADISC; | 543 | ndlp->nlp_flag &= ~NLP_NPR_ADISC; |
| @@ -593,6 +625,25 @@ lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
| 593 | return ndlp->nlp_state; | 625 | return ndlp->nlp_state; |
| 594 | } | 626 | } |
| 595 | 627 | ||
| 628 | static uint32_t | ||
| 629 | lpfc_cmpl_plogi_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | ||
| 630 | void *arg, uint32_t evt) | ||
| 631 | { | ||
| 632 | /* This transition is only legal if we previously | ||
| 633 | * rcv'ed a PLOGI. Since we don't want 2 discovery threads | ||
| 634 | * working on the same NPortID, do nothing for this thread | ||
| 635 | * to stop it. | ||
| 636 | */ | ||
| 637 | if (!(ndlp->nlp_flag & NLP_RCV_PLOGI)) { | ||
| 638 | lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, | ||
| 639 | "0253 Illegal State Transition: node x%x " | ||
| 640 | "event x%x, state x%x Data: x%x x%x\n", | ||
| 641 | ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi, | ||
| 642 | ndlp->nlp_flag); | ||
| 643 | } | ||
| 644 | return ndlp->nlp_state; | ||
| 645 | } | ||
| 646 | |||
| 596 | /* Start of Discovery State Machine routines */ | 647 | /* Start of Discovery State Machine routines */ |
| 597 | 648 | ||
| 598 | static uint32_t | 649 | static uint32_t |
| @@ -604,11 +655,8 @@ lpfc_rcv_plogi_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
| 604 | cmdiocb = (struct lpfc_iocbq *) arg; | 655 | cmdiocb = (struct lpfc_iocbq *) arg; |
| 605 | 656 | ||
| 606 | if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) { | 657 | if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) { |
| 607 | ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE; | ||
| 608 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); | ||
| 609 | return ndlp->nlp_state; | 658 | return ndlp->nlp_state; |
| 610 | } | 659 | } |
| 611 | lpfc_drop_node(vport, ndlp); | ||
| 612 | return NLP_STE_FREED_NODE; | 660 | return NLP_STE_FREED_NODE; |
| 613 | } | 661 | } |
| 614 | 662 | ||
| @@ -617,7 +665,6 @@ lpfc_rcv_els_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
| 617 | void *arg, uint32_t evt) | 665 | void *arg, uint32_t evt) |
| 618 | { | 666 | { |
| 619 | lpfc_issue_els_logo(vport, ndlp, 0); | 667 | lpfc_issue_els_logo(vport, ndlp, 0); |
| 620 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); | ||
| 621 | return ndlp->nlp_state; | 668 | return ndlp->nlp_state; |
| 622 | } | 669 | } |
| 623 | 670 | ||
| @@ -632,7 +679,6 @@ lpfc_rcv_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
| 632 | ndlp->nlp_flag |= NLP_LOGO_ACC; | 679 | ndlp->nlp_flag |= NLP_LOGO_ACC; |
| 633 | spin_unlock_irq(shost->host_lock); | 680 | spin_unlock_irq(shost->host_lock); |
| 634 | lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); | 681 | lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); |
| 635 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); | ||
| 636 | 682 | ||
| 637 | return ndlp->nlp_state; | 683 | return ndlp->nlp_state; |
| 638 | } | 684 | } |
| @@ -641,7 +687,6 @@ static uint32_t | |||
| 641 | lpfc_cmpl_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | 687 | lpfc_cmpl_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, |
| 642 | void *arg, uint32_t evt) | 688 | void *arg, uint32_t evt) |
| 643 | { | 689 | { |
| 644 | lpfc_drop_node(vport, ndlp); | ||
| 645 | return NLP_STE_FREED_NODE; | 690 | return NLP_STE_FREED_NODE; |
| 646 | } | 691 | } |
| 647 | 692 | ||
| @@ -649,7 +694,6 @@ static uint32_t | |||
| 649 | lpfc_device_rm_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | 694 | lpfc_device_rm_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, |
| 650 | void *arg, uint32_t evt) | 695 | void *arg, uint32_t evt) |
| 651 | { | 696 | { |
| 652 | lpfc_drop_node(vport, ndlp); | ||
| 653 | return NLP_STE_FREED_NODE; | 697 | return NLP_STE_FREED_NODE; |
| 654 | } | 698 | } |
| 655 | 699 | ||
| @@ -864,7 +908,7 @@ out: | |||
| 864 | 908 | ||
| 865 | /* Free this node since the driver cannot login or has the wrong | 909 | /* Free this node since the driver cannot login or has the wrong |
| 866 | sparm */ | 910 | sparm */ |
| 867 | lpfc_drop_node(vport, ndlp); | 911 | lpfc_nlp_not_used(ndlp); |
| 868 | return NLP_STE_FREED_NODE; | 912 | return NLP_STE_FREED_NODE; |
| 869 | } | 913 | } |
| 870 | 914 | ||
| @@ -1195,8 +1239,8 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, | |||
| 1195 | * retry discovery. | 1239 | * retry discovery. |
| 1196 | */ | 1240 | */ |
| 1197 | if (mb->mbxStatus == MBXERR_RPI_FULL) { | 1241 | if (mb->mbxStatus == MBXERR_RPI_FULL) { |
| 1198 | ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE; | 1242 | ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; |
| 1199 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); | 1243 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); |
| 1200 | return ndlp->nlp_state; | 1244 | return ndlp->nlp_state; |
| 1201 | } | 1245 | } |
| 1202 | 1246 | ||
| @@ -1376,7 +1420,7 @@ out: | |||
| 1376 | lpfc_issue_els_logo(vport, ndlp, 0); | 1420 | lpfc_issue_els_logo(vport, ndlp, 0); |
| 1377 | 1421 | ||
| 1378 | ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; | 1422 | ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; |
| 1379 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); | 1423 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); |
| 1380 | return ndlp->nlp_state; | 1424 | return ndlp->nlp_state; |
| 1381 | } | 1425 | } |
| 1382 | 1426 | ||
| @@ -1751,7 +1795,7 @@ lpfc_cmpl_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
| 1751 | 1795 | ||
| 1752 | irsp = &rspiocb->iocb; | 1796 | irsp = &rspiocb->iocb; |
| 1753 | if (irsp->ulpStatus) { | 1797 | if (irsp->ulpStatus) { |
| 1754 | lpfc_drop_node(vport, ndlp); | 1798 | lpfc_nlp_not_used(ndlp); |
| 1755 | return NLP_STE_FREED_NODE; | 1799 | return NLP_STE_FREED_NODE; |
| 1756 | } | 1800 | } |
| 1757 | return ndlp->nlp_state; | 1801 | return ndlp->nlp_state; |
| @@ -1966,7 +2010,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT]) | |||
| 1966 | lpfc_rcv_padisc_reglogin_issue, /* RCV_ADISC */ | 2010 | lpfc_rcv_padisc_reglogin_issue, /* RCV_ADISC */ |
| 1967 | lpfc_rcv_padisc_reglogin_issue, /* RCV_PDISC */ | 2011 | lpfc_rcv_padisc_reglogin_issue, /* RCV_PDISC */ |
| 1968 | lpfc_rcv_prlo_reglogin_issue, /* RCV_PRLO */ | 2012 | lpfc_rcv_prlo_reglogin_issue, /* RCV_PRLO */ |
| 1969 | lpfc_disc_illegal, /* CMPL_PLOGI */ | 2013 | lpfc_cmpl_plogi_illegal, /* CMPL_PLOGI */ |
| 1970 | lpfc_disc_illegal, /* CMPL_PRLI */ | 2014 | lpfc_disc_illegal, /* CMPL_PRLI */ |
| 1971 | lpfc_disc_illegal, /* CMPL_LOGO */ | 2015 | lpfc_disc_illegal, /* CMPL_LOGO */ |
| 1972 | lpfc_disc_illegal, /* CMPL_ADISC */ | 2016 | lpfc_disc_illegal, /* CMPL_ADISC */ |
| @@ -1980,7 +2024,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT]) | |||
| 1980 | lpfc_rcv_padisc_prli_issue, /* RCV_ADISC */ | 2024 | lpfc_rcv_padisc_prli_issue, /* RCV_ADISC */ |
| 1981 | lpfc_rcv_padisc_prli_issue, /* RCV_PDISC */ | 2025 | lpfc_rcv_padisc_prli_issue, /* RCV_PDISC */ |
| 1982 | lpfc_rcv_prlo_prli_issue, /* RCV_PRLO */ | 2026 | lpfc_rcv_prlo_prli_issue, /* RCV_PRLO */ |
| 1983 | lpfc_disc_illegal, /* CMPL_PLOGI */ | 2027 | lpfc_cmpl_plogi_illegal, /* CMPL_PLOGI */ |
| 1984 | lpfc_cmpl_prli_prli_issue, /* CMPL_PRLI */ | 2028 | lpfc_cmpl_prli_prli_issue, /* CMPL_PRLI */ |
| 1985 | lpfc_disc_illegal, /* CMPL_LOGO */ | 2029 | lpfc_disc_illegal, /* CMPL_LOGO */ |
| 1986 | lpfc_disc_illegal, /* CMPL_ADISC */ | 2030 | lpfc_disc_illegal, /* CMPL_ADISC */ |
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index fd07d9d7f507..378c01200b02 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c | |||
| @@ -445,7 +445,6 @@ int | |||
| 445 | lpfc_vport_delete(struct fc_vport *fc_vport) | 445 | lpfc_vport_delete(struct fc_vport *fc_vport) |
| 446 | { | 446 | { |
| 447 | struct lpfc_nodelist *ndlp = NULL; | 447 | struct lpfc_nodelist *ndlp = NULL; |
| 448 | struct lpfc_nodelist *next_ndlp; | ||
| 449 | struct Scsi_Host *shost = (struct Scsi_Host *) fc_vport->shost; | 448 | struct Scsi_Host *shost = (struct Scsi_Host *) fc_vport->shost; |
| 450 | struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data; | 449 | struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data; |
| 451 | struct lpfc_hba *phba = vport->phba; | 450 | struct lpfc_hba *phba = vport->phba; |
| @@ -531,23 +530,20 @@ lpfc_vport_delete(struct fc_vport *fc_vport) | |||
| 531 | } | 530 | } |
| 532 | 531 | ||
| 533 | skip_logo: | 532 | skip_logo: |
| 533 | lpfc_cleanup(vport); | ||
| 534 | lpfc_sli_host_down(vport); | 534 | lpfc_sli_host_down(vport); |
| 535 | 535 | ||
| 536 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { | ||
| 537 | lpfc_disc_state_machine(vport, ndlp, NULL, | ||
| 538 | NLP_EVT_DEVICE_RECOVERY); | ||
| 539 | lpfc_disc_state_machine(vport, ndlp, NULL, | ||
| 540 | NLP_EVT_DEVICE_RM); | ||
| 541 | } | ||
| 542 | |||
| 543 | lpfc_stop_vport_timers(vport); | 536 | lpfc_stop_vport_timers(vport); |
| 544 | lpfc_unreg_all_rpis(vport); | 537 | lpfc_unreg_all_rpis(vport); |
| 545 | lpfc_unreg_default_rpis(vport); | 538 | |
| 546 | /* | 539 | if (!(phba->pport->load_flag & FC_UNLOADING)) { |
| 547 | * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) does the | 540 | lpfc_unreg_default_rpis(vport); |
| 548 | * scsi_host_put() to release the vport. | 541 | /* |
| 549 | */ | 542 | * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) |
| 550 | lpfc_mbx_unreg_vpi(vport); | 543 | * does the scsi_host_put() to release the vport. |
| 544 | */ | ||
| 545 | lpfc_mbx_unreg_vpi(vport); | ||
| 546 | } | ||
| 551 | 547 | ||
| 552 | lpfc_free_vpi(phba, vport->vpi); | 548 | lpfc_free_vpi(phba, vport->vpi); |
| 553 | vport->work_port_events = 0; | 549 | vport->work_port_events = 0; |
