diff options
author | James Smart <James.Smart@Emulex.Com> | 2008-01-11 01:52:36 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-01-23 12:29:21 -0500 |
commit | 0ff10d46cf0a373c9c855a23cc9383ba4030d8d2 (patch) | |
tree | 111eb8303ad63cecad266d507af4c2c0bfec4d5b /drivers/scsi/lpfc/lpfc_els.c | |
parent | b18268fc631034882f5f3dd93daa248a3bfdd085 (diff) |
[SCSI] lpfc 8.2.4 : Miscellaneous Discovery/ELS Fixes
Miscellaneous Discovery/ELS Fixes:
- Delay free's of ELS requests if adapter reject conditions
- Fix concurrent PLOGI vs ADISC state handling
- Add retry mechanism for GFF_ID
- Correct some illegal state transitions around RSCN timeouts
- Fix missing return in FAN handling
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 | 56 |
1 files changed, 53 insertions, 3 deletions
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index bf332cba2fc0..f5e002435972 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c | |||
@@ -783,6 +783,8 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, | |||
783 | { | 783 | { |
784 | struct lpfc_vport *vport = ndlp->vport; | 784 | struct lpfc_vport *vport = ndlp->vport; |
785 | struct lpfc_nodelist *new_ndlp; | 785 | struct lpfc_nodelist *new_ndlp; |
786 | struct lpfc_rport_data *rdata; | ||
787 | struct fc_rport *rport; | ||
786 | struct serv_parm *sp; | 788 | struct serv_parm *sp; |
787 | uint8_t name[sizeof(struct lpfc_name)]; | 789 | uint8_t name[sizeof(struct lpfc_name)]; |
788 | uint32_t rc; | 790 | uint32_t rc; |
@@ -819,6 +821,11 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, | |||
819 | lpfc_unreg_rpi(vport, new_ndlp); | 821 | lpfc_unreg_rpi(vport, new_ndlp); |
820 | new_ndlp->nlp_DID = ndlp->nlp_DID; | 822 | new_ndlp->nlp_DID = ndlp->nlp_DID; |
821 | new_ndlp->nlp_prev_state = ndlp->nlp_prev_state; | 823 | new_ndlp->nlp_prev_state = ndlp->nlp_prev_state; |
824 | |||
825 | if (ndlp->nlp_flag & NLP_NPR_2B_DISC) | ||
826 | new_ndlp->nlp_flag |= NLP_NPR_2B_DISC; | ||
827 | ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; | ||
828 | |||
822 | lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state); | 829 | lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state); |
823 | 830 | ||
824 | /* Move this back to NPR state */ | 831 | /* Move this back to NPR state */ |
@@ -826,6 +833,20 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, | |||
826 | /* The new_ndlp is replacing ndlp totally, so we need | 833 | /* The new_ndlp is replacing ndlp totally, so we need |
827 | * to put ndlp on UNUSED list and try to free it. | 834 | * to put ndlp on UNUSED list and try to free it. |
828 | */ | 835 | */ |
836 | |||
837 | /* Fix up the rport accordingly */ | ||
838 | rport = ndlp->rport; | ||
839 | if (rport) { | ||
840 | rdata = rport->dd_data; | ||
841 | if (rdata->pnode == ndlp) { | ||
842 | lpfc_nlp_put(ndlp); | ||
843 | ndlp->rport = NULL; | ||
844 | rdata->pnode = lpfc_nlp_get(new_ndlp); | ||
845 | new_ndlp->rport = rport; | ||
846 | } | ||
847 | new_ndlp->nlp_type = ndlp->nlp_type; | ||
848 | } | ||
849 | |||
829 | lpfc_drop_node(vport, ndlp); | 850 | lpfc_drop_node(vport, ndlp); |
830 | } | 851 | } |
831 | else { | 852 | else { |
@@ -1149,7 +1170,7 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
1149 | return 0; | 1170 | return 0; |
1150 | } | 1171 | } |
1151 | 1172 | ||
1152 | static void | 1173 | void |
1153 | lpfc_more_adisc(struct lpfc_vport *vport) | 1174 | lpfc_more_adisc(struct lpfc_vport *vport) |
1154 | { | 1175 | { |
1155 | int sentadisc; | 1176 | int sentadisc; |
@@ -2100,8 +2121,35 @@ lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb) | |||
2100 | } | 2121 | } |
2101 | /* context2 = cmd, context2->next = rsp, context3 = bpl */ | 2122 | /* context2 = cmd, context2->next = rsp, context3 = bpl */ |
2102 | if (elsiocb->context2) { | 2123 | if (elsiocb->context2) { |
2103 | buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2; | 2124 | if (elsiocb->iocb_flag & LPFC_DELAY_MEM_FREE) { |
2104 | lpfc_els_free_data(phba, buf_ptr1); | 2125 | /* Firmware could still be in progress of DMAing |
2126 | * payload, so don't free data buffer till after | ||
2127 | * a hbeat. | ||
2128 | */ | ||
2129 | elsiocb->iocb_flag &= ~LPFC_DELAY_MEM_FREE; | ||
2130 | buf_ptr = elsiocb->context2; | ||
2131 | elsiocb->context2 = NULL; | ||
2132 | if (buf_ptr) { | ||
2133 | buf_ptr1 = NULL; | ||
2134 | spin_lock_irq(&phba->hbalock); | ||
2135 | if (!list_empty(&buf_ptr->list)) { | ||
2136 | list_remove_head(&buf_ptr->list, | ||
2137 | buf_ptr1, struct lpfc_dmabuf, | ||
2138 | list); | ||
2139 | INIT_LIST_HEAD(&buf_ptr1->list); | ||
2140 | list_add_tail(&buf_ptr1->list, | ||
2141 | &phba->elsbuf); | ||
2142 | phba->elsbuf_cnt++; | ||
2143 | } | ||
2144 | INIT_LIST_HEAD(&buf_ptr->list); | ||
2145 | list_add_tail(&buf_ptr->list, &phba->elsbuf); | ||
2146 | phba->elsbuf_cnt++; | ||
2147 | spin_unlock_irq(&phba->hbalock); | ||
2148 | } | ||
2149 | } else { | ||
2150 | buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2; | ||
2151 | lpfc_els_free_data(phba, buf_ptr1); | ||
2152 | } | ||
2105 | } | 2153 | } |
2106 | 2154 | ||
2107 | if (elsiocb->context3) { | 2155 | if (elsiocb->context3) { |
@@ -3027,6 +3075,8 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport) | |||
3027 | 3075 | ||
3028 | /* To process RSCN, first compare RSCN data with NameServer */ | 3076 | /* To process RSCN, first compare RSCN data with NameServer */ |
3029 | vport->fc_ns_retry = 0; | 3077 | vport->fc_ns_retry = 0; |
3078 | vport->num_disc_nodes = 0; | ||
3079 | |||
3030 | ndlp = lpfc_findnode_did(vport, NameServer_DID); | 3080 | ndlp = lpfc_findnode_did(vport, NameServer_DID); |
3031 | if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { | 3081 | if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { |
3032 | /* Good ndlp, issue CT Request to NameServer */ | 3082 | /* Good ndlp, issue CT Request to NameServer */ |