diff options
author | James Smart <James.Smart@Emulex.Com> | 2007-10-27 13:37:53 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-01-11 19:22:33 -0500 |
commit | a8adb83208020c913f010cb4e26d09e25300db8e (patch) | |
tree | 2245ca9f0dba5139946c99d45b80e7f2ce324b74 /drivers | |
parent | 87af33fe5f78c27cf9e43c6e586dd6efd4be3e40 (diff) |
[SCSI] lpfc 8.2.3 : Miscellaneous Small Fixes - part 2
Miscellaneous Small Fixes - part 2
- Fix ndlp left in PLOGI state after link up
- Fix cannot rcv unsol ELS frames after running HBA resets for a few minutes
- Fix HBQ buffer_count implemention
- Fix RPI leak
- Fix crash while deleting vports while HBA is reset
- Revert the FCP Fbits offset back to 7
- Fix panic when deleting vports
- Remove unused code in switch statement outside of a case
- Reject PLOGI from invalid PName or NName of 0
- Ignore PLOGI responses from WWPName or WWNName of 0
- Fix debugfs hbqinfo display for ppc
- Added 8G to list of supported speeds for sysfs parameter
- Defer ndlp cleanup to dev-loss timeout handler
- Added support for WRITE_VPARMS mailbox command by applications
Signed-off-by: James Smart <James.Smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 1 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 8 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_debugfs.c | 13 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_disc.h | 1 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 34 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 67 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw.h | 7 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 22 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nportdisc.c | 30 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 10 |
10 files changed, 152 insertions, 41 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index ff6b7d33ccab..636a930a5739 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h | |||
@@ -367,6 +367,7 @@ struct lpfc_vport { | |||
367 | 367 | ||
368 | struct hbq_s { | 368 | struct hbq_s { |
369 | uint16_t entry_count; /* Current number of HBQ slots */ | 369 | uint16_t entry_count; /* Current number of HBQ slots */ |
370 | uint16_t buffer_count; /* Current number of buffers posted */ | ||
370 | uint32_t next_hbqPutIdx; /* Index to next HBQ slot to use */ | 371 | uint32_t next_hbqPutIdx; /* Index to next HBQ slot to use */ |
371 | uint32_t hbqPutIdx; /* HBQ slot to use */ | 372 | uint32_t hbqPutIdx; /* HBQ slot to use */ |
372 | uint32_t local_hbqGetIdx; /* Local copy of Get index from Port */ | 373 | uint32_t local_hbqGetIdx; /* Local copy of Get index from Port */ |
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index e8e9905828c9..4e9e890449a3 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c | |||
@@ -187,12 +187,9 @@ lpfc_state_show(struct class_device *cdev, char *buf) | |||
187 | case LPFC_LINK_UP: | 187 | case LPFC_LINK_UP: |
188 | case LPFC_CLEAR_LA: | 188 | case LPFC_CLEAR_LA: |
189 | case LPFC_HBA_READY: | 189 | case LPFC_HBA_READY: |
190 | len += snprintf(buf + len, PAGE_SIZE-len, "Link Up - \n"); | 190 | len += snprintf(buf + len, PAGE_SIZE-len, "Link Up - "); |
191 | 191 | ||
192 | switch (vport->port_state) { | 192 | switch (vport->port_state) { |
193 | len += snprintf(buf + len, PAGE_SIZE-len, | ||
194 | "initializing\n"); | ||
195 | break; | ||
196 | case LPFC_LOCAL_CFG_LINK: | 193 | case LPFC_LOCAL_CFG_LINK: |
197 | len += snprintf(buf + len, PAGE_SIZE-len, | 194 | len += snprintf(buf + len, PAGE_SIZE-len, |
198 | "Configuring Link\n"); | 195 | "Configuring Link\n"); |
@@ -1759,7 +1756,6 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr, | |||
1759 | 1756 | ||
1760 | switch (phba->sysfs_mbox.mbox->mb.mbxCommand) { | 1757 | switch (phba->sysfs_mbox.mbox->mb.mbxCommand) { |
1761 | /* Offline only */ | 1758 | /* Offline only */ |
1762 | case MBX_WRITE_NV: | ||
1763 | case MBX_INIT_LINK: | 1759 | case MBX_INIT_LINK: |
1764 | case MBX_DOWN_LINK: | 1760 | case MBX_DOWN_LINK: |
1765 | case MBX_CONFIG_LINK: | 1761 | case MBX_CONFIG_LINK: |
@@ -1782,6 +1778,8 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr, | |||
1782 | spin_unlock_irq(&phba->hbalock); | 1778 | spin_unlock_irq(&phba->hbalock); |
1783 | return -EPERM; | 1779 | return -EPERM; |
1784 | } | 1780 | } |
1781 | case MBX_WRITE_NV: | ||
1782 | case MBX_WRITE_VPARMS: | ||
1785 | case MBX_LOAD_SM: | 1783 | case MBX_LOAD_SM: |
1786 | case MBX_READ_NV: | 1784 | case MBX_READ_NV: |
1787 | case MBX_READ_CONFIG: | 1785 | case MBX_READ_CONFIG: |
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index d6a98bc970ff..da607c775cfc 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c | |||
@@ -243,16 +243,17 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size) | |||
243 | raw_index = phba->hbq_get[i]; | 243 | raw_index = phba->hbq_get[i]; |
244 | getidx = le32_to_cpu(raw_index); | 244 | getidx = le32_to_cpu(raw_index); |
245 | len += snprintf(buf+len, size-len, | 245 | len += snprintf(buf+len, size-len, |
246 | "entrys:%d Put:%d nPut:%d localGet:%d hbaGet:%d\n", | 246 | "entrys:%d bufcnt:%d Put:%d nPut:%d localGet:%d hbaGet:%d\n", |
247 | hbqs->entry_count, hbqs->hbqPutIdx, hbqs->next_hbqPutIdx, | 247 | hbqs->entry_count, hbqs->buffer_count, hbqs->hbqPutIdx, |
248 | hbqs->local_hbqGetIdx, getidx); | 248 | hbqs->next_hbqPutIdx, hbqs->local_hbqGetIdx, getidx); |
249 | 249 | ||
250 | hbqe = (struct lpfc_hbq_entry *) phba->hbqs[i].hbq_virt; | 250 | hbqe = (struct lpfc_hbq_entry *) phba->hbqs[i].hbq_virt; |
251 | for (j=0; j<hbqs->entry_count; j++) { | 251 | for (j=0; j<hbqs->entry_count; j++) { |
252 | len += snprintf(buf+len, size-len, | 252 | len += snprintf(buf+len, size-len, |
253 | "%03d: %08x %04x %05x ", j, | 253 | "%03d: %08x %04x %05x ", j, |
254 | hbqe->bde.addrLow, hbqe->bde.tus.w, hbqe->buffer_tag); | 254 | le32_to_cpu(hbqe->bde.addrLow), |
255 | 255 | le32_to_cpu(hbqe->bde.tus.w), | |
256 | le32_to_cpu(hbqe->buffer_tag)); | ||
256 | i = 0; | 257 | i = 0; |
257 | found = 0; | 258 | found = 0; |
258 | 259 | ||
@@ -276,7 +277,7 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size) | |||
276 | list_for_each_entry(d_buf, &hbqs->hbq_buffer_list, list) { | 277 | list_for_each_entry(d_buf, &hbqs->hbq_buffer_list, list) { |
277 | hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf); | 278 | hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf); |
278 | phys = ((uint64_t)hbq_buf->dbuf.phys & 0xffffffff); | 279 | phys = ((uint64_t)hbq_buf->dbuf.phys & 0xffffffff); |
279 | if (phys == hbqe->bde.addrLow) { | 280 | if (phys == le32_to_cpu(hbqe->bde.addrLow)) { |
280 | len += snprintf(buf+len, size-len, | 281 | len += snprintf(buf+len, size-len, |
281 | "Buf%d: %p %06x\n", i, | 282 | "Buf%d: %p %06x\n", i, |
282 | hbq_buf->dbuf.virt, hbq_buf->tag); | 283 | hbq_buf->dbuf.virt, hbq_buf->tag); |
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index 99bc1a1ecac2..cfe81c50529a 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h | |||
@@ -91,6 +91,7 @@ struct lpfc_nodelist { | |||
91 | #define NLP_LOGO_SND 0x100 /* sent LOGO request for this entry */ | 91 | #define NLP_LOGO_SND 0x100 /* sent LOGO request for this entry */ |
92 | #define NLP_RNID_SND 0x400 /* sent RNID request for this entry */ | 92 | #define NLP_RNID_SND 0x400 /* sent RNID request for this entry */ |
93 | #define NLP_ELS_SND_MASK 0x7e0 /* sent ELS request for this entry */ | 93 | #define NLP_ELS_SND_MASK 0x7e0 /* sent ELS request for this entry */ |
94 | #define NLP_DEFER_RM 0x10000 /* Remove this ndlp if no longer used */ | ||
94 | #define NLP_DELAY_TMO 0x20000 /* delay timeout is running for node */ | 95 | #define NLP_DELAY_TMO 0x20000 /* delay timeout is running for node */ |
95 | #define NLP_NPR_2B_DISC 0x40000 /* node is included in num_disc_nodes */ | 96 | #define NLP_NPR_2B_DISC 0x40000 /* node is included in num_disc_nodes */ |
96 | #define NLP_RCV_PLOGI 0x80000 /* Rcv'ed PLOGI from remote system */ | 97 | #define NLP_RCV_PLOGI 0x80000 /* Rcv'ed PLOGI from remote system */ |
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 0a5006ea9909..9315c3c2e6f6 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c | |||
@@ -2069,9 +2069,25 @@ int | |||
2069 | 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) |
2070 | { | 2070 | { |
2071 | struct lpfc_dmabuf *buf_ptr, *buf_ptr1; | 2071 | struct lpfc_dmabuf *buf_ptr, *buf_ptr1; |
2072 | struct lpfc_nodelist *ndlp; | ||
2072 | 2073 | ||
2073 | if (elsiocb->context1) { | 2074 | ndlp = (struct lpfc_nodelist *)elsiocb->context1; |
2074 | lpfc_nlp_put(elsiocb->context1); | 2075 | if (ndlp) { |
2076 | if (ndlp->nlp_flag & NLP_DEFER_RM) { | ||
2077 | lpfc_nlp_put(ndlp); | ||
2078 | |||
2079 | /* If the ndlp is not being used by another discovery | ||
2080 | * thread, free it. | ||
2081 | */ | ||
2082 | if (!lpfc_nlp_not_used(ndlp)) { | ||
2083 | /* If ndlp is being used by another discovery | ||
2084 | * thread, just clear NLP_DEFER_RM | ||
2085 | */ | ||
2086 | ndlp->nlp_flag &= ~NLP_DEFER_RM; | ||
2087 | } | ||
2088 | } | ||
2089 | else | ||
2090 | lpfc_nlp_put(ndlp); | ||
2075 | elsiocb->context1 = NULL; | 2091 | elsiocb->context1 = NULL; |
2076 | } | 2092 | } |
2077 | /* context2 = cmd, context2->next = rsp, context3 = bpl */ | 2093 | /* context2 = cmd, context2->next = rsp, context3 = bpl */ |
@@ -2130,13 +2146,15 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | |||
2130 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | 2146 | lpfc_mbuf_free(phba, mp->virt, mp->phys); |
2131 | kfree(mp); | 2147 | kfree(mp); |
2132 | mempool_free(pmb, phba->mbox_mem_pool); | 2148 | mempool_free(pmb, phba->mbox_mem_pool); |
2133 | lpfc_nlp_put(ndlp); | 2149 | if (ndlp) { |
2150 | lpfc_nlp_put(ndlp); | ||
2134 | 2151 | ||
2135 | /* This is the end of the default RPI cleanup logic for this | 2152 | /* This is the end of the default RPI cleanup logic for this |
2136 | * ndlp. If no other discovery threads are using this ndlp. | 2153 | * ndlp. If no other discovery threads are using this ndlp. |
2137 | * we should free all resources associated with it. | 2154 | * we should free all resources associated with it. |
2138 | */ | 2155 | */ |
2139 | lpfc_nlp_not_used(ndlp); | 2156 | lpfc_nlp_not_used(ndlp); |
2157 | } | ||
2140 | return; | 2158 | return; |
2141 | } | 2159 | } |
2142 | 2160 | ||
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index f64ce88e8a06..371f41e886d6 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c | |||
@@ -108,6 +108,8 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) | |||
108 | struct lpfc_vport *vport; | 108 | struct lpfc_vport *vport; |
109 | struct lpfc_hba *phba; | 109 | struct lpfc_hba *phba; |
110 | struct lpfc_work_evt *evtp; | 110 | struct lpfc_work_evt *evtp; |
111 | int put_node; | ||
112 | int put_rport; | ||
111 | 113 | ||
112 | rdata = rport->dd_data; | 114 | rdata = rport->dd_data; |
113 | ndlp = rdata->pnode; | 115 | ndlp = rdata->pnode; |
@@ -128,6 +130,25 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) | |||
128 | "rport devlosscb: sid:x%x did:x%x flg:x%x", | 130 | "rport devlosscb: sid:x%x did:x%x flg:x%x", |
129 | ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag); | 131 | ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag); |
130 | 132 | ||
133 | /* Don't defer this if we are in the process of deleting the vport | ||
134 | * or unloading the driver. The unload will cleanup the node | ||
135 | * appropriately we just need to cleanup the ndlp rport info here. | ||
136 | */ | ||
137 | if (vport->load_flag & FC_UNLOADING) { | ||
138 | put_node = rdata->pnode != NULL; | ||
139 | put_rport = ndlp->rport != NULL; | ||
140 | rdata->pnode = NULL; | ||
141 | ndlp->rport = NULL; | ||
142 | if (put_node) | ||
143 | lpfc_nlp_put(ndlp); | ||
144 | if (put_rport) | ||
145 | put_device(&rport->dev); | ||
146 | return; | ||
147 | } | ||
148 | |||
149 | if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) | ||
150 | return; | ||
151 | |||
131 | evtp = &ndlp->dev_loss_evt; | 152 | evtp = &ndlp->dev_loss_evt; |
132 | 153 | ||
133 | if (!list_empty(&evtp->evt_listp)) | 154 | if (!list_empty(&evtp->evt_listp)) |
@@ -175,8 +196,23 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) | |||
175 | "rport devlosstmo:did:x%x type:x%x id:x%x", | 196 | "rport devlosstmo:did:x%x type:x%x id:x%x", |
176 | ndlp->nlp_DID, ndlp->nlp_type, rport->scsi_target_id); | 197 | ndlp->nlp_DID, ndlp->nlp_type, rport->scsi_target_id); |
177 | 198 | ||
178 | if (!(vport->load_flag & FC_UNLOADING) && | 199 | /* Don't defer this if we are in the process of deleting the vport |
179 | ndlp->nlp_state == NLP_STE_MAPPED_NODE) | 200 | * or unloading the driver. The unload will cleanup the node |
201 | * appropriately we just need to cleanup the ndlp rport info here. | ||
202 | */ | ||
203 | if (vport->load_flag & FC_UNLOADING) { | ||
204 | put_node = rdata->pnode != NULL; | ||
205 | put_rport = ndlp->rport != NULL; | ||
206 | rdata->pnode = NULL; | ||
207 | ndlp->rport = NULL; | ||
208 | if (put_node) | ||
209 | lpfc_nlp_put(ndlp); | ||
210 | if (put_rport) | ||
211 | put_device(&rport->dev); | ||
212 | return; | ||
213 | } | ||
214 | |||
215 | if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) | ||
180 | return; | 216 | return; |
181 | 217 | ||
182 | if (ndlp->nlp_type & NLP_FABRIC) { | 218 | if (ndlp->nlp_type & NLP_FABRIC) { |
@@ -1965,12 +2001,39 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | |||
1965 | static void | 2001 | static void |
1966 | lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | 2002 | lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) |
1967 | { | 2003 | { |
2004 | struct lpfc_hba *phba = vport->phba; | ||
1968 | struct lpfc_rport_data *rdata; | 2005 | struct lpfc_rport_data *rdata; |
2006 | LPFC_MBOXQ_t *mbox; | ||
2007 | int rc; | ||
1969 | 2008 | ||
1970 | if (ndlp->nlp_flag & NLP_DELAY_TMO) { | 2009 | if (ndlp->nlp_flag & NLP_DELAY_TMO) { |
1971 | lpfc_cancel_retry_delay_tmo(vport, ndlp); | 2010 | lpfc_cancel_retry_delay_tmo(vport, ndlp); |
1972 | } | 2011 | } |
1973 | 2012 | ||
2013 | if (ndlp->nlp_flag & NLP_DEFER_RM && !ndlp->nlp_rpi) { | ||
2014 | /* For this case we need to cleanup the default rpi | ||
2015 | * allocated by the firmware. | ||
2016 | */ | ||
2017 | if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL)) | ||
2018 | != NULL) { | ||
2019 | rc = lpfc_reg_login(phba, vport->vpi, ndlp->nlp_DID, | ||
2020 | (uint8_t *) &vport->fc_sparam, mbox, 0); | ||
2021 | if (rc) { | ||
2022 | mempool_free(mbox, phba->mbox_mem_pool); | ||
2023 | } | ||
2024 | else { | ||
2025 | mbox->mbox_flag |= LPFC_MBX_IMED_UNREG; | ||
2026 | mbox->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi; | ||
2027 | mbox->vport = vport; | ||
2028 | mbox->context2 = 0; | ||
2029 | rc =lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); | ||
2030 | if (rc == MBX_NOT_FINISHED) { | ||
2031 | mempool_free(mbox, phba->mbox_mem_pool); | ||
2032 | } | ||
2033 | } | ||
2034 | } | ||
2035 | } | ||
2036 | |||
1974 | lpfc_cleanup_node(vport, ndlp); | 2037 | lpfc_cleanup_node(vport, ndlp); |
1975 | 2038 | ||
1976 | /* | 2039 | /* |
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index b075d5956488..8635b9294640 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h | |||
@@ -153,11 +153,7 @@ struct lpfc_sli_ct_request { | |||
153 | struct gff_acc { | 153 | struct gff_acc { |
154 | uint8_t fbits[128]; | 154 | uint8_t fbits[128]; |
155 | } gff_acc; | 155 | } gff_acc; |
156 | #ifdef __BIG_ENDIAN_BITFIELD | ||
157 | #define FCP_TYPE_FEATURE_OFFSET 7 | 156 | #define FCP_TYPE_FEATURE_OFFSET 7 |
158 | #else /* __LITTLE_ENDIAN_BITFIELD */ | ||
159 | #define FCP_TYPE_FEATURE_OFFSET 4 | ||
160 | #endif | ||
161 | struct rff { | 157 | struct rff { |
162 | uint32_t PortId; | 158 | uint32_t PortId; |
163 | uint8_t reserved[2]; | 159 | uint8_t reserved[2]; |
@@ -1288,8 +1284,9 @@ typedef struct { /* FireFly BIU registers */ | |||
1288 | #define MBX_KILL_BOARD 0x24 | 1284 | #define MBX_KILL_BOARD 0x24 |
1289 | #define MBX_CONFIG_FARP 0x25 | 1285 | #define MBX_CONFIG_FARP 0x25 |
1290 | #define MBX_BEACON 0x2A | 1286 | #define MBX_BEACON 0x2A |
1291 | #define MBX_ASYNCEVT_ENABLE 0x33 | ||
1292 | #define MBX_HEARTBEAT 0x31 | 1287 | #define MBX_HEARTBEAT 0x31 |
1288 | #define MBX_WRITE_VPARMS 0x32 | ||
1289 | #define MBX_ASYNCEVT_ENABLE 0x33 | ||
1293 | 1290 | ||
1294 | #define MBX_CONFIG_HBQ 0x7C | 1291 | #define MBX_CONFIG_HBQ 0x7C |
1295 | #define MBX_LOAD_AREA 0x81 | 1292 | #define MBX_LOAD_AREA 0x81 |
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index ceb185fa3216..db96f7504a14 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
@@ -1339,6 +1339,7 @@ lpfc_cleanup(struct lpfc_vport *vport) | |||
1339 | { | 1339 | { |
1340 | struct lpfc_hba *phba = vport->phba; | 1340 | struct lpfc_hba *phba = vport->phba; |
1341 | struct lpfc_nodelist *ndlp, *next_ndlp; | 1341 | struct lpfc_nodelist *ndlp, *next_ndlp; |
1342 | int i = 0; | ||
1342 | 1343 | ||
1343 | if (phba->link_state > LPFC_LINK_DOWN) | 1344 | if (phba->link_state > LPFC_LINK_DOWN) |
1344 | lpfc_port_link_failure(vport); | 1345 | lpfc_port_link_failure(vport); |
@@ -1351,17 +1352,20 @@ lpfc_cleanup(struct lpfc_vport *vport) | |||
1351 | NLP_EVT_DEVICE_RM); | 1352 | NLP_EVT_DEVICE_RM); |
1352 | } | 1353 | } |
1353 | 1354 | ||
1354 | /* At this point, ALL ndlp's should be gone */ | 1355 | /* At this point, ALL ndlp's should be gone |
1356 | * because of the previous NLP_EVT_DEVICE_RM. | ||
1357 | * Lets wait for this to happen, if needed. | ||
1358 | */ | ||
1355 | while (!list_empty(&vport->fc_nodes)) { | 1359 | while (!list_empty(&vport->fc_nodes)) { |
1356 | 1360 | ||
1357 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, | 1361 | if (i++ > 3000) { |
1358 | nlp_listp) { | ||
1359 | lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, | 1362 | lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, |
1360 | "0233 Nodelist x%x not free: %d\n", | 1363 | "0233 Nodelist not empty\n"); |
1361 | ndlp->nlp_DID, | 1364 | break; |
1362 | atomic_read(&ndlp->kref.refcount)); | ||
1363 | lpfc_drop_node(vport, ndlp); | ||
1364 | } | 1365 | } |
1366 | |||
1367 | /* Wait for any activity on ndlps to settle */ | ||
1368 | msleep(10); | ||
1365 | } | 1369 | } |
1366 | return; | 1370 | return; |
1367 | } | 1371 | } |
@@ -1499,6 +1503,8 @@ lpfc_offline_prep(struct lpfc_hba * phba) | |||
1499 | for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { | 1503 | for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { |
1500 | struct Scsi_Host *shost; | 1504 | struct Scsi_Host *shost; |
1501 | 1505 | ||
1506 | if (vports[i]->load_flag & FC_UNLOADING) | ||
1507 | continue; | ||
1502 | shost = lpfc_shost_from_vport(vports[i]); | 1508 | shost = lpfc_shost_from_vport(vports[i]); |
1503 | list_for_each_entry_safe(ndlp, next_ndlp, | 1509 | list_for_each_entry_safe(ndlp, next_ndlp, |
1504 | &vports[i]->fc_nodes, | 1510 | &vports[i]->fc_nodes, |
@@ -1771,6 +1777,8 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost) | |||
1771 | fc_host_supported_speeds(shost) = 0; | 1777 | fc_host_supported_speeds(shost) = 0; |
1772 | if (phba->lmt & LMT_10Gb) | 1778 | if (phba->lmt & LMT_10Gb) |
1773 | fc_host_supported_speeds(shost) |= FC_PORTSPEED_10GBIT; | 1779 | fc_host_supported_speeds(shost) |= FC_PORTSPEED_10GBIT; |
1780 | if (phba->lmt & LMT_8Gb) | ||
1781 | fc_host_supported_speeds(shost) |= FC_PORTSPEED_8GBIT; | ||
1774 | if (phba->lmt & LMT_4Gb) | 1782 | if (phba->lmt & LMT_4Gb) |
1775 | fc_host_supported_speeds(shost) |= FC_PORTSPEED_4GBIT; | 1783 | fc_host_supported_speeds(shost) |= FC_PORTSPEED_4GBIT; |
1776 | if (phba->lmt & LMT_2Gb) | 1784 | if (phba->lmt & LMT_2Gb) |
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index bba1fb6103f6..c654c787c3e6 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c | |||
@@ -287,6 +287,24 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
287 | pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; | 287 | pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; |
288 | lp = (uint32_t *) pcmd->virt; | 288 | lp = (uint32_t *) pcmd->virt; |
289 | sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t)); | 289 | sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t)); |
290 | if (wwn_to_u64(sp->portName.u.wwn) == 0) { | ||
291 | lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, | ||
292 | "0140 PLOGI Reject: invalid nname\n"); | ||
293 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; | ||
294 | stat.un.b.lsRjtRsnCodeExp = LSEXP_INVALID_PNAME; | ||
295 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, | ||
296 | NULL); | ||
297 | return 0; | ||
298 | } | ||
299 | if (wwn_to_u64(sp->nodeName.u.wwn) == 0) { | ||
300 | lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, | ||
301 | "0141 PLOGI Reject: invalid pname\n"); | ||
302 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; | ||
303 | stat.un.b.lsRjtRsnCodeExp = LSEXP_INVALID_NNAME; | ||
304 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, | ||
305 | NULL); | ||
306 | return 0; | ||
307 | } | ||
290 | if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3) == 0)) { | 308 | if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3) == 0)) { |
291 | /* Reject this request because invalid parameters */ | 309 | /* Reject this request because invalid parameters */ |
292 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; | 310 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; |
@@ -821,6 +839,12 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, | |||
821 | 839 | ||
822 | lp = (uint32_t *) prsp->virt; | 840 | lp = (uint32_t *) prsp->virt; |
823 | sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t)); | 841 | sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t)); |
842 | if (wwn_to_u64(sp->portName.u.wwn) == 0 || | ||
843 | wwn_to_u64(sp->nodeName.u.wwn) == 0) { | ||
844 | lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, | ||
845 | "0142 PLOGI RSP: Invalid WWN.\n"); | ||
846 | goto out; | ||
847 | } | ||
824 | if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3)) | 848 | if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3)) |
825 | goto out; | 849 | goto out; |
826 | /* PLOGI chkparm OK */ | 850 | /* PLOGI chkparm OK */ |
@@ -906,9 +930,7 @@ out: | |||
906 | "0261 Cannot Register NameServer login\n"); | 930 | "0261 Cannot Register NameServer login\n"); |
907 | } | 931 | } |
908 | 932 | ||
909 | /* Free this node since the driver cannot login or has the wrong | 933 | ndlp->nlp_flag |= NLP_DEFER_RM; |
910 | sparm */ | ||
911 | lpfc_nlp_not_used(ndlp); | ||
912 | return NLP_STE_FREED_NODE; | 934 | return NLP_STE_FREED_NODE; |
913 | } | 935 | } |
914 | 936 | ||
@@ -1795,7 +1817,7 @@ lpfc_cmpl_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
1795 | 1817 | ||
1796 | irsp = &rspiocb->iocb; | 1818 | irsp = &rspiocb->iocb; |
1797 | if (irsp->ulpStatus) { | 1819 | if (irsp->ulpStatus) { |
1798 | lpfc_nlp_not_used(ndlp); | 1820 | ndlp->nlp_flag |= NLP_DEFER_RM; |
1799 | return NLP_STE_FREED_NODE; | 1821 | return NLP_STE_FREED_NODE; |
1800 | } | 1822 | } |
1801 | return ndlp->nlp_state; | 1823 | return ndlp->nlp_state; |
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 49f2fdd2ba2b..c3743d6f445b 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c | |||
@@ -540,6 +540,7 @@ lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba) | |||
540 | list_del(&hbq_buf->dbuf.list); | 540 | list_del(&hbq_buf->dbuf.list); |
541 | (phba->hbqs[i].hbq_free_buffer)(phba, hbq_buf); | 541 | (phba->hbqs[i].hbq_free_buffer)(phba, hbq_buf); |
542 | } | 542 | } |
543 | phba->hbqs[i].buffer_count = 0; | ||
543 | } | 544 | } |
544 | } | 545 | } |
545 | 546 | ||
@@ -608,8 +609,8 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count) | |||
608 | return 0; | 609 | return 0; |
609 | } | 610 | } |
610 | 611 | ||
611 | start = lpfc_hbq_defs[hbqno]->buffer_count; | 612 | start = phba->hbqs[hbqno].buffer_count; |
612 | end = count + lpfc_hbq_defs[hbqno]->buffer_count; | 613 | end = count + start; |
613 | if (end > lpfc_hbq_defs[hbqno]->entry_count) { | 614 | if (end > lpfc_hbq_defs[hbqno]->entry_count) { |
614 | end = lpfc_hbq_defs[hbqno]->entry_count; | 615 | end = lpfc_hbq_defs[hbqno]->entry_count; |
615 | } | 616 | } |
@@ -621,7 +622,7 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count) | |||
621 | return 1; | 622 | return 1; |
622 | hbq_buffer->tag = (i | (hbqno << 16)); | 623 | hbq_buffer->tag = (i | (hbqno << 16)); |
623 | if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer)) | 624 | if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer)) |
624 | lpfc_hbq_defs[hbqno]->buffer_count++; | 625 | phba->hbqs[hbqno].buffer_count++; |
625 | else | 626 | else |
626 | (phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer); | 627 | (phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer); |
627 | } | 628 | } |
@@ -661,7 +662,7 @@ lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag) | |||
661 | } | 662 | } |
662 | lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_VPORT, | 663 | lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_VPORT, |
663 | "1803 Bad hbq tag. Data: x%x x%x\n", | 664 | "1803 Bad hbq tag. Data: x%x x%x\n", |
664 | tag, lpfc_hbq_defs[tag >> 16]->buffer_count); | 665 | tag, phba->hbqs[tag >> 16].buffer_count); |
665 | return NULL; | 666 | return NULL; |
666 | } | 667 | } |
667 | 668 | ||
@@ -687,6 +688,7 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand) | |||
687 | case MBX_LOAD_SM: | 688 | case MBX_LOAD_SM: |
688 | case MBX_READ_NV: | 689 | case MBX_READ_NV: |
689 | case MBX_WRITE_NV: | 690 | case MBX_WRITE_NV: |
691 | case MBX_WRITE_VPARMS: | ||
690 | case MBX_RUN_BIU_DIAG: | 692 | case MBX_RUN_BIU_DIAG: |
691 | case MBX_INIT_LINK: | 693 | case MBX_INIT_LINK: |
692 | case MBX_DOWN_LINK: | 694 | case MBX_DOWN_LINK: |