diff options
author | <jejb@titanic.il.steeleye.com> | 2005-04-17 17:05:31 -0400 |
---|---|---|
committer | James Bottomley <jejb@titanic> | 2005-04-18 14:50:53 -0400 |
commit | dea3101e0a5c897d2c9351a7444e139db9f40247 (patch) | |
tree | 61de19e98eed08bb760703b362eab2038c34f261 /drivers/scsi/lpfc/lpfc_els.c | |
parent | 8e8790415e91964096f862a58cacb55d2bc9a817 (diff) |
lpfc: add Emulex FC driver version 8.0.28
From: James.Smart@Emulex.Com
Modified for kernel import and
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_els.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 3258 |
1 files changed, 3258 insertions, 0 deletions
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c new file mode 100644 index 000000000000..68d1b77e0256 --- /dev/null +++ b/drivers/scsi/lpfc/lpfc_els.c | |||
@@ -0,0 +1,3258 @@ | |||
1 | /******************************************************************* | ||
2 | * This file is part of the Emulex Linux Device Driver for * | ||
3 | * Enterprise Fibre Channel Host Bus Adapters. * | ||
4 | * Refer to the README file included with this package for * | ||
5 | * driver version and adapter support. * | ||
6 | * Copyright (C) 2004 Emulex Corporation. * | ||
7 | * www.emulex.com * | ||
8 | * * | ||
9 | * This program is free software; you can redistribute it and/or * | ||
10 | * modify it under the terms of the GNU General Public License * | ||
11 | * as published by the Free Software Foundation; either version 2 * | ||
12 | * of the License, or (at your option) any later version. * | ||
13 | * * | ||
14 | * This program is distributed in the hope that it will be useful, * | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
17 | * GNU General Public License for more details, a copy of which * | ||
18 | * can be found in the file COPYING included with this package. * | ||
19 | *******************************************************************/ | ||
20 | |||
21 | /* | ||
22 | * $Id: lpfc_els.c 1.186 2005/04/13 14:26:55EDT sf_support Exp $ | ||
23 | */ | ||
24 | |||
25 | #include <linux/blkdev.h> | ||
26 | #include <linux/pci.h> | ||
27 | #include <linux/interrupt.h> | ||
28 | |||
29 | #include <scsi/scsi_device.h> | ||
30 | #include <scsi/scsi_host.h> | ||
31 | #include <scsi/scsi_transport_fc.h> | ||
32 | |||
33 | #include "lpfc_hw.h" | ||
34 | #include "lpfc_sli.h" | ||
35 | #include "lpfc_disc.h" | ||
36 | #include "lpfc_scsi.h" | ||
37 | #include "lpfc.h" | ||
38 | #include "lpfc_logmsg.h" | ||
39 | #include "lpfc_crtn.h" | ||
40 | |||
41 | static int lpfc_els_retry(struct lpfc_hba *, struct lpfc_iocbq *, | ||
42 | struct lpfc_iocbq *); | ||
43 | static int lpfc_max_els_tries = 3; | ||
44 | |||
45 | static int | ||
46 | lpfc_els_chk_latt(struct lpfc_hba * phba) | ||
47 | { | ||
48 | struct lpfc_sli *psli; | ||
49 | LPFC_MBOXQ_t *mbox; | ||
50 | uint32_t ha_copy; | ||
51 | int rc; | ||
52 | |||
53 | psli = &phba->sli; | ||
54 | |||
55 | if ((phba->hba_state >= LPFC_HBA_READY) || | ||
56 | (phba->hba_state == LPFC_LINK_DOWN)) | ||
57 | return 0; | ||
58 | |||
59 | /* Read the HBA Host Attention Register */ | ||
60 | spin_lock_irq(phba->host->host_lock); | ||
61 | ha_copy = readl(phba->HAregaddr); | ||
62 | spin_unlock_irq(phba->host->host_lock); | ||
63 | |||
64 | if (!(ha_copy & HA_LATT)) | ||
65 | return 0; | ||
66 | |||
67 | /* Pending Link Event during Discovery */ | ||
68 | lpfc_printf_log(phba, KERN_WARNING, LOG_DISCOVERY, | ||
69 | "%d:0237 Pending Link Event during " | ||
70 | "Discovery: State x%x\n", | ||
71 | phba->brd_no, phba->hba_state); | ||
72 | |||
73 | /* CLEAR_LA should re-enable link attention events and | ||
74 | * we should then imediately take a LATT event. The | ||
75 | * LATT processing should call lpfc_linkdown() which | ||
76 | * will cleanup any left over in-progress discovery | ||
77 | * events. | ||
78 | */ | ||
79 | spin_lock_irq(phba->host->host_lock); | ||
80 | phba->fc_flag |= FC_ABORT_DISCOVERY; | ||
81 | spin_unlock_irq(phba->host->host_lock); | ||
82 | |||
83 | if (phba->hba_state != LPFC_CLEAR_LA) { | ||
84 | if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) { | ||
85 | phba->hba_state = LPFC_CLEAR_LA; | ||
86 | lpfc_clear_la(phba, mbox); | ||
87 | mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la; | ||
88 | rc = lpfc_sli_issue_mbox (phba, mbox, | ||
89 | (MBX_NOWAIT | MBX_STOP_IOCB)); | ||
90 | if (rc == MBX_NOT_FINISHED) { | ||
91 | mempool_free(mbox, phba->mbox_mem_pool); | ||
92 | phba->hba_state = LPFC_HBA_ERROR; | ||
93 | } | ||
94 | } | ||
95 | } | ||
96 | |||
97 | return (1); | ||
98 | |||
99 | } | ||
100 | |||
101 | static struct lpfc_iocbq * | ||
102 | lpfc_prep_els_iocb(struct lpfc_hba * phba, | ||
103 | uint8_t expectRsp, | ||
104 | uint16_t cmdSize, | ||
105 | uint8_t retry, struct lpfc_nodelist * ndlp, uint32_t elscmd) | ||
106 | { | ||
107 | struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list; | ||
108 | struct lpfc_sli_ring *pring; | ||
109 | struct lpfc_iocbq *elsiocb = NULL; | ||
110 | struct lpfc_dmabuf *pcmd, *prsp, *pbuflist; | ||
111 | struct ulp_bde64 *bpl; | ||
112 | IOCB_t *icmd; | ||
113 | |||
114 | pring = &phba->sli.ring[LPFC_ELS_RING]; | ||
115 | |||
116 | if (phba->hba_state < LPFC_LINK_UP) | ||
117 | return NULL; | ||
118 | |||
119 | |||
120 | /* Allocate buffer for command iocb */ | ||
121 | spin_lock_irq(phba->host->host_lock); | ||
122 | list_remove_head(lpfc_iocb_list, elsiocb, struct lpfc_iocbq, list); | ||
123 | spin_unlock_irq(phba->host->host_lock); | ||
124 | |||
125 | if (elsiocb == NULL) | ||
126 | return NULL; | ||
127 | memset(elsiocb, 0, sizeof (struct lpfc_iocbq)); | ||
128 | icmd = &elsiocb->iocb; | ||
129 | |||
130 | /* fill in BDEs for command */ | ||
131 | /* Allocate buffer for command payload */ | ||
132 | if (((pcmd = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == 0) || | ||
133 | ((pcmd->virt = lpfc_mbuf_alloc(phba, | ||
134 | MEM_PRI, &(pcmd->phys))) == 0)) { | ||
135 | if (pcmd) | ||
136 | kfree(pcmd); | ||
137 | |||
138 | list_add_tail(&elsiocb->list, lpfc_iocb_list); | ||
139 | return NULL; | ||
140 | } | ||
141 | |||
142 | INIT_LIST_HEAD(&pcmd->list); | ||
143 | |||
144 | /* Allocate buffer for response payload */ | ||
145 | if (expectRsp) { | ||
146 | prsp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); | ||
147 | if (prsp) | ||
148 | prsp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, | ||
149 | &prsp->phys); | ||
150 | if (prsp == 0 || prsp->virt == 0) { | ||
151 | if (prsp) | ||
152 | kfree(prsp); | ||
153 | lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); | ||
154 | kfree(pcmd); | ||
155 | list_add_tail(&elsiocb->list, lpfc_iocb_list); | ||
156 | return NULL; | ||
157 | } | ||
158 | INIT_LIST_HEAD(&prsp->list); | ||
159 | } else { | ||
160 | prsp = NULL; | ||
161 | } | ||
162 | |||
163 | /* Allocate buffer for Buffer ptr list */ | ||
164 | pbuflist = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); | ||
165 | if (pbuflist) | ||
166 | pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI, | ||
167 | &pbuflist->phys); | ||
168 | if (pbuflist == 0 || pbuflist->virt == 0) { | ||
169 | list_add_tail(&elsiocb->list, lpfc_iocb_list); | ||
170 | lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); | ||
171 | lpfc_mbuf_free(phba, prsp->virt, prsp->phys); | ||
172 | kfree(pcmd); | ||
173 | kfree(prsp); | ||
174 | if (pbuflist) | ||
175 | kfree(pbuflist); | ||
176 | return NULL; | ||
177 | } | ||
178 | |||
179 | INIT_LIST_HEAD(&pbuflist->list); | ||
180 | |||
181 | icmd->un.elsreq64.bdl.addrHigh = putPaddrHigh(pbuflist->phys); | ||
182 | icmd->un.elsreq64.bdl.addrLow = putPaddrLow(pbuflist->phys); | ||
183 | icmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BDL; | ||
184 | if (expectRsp) { | ||
185 | icmd->un.elsreq64.bdl.bdeSize = (2 * sizeof (struct ulp_bde64)); | ||
186 | icmd->un.elsreq64.remoteID = ndlp->nlp_DID; /* DID */ | ||
187 | icmd->ulpCommand = CMD_ELS_REQUEST64_CR; | ||
188 | } else { | ||
189 | icmd->un.elsreq64.bdl.bdeSize = sizeof (struct ulp_bde64); | ||
190 | icmd->ulpCommand = CMD_XMIT_ELS_RSP64_CX; | ||
191 | } | ||
192 | |||
193 | icmd->ulpBdeCount = 1; | ||
194 | icmd->ulpLe = 1; | ||
195 | icmd->ulpClass = CLASS3; | ||
196 | |||
197 | bpl = (struct ulp_bde64 *) pbuflist->virt; | ||
198 | bpl->addrLow = le32_to_cpu(putPaddrLow(pcmd->phys)); | ||
199 | bpl->addrHigh = le32_to_cpu(putPaddrHigh(pcmd->phys)); | ||
200 | bpl->tus.f.bdeSize = cmdSize; | ||
201 | bpl->tus.f.bdeFlags = 0; | ||
202 | bpl->tus.w = le32_to_cpu(bpl->tus.w); | ||
203 | |||
204 | if (expectRsp) { | ||
205 | bpl++; | ||
206 | bpl->addrLow = le32_to_cpu(putPaddrLow(prsp->phys)); | ||
207 | bpl->addrHigh = le32_to_cpu(putPaddrHigh(prsp->phys)); | ||
208 | bpl->tus.f.bdeSize = FCELSSIZE; | ||
209 | bpl->tus.f.bdeFlags = BUFF_USE_RCV; | ||
210 | bpl->tus.w = le32_to_cpu(bpl->tus.w); | ||
211 | } | ||
212 | |||
213 | /* Save for completion so we can release these resources */ | ||
214 | elsiocb->context1 = (uint8_t *) ndlp; | ||
215 | elsiocb->context2 = (uint8_t *) pcmd; | ||
216 | elsiocb->context3 = (uint8_t *) pbuflist; | ||
217 | elsiocb->retry = retry; | ||
218 | elsiocb->drvrTimeout = (phba->fc_ratov << 1) + LPFC_DRVR_TIMEOUT; | ||
219 | |||
220 | if (prsp) { | ||
221 | list_add(&prsp->list, &pcmd->list); | ||
222 | } | ||
223 | |||
224 | if (expectRsp) { | ||
225 | /* Xmit ELS command <elsCmd> to remote NPORT <did> */ | ||
226 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, | ||
227 | "%d:0116 Xmit ELS command x%x to remote " | ||
228 | "NPORT x%x Data: x%x x%x\n", | ||
229 | phba->brd_no, elscmd, | ||
230 | ndlp->nlp_DID, icmd->ulpIoTag, phba->hba_state); | ||
231 | } else { | ||
232 | /* Xmit ELS response <elsCmd> to remote NPORT <did> */ | ||
233 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, | ||
234 | "%d:0117 Xmit ELS response x%x to remote " | ||
235 | "NPORT x%x Data: x%x x%x\n", | ||
236 | phba->brd_no, elscmd, | ||
237 | ndlp->nlp_DID, icmd->ulpIoTag, cmdSize); | ||
238 | } | ||
239 | |||
240 | return (elsiocb); | ||
241 | } | ||
242 | |||
243 | |||
244 | static int | ||
245 | lpfc_cmpl_els_flogi_fabric(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, | ||
246 | struct serv_parm *sp, IOCB_t *irsp) | ||
247 | { | ||
248 | LPFC_MBOXQ_t *mbox; | ||
249 | int rc; | ||
250 | |||
251 | spin_lock_irq(phba->host->host_lock); | ||
252 | phba->fc_flag |= FC_FABRIC; | ||
253 | spin_unlock_irq(phba->host->host_lock); | ||
254 | |||
255 | phba->fc_edtov = be32_to_cpu(sp->cmn.e_d_tov); | ||
256 | if (sp->cmn.edtovResolution) /* E_D_TOV ticks are in nanoseconds */ | ||
257 | phba->fc_edtov = (phba->fc_edtov + 999999) / 1000000; | ||
258 | |||
259 | phba->fc_ratov = (be32_to_cpu(sp->cmn.w2.r_a_tov) + 999) / 1000; | ||
260 | |||
261 | if (phba->fc_topology == TOPOLOGY_LOOP) { | ||
262 | spin_lock_irq(phba->host->host_lock); | ||
263 | phba->fc_flag |= FC_PUBLIC_LOOP; | ||
264 | spin_unlock_irq(phba->host->host_lock); | ||
265 | } else { | ||
266 | /* | ||
267 | * If we are a N-port connected to a Fabric, fixup sparam's so | ||
268 | * logins to devices on remote loops work. | ||
269 | */ | ||
270 | phba->fc_sparam.cmn.altBbCredit = 1; | ||
271 | } | ||
272 | |||
273 | phba->fc_myDID = irsp->un.ulpWord[4] & Mask_DID; | ||
274 | memcpy(&ndlp->nlp_portname, &sp->portName, sizeof(struct lpfc_name)); | ||
275 | memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof (struct lpfc_name)); | ||
276 | ndlp->nlp_class_sup = 0; | ||
277 | if (sp->cls1.classValid) | ||
278 | ndlp->nlp_class_sup |= FC_COS_CLASS1; | ||
279 | if (sp->cls2.classValid) | ||
280 | ndlp->nlp_class_sup |= FC_COS_CLASS2; | ||
281 | if (sp->cls3.classValid) | ||
282 | ndlp->nlp_class_sup |= FC_COS_CLASS3; | ||
283 | if (sp->cls4.classValid) | ||
284 | ndlp->nlp_class_sup |= FC_COS_CLASS4; | ||
285 | ndlp->nlp_maxframe = ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | | ||
286 | sp->cmn.bbRcvSizeLsb; | ||
287 | memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm)); | ||
288 | |||
289 | mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); | ||
290 | if (!mbox) | ||
291 | goto fail; | ||
292 | |||
293 | phba->hba_state = LPFC_FABRIC_CFG_LINK; | ||
294 | lpfc_config_link(phba, mbox); | ||
295 | mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; | ||
296 | |||
297 | rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB); | ||
298 | if (rc == MBX_NOT_FINISHED) | ||
299 | goto fail_free_mbox; | ||
300 | |||
301 | mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); | ||
302 | if (!mbox) | ||
303 | goto fail; | ||
304 | |||
305 | if (lpfc_reg_login(phba, Fabric_DID, (uint8_t *) sp, mbox, 0)) | ||
306 | goto fail_free_mbox; | ||
307 | |||
308 | /* | ||
309 | * set_slim mailbox command needs to execute first, | ||
310 | * queue this command to be processed later. | ||
311 | */ | ||
312 | mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login; | ||
313 | mbox->context2 = ndlp; | ||
314 | |||
315 | rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB); | ||
316 | if (rc == MBX_NOT_FINISHED) | ||
317 | goto fail_free_mbox; | ||
318 | |||
319 | return 0; | ||
320 | |||
321 | fail_free_mbox: | ||
322 | mempool_free(mbox, phba->mbox_mem_pool); | ||
323 | fail: | ||
324 | return -ENXIO; | ||
325 | } | ||
326 | |||
327 | /* | ||
328 | * We FLOGIed into an NPort, initiate pt2pt protocol | ||
329 | */ | ||
330 | static int | ||
331 | lpfc_cmpl_els_flogi_nport(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, | ||
332 | struct serv_parm *sp) | ||
333 | { | ||
334 | LPFC_MBOXQ_t *mbox; | ||
335 | int rc; | ||
336 | |||
337 | spin_lock_irq(phba->host->host_lock); | ||
338 | phba->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); | ||
339 | spin_unlock_irq(phba->host->host_lock); | ||
340 | |||
341 | phba->fc_edtov = FF_DEF_EDTOV; | ||
342 | phba->fc_ratov = FF_DEF_RATOV; | ||
343 | rc = memcmp(&phba->fc_portname, &sp->portName, | ||
344 | sizeof(struct lpfc_name)); | ||
345 | if (rc >= 0) { | ||
346 | /* This side will initiate the PLOGI */ | ||
347 | spin_lock_irq(phba->host->host_lock); | ||
348 | phba->fc_flag |= FC_PT2PT_PLOGI; | ||
349 | spin_unlock_irq(phba->host->host_lock); | ||
350 | |||
351 | /* | ||
352 | * N_Port ID cannot be 0, set our to LocalID the other | ||
353 | * side will be RemoteID. | ||
354 | */ | ||
355 | |||
356 | /* not equal */ | ||
357 | if (rc) | ||
358 | phba->fc_myDID = PT2PT_LocalID; | ||
359 | |||
360 | mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); | ||
361 | if (!mbox) | ||
362 | goto fail; | ||
363 | |||
364 | lpfc_config_link(phba, mbox); | ||
365 | |||
366 | mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; | ||
367 | rc = lpfc_sli_issue_mbox(phba, mbox, | ||
368 | MBX_NOWAIT | MBX_STOP_IOCB); | ||
369 | if (rc == MBX_NOT_FINISHED) { | ||
370 | mempool_free(mbox, phba->mbox_mem_pool); | ||
371 | goto fail; | ||
372 | } | ||
373 | mempool_free(ndlp, phba->nlp_mem_pool); | ||
374 | |||
375 | ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, PT2PT_RemoteID); | ||
376 | if (!ndlp) { | ||
377 | /* | ||
378 | * Cannot find existing Fabric ndlp, so allocate a | ||
379 | * new one | ||
380 | */ | ||
381 | ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); | ||
382 | if (!ndlp) | ||
383 | goto fail; | ||
384 | |||
385 | lpfc_nlp_init(phba, ndlp, PT2PT_RemoteID); | ||
386 | } | ||
387 | |||
388 | memcpy(&ndlp->nlp_portname, &sp->portName, | ||
389 | sizeof(struct lpfc_name)); | ||
390 | memcpy(&ndlp->nlp_nodename, &sp->nodeName, | ||
391 | sizeof(struct lpfc_name)); | ||
392 | ndlp->nlp_state = NLP_STE_NPR_NODE; | ||
393 | lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); | ||
394 | ndlp->nlp_flag |= NLP_NPR_2B_DISC; | ||
395 | } else { | ||
396 | /* This side will wait for the PLOGI */ | ||
397 | mempool_free( ndlp, phba->nlp_mem_pool); | ||
398 | } | ||
399 | |||
400 | spin_lock_irq(phba->host->host_lock); | ||
401 | phba->fc_flag |= FC_PT2PT; | ||
402 | spin_unlock_irq(phba->host->host_lock); | ||
403 | |||
404 | /* Start discovery - this should just do CLEAR_LA */ | ||
405 | lpfc_disc_start(phba); | ||
406 | return 0; | ||
407 | fail: | ||
408 | return -ENXIO; | ||
409 | } | ||
410 | |||
411 | static void | ||
412 | lpfc_cmpl_els_flogi(struct lpfc_hba * phba, | ||
413 | struct lpfc_iocbq * cmdiocb, struct lpfc_iocbq * rspiocb) | ||
414 | { | ||
415 | IOCB_t *irsp = &rspiocb->iocb; | ||
416 | struct lpfc_nodelist *ndlp = cmdiocb->context1; | ||
417 | struct lpfc_dmabuf *pcmd = cmdiocb->context2, *prsp; | ||
418 | struct serv_parm *sp; | ||
419 | int rc; | ||
420 | |||
421 | /* Check to see if link went down during discovery */ | ||
422 | if (lpfc_els_chk_latt(phba)) { | ||
423 | lpfc_nlp_remove(phba, ndlp); | ||
424 | goto out; | ||
425 | } | ||
426 | |||
427 | if (irsp->ulpStatus) { | ||
428 | /* Check for retry */ | ||
429 | if (lpfc_els_retry(phba, cmdiocb, rspiocb)) { | ||
430 | /* ELS command is being retried */ | ||
431 | goto out; | ||
432 | } | ||
433 | /* FLOGI failed, so there is no fabric */ | ||
434 | spin_lock_irq(phba->host->host_lock); | ||
435 | phba->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); | ||
436 | spin_unlock_irq(phba->host->host_lock); | ||
437 | |||
438 | /* If private loop, then allow max outstandting els to be | ||
439 | * LPFC_MAX_DISC_THREADS (32). Scanning in the case of no | ||
440 | * alpa map would take too long otherwise. | ||
441 | */ | ||
442 | if (phba->alpa_map[0] == 0) { | ||
443 | phba->cfg_discovery_threads = | ||
444 | LPFC_MAX_DISC_THREADS; | ||
445 | } | ||
446 | |||
447 | /* FLOGI failure */ | ||
448 | lpfc_printf_log(phba, | ||
449 | KERN_INFO, | ||
450 | LOG_ELS, | ||
451 | "%d:0100 FLOGI failure Data: x%x x%x\n", | ||
452 | phba->brd_no, | ||
453 | irsp->ulpStatus, irsp->un.ulpWord[4]); | ||
454 | goto flogifail; | ||
455 | } | ||
456 | |||
457 | /* | ||
458 | * The FLogI succeeded. Sync the data for the CPU before | ||
459 | * accessing it. | ||
460 | */ | ||
461 | prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list); | ||
462 | |||
463 | sp = prsp->virt + sizeof(uint32_t); | ||
464 | |||
465 | /* FLOGI completes successfully */ | ||
466 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, | ||
467 | "%d:0101 FLOGI completes sucessfully " | ||
468 | "Data: x%x x%x x%x x%x\n", | ||
469 | phba->brd_no, | ||
470 | irsp->un.ulpWord[4], sp->cmn.e_d_tov, | ||
471 | sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution); | ||
472 | |||
473 | if (phba->hba_state == LPFC_FLOGI) { | ||
474 | /* | ||
475 | * If Common Service Parameters indicate Nport | ||
476 | * we are point to point, if Fport we are Fabric. | ||
477 | */ | ||
478 | if (sp->cmn.fPort) | ||
479 | rc = lpfc_cmpl_els_flogi_fabric(phba, ndlp, sp, irsp); | ||
480 | else | ||
481 | rc = lpfc_cmpl_els_flogi_nport(phba, ndlp, sp); | ||
482 | |||
483 | if (!rc) | ||
484 | goto out; | ||
485 | } | ||
486 | |||
487 | flogifail: | ||
488 | lpfc_nlp_remove(phba, ndlp); | ||
489 | |||
490 | if (irsp->ulpStatus != IOSTAT_LOCAL_REJECT || | ||
491 | (irsp->un.ulpWord[4] != IOERR_SLI_ABORTED && | ||
492 | irsp->un.ulpWord[4] != IOERR_SLI_DOWN)) { | ||
493 | /* FLOGI failed, so just use loop map to make discovery list */ | ||
494 | lpfc_disc_list_loopmap(phba); | ||
495 | |||
496 | /* Start discovery */ | ||
497 | lpfc_disc_start(phba); | ||
498 | } | ||
499 | |||
500 | out: | ||
501 | lpfc_els_free_iocb(phba, cmdiocb); | ||
502 | } | ||
503 | |||
504 | static int | ||
505 | lpfc_issue_els_flogi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, | ||
506 | uint8_t retry) | ||
507 | { | ||
508 | struct serv_parm *sp; | ||
509 | IOCB_t *icmd; | ||
510 | struct lpfc_iocbq *elsiocb; | ||
511 | struct lpfc_sli_ring *pring; | ||
512 | uint8_t *pcmd; | ||
513 | uint16_t cmdsize; | ||
514 | uint32_t tmo; | ||
515 | int rc; | ||
516 | |||
517 | pring = &phba->sli.ring[LPFC_ELS_RING]; | ||
518 | |||
519 | cmdsize = (sizeof (uint32_t) + sizeof (struct serv_parm)); | ||
520 | if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, | ||
521 | ndlp, ELS_CMD_FLOGI)) == 0) { | ||
522 | return (1); | ||
523 | } | ||
524 | |||
525 | icmd = &elsiocb->iocb; | ||
526 | pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); | ||
527 | |||
528 | /* For FLOGI request, remainder of payload is service parameters */ | ||
529 | *((uint32_t *) (pcmd)) = ELS_CMD_FLOGI; | ||
530 | pcmd += sizeof (uint32_t); | ||
531 | memcpy(pcmd, &phba->fc_sparam, sizeof (struct serv_parm)); | ||
532 | sp = (struct serv_parm *) pcmd; | ||
533 | |||
534 | /* Setup CSPs accordingly for Fabric */ | ||
535 | sp->cmn.e_d_tov = 0; | ||
536 | sp->cmn.w2.r_a_tov = 0; | ||
537 | sp->cls1.classValid = 0; | ||
538 | sp->cls2.seqDelivery = 1; | ||
539 | sp->cls3.seqDelivery = 1; | ||
540 | if (sp->cmn.fcphLow < FC_PH3) | ||
541 | sp->cmn.fcphLow = FC_PH3; | ||
542 | if (sp->cmn.fcphHigh < FC_PH3) | ||
543 | sp->cmn.fcphHigh = FC_PH3; | ||
544 | |||
545 | tmo = phba->fc_ratov; | ||
546 | phba->fc_ratov = LPFC_DISC_FLOGI_TMO; | ||
547 | lpfc_set_disctmo(phba); | ||
548 | phba->fc_ratov = tmo; | ||
549 | |||
550 | phba->fc_stat.elsXmitFLOGI++; | ||
551 | elsiocb->iocb_cmpl = lpfc_cmpl_els_flogi; | ||
552 | spin_lock_irq(phba->host->host_lock); | ||
553 | rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0); | ||
554 | spin_unlock_irq(phba->host->host_lock); | ||
555 | if (rc == IOCB_ERROR) { | ||
556 | lpfc_els_free_iocb(phba, elsiocb); | ||
557 | return (1); | ||
558 | } | ||
559 | return (0); | ||
560 | } | ||
561 | |||
562 | int | ||
563 | lpfc_els_abort_flogi(struct lpfc_hba * phba) | ||
564 | { | ||
565 | struct lpfc_sli_ring *pring; | ||
566 | struct lpfc_iocbq *iocb, *next_iocb; | ||
567 | struct lpfc_nodelist *ndlp; | ||
568 | IOCB_t *icmd; | ||
569 | |||
570 | /* Abort outstanding I/O on NPort <nlp_DID> */ | ||
571 | lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, | ||
572 | "%d:0201 Abort outstanding I/O on NPort x%x\n", | ||
573 | phba->brd_no, Fabric_DID); | ||
574 | |||
575 | pring = &phba->sli.ring[LPFC_ELS_RING]; | ||
576 | |||
577 | /* | ||
578 | * Check the txcmplq for an iocb that matches the nport the driver is | ||
579 | * searching for. | ||
580 | */ | ||
581 | spin_lock_irq(phba->host->host_lock); | ||
582 | list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { | ||
583 | icmd = &iocb->iocb; | ||
584 | if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) { | ||
585 | ndlp = (struct lpfc_nodelist *)(iocb->context1); | ||
586 | if (ndlp && (ndlp->nlp_DID == Fabric_DID)) { | ||
587 | list_del(&iocb->list); | ||
588 | pring->txcmplq_cnt--; | ||
589 | |||
590 | if ((icmd->un.elsreq64.bdl.ulpIoTag32)) { | ||
591 | lpfc_sli_issue_abort_iotag32 | ||
592 | (phba, pring, iocb); | ||
593 | } | ||
594 | if (iocb->iocb_cmpl) { | ||
595 | icmd->ulpStatus = IOSTAT_LOCAL_REJECT; | ||
596 | icmd->un.ulpWord[4] = | ||
597 | IOERR_SLI_ABORTED; | ||
598 | spin_unlock_irq(phba->host->host_lock); | ||
599 | (iocb->iocb_cmpl) (phba, iocb, iocb); | ||
600 | spin_lock_irq(phba->host->host_lock); | ||
601 | } else { | ||
602 | list_add_tail(&iocb->list, | ||
603 | &phba->lpfc_iocb_list); | ||
604 | } | ||
605 | } | ||
606 | } | ||
607 | } | ||
608 | spin_unlock_irq(phba->host->host_lock); | ||
609 | |||
610 | return 0; | ||
611 | } | ||
612 | |||
613 | int | ||
614 | lpfc_initial_flogi(struct lpfc_hba * phba) | ||
615 | { | ||
616 | struct lpfc_nodelist *ndlp; | ||
617 | |||
618 | /* First look for Fabric ndlp on the unmapped list */ | ||
619 | |||
620 | if ((ndlp = | ||
621 | lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED, | ||
622 | Fabric_DID)) == 0) { | ||
623 | /* Cannot find existing Fabric ndlp, so allocate a new one */ | ||
624 | if ((ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL)) | ||
625 | == 0) { | ||
626 | return (0); | ||
627 | } | ||
628 | lpfc_nlp_init(phba, ndlp, Fabric_DID); | ||
629 | } | ||
630 | else { | ||
631 | phba->fc_unmap_cnt--; | ||
632 | list_del(&ndlp->nlp_listp); | ||
633 | spin_lock_irq(phba->host->host_lock); | ||
634 | ndlp->nlp_flag &= ~NLP_LIST_MASK; | ||
635 | spin_unlock_irq(phba->host->host_lock); | ||
636 | } | ||
637 | if (lpfc_issue_els_flogi(phba, ndlp, 0)) { | ||
638 | mempool_free( ndlp, phba->nlp_mem_pool); | ||
639 | } | ||
640 | return (1); | ||
641 | } | ||
642 | |||
643 | static void | ||
644 | lpfc_more_plogi(struct lpfc_hba * phba) | ||
645 | { | ||
646 | int sentplogi; | ||
647 | |||
648 | if (phba->num_disc_nodes) | ||
649 | phba->num_disc_nodes--; | ||
650 | |||
651 | /* Continue discovery with <num_disc_nodes> PLOGIs to go */ | ||
652 | lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, | ||
653 | "%d:0232 Continue discovery with %d PLOGIs to go " | ||
654 | "Data: x%x x%x x%x\n", | ||
655 | phba->brd_no, phba->num_disc_nodes, phba->fc_plogi_cnt, | ||
656 | phba->fc_flag, phba->hba_state); | ||
657 | |||
658 | /* Check to see if there are more PLOGIs to be sent */ | ||
659 | if (phba->fc_flag & FC_NLP_MORE) { | ||
660 | /* go thru NPR list and issue any remaining ELS PLOGIs */ | ||
661 | sentplogi = lpfc_els_disc_plogi(phba); | ||
662 | } | ||
663 | return; | ||
664 | } | ||
665 | |||
666 | static void | ||
667 | lpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, | ||
668 | struct lpfc_iocbq * rspiocb) | ||
669 | { | ||
670 | IOCB_t *irsp; | ||
671 | struct lpfc_sli *psli; | ||
672 | struct lpfc_nodelist *ndlp; | ||
673 | int disc, rc, did, type; | ||
674 | |||
675 | psli = &phba->sli; | ||
676 | |||
677 | /* we pass cmdiocb to state machine which needs rspiocb as well */ | ||
678 | cmdiocb->context_un.rsp_iocb = rspiocb; | ||
679 | |||
680 | irsp = &rspiocb->iocb; | ||
681 | ndlp = (struct lpfc_nodelist *) cmdiocb->context1; | ||
682 | spin_lock_irq(phba->host->host_lock); | ||
683 | ndlp->nlp_flag &= ~NLP_PLOGI_SND; | ||
684 | spin_unlock_irq(phba->host->host_lock); | ||
685 | |||
686 | /* Since ndlp can be freed in the disc state machine, note if this node | ||
687 | * is being used during discovery. | ||
688 | */ | ||
689 | disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC); | ||
690 | rc = 0; | ||
691 | |||
692 | /* PLOGI completes to NPort <nlp_DID> */ | ||
693 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, | ||
694 | "%d:0102 PLOGI completes to NPort x%x " | ||
695 | "Data: x%x x%x x%x x%x\n", | ||
696 | phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus, | ||
697 | irsp->un.ulpWord[4], disc, phba->num_disc_nodes); | ||
698 | |||
699 | /* Check to see if link went down during discovery */ | ||
700 | if (lpfc_els_chk_latt(phba)) { | ||
701 | spin_lock_irq(phba->host->host_lock); | ||
702 | ndlp->nlp_flag |= NLP_NPR_2B_DISC; | ||
703 | spin_unlock_irq(phba->host->host_lock); | ||
704 | goto out; | ||
705 | } | ||
706 | |||
707 | /* ndlp could be freed in DSM, save these values now */ | ||
708 | type = ndlp->nlp_type; | ||
709 | did = ndlp->nlp_DID; | ||
710 | |||
711 | if (irsp->ulpStatus) { | ||
712 | /* Check for retry */ | ||
713 | if (lpfc_els_retry(phba, cmdiocb, rspiocb)) { | ||
714 | /* ELS command is being retried */ | ||
715 | if (disc) { | ||
716 | spin_lock_irq(phba->host->host_lock); | ||
717 | ndlp->nlp_flag |= NLP_NPR_2B_DISC; | ||
718 | spin_unlock_irq(phba->host->host_lock); | ||
719 | } | ||
720 | goto out; | ||
721 | } | ||
722 | |||
723 | /* PLOGI failed */ | ||
724 | /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ | ||
725 | if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && | ||
726 | ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) || | ||
727 | (irsp->un.ulpWord[4] == IOERR_SLI_DOWN))) { | ||
728 | disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC); | ||
729 | } | ||
730 | else { | ||
731 | rc = lpfc_disc_state_machine(phba, ndlp, cmdiocb, | ||
732 | NLP_EVT_CMPL_PLOGI); | ||
733 | } | ||
734 | } else { | ||
735 | /* Good status, call state machine */ | ||
736 | rc = lpfc_disc_state_machine(phba, ndlp, cmdiocb, | ||
737 | NLP_EVT_CMPL_PLOGI); | ||
738 | } | ||
739 | |||
740 | if (type & NLP_FABRIC) { | ||
741 | /* If we cannot login to Nameserver, kick off discovery now */ | ||
742 | if ((did == NameServer_DID) && (rc == NLP_STE_FREED_NODE)) { | ||
743 | lpfc_disc_start(phba); | ||
744 | } | ||
745 | goto out; | ||
746 | } | ||
747 | |||
748 | if (disc && phba->num_disc_nodes) { | ||
749 | /* Check to see if there are more PLOGIs to be sent */ | ||
750 | lpfc_more_plogi(phba); | ||
751 | } | ||
752 | |||
753 | if (rc != NLP_STE_FREED_NODE) { | ||
754 | spin_lock_irq(phba->host->host_lock); | ||
755 | ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; | ||
756 | spin_unlock_irq(phba->host->host_lock); | ||
757 | } | ||
758 | |||
759 | if (phba->num_disc_nodes == 0) { | ||
760 | if(disc) { | ||
761 | spin_lock_irq(phba->host->host_lock); | ||
762 | phba->fc_flag &= ~FC_NDISC_ACTIVE; | ||
763 | spin_unlock_irq(phba->host->host_lock); | ||
764 | } | ||
765 | lpfc_can_disctmo(phba); | ||
766 | if (phba->fc_flag & FC_RSCN_MODE) { | ||
767 | /* Check to see if more RSCNs came in while we were | ||
768 | * processing this one. | ||
769 | */ | ||
770 | if ((phba->fc_rscn_id_cnt == 0) && | ||
771 | (!(phba->fc_flag & FC_RSCN_DISCOVERY))) { | ||
772 | spin_lock_irq(phba->host->host_lock); | ||
773 | phba->fc_flag &= ~FC_RSCN_MODE; | ||
774 | spin_unlock_irq(phba->host->host_lock); | ||
775 | } else { | ||
776 | lpfc_els_handle_rscn(phba); | ||
777 | } | ||
778 | } | ||
779 | } | ||
780 | |||
781 | out: | ||
782 | lpfc_els_free_iocb(phba, cmdiocb); | ||
783 | return; | ||
784 | } | ||
785 | |||
786 | int | ||
787 | lpfc_issue_els_plogi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, | ||
788 | uint8_t retry) | ||
789 | { | ||
790 | struct serv_parm *sp; | ||
791 | IOCB_t *icmd; | ||
792 | struct lpfc_iocbq *elsiocb; | ||
793 | struct lpfc_sli_ring *pring; | ||
794 | struct lpfc_sli *psli; | ||
795 | uint8_t *pcmd; | ||
796 | uint16_t cmdsize; | ||
797 | |||
798 | psli = &phba->sli; | ||
799 | pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ | ||
800 | |||
801 | cmdsize = (sizeof (uint32_t) + sizeof (struct serv_parm)); | ||
802 | if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, | ||
803 | ndlp, ELS_CMD_PLOGI)) == 0) { | ||
804 | return (1); | ||
805 | } | ||
806 | |||
807 | icmd = &elsiocb->iocb; | ||
808 | pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); | ||
809 | |||
810 | /* For PLOGI request, remainder of payload is service parameters */ | ||
811 | *((uint32_t *) (pcmd)) = ELS_CMD_PLOGI; | ||
812 | pcmd += sizeof (uint32_t); | ||
813 | memcpy(pcmd, &phba->fc_sparam, sizeof (struct serv_parm)); | ||
814 | sp = (struct serv_parm *) pcmd; | ||
815 | |||
816 | if (sp->cmn.fcphLow < FC_PH_4_3) | ||
817 | sp->cmn.fcphLow = FC_PH_4_3; | ||
818 | |||
819 | if (sp->cmn.fcphHigh < FC_PH3) | ||
820 | sp->cmn.fcphHigh = FC_PH3; | ||
821 | |||
822 | phba->fc_stat.elsXmitPLOGI++; | ||
823 | elsiocb->iocb_cmpl = lpfc_cmpl_els_plogi; | ||
824 | spin_lock_irq(phba->host->host_lock); | ||
825 | ndlp->nlp_flag |= NLP_PLOGI_SND; | ||
826 | if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { | ||
827 | ndlp->nlp_flag &= ~NLP_PLOGI_SND; | ||
828 | spin_unlock_irq(phba->host->host_lock); | ||
829 | lpfc_els_free_iocb(phba, elsiocb); | ||
830 | return (1); | ||
831 | } | ||
832 | spin_unlock_irq(phba->host->host_lock); | ||
833 | return (0); | ||
834 | } | ||
835 | |||
836 | static void | ||
837 | lpfc_cmpl_els_prli(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, | ||
838 | struct lpfc_iocbq * rspiocb) | ||
839 | { | ||
840 | IOCB_t *irsp; | ||
841 | struct lpfc_sli *psli; | ||
842 | struct lpfc_nodelist *ndlp; | ||
843 | |||
844 | psli = &phba->sli; | ||
845 | /* we pass cmdiocb to state machine which needs rspiocb as well */ | ||
846 | cmdiocb->context_un.rsp_iocb = rspiocb; | ||
847 | |||
848 | irsp = &(rspiocb->iocb); | ||
849 | ndlp = (struct lpfc_nodelist *) cmdiocb->context1; | ||
850 | spin_lock_irq(phba->host->host_lock); | ||
851 | ndlp->nlp_flag &= ~NLP_PRLI_SND; | ||
852 | spin_unlock_irq(phba->host->host_lock); | ||
853 | |||
854 | /* PRLI completes to NPort <nlp_DID> */ | ||
855 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, | ||
856 | "%d:0103 PRLI completes to NPort x%x " | ||
857 | "Data: x%x x%x x%x\n", | ||
858 | phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus, | ||
859 | irsp->un.ulpWord[4], phba->num_disc_nodes); | ||
860 | |||
861 | phba->fc_prli_sent--; | ||
862 | /* Check to see if link went down during discovery */ | ||
863 | if (lpfc_els_chk_latt(phba)) | ||
864 | goto out; | ||
865 | |||
866 | if (irsp->ulpStatus) { | ||
867 | /* Check for retry */ | ||
868 | if (lpfc_els_retry(phba, cmdiocb, rspiocb)) { | ||
869 | /* ELS command is being retried */ | ||
870 | goto out; | ||
871 | } | ||
872 | /* PRLI failed */ | ||
873 | /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ | ||
874 | if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && | ||
875 | ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) || | ||
876 | (irsp->un.ulpWord[4] == IOERR_SLI_DOWN))) { | ||
877 | goto out; | ||
878 | } | ||
879 | else { | ||
880 | lpfc_disc_state_machine(phba, ndlp, cmdiocb, | ||
881 | NLP_EVT_CMPL_PRLI); | ||
882 | } | ||
883 | } else { | ||
884 | /* Good status, call state machine */ | ||
885 | lpfc_disc_state_machine(phba, ndlp, cmdiocb, NLP_EVT_CMPL_PRLI); | ||
886 | } | ||
887 | |||
888 | out: | ||
889 | lpfc_els_free_iocb(phba, cmdiocb); | ||
890 | return; | ||
891 | } | ||
892 | |||
893 | int | ||
894 | lpfc_issue_els_prli(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, | ||
895 | uint8_t retry) | ||
896 | { | ||
897 | PRLI *npr; | ||
898 | IOCB_t *icmd; | ||
899 | struct lpfc_iocbq *elsiocb; | ||
900 | struct lpfc_sli_ring *pring; | ||
901 | struct lpfc_sli *psli; | ||
902 | uint8_t *pcmd; | ||
903 | uint16_t cmdsize; | ||
904 | |||
905 | psli = &phba->sli; | ||
906 | pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ | ||
907 | |||
908 | cmdsize = (sizeof (uint32_t) + sizeof (PRLI)); | ||
909 | if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, | ||
910 | ndlp, ELS_CMD_PRLI)) == 0) { | ||
911 | return (1); | ||
912 | } | ||
913 | |||
914 | icmd = &elsiocb->iocb; | ||
915 | pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); | ||
916 | |||
917 | /* For PRLI request, remainder of payload is service parameters */ | ||
918 | memset(pcmd, 0, (sizeof (PRLI) + sizeof (uint32_t))); | ||
919 | *((uint32_t *) (pcmd)) = ELS_CMD_PRLI; | ||
920 | pcmd += sizeof (uint32_t); | ||
921 | |||
922 | /* For PRLI, remainder of payload is PRLI parameter page */ | ||
923 | npr = (PRLI *) pcmd; | ||
924 | /* | ||
925 | * If our firmware version is 3.20 or later, | ||
926 | * set the following bits for FC-TAPE support. | ||
927 | */ | ||
928 | if (phba->vpd.rev.feaLevelHigh >= 0x02) { | ||
929 | npr->ConfmComplAllowed = 1; | ||
930 | npr->Retry = 1; | ||
931 | npr->TaskRetryIdReq = 1; | ||
932 | } | ||
933 | npr->estabImagePair = 1; | ||
934 | npr->readXferRdyDis = 1; | ||
935 | |||
936 | /* For FCP support */ | ||
937 | npr->prliType = PRLI_FCP_TYPE; | ||
938 | npr->initiatorFunc = 1; | ||
939 | |||
940 | phba->fc_stat.elsXmitPRLI++; | ||
941 | elsiocb->iocb_cmpl = lpfc_cmpl_els_prli; | ||
942 | spin_lock_irq(phba->host->host_lock); | ||
943 | ndlp->nlp_flag |= NLP_PRLI_SND; | ||
944 | if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { | ||
945 | ndlp->nlp_flag &= ~NLP_PRLI_SND; | ||
946 | spin_unlock_irq(phba->host->host_lock); | ||
947 | lpfc_els_free_iocb(phba, elsiocb); | ||
948 | return (1); | ||
949 | } | ||
950 | spin_unlock_irq(phba->host->host_lock); | ||
951 | phba->fc_prli_sent++; | ||
952 | return (0); | ||
953 | } | ||
954 | |||
955 | static void | ||
956 | lpfc_more_adisc(struct lpfc_hba * phba) | ||
957 | { | ||
958 | int sentadisc; | ||
959 | |||
960 | if (phba->num_disc_nodes) | ||
961 | phba->num_disc_nodes--; | ||
962 | |||
963 | /* Continue discovery with <num_disc_nodes> ADISCs to go */ | ||
964 | lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, | ||
965 | "%d:0210 Continue discovery with %d ADISCs to go " | ||
966 | "Data: x%x x%x x%x\n", | ||
967 | phba->brd_no, phba->num_disc_nodes, phba->fc_adisc_cnt, | ||
968 | phba->fc_flag, phba->hba_state); | ||
969 | |||
970 | /* Check to see if there are more ADISCs to be sent */ | ||
971 | if (phba->fc_flag & FC_NLP_MORE) { | ||
972 | lpfc_set_disctmo(phba); | ||
973 | |||
974 | /* go thru NPR list and issue any remaining ELS ADISCs */ | ||
975 | sentadisc = lpfc_els_disc_adisc(phba); | ||
976 | } | ||
977 | return; | ||
978 | } | ||
979 | |||
980 | static void | ||
981 | lpfc_rscn_disc(struct lpfc_hba * phba) | ||
982 | { | ||
983 | /* RSCN discovery */ | ||
984 | /* go thru NPR list and issue ELS PLOGIs */ | ||
985 | if (phba->fc_npr_cnt) { | ||
986 | if (lpfc_els_disc_plogi(phba)) | ||
987 | return; | ||
988 | } | ||
989 | if (phba->fc_flag & FC_RSCN_MODE) { | ||
990 | /* Check to see if more RSCNs came in while we were | ||
991 | * processing this one. | ||
992 | */ | ||
993 | if ((phba->fc_rscn_id_cnt == 0) && | ||
994 | (!(phba->fc_flag & FC_RSCN_DISCOVERY))) { | ||
995 | spin_lock_irq(phba->host->host_lock); | ||
996 | phba->fc_flag &= ~FC_RSCN_MODE; | ||
997 | spin_unlock_irq(phba->host->host_lock); | ||
998 | } else { | ||
999 | lpfc_els_handle_rscn(phba); | ||
1000 | } | ||
1001 | } | ||
1002 | } | ||
1003 | |||
1004 | static void | ||
1005 | lpfc_cmpl_els_adisc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, | ||
1006 | struct lpfc_iocbq * rspiocb) | ||
1007 | { | ||
1008 | IOCB_t *irsp; | ||
1009 | struct lpfc_sli *psli; | ||
1010 | struct lpfc_nodelist *ndlp; | ||
1011 | LPFC_MBOXQ_t *mbox; | ||
1012 | int disc, rc; | ||
1013 | |||
1014 | psli = &phba->sli; | ||
1015 | |||
1016 | /* we pass cmdiocb to state machine which needs rspiocb as well */ | ||
1017 | cmdiocb->context_un.rsp_iocb = rspiocb; | ||
1018 | |||
1019 | irsp = &(rspiocb->iocb); | ||
1020 | ndlp = (struct lpfc_nodelist *) cmdiocb->context1; | ||
1021 | spin_lock_irq(phba->host->host_lock); | ||
1022 | ndlp->nlp_flag &= ~NLP_ADISC_SND; | ||
1023 | spin_unlock_irq(phba->host->host_lock); | ||
1024 | |||
1025 | /* Since ndlp can be freed in the disc state machine, note if this node | ||
1026 | * is being used during discovery. | ||
1027 | */ | ||
1028 | disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC); | ||
1029 | |||
1030 | /* ADISC completes to NPort <nlp_DID> */ | ||
1031 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, | ||
1032 | "%d:0104 ADISC completes to NPort x%x " | ||
1033 | "Data: x%x x%x x%x x%x\n", | ||
1034 | phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus, | ||
1035 | irsp->un.ulpWord[4], disc, phba->num_disc_nodes); | ||
1036 | |||
1037 | /* Check to see if link went down during discovery */ | ||
1038 | if (lpfc_els_chk_latt(phba)) { | ||
1039 | spin_lock_irq(phba->host->host_lock); | ||
1040 | ndlp->nlp_flag |= NLP_NPR_2B_DISC; | ||
1041 | spin_unlock_irq(phba->host->host_lock); | ||
1042 | goto out; | ||
1043 | } | ||
1044 | |||
1045 | if (irsp->ulpStatus) { | ||
1046 | /* Check for retry */ | ||
1047 | if (lpfc_els_retry(phba, cmdiocb, rspiocb)) { | ||
1048 | /* ELS command is being retried */ | ||
1049 | if (disc) { | ||
1050 | spin_lock_irq(phba->host->host_lock); | ||
1051 | ndlp->nlp_flag |= NLP_NPR_2B_DISC; | ||
1052 | spin_unlock_irq(phba->host->host_lock); | ||
1053 | lpfc_set_disctmo(phba); | ||
1054 | } | ||
1055 | goto out; | ||
1056 | } | ||
1057 | /* ADISC failed */ | ||
1058 | /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ | ||
1059 | if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && | ||
1060 | ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) || | ||
1061 | (irsp->un.ulpWord[4] == IOERR_SLI_DOWN))) { | ||
1062 | disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC); | ||
1063 | } | ||
1064 | else { | ||
1065 | lpfc_disc_state_machine(phba, ndlp, cmdiocb, | ||
1066 | NLP_EVT_CMPL_ADISC); | ||
1067 | } | ||
1068 | } else { | ||
1069 | /* Good status, call state machine */ | ||
1070 | lpfc_disc_state_machine(phba, ndlp, cmdiocb, | ||
1071 | NLP_EVT_CMPL_ADISC); | ||
1072 | } | ||
1073 | |||
1074 | if (disc && phba->num_disc_nodes) { | ||
1075 | /* Check to see if there are more ADISCs to be sent */ | ||
1076 | lpfc_more_adisc(phba); | ||
1077 | |||
1078 | /* Check to see if we are done with ADISC authentication */ | ||
1079 | if (phba->num_disc_nodes == 0) { | ||
1080 | lpfc_can_disctmo(phba); | ||
1081 | /* If we get here, there is nothing left to wait for */ | ||
1082 | if ((phba->hba_state < LPFC_HBA_READY) && | ||
1083 | (phba->hba_state != LPFC_CLEAR_LA)) { | ||
1084 | /* Link up discovery */ | ||
1085 | if ((mbox = mempool_alloc(phba->mbox_mem_pool, | ||
1086 | GFP_KERNEL))) { | ||
1087 | phba->hba_state = LPFC_CLEAR_LA; | ||
1088 | lpfc_clear_la(phba, mbox); | ||
1089 | mbox->mbox_cmpl = | ||
1090 | lpfc_mbx_cmpl_clear_la; | ||
1091 | rc = lpfc_sli_issue_mbox | ||
1092 | (phba, mbox, | ||
1093 | (MBX_NOWAIT | MBX_STOP_IOCB)); | ||
1094 | if (rc == MBX_NOT_FINISHED) { | ||
1095 | mempool_free(mbox, | ||
1096 | phba->mbox_mem_pool); | ||
1097 | lpfc_disc_flush_list(phba); | ||
1098 | psli->ring[(psli->ip_ring)]. | ||
1099 | flag &= | ||
1100 | ~LPFC_STOP_IOCB_EVENT; | ||
1101 | psli->ring[(psli->fcp_ring)]. | ||
1102 | flag &= | ||
1103 | ~LPFC_STOP_IOCB_EVENT; | ||
1104 | psli->ring[(psli->next_ring)]. | ||
1105 | flag &= | ||
1106 | ~LPFC_STOP_IOCB_EVENT; | ||
1107 | phba->hba_state = | ||
1108 | LPFC_HBA_READY; | ||
1109 | } | ||
1110 | } | ||
1111 | } else { | ||
1112 | lpfc_rscn_disc(phba); | ||
1113 | } | ||
1114 | } | ||
1115 | } | ||
1116 | spin_lock_irq(phba->host->host_lock); | ||
1117 | ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; | ||
1118 | spin_unlock_irq(phba->host->host_lock); | ||
1119 | out: | ||
1120 | lpfc_els_free_iocb(phba, cmdiocb); | ||
1121 | return; | ||
1122 | } | ||
1123 | |||
1124 | int | ||
1125 | lpfc_issue_els_adisc(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, | ||
1126 | uint8_t retry) | ||
1127 | { | ||
1128 | ADISC *ap; | ||
1129 | IOCB_t *icmd; | ||
1130 | struct lpfc_iocbq *elsiocb; | ||
1131 | struct lpfc_sli_ring *pring; | ||
1132 | struct lpfc_sli *psli; | ||
1133 | uint8_t *pcmd; | ||
1134 | uint16_t cmdsize; | ||
1135 | |||
1136 | psli = &phba->sli; | ||
1137 | pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ | ||
1138 | |||
1139 | cmdsize = (sizeof (uint32_t) + sizeof (ADISC)); | ||
1140 | if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, | ||
1141 | ndlp, ELS_CMD_ADISC)) == 0) { | ||
1142 | return (1); | ||
1143 | } | ||
1144 | |||
1145 | icmd = &elsiocb->iocb; | ||
1146 | pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); | ||
1147 | |||
1148 | /* For ADISC request, remainder of payload is service parameters */ | ||
1149 | *((uint32_t *) (pcmd)) = ELS_CMD_ADISC; | ||
1150 | pcmd += sizeof (uint32_t); | ||
1151 | |||
1152 | /* Fill in ADISC payload */ | ||
1153 | ap = (ADISC *) pcmd; | ||
1154 | ap->hardAL_PA = phba->fc_pref_ALPA; | ||
1155 | memcpy(&ap->portName, &phba->fc_portname, sizeof (struct lpfc_name)); | ||
1156 | memcpy(&ap->nodeName, &phba->fc_nodename, sizeof (struct lpfc_name)); | ||
1157 | ap->DID = be32_to_cpu(phba->fc_myDID); | ||
1158 | |||
1159 | phba->fc_stat.elsXmitADISC++; | ||
1160 | elsiocb->iocb_cmpl = lpfc_cmpl_els_adisc; | ||
1161 | spin_lock_irq(phba->host->host_lock); | ||
1162 | ndlp->nlp_flag |= NLP_ADISC_SND; | ||
1163 | if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { | ||
1164 | ndlp->nlp_flag &= ~NLP_ADISC_SND; | ||
1165 | spin_unlock_irq(phba->host->host_lock); | ||
1166 | lpfc_els_free_iocb(phba, elsiocb); | ||
1167 | return (1); | ||
1168 | } | ||
1169 | spin_unlock_irq(phba->host->host_lock); | ||
1170 | return (0); | ||
1171 | } | ||
1172 | |||
1173 | static void | ||
1174 | lpfc_cmpl_els_logo(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, | ||
1175 | struct lpfc_iocbq * rspiocb) | ||
1176 | { | ||
1177 | IOCB_t *irsp; | ||
1178 | struct lpfc_sli *psli; | ||
1179 | struct lpfc_nodelist *ndlp; | ||
1180 | |||
1181 | psli = &phba->sli; | ||
1182 | /* we pass cmdiocb to state machine which needs rspiocb as well */ | ||
1183 | cmdiocb->context_un.rsp_iocb = rspiocb; | ||
1184 | |||
1185 | irsp = &(rspiocb->iocb); | ||
1186 | ndlp = (struct lpfc_nodelist *) cmdiocb->context1; | ||
1187 | spin_lock_irq(phba->host->host_lock); | ||
1188 | ndlp->nlp_flag &= ~NLP_LOGO_SND; | ||
1189 | spin_unlock_irq(phba->host->host_lock); | ||
1190 | |||
1191 | /* LOGO completes to NPort <nlp_DID> */ | ||
1192 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, | ||
1193 | "%d:0105 LOGO completes to NPort x%x " | ||
1194 | "Data: x%x x%x x%x\n", | ||
1195 | phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus, | ||
1196 | irsp->un.ulpWord[4], phba->num_disc_nodes); | ||
1197 | |||
1198 | /* Check to see if link went down during discovery */ | ||
1199 | if (lpfc_els_chk_latt(phba)) | ||
1200 | goto out; | ||
1201 | |||
1202 | if (irsp->ulpStatus) { | ||
1203 | /* Check for retry */ | ||
1204 | if (lpfc_els_retry(phba, cmdiocb, rspiocb)) { | ||
1205 | /* ELS command is being retried */ | ||
1206 | goto out; | ||
1207 | } | ||
1208 | /* LOGO failed */ | ||
1209 | /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ | ||
1210 | if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && | ||
1211 | ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) || | ||
1212 | (irsp->un.ulpWord[4] == IOERR_SLI_DOWN))) { | ||
1213 | goto out; | ||
1214 | } | ||
1215 | else { | ||
1216 | lpfc_disc_state_machine(phba, ndlp, cmdiocb, | ||
1217 | NLP_EVT_CMPL_LOGO); | ||
1218 | } | ||
1219 | } else { | ||
1220 | /* Good status, call state machine */ | ||
1221 | lpfc_disc_state_machine(phba, ndlp, cmdiocb, NLP_EVT_CMPL_LOGO); | ||
1222 | |||
1223 | if (ndlp->nlp_flag & NLP_DELAY_TMO) { | ||
1224 | lpfc_unreg_rpi(phba, ndlp); | ||
1225 | } | ||
1226 | } | ||
1227 | |||
1228 | out: | ||
1229 | lpfc_els_free_iocb(phba, cmdiocb); | ||
1230 | return; | ||
1231 | } | ||
1232 | |||
1233 | int | ||
1234 | lpfc_issue_els_logo(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, | ||
1235 | uint8_t retry) | ||
1236 | { | ||
1237 | IOCB_t *icmd; | ||
1238 | struct lpfc_iocbq *elsiocb; | ||
1239 | struct lpfc_sli_ring *pring; | ||
1240 | struct lpfc_sli *psli; | ||
1241 | uint8_t *pcmd; | ||
1242 | uint16_t cmdsize; | ||
1243 | |||
1244 | psli = &phba->sli; | ||
1245 | pring = &psli->ring[LPFC_ELS_RING]; | ||
1246 | |||
1247 | cmdsize = 2 * (sizeof (uint32_t) + sizeof (struct lpfc_name)); | ||
1248 | if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, | ||
1249 | ndlp, ELS_CMD_LOGO)) == 0) { | ||
1250 | return (1); | ||
1251 | } | ||
1252 | |||
1253 | icmd = &elsiocb->iocb; | ||
1254 | pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); | ||
1255 | *((uint32_t *) (pcmd)) = ELS_CMD_LOGO; | ||
1256 | pcmd += sizeof (uint32_t); | ||
1257 | |||
1258 | /* Fill in LOGO payload */ | ||
1259 | *((uint32_t *) (pcmd)) = be32_to_cpu(phba->fc_myDID); | ||
1260 | pcmd += sizeof (uint32_t); | ||
1261 | memcpy(pcmd, &phba->fc_portname, sizeof (struct lpfc_name)); | ||
1262 | |||
1263 | phba->fc_stat.elsXmitLOGO++; | ||
1264 | elsiocb->iocb_cmpl = lpfc_cmpl_els_logo; | ||
1265 | spin_lock_irq(phba->host->host_lock); | ||
1266 | ndlp->nlp_flag |= NLP_LOGO_SND; | ||
1267 | if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { | ||
1268 | ndlp->nlp_flag &= ~NLP_LOGO_SND; | ||
1269 | spin_unlock_irq(phba->host->host_lock); | ||
1270 | lpfc_els_free_iocb(phba, elsiocb); | ||
1271 | return (1); | ||
1272 | } | ||
1273 | spin_unlock_irq(phba->host->host_lock); | ||
1274 | return (0); | ||
1275 | } | ||
1276 | |||
1277 | static void | ||
1278 | lpfc_cmpl_els_cmd(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, | ||
1279 | struct lpfc_iocbq * rspiocb) | ||
1280 | { | ||
1281 | IOCB_t *irsp; | ||
1282 | |||
1283 | irsp = &rspiocb->iocb; | ||
1284 | |||
1285 | /* ELS cmd tag <ulpIoTag> completes */ | ||
1286 | lpfc_printf_log(phba, | ||
1287 | KERN_INFO, | ||
1288 | LOG_ELS, | ||
1289 | "%d:0106 ELS cmd tag x%x completes Data: x%x x%x\n", | ||
1290 | phba->brd_no, | ||
1291 | irsp->ulpIoTag, irsp->ulpStatus, irsp->un.ulpWord[4]); | ||
1292 | |||
1293 | /* Check to see if link went down during discovery */ | ||
1294 | lpfc_els_chk_latt(phba); | ||
1295 | lpfc_els_free_iocb(phba, cmdiocb); | ||
1296 | return; | ||
1297 | } | ||
1298 | |||
1299 | int | ||
1300 | lpfc_issue_els_scr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry) | ||
1301 | { | ||
1302 | IOCB_t *icmd; | ||
1303 | struct lpfc_iocbq *elsiocb; | ||
1304 | struct lpfc_sli_ring *pring; | ||
1305 | struct lpfc_sli *psli; | ||
1306 | uint8_t *pcmd; | ||
1307 | uint16_t cmdsize; | ||
1308 | struct lpfc_nodelist *ndlp; | ||
1309 | |||
1310 | psli = &phba->sli; | ||
1311 | pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ | ||
1312 | cmdsize = (sizeof (uint32_t) + sizeof (SCR)); | ||
1313 | if ((ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL)) == 0) { | ||
1314 | return (1); | ||
1315 | } | ||
1316 | |||
1317 | lpfc_nlp_init(phba, ndlp, nportid); | ||
1318 | |||
1319 | if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, | ||
1320 | ndlp, ELS_CMD_SCR)) == 0) { | ||
1321 | mempool_free( ndlp, phba->nlp_mem_pool); | ||
1322 | return (1); | ||
1323 | } | ||
1324 | |||
1325 | icmd = &elsiocb->iocb; | ||
1326 | pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); | ||
1327 | |||
1328 | *((uint32_t *) (pcmd)) = ELS_CMD_SCR; | ||
1329 | pcmd += sizeof (uint32_t); | ||
1330 | |||
1331 | /* For SCR, remainder of payload is SCR parameter page */ | ||
1332 | memset(pcmd, 0, sizeof (SCR)); | ||
1333 | ((SCR *) pcmd)->Function = SCR_FUNC_FULL; | ||
1334 | |||
1335 | phba->fc_stat.elsXmitSCR++; | ||
1336 | elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd; | ||
1337 | spin_lock_irq(phba->host->host_lock); | ||
1338 | if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { | ||
1339 | spin_unlock_irq(phba->host->host_lock); | ||
1340 | mempool_free( ndlp, phba->nlp_mem_pool); | ||
1341 | lpfc_els_free_iocb(phba, elsiocb); | ||
1342 | return (1); | ||
1343 | } | ||
1344 | spin_unlock_irq(phba->host->host_lock); | ||
1345 | mempool_free( ndlp, phba->nlp_mem_pool); | ||
1346 | return (0); | ||
1347 | } | ||
1348 | |||
1349 | static int | ||
1350 | lpfc_issue_els_farpr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry) | ||
1351 | { | ||
1352 | IOCB_t *icmd; | ||
1353 | struct lpfc_iocbq *elsiocb; | ||
1354 | struct lpfc_sli_ring *pring; | ||
1355 | struct lpfc_sli *psli; | ||
1356 | FARP *fp; | ||
1357 | uint8_t *pcmd; | ||
1358 | uint32_t *lp; | ||
1359 | uint16_t cmdsize; | ||
1360 | struct lpfc_nodelist *ondlp; | ||
1361 | struct lpfc_nodelist *ndlp; | ||
1362 | |||
1363 | psli = &phba->sli; | ||
1364 | pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ | ||
1365 | cmdsize = (sizeof (uint32_t) + sizeof (FARP)); | ||
1366 | if ((ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL)) == 0) { | ||
1367 | return (1); | ||
1368 | } | ||
1369 | lpfc_nlp_init(phba, ndlp, nportid); | ||
1370 | |||
1371 | if ((elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, | ||
1372 | ndlp, ELS_CMD_RNID)) == 0) { | ||
1373 | mempool_free( ndlp, phba->nlp_mem_pool); | ||
1374 | return (1); | ||
1375 | } | ||
1376 | |||
1377 | icmd = &elsiocb->iocb; | ||
1378 | pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); | ||
1379 | |||
1380 | *((uint32_t *) (pcmd)) = ELS_CMD_FARPR; | ||
1381 | pcmd += sizeof (uint32_t); | ||
1382 | |||
1383 | /* Fill in FARPR payload */ | ||
1384 | fp = (FARP *) (pcmd); | ||
1385 | memset(fp, 0, sizeof (FARP)); | ||
1386 | lp = (uint32_t *) pcmd; | ||
1387 | *lp++ = be32_to_cpu(nportid); | ||
1388 | *lp++ = be32_to_cpu(phba->fc_myDID); | ||
1389 | fp->Rflags = 0; | ||
1390 | fp->Mflags = (FARP_MATCH_PORT | FARP_MATCH_NODE); | ||
1391 | |||
1392 | memcpy(&fp->RportName, &phba->fc_portname, sizeof (struct lpfc_name)); | ||
1393 | memcpy(&fp->RnodeName, &phba->fc_nodename, sizeof (struct lpfc_name)); | ||
1394 | if ((ondlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, nportid))) { | ||
1395 | memcpy(&fp->OportName, &ondlp->nlp_portname, | ||
1396 | sizeof (struct lpfc_name)); | ||
1397 | memcpy(&fp->OnodeName, &ondlp->nlp_nodename, | ||
1398 | sizeof (struct lpfc_name)); | ||
1399 | } | ||
1400 | |||
1401 | phba->fc_stat.elsXmitFARPR++; | ||
1402 | elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd; | ||
1403 | spin_lock_irq(phba->host->host_lock); | ||
1404 | if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { | ||
1405 | spin_unlock_irq(phba->host->host_lock); | ||
1406 | mempool_free( ndlp, phba->nlp_mem_pool); | ||
1407 | lpfc_els_free_iocb(phba, elsiocb); | ||
1408 | return (1); | ||
1409 | } | ||
1410 | spin_unlock_irq(phba->host->host_lock); | ||
1411 | mempool_free( ndlp, phba->nlp_mem_pool); | ||
1412 | return (0); | ||
1413 | } | ||
1414 | |||
1415 | void | ||
1416 | lpfc_els_retry_delay(unsigned long ptr) | ||
1417 | { | ||
1418 | struct lpfc_nodelist *ndlp; | ||
1419 | struct lpfc_hba *phba; | ||
1420 | unsigned long iflag; | ||
1421 | struct lpfc_work_evt *evtp; | ||
1422 | |||
1423 | ndlp = (struct lpfc_nodelist *)ptr; | ||
1424 | phba = ndlp->nlp_phba; | ||
1425 | evtp = &ndlp->els_retry_evt; | ||
1426 | |||
1427 | spin_lock_irqsave(phba->host->host_lock, iflag); | ||
1428 | if (!list_empty(&evtp->evt_listp)) { | ||
1429 | spin_unlock_irqrestore(phba->host->host_lock, iflag); | ||
1430 | return; | ||
1431 | } | ||
1432 | |||
1433 | evtp->evt_arg1 = ndlp; | ||
1434 | evtp->evt = LPFC_EVT_ELS_RETRY; | ||
1435 | list_add_tail(&evtp->evt_listp, &phba->work_list); | ||
1436 | if (phba->work_wait) | ||
1437 | wake_up(phba->work_wait); | ||
1438 | |||
1439 | spin_unlock_irqrestore(phba->host->host_lock, iflag); | ||
1440 | return; | ||
1441 | } | ||
1442 | |||
1443 | void | ||
1444 | lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp) | ||
1445 | { | ||
1446 | struct lpfc_hba *phba; | ||
1447 | uint32_t cmd; | ||
1448 | uint32_t did; | ||
1449 | uint8_t retry; | ||
1450 | |||
1451 | phba = ndlp->nlp_phba; | ||
1452 | spin_lock_irq(phba->host->host_lock); | ||
1453 | did = (uint32_t) (ndlp->nlp_DID); | ||
1454 | cmd = (uint32_t) (ndlp->nlp_last_elscmd); | ||
1455 | |||
1456 | if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) { | ||
1457 | spin_unlock_irq(phba->host->host_lock); | ||
1458 | return; | ||
1459 | } | ||
1460 | |||
1461 | ndlp->nlp_flag &= ~NLP_DELAY_TMO; | ||
1462 | spin_unlock_irq(phba->host->host_lock); | ||
1463 | retry = ndlp->nlp_retry; | ||
1464 | |||
1465 | switch (cmd) { | ||
1466 | case ELS_CMD_FLOGI: | ||
1467 | lpfc_issue_els_flogi(phba, ndlp, retry); | ||
1468 | break; | ||
1469 | case ELS_CMD_PLOGI: | ||
1470 | ndlp->nlp_state = NLP_STE_PLOGI_ISSUE; | ||
1471 | lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST); | ||
1472 | lpfc_issue_els_plogi(phba, ndlp, retry); | ||
1473 | break; | ||
1474 | case ELS_CMD_ADISC: | ||
1475 | ndlp->nlp_state = NLP_STE_ADISC_ISSUE; | ||
1476 | lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST); | ||
1477 | lpfc_issue_els_adisc(phba, ndlp, retry); | ||
1478 | break; | ||
1479 | case ELS_CMD_PRLI: | ||
1480 | ndlp->nlp_state = NLP_STE_PRLI_ISSUE; | ||
1481 | lpfc_nlp_list(phba, ndlp, NLP_PRLI_LIST); | ||
1482 | lpfc_issue_els_prli(phba, ndlp, retry); | ||
1483 | break; | ||
1484 | case ELS_CMD_LOGO: | ||
1485 | ndlp->nlp_state = NLP_STE_NPR_NODE; | ||
1486 | lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); | ||
1487 | lpfc_issue_els_logo(phba, ndlp, retry); | ||
1488 | break; | ||
1489 | } | ||
1490 | return; | ||
1491 | } | ||
1492 | |||
1493 | static int | ||
1494 | lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, | ||
1495 | struct lpfc_iocbq * rspiocb) | ||
1496 | { | ||
1497 | IOCB_t *irsp; | ||
1498 | struct lpfc_dmabuf *pcmd; | ||
1499 | struct lpfc_nodelist *ndlp; | ||
1500 | uint32_t *elscmd; | ||
1501 | struct ls_rjt stat; | ||
1502 | int retry, maxretry; | ||
1503 | int delay; | ||
1504 | uint32_t cmd; | ||
1505 | |||
1506 | retry = 0; | ||
1507 | delay = 0; | ||
1508 | maxretry = lpfc_max_els_tries; | ||
1509 | irsp = &rspiocb->iocb; | ||
1510 | ndlp = (struct lpfc_nodelist *) cmdiocb->context1; | ||
1511 | pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; | ||
1512 | cmd = 0; | ||
1513 | /* Note: context2 may be 0 for internal driver abort | ||
1514 | * of delays ELS command. | ||
1515 | */ | ||
1516 | |||
1517 | if (pcmd && pcmd->virt) { | ||
1518 | elscmd = (uint32_t *) (pcmd->virt); | ||
1519 | cmd = *elscmd++; | ||
1520 | } | ||
1521 | |||
1522 | switch (irsp->ulpStatus) { | ||
1523 | case IOSTAT_FCP_RSP_ERROR: | ||
1524 | case IOSTAT_REMOTE_STOP: | ||
1525 | break; | ||
1526 | |||
1527 | case IOSTAT_LOCAL_REJECT: | ||
1528 | switch ((irsp->un.ulpWord[4] & 0xff)) { | ||
1529 | case IOERR_LOOP_OPEN_FAILURE: | ||
1530 | if (cmd == ELS_CMD_PLOGI) { | ||
1531 | if (cmdiocb->retry == 0) { | ||
1532 | delay = 1; | ||
1533 | } | ||
1534 | } | ||
1535 | retry = 1; | ||
1536 | break; | ||
1537 | |||
1538 | case IOERR_SEQUENCE_TIMEOUT: | ||
1539 | retry = 1; | ||
1540 | if ((cmd == ELS_CMD_FLOGI) | ||
1541 | && (phba->fc_topology != TOPOLOGY_LOOP)) { | ||
1542 | delay = 1; | ||
1543 | maxretry = 48; | ||
1544 | } | ||
1545 | break; | ||
1546 | |||
1547 | case IOERR_NO_RESOURCES: | ||
1548 | if (cmd == ELS_CMD_PLOGI) { | ||
1549 | delay = 1; | ||
1550 | } | ||
1551 | retry = 1; | ||
1552 | break; | ||
1553 | |||
1554 | case IOERR_INVALID_RPI: | ||
1555 | retry = 1; | ||
1556 | break; | ||
1557 | } | ||
1558 | break; | ||
1559 | |||
1560 | case IOSTAT_NPORT_RJT: | ||
1561 | case IOSTAT_FABRIC_RJT: | ||
1562 | if (irsp->un.ulpWord[4] & RJT_UNAVAIL_TEMP) { | ||
1563 | retry = 1; | ||
1564 | break; | ||
1565 | } | ||
1566 | break; | ||
1567 | |||
1568 | case IOSTAT_NPORT_BSY: | ||
1569 | case IOSTAT_FABRIC_BSY: | ||
1570 | retry = 1; | ||
1571 | break; | ||
1572 | |||
1573 | case IOSTAT_LS_RJT: | ||
1574 | stat.un.lsRjtError = be32_to_cpu(irsp->un.ulpWord[4]); | ||
1575 | /* Added for Vendor specifc support | ||
1576 | * Just keep retrying for these Rsn / Exp codes | ||
1577 | */ | ||
1578 | switch (stat.un.b.lsRjtRsnCode) { | ||
1579 | case LSRJT_UNABLE_TPC: | ||
1580 | if (stat.un.b.lsRjtRsnCodeExp == | ||
1581 | LSEXP_CMD_IN_PROGRESS) { | ||
1582 | if (cmd == ELS_CMD_PLOGI) { | ||
1583 | delay = 1; | ||
1584 | maxretry = 48; | ||
1585 | } | ||
1586 | retry = 1; | ||
1587 | break; | ||
1588 | } | ||
1589 | if (cmd == ELS_CMD_PLOGI) { | ||
1590 | delay = 1; | ||
1591 | maxretry = lpfc_max_els_tries + 1; | ||
1592 | retry = 1; | ||
1593 | break; | ||
1594 | } | ||
1595 | break; | ||
1596 | |||
1597 | case LSRJT_LOGICAL_BSY: | ||
1598 | if (cmd == ELS_CMD_PLOGI) { | ||
1599 | delay = 1; | ||
1600 | maxretry = 48; | ||
1601 | } | ||
1602 | retry = 1; | ||
1603 | break; | ||
1604 | } | ||
1605 | break; | ||
1606 | |||
1607 | case IOSTAT_INTERMED_RSP: | ||
1608 | case IOSTAT_BA_RJT: | ||
1609 | break; | ||
1610 | |||
1611 | default: | ||
1612 | break; | ||
1613 | } | ||
1614 | |||
1615 | if (ndlp->nlp_DID == FDMI_DID) { | ||
1616 | retry = 1; | ||
1617 | } | ||
1618 | |||
1619 | if ((++cmdiocb->retry) >= maxretry) { | ||
1620 | phba->fc_stat.elsRetryExceeded++; | ||
1621 | retry = 0; | ||
1622 | } | ||
1623 | |||
1624 | if (retry) { | ||
1625 | |||
1626 | /* Retry ELS command <elsCmd> to remote NPORT <did> */ | ||
1627 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, | ||
1628 | "%d:0107 Retry ELS command x%x to remote " | ||
1629 | "NPORT x%x Data: x%x x%x\n", | ||
1630 | phba->brd_no, | ||
1631 | cmd, ndlp->nlp_DID, cmdiocb->retry, delay); | ||
1632 | |||
1633 | if ((cmd == ELS_CMD_PLOGI) || (cmd == ELS_CMD_ADISC)) { | ||
1634 | /* If discovery / RSCN timer is running, reset it */ | ||
1635 | if (timer_pending(&phba->fc_disctmo) || | ||
1636 | (phba->fc_flag & FC_RSCN_MODE)) { | ||
1637 | lpfc_set_disctmo(phba); | ||
1638 | } | ||
1639 | } | ||
1640 | |||
1641 | phba->fc_stat.elsXmitRetry++; | ||
1642 | if (delay) { | ||
1643 | phba->fc_stat.elsDelayRetry++; | ||
1644 | ndlp->nlp_retry = cmdiocb->retry; | ||
1645 | |||
1646 | mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ); | ||
1647 | ndlp->nlp_flag |= NLP_DELAY_TMO; | ||
1648 | |||
1649 | ndlp->nlp_state = NLP_STE_NPR_NODE; | ||
1650 | lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); | ||
1651 | ndlp->nlp_last_elscmd = cmd; | ||
1652 | |||
1653 | return (1); | ||
1654 | } | ||
1655 | switch (cmd) { | ||
1656 | case ELS_CMD_FLOGI: | ||
1657 | lpfc_issue_els_flogi(phba, ndlp, cmdiocb->retry); | ||
1658 | return (1); | ||
1659 | case ELS_CMD_PLOGI: | ||
1660 | ndlp->nlp_state = NLP_STE_PLOGI_ISSUE; | ||
1661 | lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST); | ||
1662 | lpfc_issue_els_plogi(phba, ndlp, cmdiocb->retry); | ||
1663 | return (1); | ||
1664 | case ELS_CMD_ADISC: | ||
1665 | ndlp->nlp_state = NLP_STE_ADISC_ISSUE; | ||
1666 | lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST); | ||
1667 | lpfc_issue_els_adisc(phba, ndlp, cmdiocb->retry); | ||
1668 | return (1); | ||
1669 | case ELS_CMD_PRLI: | ||
1670 | ndlp->nlp_state = NLP_STE_PRLI_ISSUE; | ||
1671 | lpfc_nlp_list(phba, ndlp, NLP_PRLI_LIST); | ||
1672 | lpfc_issue_els_prli(phba, ndlp, cmdiocb->retry); | ||
1673 | return (1); | ||
1674 | case ELS_CMD_LOGO: | ||
1675 | ndlp->nlp_state = NLP_STE_NPR_NODE; | ||
1676 | lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); | ||
1677 | lpfc_issue_els_logo(phba, ndlp, cmdiocb->retry); | ||
1678 | return (1); | ||
1679 | } | ||
1680 | } | ||
1681 | |||
1682 | /* No retry ELS command <elsCmd> to remote NPORT <did> */ | ||
1683 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, | ||
1684 | "%d:0108 No retry ELS command x%x to remote NPORT x%x " | ||
1685 | "Data: x%x x%x\n", | ||
1686 | phba->brd_no, | ||
1687 | cmd, ndlp->nlp_DID, cmdiocb->retry, ndlp->nlp_flag); | ||
1688 | |||
1689 | return (0); | ||
1690 | } | ||
1691 | |||
1692 | int | ||
1693 | lpfc_els_free_iocb(struct lpfc_hba * phba, struct lpfc_iocbq * elsiocb) | ||
1694 | { | ||
1695 | struct lpfc_dmabuf *buf_ptr, *buf_ptr1; | ||
1696 | |||
1697 | /* context2 = cmd, context2->next = rsp, context3 = bpl */ | ||
1698 | if (elsiocb->context2) { | ||
1699 | buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2; | ||
1700 | /* Free the response before processing the command. */ | ||
1701 | if (!list_empty(&buf_ptr1->list)) { | ||
1702 | list_remove_head(&buf_ptr1->list, buf_ptr, | ||
1703 | struct lpfc_dmabuf, | ||
1704 | list); | ||
1705 | lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); | ||
1706 | kfree(buf_ptr); | ||
1707 | } | ||
1708 | lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys); | ||
1709 | kfree(buf_ptr1); | ||
1710 | } | ||
1711 | |||
1712 | if (elsiocb->context3) { | ||
1713 | buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3; | ||
1714 | lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); | ||
1715 | kfree(buf_ptr); | ||
1716 | } | ||
1717 | spin_lock_irq(phba->host->host_lock); | ||
1718 | list_add_tail(&elsiocb->list, &phba->lpfc_iocb_list); | ||
1719 | spin_unlock_irq(phba->host->host_lock); | ||
1720 | return 0; | ||
1721 | } | ||
1722 | |||
1723 | static void | ||
1724 | lpfc_cmpl_els_logo_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, | ||
1725 | struct lpfc_iocbq * rspiocb) | ||
1726 | { | ||
1727 | struct lpfc_nodelist *ndlp; | ||
1728 | |||
1729 | ndlp = (struct lpfc_nodelist *) cmdiocb->context1; | ||
1730 | |||
1731 | /* ACC to LOGO completes to NPort <nlp_DID> */ | ||
1732 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, | ||
1733 | "%d:0109 ACC to LOGO completes to NPort x%x " | ||
1734 | "Data: x%x x%x x%x\n", | ||
1735 | phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag, | ||
1736 | ndlp->nlp_state, ndlp->nlp_rpi); | ||
1737 | |||
1738 | spin_lock_irq(phba->host->host_lock); | ||
1739 | ndlp->nlp_flag &= ~NLP_LOGO_ACC; | ||
1740 | spin_unlock_irq(phba->host->host_lock); | ||
1741 | |||
1742 | switch (ndlp->nlp_state) { | ||
1743 | case NLP_STE_UNUSED_NODE: /* node is just allocated */ | ||
1744 | lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); | ||
1745 | break; | ||
1746 | case NLP_STE_NPR_NODE: /* NPort Recovery mode */ | ||
1747 | lpfc_unreg_rpi(phba, ndlp); | ||
1748 | break; | ||
1749 | default: | ||
1750 | break; | ||
1751 | } | ||
1752 | lpfc_els_free_iocb(phba, cmdiocb); | ||
1753 | return; | ||
1754 | } | ||
1755 | |||
1756 | static void | ||
1757 | lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, | ||
1758 | struct lpfc_iocbq * rspiocb) | ||
1759 | { | ||
1760 | struct lpfc_nodelist *ndlp; | ||
1761 | LPFC_MBOXQ_t *mbox = NULL; | ||
1762 | |||
1763 | ndlp = (struct lpfc_nodelist *) cmdiocb->context1; | ||
1764 | if (cmdiocb->context_un.mbox) | ||
1765 | mbox = cmdiocb->context_un.mbox; | ||
1766 | |||
1767 | |||
1768 | /* Check to see if link went down during discovery */ | ||
1769 | if ((lpfc_els_chk_latt(phba)) || !ndlp) { | ||
1770 | if (mbox) { | ||
1771 | mempool_free( mbox, phba->mbox_mem_pool); | ||
1772 | } | ||
1773 | goto out; | ||
1774 | } | ||
1775 | |||
1776 | /* ELS response tag <ulpIoTag> completes */ | ||
1777 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, | ||
1778 | "%d:0110 ELS response tag x%x completes " | ||
1779 | "Data: x%x x%x x%x x%x x%x x%x\n", | ||
1780 | phba->brd_no, | ||
1781 | cmdiocb->iocb.ulpIoTag, rspiocb->iocb.ulpStatus, | ||
1782 | rspiocb->iocb.un.ulpWord[4], ndlp->nlp_DID, | ||
1783 | ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); | ||
1784 | |||
1785 | if (mbox) { | ||
1786 | if ((rspiocb->iocb.ulpStatus == 0) | ||
1787 | && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) { | ||
1788 | /* set_slim mailbox command needs to execute first, | ||
1789 | * queue this command to be processed later. | ||
1790 | */ | ||
1791 | lpfc_unreg_rpi(phba, ndlp); | ||
1792 | mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login; | ||
1793 | mbox->context2 = ndlp; | ||
1794 | ndlp->nlp_state = NLP_STE_REG_LOGIN_ISSUE; | ||
1795 | lpfc_nlp_list(phba, ndlp, NLP_REGLOGIN_LIST); | ||
1796 | if (lpfc_sli_issue_mbox(phba, mbox, | ||
1797 | (MBX_NOWAIT | MBX_STOP_IOCB)) | ||
1798 | != MBX_NOT_FINISHED) { | ||
1799 | goto out; | ||
1800 | } | ||
1801 | /* NOTE: we should have messages for unsuccessful | ||
1802 | reglogin */ | ||
1803 | mempool_free( mbox, phba->mbox_mem_pool); | ||
1804 | } else { | ||
1805 | mempool_free( mbox, phba->mbox_mem_pool); | ||
1806 | if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) { | ||
1807 | lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); | ||
1808 | } | ||
1809 | } | ||
1810 | } | ||
1811 | out: | ||
1812 | if (ndlp) { | ||
1813 | spin_lock_irq(phba->host->host_lock); | ||
1814 | ndlp->nlp_flag &= ~NLP_ACC_REGLOGIN; | ||
1815 | spin_unlock_irq(phba->host->host_lock); | ||
1816 | } | ||
1817 | lpfc_els_free_iocb(phba, cmdiocb); | ||
1818 | return; | ||
1819 | } | ||
1820 | |||
1821 | int | ||
1822 | lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag, | ||
1823 | struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp, | ||
1824 | LPFC_MBOXQ_t * mbox, uint8_t newnode) | ||
1825 | { | ||
1826 | IOCB_t *icmd; | ||
1827 | IOCB_t *oldcmd; | ||
1828 | struct lpfc_iocbq *elsiocb; | ||
1829 | struct lpfc_sli_ring *pring; | ||
1830 | struct lpfc_sli *psli; | ||
1831 | uint8_t *pcmd; | ||
1832 | uint16_t cmdsize; | ||
1833 | int rc; | ||
1834 | |||
1835 | psli = &phba->sli; | ||
1836 | pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ | ||
1837 | oldcmd = &oldiocb->iocb; | ||
1838 | |||
1839 | switch (flag) { | ||
1840 | case ELS_CMD_ACC: | ||
1841 | cmdsize = sizeof (uint32_t); | ||
1842 | if ((elsiocb = | ||
1843 | lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry, | ||
1844 | ndlp, ELS_CMD_ACC)) == 0) { | ||
1845 | return (1); | ||
1846 | } | ||
1847 | icmd = &elsiocb->iocb; | ||
1848 | icmd->ulpContext = oldcmd->ulpContext; /* Xri */ | ||
1849 | pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt); | ||
1850 | *((uint32_t *) (pcmd)) = ELS_CMD_ACC; | ||
1851 | pcmd += sizeof (uint32_t); | ||
1852 | break; | ||
1853 | case ELS_CMD_PLOGI: | ||
1854 | cmdsize = (sizeof (struct serv_parm) + sizeof (uint32_t)); | ||
1855 | if ((elsiocb = | ||
1856 | lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry, | ||
1857 | ndlp, ELS_CMD_ACC)) == 0) { | ||
1858 | return (1); | ||
1859 | } | ||
1860 | icmd = &elsiocb->iocb; | ||
1861 | icmd->ulpContext = oldcmd->ulpContext; /* Xri */ | ||
1862 | pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt); | ||
1863 | |||
1864 | if (mbox) | ||
1865 | elsiocb->context_un.mbox = mbox; | ||
1866 | |||
1867 | *((uint32_t *) (pcmd)) = ELS_CMD_ACC; | ||
1868 | pcmd += sizeof (uint32_t); | ||
1869 | memcpy(pcmd, &phba->fc_sparam, sizeof (struct serv_parm)); | ||
1870 | break; | ||
1871 | default: | ||
1872 | return (1); | ||
1873 | } | ||
1874 | |||
1875 | if (newnode) | ||
1876 | elsiocb->context1 = NULL; | ||
1877 | |||
1878 | /* Xmit ELS ACC response tag <ulpIoTag> */ | ||
1879 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, | ||
1880 | "%d:0128 Xmit ELS ACC response tag x%x " | ||
1881 | "Data: x%x x%x x%x x%x x%x\n", | ||
1882 | phba->brd_no, | ||
1883 | elsiocb->iocb.ulpIoTag, | ||
1884 | elsiocb->iocb.ulpContext, ndlp->nlp_DID, | ||
1885 | ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); | ||
1886 | |||
1887 | if (ndlp->nlp_flag & NLP_LOGO_ACC) { | ||
1888 | elsiocb->iocb_cmpl = lpfc_cmpl_els_logo_acc; | ||
1889 | } else { | ||
1890 | elsiocb->iocb_cmpl = lpfc_cmpl_els_acc; | ||
1891 | } | ||
1892 | |||
1893 | phba->fc_stat.elsXmitACC++; | ||
1894 | spin_lock_irq(phba->host->host_lock); | ||
1895 | rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0); | ||
1896 | spin_unlock_irq(phba->host->host_lock); | ||
1897 | if (rc == IOCB_ERROR) { | ||
1898 | lpfc_els_free_iocb(phba, elsiocb); | ||
1899 | return (1); | ||
1900 | } | ||
1901 | return (0); | ||
1902 | } | ||
1903 | |||
1904 | int | ||
1905 | lpfc_els_rsp_reject(struct lpfc_hba * phba, uint32_t rejectError, | ||
1906 | struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp) | ||
1907 | { | ||
1908 | IOCB_t *icmd; | ||
1909 | IOCB_t *oldcmd; | ||
1910 | struct lpfc_iocbq *elsiocb; | ||
1911 | struct lpfc_sli_ring *pring; | ||
1912 | struct lpfc_sli *psli; | ||
1913 | uint8_t *pcmd; | ||
1914 | uint16_t cmdsize; | ||
1915 | int rc; | ||
1916 | |||
1917 | psli = &phba->sli; | ||
1918 | pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ | ||
1919 | |||
1920 | cmdsize = 2 * sizeof (uint32_t); | ||
1921 | if ((elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry, | ||
1922 | ndlp, ELS_CMD_LS_RJT)) == 0) { | ||
1923 | return (1); | ||
1924 | } | ||
1925 | |||
1926 | icmd = &elsiocb->iocb; | ||
1927 | oldcmd = &oldiocb->iocb; | ||
1928 | icmd->ulpContext = oldcmd->ulpContext; /* Xri */ | ||
1929 | pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); | ||
1930 | |||
1931 | *((uint32_t *) (pcmd)) = ELS_CMD_LS_RJT; | ||
1932 | pcmd += sizeof (uint32_t); | ||
1933 | *((uint32_t *) (pcmd)) = rejectError; | ||
1934 | |||
1935 | /* Xmit ELS RJT <err> response tag <ulpIoTag> */ | ||
1936 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, | ||
1937 | "%d:0129 Xmit ELS RJT x%x response tag x%x " | ||
1938 | "Data: x%x x%x x%x x%x x%x\n", | ||
1939 | phba->brd_no, | ||
1940 | rejectError, elsiocb->iocb.ulpIoTag, | ||
1941 | elsiocb->iocb.ulpContext, ndlp->nlp_DID, | ||
1942 | ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); | ||
1943 | |||
1944 | phba->fc_stat.elsXmitLSRJT++; | ||
1945 | elsiocb->iocb_cmpl = lpfc_cmpl_els_acc; | ||
1946 | spin_lock_irq(phba->host->host_lock); | ||
1947 | rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0); | ||
1948 | spin_unlock_irq(phba->host->host_lock); | ||
1949 | if (rc == IOCB_ERROR) { | ||
1950 | lpfc_els_free_iocb(phba, elsiocb); | ||
1951 | return (1); | ||
1952 | } | ||
1953 | return (0); | ||
1954 | } | ||
1955 | |||
1956 | int | ||
1957 | lpfc_els_rsp_adisc_acc(struct lpfc_hba * phba, | ||
1958 | struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp) | ||
1959 | { | ||
1960 | ADISC *ap; | ||
1961 | IOCB_t *icmd; | ||
1962 | IOCB_t *oldcmd; | ||
1963 | struct lpfc_iocbq *elsiocb; | ||
1964 | struct lpfc_sli_ring *pring; | ||
1965 | struct lpfc_sli *psli; | ||
1966 | uint8_t *pcmd; | ||
1967 | uint16_t cmdsize; | ||
1968 | int rc; | ||
1969 | |||
1970 | psli = &phba->sli; | ||
1971 | pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ | ||
1972 | |||
1973 | cmdsize = sizeof (uint32_t) + sizeof (ADISC); | ||
1974 | if ((elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry, | ||
1975 | ndlp, ELS_CMD_ACC)) == 0) { | ||
1976 | return (1); | ||
1977 | } | ||
1978 | |||
1979 | /* Xmit ADISC ACC response tag <ulpIoTag> */ | ||
1980 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, | ||
1981 | "%d:0130 Xmit ADISC ACC response tag x%x " | ||
1982 | "Data: x%x x%x x%x x%x x%x\n", | ||
1983 | phba->brd_no, | ||
1984 | elsiocb->iocb.ulpIoTag, | ||
1985 | elsiocb->iocb.ulpContext, ndlp->nlp_DID, | ||
1986 | ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); | ||
1987 | |||
1988 | icmd = &elsiocb->iocb; | ||
1989 | oldcmd = &oldiocb->iocb; | ||
1990 | icmd->ulpContext = oldcmd->ulpContext; /* Xri */ | ||
1991 | pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); | ||
1992 | |||
1993 | *((uint32_t *) (pcmd)) = ELS_CMD_ACC; | ||
1994 | pcmd += sizeof (uint32_t); | ||
1995 | |||
1996 | ap = (ADISC *) (pcmd); | ||
1997 | ap->hardAL_PA = phba->fc_pref_ALPA; | ||
1998 | memcpy(&ap->portName, &phba->fc_portname, sizeof (struct lpfc_name)); | ||
1999 | memcpy(&ap->nodeName, &phba->fc_nodename, sizeof (struct lpfc_name)); | ||
2000 | ap->DID = be32_to_cpu(phba->fc_myDID); | ||
2001 | |||
2002 | phba->fc_stat.elsXmitACC++; | ||
2003 | elsiocb->iocb_cmpl = lpfc_cmpl_els_acc; | ||
2004 | spin_lock_irq(phba->host->host_lock); | ||
2005 | rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0); | ||
2006 | spin_unlock_irq(phba->host->host_lock); | ||
2007 | if (rc == IOCB_ERROR) { | ||
2008 | lpfc_els_free_iocb(phba, elsiocb); | ||
2009 | return (1); | ||
2010 | } | ||
2011 | return (0); | ||
2012 | } | ||
2013 | |||
2014 | int | ||
2015 | lpfc_els_rsp_prli_acc(struct lpfc_hba * phba, | ||
2016 | struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp) | ||
2017 | { | ||
2018 | PRLI *npr; | ||
2019 | lpfc_vpd_t *vpd; | ||
2020 | IOCB_t *icmd; | ||
2021 | IOCB_t *oldcmd; | ||
2022 | struct lpfc_iocbq *elsiocb; | ||
2023 | struct lpfc_sli_ring *pring; | ||
2024 | struct lpfc_sli *psli; | ||
2025 | uint8_t *pcmd; | ||
2026 | uint16_t cmdsize; | ||
2027 | int rc; | ||
2028 | |||
2029 | psli = &phba->sli; | ||
2030 | pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ | ||
2031 | |||
2032 | cmdsize = sizeof (uint32_t) + sizeof (PRLI); | ||
2033 | if ((elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry, | ||
2034 | ndlp, | ||
2035 | (ELS_CMD_ACC | | ||
2036 | (ELS_CMD_PRLI & ~ELS_RSP_MASK)))) == | ||
2037 | 0) { | ||
2038 | return (1); | ||
2039 | } | ||
2040 | |||
2041 | /* Xmit PRLI ACC response tag <ulpIoTag> */ | ||
2042 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, | ||
2043 | "%d:0131 Xmit PRLI ACC response tag x%x " | ||
2044 | "Data: x%x x%x x%x x%x x%x\n", | ||
2045 | phba->brd_no, | ||
2046 | elsiocb->iocb.ulpIoTag, | ||
2047 | elsiocb->iocb.ulpContext, ndlp->nlp_DID, | ||
2048 | ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); | ||
2049 | |||
2050 | icmd = &elsiocb->iocb; | ||
2051 | oldcmd = &oldiocb->iocb; | ||
2052 | icmd->ulpContext = oldcmd->ulpContext; /* Xri */ | ||
2053 | pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); | ||
2054 | |||
2055 | *((uint32_t *) (pcmd)) = (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK)); | ||
2056 | pcmd += sizeof (uint32_t); | ||
2057 | |||
2058 | /* For PRLI, remainder of payload is PRLI parameter page */ | ||
2059 | memset(pcmd, 0, sizeof (PRLI)); | ||
2060 | |||
2061 | npr = (PRLI *) pcmd; | ||
2062 | vpd = &phba->vpd; | ||
2063 | /* | ||
2064 | * If our firmware version is 3.20 or later, | ||
2065 | * set the following bits for FC-TAPE support. | ||
2066 | */ | ||
2067 | if (vpd->rev.feaLevelHigh >= 0x02) { | ||
2068 | npr->ConfmComplAllowed = 1; | ||
2069 | npr->Retry = 1; | ||
2070 | npr->TaskRetryIdReq = 1; | ||
2071 | } | ||
2072 | |||
2073 | npr->acceptRspCode = PRLI_REQ_EXECUTED; | ||
2074 | npr->estabImagePair = 1; | ||
2075 | npr->readXferRdyDis = 1; | ||
2076 | npr->ConfmComplAllowed = 1; | ||
2077 | |||
2078 | npr->prliType = PRLI_FCP_TYPE; | ||
2079 | npr->initiatorFunc = 1; | ||
2080 | |||
2081 | phba->fc_stat.elsXmitACC++; | ||
2082 | elsiocb->iocb_cmpl = lpfc_cmpl_els_acc; | ||
2083 | |||
2084 | spin_lock_irq(phba->host->host_lock); | ||
2085 | rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0); | ||
2086 | spin_unlock_irq(phba->host->host_lock); | ||
2087 | if (rc == IOCB_ERROR) { | ||
2088 | lpfc_els_free_iocb(phba, elsiocb); | ||
2089 | return (1); | ||
2090 | } | ||
2091 | return (0); | ||
2092 | } | ||
2093 | |||
2094 | static int | ||
2095 | lpfc_els_rsp_rnid_acc(struct lpfc_hba * phba, | ||
2096 | uint8_t format, | ||
2097 | struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp) | ||
2098 | { | ||
2099 | RNID *rn; | ||
2100 | IOCB_t *icmd; | ||
2101 | IOCB_t *oldcmd; | ||
2102 | struct lpfc_iocbq *elsiocb; | ||
2103 | struct lpfc_sli_ring *pring; | ||
2104 | struct lpfc_sli *psli; | ||
2105 | uint8_t *pcmd; | ||
2106 | uint16_t cmdsize; | ||
2107 | int rc; | ||
2108 | |||
2109 | psli = &phba->sli; | ||
2110 | pring = &psli->ring[LPFC_ELS_RING]; | ||
2111 | |||
2112 | cmdsize = sizeof (uint32_t) + sizeof (uint32_t) | ||
2113 | + (2 * sizeof (struct lpfc_name)); | ||
2114 | if (format) | ||
2115 | cmdsize += sizeof (RNID_TOP_DISC); | ||
2116 | |||
2117 | if ((elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry, | ||
2118 | ndlp, ELS_CMD_ACC)) == 0) { | ||
2119 | return (1); | ||
2120 | } | ||
2121 | |||
2122 | /* Xmit RNID ACC response tag <ulpIoTag> */ | ||
2123 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, | ||
2124 | "%d:0132 Xmit RNID ACC response tag x%x " | ||
2125 | "Data: x%x\n", | ||
2126 | phba->brd_no, | ||
2127 | elsiocb->iocb.ulpIoTag, | ||
2128 | elsiocb->iocb.ulpContext); | ||
2129 | |||
2130 | icmd = &elsiocb->iocb; | ||
2131 | oldcmd = &oldiocb->iocb; | ||
2132 | icmd->ulpContext = oldcmd->ulpContext; /* Xri */ | ||
2133 | pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); | ||
2134 | |||
2135 | *((uint32_t *) (pcmd)) = ELS_CMD_ACC; | ||
2136 | pcmd += sizeof (uint32_t); | ||
2137 | |||
2138 | memset(pcmd, 0, sizeof (RNID)); | ||
2139 | rn = (RNID *) (pcmd); | ||
2140 | rn->Format = format; | ||
2141 | rn->CommonLen = (2 * sizeof (struct lpfc_name)); | ||
2142 | memcpy(&rn->portName, &phba->fc_portname, sizeof (struct lpfc_name)); | ||
2143 | memcpy(&rn->nodeName, &phba->fc_nodename, sizeof (struct lpfc_name)); | ||
2144 | switch (format) { | ||
2145 | case 0: | ||
2146 | rn->SpecificLen = 0; | ||
2147 | break; | ||
2148 | case RNID_TOPOLOGY_DISC: | ||
2149 | rn->SpecificLen = sizeof (RNID_TOP_DISC); | ||
2150 | memcpy(&rn->un.topologyDisc.portName, | ||
2151 | &phba->fc_portname, sizeof (struct lpfc_name)); | ||
2152 | rn->un.topologyDisc.unitType = RNID_HBA; | ||
2153 | rn->un.topologyDisc.physPort = 0; | ||
2154 | rn->un.topologyDisc.attachedNodes = 0; | ||
2155 | break; | ||
2156 | default: | ||
2157 | rn->CommonLen = 0; | ||
2158 | rn->SpecificLen = 0; | ||
2159 | break; | ||
2160 | } | ||
2161 | |||
2162 | phba->fc_stat.elsXmitACC++; | ||
2163 | elsiocb->iocb_cmpl = lpfc_cmpl_els_acc; | ||
2164 | elsiocb->context1 = NULL; /* Don't need ndlp for cmpl, | ||
2165 | * it could be freed */ | ||
2166 | |||
2167 | spin_lock_irq(phba->host->host_lock); | ||
2168 | rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0); | ||
2169 | spin_unlock_irq(phba->host->host_lock); | ||
2170 | if (rc == IOCB_ERROR) { | ||
2171 | lpfc_els_free_iocb(phba, elsiocb); | ||
2172 | return (1); | ||
2173 | } | ||
2174 | return (0); | ||
2175 | } | ||
2176 | |||
2177 | int | ||
2178 | lpfc_els_disc_adisc(struct lpfc_hba * phba) | ||
2179 | { | ||
2180 | int sentadisc; | ||
2181 | struct lpfc_nodelist *ndlp, *next_ndlp; | ||
2182 | |||
2183 | sentadisc = 0; | ||
2184 | /* go thru NPR list and issue any remaining ELS ADISCs */ | ||
2185 | list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list, | ||
2186 | nlp_listp) { | ||
2187 | if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { | ||
2188 | if (ndlp->nlp_flag & NLP_NPR_ADISC) { | ||
2189 | ndlp->nlp_flag &= ~NLP_NPR_ADISC; | ||
2190 | ndlp->nlp_state = NLP_STE_ADISC_ISSUE; | ||
2191 | lpfc_nlp_list(phba, ndlp, | ||
2192 | NLP_ADISC_LIST); | ||
2193 | lpfc_issue_els_adisc(phba, ndlp, 0); | ||
2194 | sentadisc++; | ||
2195 | phba->num_disc_nodes++; | ||
2196 | if (phba->num_disc_nodes >= | ||
2197 | phba->cfg_discovery_threads) { | ||
2198 | spin_lock_irq(phba->host->host_lock); | ||
2199 | phba->fc_flag |= FC_NLP_MORE; | ||
2200 | spin_unlock_irq(phba->host->host_lock); | ||
2201 | break; | ||
2202 | } | ||
2203 | } | ||
2204 | } | ||
2205 | } | ||
2206 | if (sentadisc == 0) { | ||
2207 | spin_lock_irq(phba->host->host_lock); | ||
2208 | phba->fc_flag &= ~FC_NLP_MORE; | ||
2209 | spin_unlock_irq(phba->host->host_lock); | ||
2210 | } | ||
2211 | return(sentadisc); | ||
2212 | } | ||
2213 | |||
2214 | int | ||
2215 | lpfc_els_disc_plogi(struct lpfc_hba * phba) | ||
2216 | { | ||
2217 | int sentplogi; | ||
2218 | struct lpfc_nodelist *ndlp, *next_ndlp; | ||
2219 | |||
2220 | sentplogi = 0; | ||
2221 | /* go thru NPR list and issue any remaining ELS PLOGIs */ | ||
2222 | list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list, | ||
2223 | nlp_listp) { | ||
2224 | if ((ndlp->nlp_flag & NLP_NPR_2B_DISC) && | ||
2225 | (!(ndlp->nlp_flag & NLP_DELAY_TMO))) { | ||
2226 | if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { | ||
2227 | ndlp->nlp_state = NLP_STE_PLOGI_ISSUE; | ||
2228 | lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST); | ||
2229 | lpfc_issue_els_plogi(phba, ndlp, 0); | ||
2230 | sentplogi++; | ||
2231 | phba->num_disc_nodes++; | ||
2232 | if (phba->num_disc_nodes >= | ||
2233 | phba->cfg_discovery_threads) { | ||
2234 | spin_lock_irq(phba->host->host_lock); | ||
2235 | phba->fc_flag |= FC_NLP_MORE; | ||
2236 | spin_unlock_irq(phba->host->host_lock); | ||
2237 | break; | ||
2238 | } | ||
2239 | } | ||
2240 | } | ||
2241 | } | ||
2242 | if (sentplogi == 0) { | ||
2243 | spin_lock_irq(phba->host->host_lock); | ||
2244 | phba->fc_flag &= ~FC_NLP_MORE; | ||
2245 | spin_unlock_irq(phba->host->host_lock); | ||
2246 | } | ||
2247 | return(sentplogi); | ||
2248 | } | ||
2249 | |||
2250 | int | ||
2251 | lpfc_els_flush_rscn(struct lpfc_hba * phba) | ||
2252 | { | ||
2253 | struct lpfc_dmabuf *mp; | ||
2254 | int i; | ||
2255 | |||
2256 | for (i = 0; i < phba->fc_rscn_id_cnt; i++) { | ||
2257 | mp = phba->fc_rscn_id_list[i]; | ||
2258 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | ||
2259 | kfree(mp); | ||
2260 | phba->fc_rscn_id_list[i] = NULL; | ||
2261 | } | ||
2262 | phba->fc_rscn_id_cnt = 0; | ||
2263 | spin_lock_irq(phba->host->host_lock); | ||
2264 | phba->fc_flag &= ~(FC_RSCN_MODE | FC_RSCN_DISCOVERY); | ||
2265 | spin_unlock_irq(phba->host->host_lock); | ||
2266 | lpfc_can_disctmo(phba); | ||
2267 | return (0); | ||
2268 | } | ||
2269 | |||
2270 | int | ||
2271 | lpfc_rscn_payload_check(struct lpfc_hba * phba, uint32_t did) | ||
2272 | { | ||
2273 | D_ID ns_did; | ||
2274 | D_ID rscn_did; | ||
2275 | struct lpfc_dmabuf *mp; | ||
2276 | uint32_t *lp; | ||
2277 | uint32_t payload_len, cmd, i, match; | ||
2278 | |||
2279 | ns_did.un.word = did; | ||
2280 | match = 0; | ||
2281 | |||
2282 | /* Never match fabric nodes for RSCNs */ | ||
2283 | if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) | ||
2284 | return(0); | ||
2285 | |||
2286 | /* If we are doing a FULL RSCN rediscovery, match everything */ | ||
2287 | if (phba->fc_flag & FC_RSCN_DISCOVERY) { | ||
2288 | return (did); | ||
2289 | } | ||
2290 | |||
2291 | for (i = 0; i < phba->fc_rscn_id_cnt; i++) { | ||
2292 | mp = phba->fc_rscn_id_list[i]; | ||
2293 | lp = (uint32_t *) mp->virt; | ||
2294 | cmd = *lp++; | ||
2295 | payload_len = be32_to_cpu(cmd) & 0xffff; /* payload length */ | ||
2296 | payload_len -= sizeof (uint32_t); /* take off word 0 */ | ||
2297 | while (payload_len) { | ||
2298 | rscn_did.un.word = *lp++; | ||
2299 | rscn_did.un.word = be32_to_cpu(rscn_did.un.word); | ||
2300 | payload_len -= sizeof (uint32_t); | ||
2301 | switch (rscn_did.un.b.resv) { | ||
2302 | case 0: /* Single N_Port ID effected */ | ||
2303 | if (ns_did.un.word == rscn_did.un.word) { | ||
2304 | match = did; | ||
2305 | } | ||
2306 | break; | ||
2307 | case 1: /* Whole N_Port Area effected */ | ||
2308 | if ((ns_did.un.b.domain == rscn_did.un.b.domain) | ||
2309 | && (ns_did.un.b.area == rscn_did.un.b.area)) | ||
2310 | { | ||
2311 | match = did; | ||
2312 | } | ||
2313 | break; | ||
2314 | case 2: /* Whole N_Port Domain effected */ | ||
2315 | if (ns_did.un.b.domain == rscn_did.un.b.domain) | ||
2316 | { | ||
2317 | match = did; | ||
2318 | } | ||
2319 | break; | ||
2320 | case 3: /* Whole Fabric effected */ | ||
2321 | match = did; | ||
2322 | break; | ||
2323 | default: | ||
2324 | /* Unknown Identifier in RSCN list */ | ||
2325 | lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, | ||
2326 | "%d:0217 Unknown Identifier in " | ||
2327 | "RSCN payload Data: x%x\n", | ||
2328 | phba->brd_no, rscn_did.un.word); | ||
2329 | break; | ||
2330 | } | ||
2331 | if (match) { | ||
2332 | break; | ||
2333 | } | ||
2334 | } | ||
2335 | } | ||
2336 | return (match); | ||
2337 | } | ||
2338 | |||
2339 | static int | ||
2340 | lpfc_rscn_recovery_check(struct lpfc_hba * phba) | ||
2341 | { | ||
2342 | struct lpfc_nodelist *ndlp = NULL, *next_ndlp; | ||
2343 | struct list_head *listp; | ||
2344 | struct list_head *node_list[7]; | ||
2345 | int i; | ||
2346 | |||
2347 | /* Look at all nodes effected by pending RSCNs and move | ||
2348 | * them to NPR list. | ||
2349 | */ | ||
2350 | node_list[0] = &phba->fc_npr_list; /* MUST do this list first */ | ||
2351 | node_list[1] = &phba->fc_nlpmap_list; | ||
2352 | node_list[2] = &phba->fc_nlpunmap_list; | ||
2353 | node_list[3] = &phba->fc_prli_list; | ||
2354 | node_list[4] = &phba->fc_reglogin_list; | ||
2355 | node_list[5] = &phba->fc_adisc_list; | ||
2356 | node_list[6] = &phba->fc_plogi_list; | ||
2357 | for (i = 0; i < 7; i++) { | ||
2358 | listp = node_list[i]; | ||
2359 | if (list_empty(listp)) | ||
2360 | continue; | ||
2361 | |||
2362 | list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp) { | ||
2363 | if (!(lpfc_rscn_payload_check(phba, ndlp->nlp_DID))) | ||
2364 | continue; | ||
2365 | |||
2366 | lpfc_disc_state_machine(phba, ndlp, NULL, | ||
2367 | NLP_EVT_DEVICE_RECOVERY); | ||
2368 | if (ndlp->nlp_flag & NLP_DELAY_TMO) { | ||
2369 | ndlp->nlp_flag &= ~NLP_DELAY_TMO; | ||
2370 | del_timer_sync(&ndlp->nlp_delayfunc); | ||
2371 | if (!list_empty(&ndlp-> | ||
2372 | els_retry_evt.evt_listp)) | ||
2373 | list_del_init(&ndlp-> | ||
2374 | els_retry_evt.evt_listp); | ||
2375 | } | ||
2376 | } | ||
2377 | } | ||
2378 | return (0); | ||
2379 | } | ||
2380 | |||
2381 | static int | ||
2382 | lpfc_els_rcv_rscn(struct lpfc_hba * phba, | ||
2383 | struct lpfc_iocbq * cmdiocb, | ||
2384 | struct lpfc_nodelist * ndlp, uint8_t newnode) | ||
2385 | { | ||
2386 | struct lpfc_dmabuf *pcmd; | ||
2387 | uint32_t *lp; | ||
2388 | IOCB_t *icmd; | ||
2389 | uint32_t payload_len, cmd; | ||
2390 | |||
2391 | icmd = &cmdiocb->iocb; | ||
2392 | pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; | ||
2393 | lp = (uint32_t *) pcmd->virt; | ||
2394 | |||
2395 | cmd = *lp++; | ||
2396 | payload_len = be32_to_cpu(cmd) & 0xffff; /* payload length */ | ||
2397 | payload_len -= sizeof (uint32_t); /* take off word 0 */ | ||
2398 | cmd &= ELS_CMD_MASK; | ||
2399 | |||
2400 | /* RSCN received */ | ||
2401 | lpfc_printf_log(phba, | ||
2402 | KERN_INFO, | ||
2403 | LOG_DISCOVERY, | ||
2404 | "%d:0214 RSCN received Data: x%x x%x x%x x%x\n", | ||
2405 | phba->brd_no, | ||
2406 | phba->fc_flag, payload_len, *lp, phba->fc_rscn_id_cnt); | ||
2407 | |||
2408 | /* If we are about to begin discovery, just ACC the RSCN. | ||
2409 | * Discovery processing will satisfy it. | ||
2410 | */ | ||
2411 | if (phba->hba_state < LPFC_NS_QRY) { | ||
2412 | lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, | ||
2413 | newnode); | ||
2414 | return (0); | ||
2415 | } | ||
2416 | |||
2417 | /* If we are already processing an RSCN, save the received | ||
2418 | * RSCN payload buffer, cmdiocb->context2 to process later. | ||
2419 | */ | ||
2420 | if (phba->fc_flag & (FC_RSCN_MODE | FC_NDISC_ACTIVE)) { | ||
2421 | if ((phba->fc_rscn_id_cnt < FC_MAX_HOLD_RSCN) && | ||
2422 | !(phba->fc_flag & FC_RSCN_DISCOVERY)) { | ||
2423 | spin_lock_irq(phba->host->host_lock); | ||
2424 | phba->fc_flag |= FC_RSCN_MODE; | ||
2425 | spin_unlock_irq(phba->host->host_lock); | ||
2426 | phba->fc_rscn_id_list[phba->fc_rscn_id_cnt++] = pcmd; | ||
2427 | |||
2428 | /* If we zero, cmdiocb->context2, the calling | ||
2429 | * routine will not try to free it. | ||
2430 | */ | ||
2431 | cmdiocb->context2 = NULL; | ||
2432 | |||
2433 | /* Deferred RSCN */ | ||
2434 | lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, | ||
2435 | "%d:0235 Deferred RSCN " | ||
2436 | "Data: x%x x%x x%x\n", | ||
2437 | phba->brd_no, phba->fc_rscn_id_cnt, | ||
2438 | phba->fc_flag, phba->hba_state); | ||
2439 | } else { | ||
2440 | spin_lock_irq(phba->host->host_lock); | ||
2441 | phba->fc_flag |= FC_RSCN_DISCOVERY; | ||
2442 | spin_unlock_irq(phba->host->host_lock); | ||
2443 | /* ReDiscovery RSCN */ | ||
2444 | lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, | ||
2445 | "%d:0234 ReDiscovery RSCN " | ||
2446 | "Data: x%x x%x x%x\n", | ||
2447 | phba->brd_no, phba->fc_rscn_id_cnt, | ||
2448 | phba->fc_flag, phba->hba_state); | ||
2449 | } | ||
2450 | /* Send back ACC */ | ||
2451 | lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, | ||
2452 | newnode); | ||
2453 | |||
2454 | /* send RECOVERY event for ALL nodes that match RSCN payload */ | ||
2455 | lpfc_rscn_recovery_check(phba); | ||
2456 | return (0); | ||
2457 | } | ||
2458 | |||
2459 | phba->fc_flag |= FC_RSCN_MODE; | ||
2460 | phba->fc_rscn_id_list[phba->fc_rscn_id_cnt++] = pcmd; | ||
2461 | /* | ||
2462 | * If we zero, cmdiocb->context2, the calling routine will | ||
2463 | * not try to free it. | ||
2464 | */ | ||
2465 | cmdiocb->context2 = NULL; | ||
2466 | |||
2467 | lpfc_set_disctmo(phba); | ||
2468 | |||
2469 | /* Send back ACC */ | ||
2470 | lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, newnode); | ||
2471 | |||
2472 | /* send RECOVERY event for ALL nodes that match RSCN payload */ | ||
2473 | lpfc_rscn_recovery_check(phba); | ||
2474 | |||
2475 | return (lpfc_els_handle_rscn(phba)); | ||
2476 | } | ||
2477 | |||
2478 | int | ||
2479 | lpfc_els_handle_rscn(struct lpfc_hba * phba) | ||
2480 | { | ||
2481 | struct lpfc_nodelist *ndlp; | ||
2482 | |||
2483 | /* Start timer for RSCN processing */ | ||
2484 | lpfc_set_disctmo(phba); | ||
2485 | |||
2486 | /* RSCN processed */ | ||
2487 | lpfc_printf_log(phba, | ||
2488 | KERN_INFO, | ||
2489 | LOG_DISCOVERY, | ||
2490 | "%d:0215 RSCN processed Data: x%x x%x x%x x%x\n", | ||
2491 | phba->brd_no, | ||
2492 | phba->fc_flag, 0, phba->fc_rscn_id_cnt, | ||
2493 | phba->hba_state); | ||
2494 | |||
2495 | /* To process RSCN, first compare RSCN data with NameServer */ | ||
2496 | phba->fc_ns_retry = 0; | ||
2497 | if ((ndlp = lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED, | ||
2498 | NameServer_DID))) { | ||
2499 | /* Good ndlp, issue CT Request to NameServer */ | ||
2500 | if (lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT) == 0) { | ||
2501 | /* Wait for NameServer query cmpl before we can | ||
2502 | continue */ | ||
2503 | return (1); | ||
2504 | } | ||
2505 | } else { | ||
2506 | /* If login to NameServer does not exist, issue one */ | ||
2507 | /* Good status, issue PLOGI to NameServer */ | ||
2508 | if ((ndlp = | ||
2509 | lpfc_findnode_did(phba, NLP_SEARCH_ALL, NameServer_DID))) { | ||
2510 | /* Wait for NameServer login cmpl before we can | ||
2511 | continue */ | ||
2512 | return (1); | ||
2513 | } | ||
2514 | if ((ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL)) | ||
2515 | == 0) { | ||
2516 | lpfc_els_flush_rscn(phba); | ||
2517 | return (0); | ||
2518 | } else { | ||
2519 | lpfc_nlp_init(phba, ndlp, NameServer_DID); | ||
2520 | ndlp->nlp_type |= NLP_FABRIC; | ||
2521 | ndlp->nlp_state = NLP_STE_PLOGI_ISSUE; | ||
2522 | lpfc_issue_els_plogi(phba, ndlp, 0); | ||
2523 | /* Wait for NameServer login cmpl before we can | ||
2524 | continue */ | ||
2525 | return (1); | ||
2526 | } | ||
2527 | } | ||
2528 | |||
2529 | lpfc_els_flush_rscn(phba); | ||
2530 | return (0); | ||
2531 | } | ||
2532 | |||
2533 | static int | ||
2534 | lpfc_els_rcv_flogi(struct lpfc_hba * phba, | ||
2535 | struct lpfc_iocbq * cmdiocb, | ||
2536 | struct lpfc_nodelist * ndlp, uint8_t newnode) | ||
2537 | { | ||
2538 | struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; | ||
2539 | uint32_t *lp = (uint32_t *) pcmd->virt; | ||
2540 | IOCB_t *icmd = &cmdiocb->iocb; | ||
2541 | struct serv_parm *sp; | ||
2542 | LPFC_MBOXQ_t *mbox; | ||
2543 | struct ls_rjt stat; | ||
2544 | uint32_t cmd, did; | ||
2545 | int rc; | ||
2546 | |||
2547 | cmd = *lp++; | ||
2548 | sp = (struct serv_parm *) lp; | ||
2549 | |||
2550 | /* FLOGI received */ | ||
2551 | |||
2552 | lpfc_set_disctmo(phba); | ||
2553 | |||
2554 | if (phba->fc_topology == TOPOLOGY_LOOP) { | ||
2555 | /* We should never receive a FLOGI in loop mode, ignore it */ | ||
2556 | did = icmd->un.elsreq64.remoteID; | ||
2557 | |||
2558 | /* An FLOGI ELS command <elsCmd> was received from DID <did> in | ||
2559 | Loop Mode */ | ||
2560 | lpfc_printf_log(phba, KERN_ERR, LOG_ELS, | ||
2561 | "%d:0113 An FLOGI ELS command x%x was received " | ||
2562 | "from DID x%x in Loop Mode\n", | ||
2563 | phba->brd_no, cmd, did); | ||
2564 | return (1); | ||
2565 | } | ||
2566 | |||
2567 | did = Fabric_DID; | ||
2568 | |||
2569 | if ((lpfc_check_sparm(phba, ndlp, sp, CLASS3))) { | ||
2570 | /* For a FLOGI we accept, then if our portname is greater | ||
2571 | * then the remote portname we initiate Nport login. | ||
2572 | */ | ||
2573 | |||
2574 | rc = memcmp(&phba->fc_portname, &sp->portName, | ||
2575 | sizeof (struct lpfc_name)); | ||
2576 | |||
2577 | if (!rc) { | ||
2578 | if ((mbox = mempool_alloc(phba->mbox_mem_pool, | ||
2579 | GFP_KERNEL)) == 0) { | ||
2580 | return (1); | ||
2581 | } | ||
2582 | lpfc_linkdown(phba); | ||
2583 | lpfc_init_link(phba, mbox, | ||
2584 | phba->cfg_topology, | ||
2585 | phba->cfg_link_speed); | ||
2586 | mbox->mb.un.varInitLnk.lipsr_AL_PA = 0; | ||
2587 | mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; | ||
2588 | rc = lpfc_sli_issue_mbox | ||
2589 | (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); | ||
2590 | if (rc == MBX_NOT_FINISHED) { | ||
2591 | mempool_free( mbox, phba->mbox_mem_pool); | ||
2592 | } | ||
2593 | return (1); | ||
2594 | } | ||
2595 | else if (rc > 0) { /* greater than */ | ||
2596 | spin_lock_irq(phba->host->host_lock); | ||
2597 | phba->fc_flag |= FC_PT2PT_PLOGI; | ||
2598 | spin_unlock_irq(phba->host->host_lock); | ||
2599 | } | ||
2600 | phba->fc_flag |= FC_PT2PT; | ||
2601 | phba->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); | ||
2602 | } else { | ||
2603 | /* Reject this request because invalid parameters */ | ||
2604 | stat.un.b.lsRjtRsvd0 = 0; | ||
2605 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; | ||
2606 | stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS; | ||
2607 | stat.un.b.vendorUnique = 0; | ||
2608 | lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp); | ||
2609 | return (1); | ||
2610 | } | ||
2611 | |||
2612 | /* Send back ACC */ | ||
2613 | lpfc_els_rsp_acc(phba, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL, newnode); | ||
2614 | |||
2615 | return (0); | ||
2616 | } | ||
2617 | |||
2618 | static int | ||
2619 | lpfc_els_rcv_rnid(struct lpfc_hba * phba, | ||
2620 | struct lpfc_iocbq * cmdiocb, struct lpfc_nodelist * ndlp) | ||
2621 | { | ||
2622 | struct lpfc_dmabuf *pcmd; | ||
2623 | uint32_t *lp; | ||
2624 | IOCB_t *icmd; | ||
2625 | RNID *rn; | ||
2626 | struct ls_rjt stat; | ||
2627 | uint32_t cmd, did; | ||
2628 | |||
2629 | icmd = &cmdiocb->iocb; | ||
2630 | did = icmd->un.elsreq64.remoteID; | ||
2631 | pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; | ||
2632 | lp = (uint32_t *) pcmd->virt; | ||
2633 | |||
2634 | cmd = *lp++; | ||
2635 | rn = (RNID *) lp; | ||
2636 | |||
2637 | /* RNID received */ | ||
2638 | |||
2639 | switch (rn->Format) { | ||
2640 | case 0: | ||
2641 | case RNID_TOPOLOGY_DISC: | ||
2642 | /* Send back ACC */ | ||
2643 | lpfc_els_rsp_rnid_acc(phba, rn->Format, cmdiocb, ndlp); | ||
2644 | break; | ||
2645 | default: | ||
2646 | /* Reject this request because format not supported */ | ||
2647 | stat.un.b.lsRjtRsvd0 = 0; | ||
2648 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; | ||
2649 | stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; | ||
2650 | stat.un.b.vendorUnique = 0; | ||
2651 | lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp); | ||
2652 | } | ||
2653 | return (0); | ||
2654 | } | ||
2655 | |||
2656 | static int | ||
2657 | lpfc_els_rcv_rrq(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, | ||
2658 | struct lpfc_nodelist * ndlp) | ||
2659 | { | ||
2660 | struct lpfc_dmabuf *pcmd; | ||
2661 | uint32_t *lp; | ||
2662 | IOCB_t *icmd; | ||
2663 | struct lpfc_sli_ring *pring; | ||
2664 | struct lpfc_sli *psli; | ||
2665 | RRQ *rrq; | ||
2666 | uint32_t cmd, did; | ||
2667 | |||
2668 | psli = &phba->sli; | ||
2669 | pring = &psli->ring[LPFC_FCP_RING]; | ||
2670 | icmd = &cmdiocb->iocb; | ||
2671 | did = icmd->un.elsreq64.remoteID; | ||
2672 | pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; | ||
2673 | lp = (uint32_t *) pcmd->virt; | ||
2674 | |||
2675 | cmd = *lp++; | ||
2676 | rrq = (RRQ *) lp; | ||
2677 | |||
2678 | /* RRQ received */ | ||
2679 | /* Get oxid / rxid from payload and abort it */ | ||
2680 | spin_lock_irq(phba->host->host_lock); | ||
2681 | if ((rrq->SID == be32_to_cpu(phba->fc_myDID))) { | ||
2682 | lpfc_sli_abort_iocb(phba, pring, 0, 0, rrq->Oxid, | ||
2683 | LPFC_CTX_CTX); | ||
2684 | } else { | ||
2685 | lpfc_sli_abort_iocb(phba, pring, 0, 0, rrq->Rxid, | ||
2686 | LPFC_CTX_CTX); | ||
2687 | } | ||
2688 | |||
2689 | spin_unlock_irq(phba->host->host_lock); | ||
2690 | /* ACCEPT the rrq request */ | ||
2691 | lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0); | ||
2692 | |||
2693 | return 0; | ||
2694 | } | ||
2695 | |||
2696 | static int | ||
2697 | lpfc_els_rcv_farp(struct lpfc_hba * phba, | ||
2698 | struct lpfc_iocbq * cmdiocb, struct lpfc_nodelist * ndlp) | ||
2699 | { | ||
2700 | struct lpfc_dmabuf *pcmd; | ||
2701 | uint32_t *lp; | ||
2702 | IOCB_t *icmd; | ||
2703 | FARP *fp; | ||
2704 | uint32_t cmd, cnt, did; | ||
2705 | |||
2706 | icmd = &cmdiocb->iocb; | ||
2707 | did = icmd->un.elsreq64.remoteID; | ||
2708 | pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; | ||
2709 | lp = (uint32_t *) pcmd->virt; | ||
2710 | |||
2711 | cmd = *lp++; | ||
2712 | fp = (FARP *) lp; | ||
2713 | |||
2714 | /* FARP-REQ received from DID <did> */ | ||
2715 | lpfc_printf_log(phba, | ||
2716 | KERN_INFO, | ||
2717 | LOG_IP, | ||
2718 | "%d:0601 FARP-REQ received from DID x%x\n", | ||
2719 | phba->brd_no, did); | ||
2720 | |||
2721 | /* We will only support match on WWPN or WWNN */ | ||
2722 | if (fp->Mflags & ~(FARP_MATCH_NODE | FARP_MATCH_PORT)) { | ||
2723 | return (0); | ||
2724 | } | ||
2725 | |||
2726 | cnt = 0; | ||
2727 | /* If this FARP command is searching for my portname */ | ||
2728 | if (fp->Mflags & FARP_MATCH_PORT) { | ||
2729 | if (memcmp(&fp->RportName, &phba->fc_portname, | ||
2730 | sizeof (struct lpfc_name)) == 0) | ||
2731 | cnt = 1; | ||
2732 | } | ||
2733 | |||
2734 | /* If this FARP command is searching for my nodename */ | ||
2735 | if (fp->Mflags & FARP_MATCH_NODE) { | ||
2736 | if (memcmp(&fp->RnodeName, &phba->fc_nodename, | ||
2737 | sizeof (struct lpfc_name)) == 0) | ||
2738 | cnt = 1; | ||
2739 | } | ||
2740 | |||
2741 | if (cnt) { | ||
2742 | if ((ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) || | ||
2743 | (ndlp->nlp_state == NLP_STE_MAPPED_NODE)) { | ||
2744 | /* Log back into the node before sending the FARP. */ | ||
2745 | if (fp->Rflags & FARP_REQUEST_PLOGI) { | ||
2746 | ndlp->nlp_state = NLP_STE_PLOGI_ISSUE; | ||
2747 | lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST); | ||
2748 | lpfc_issue_els_plogi(phba, ndlp, 0); | ||
2749 | } | ||
2750 | |||
2751 | /* Send a FARP response to that node */ | ||
2752 | if (fp->Rflags & FARP_REQUEST_FARPR) { | ||
2753 | lpfc_issue_els_farpr(phba, did, 0); | ||
2754 | } | ||
2755 | } | ||
2756 | } | ||
2757 | return (0); | ||
2758 | } | ||
2759 | |||
2760 | static int | ||
2761 | lpfc_els_rcv_farpr(struct lpfc_hba * phba, | ||
2762 | struct lpfc_iocbq * cmdiocb, struct lpfc_nodelist * ndlp) | ||
2763 | { | ||
2764 | struct lpfc_dmabuf *pcmd; | ||
2765 | uint32_t *lp; | ||
2766 | IOCB_t *icmd; | ||
2767 | uint32_t cmd, did; | ||
2768 | |||
2769 | icmd = &cmdiocb->iocb; | ||
2770 | did = icmd->un.elsreq64.remoteID; | ||
2771 | pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; | ||
2772 | lp = (uint32_t *) pcmd->virt; | ||
2773 | |||
2774 | cmd = *lp++; | ||
2775 | /* FARP-RSP received from DID <did> */ | ||
2776 | lpfc_printf_log(phba, | ||
2777 | KERN_INFO, | ||
2778 | LOG_IP, | ||
2779 | "%d:0600 FARP-RSP received from DID x%x\n", | ||
2780 | phba->brd_no, did); | ||
2781 | |||
2782 | /* ACCEPT the Farp resp request */ | ||
2783 | lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0); | ||
2784 | |||
2785 | return 0; | ||
2786 | } | ||
2787 | |||
2788 | static int | ||
2789 | lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, | ||
2790 | struct lpfc_nodelist * ndlp) | ||
2791 | { | ||
2792 | struct lpfc_dmabuf *pcmd; | ||
2793 | uint32_t *lp; | ||
2794 | IOCB_t *icmd; | ||
2795 | FAN *fp; | ||
2796 | uint32_t cmd, did; | ||
2797 | |||
2798 | icmd = &cmdiocb->iocb; | ||
2799 | did = icmd->un.elsreq64.remoteID; | ||
2800 | pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; | ||
2801 | lp = (uint32_t *) pcmd->virt; | ||
2802 | |||
2803 | cmd = *lp++; | ||
2804 | fp = (FAN *) lp; | ||
2805 | |||
2806 | /* FAN received */ | ||
2807 | |||
2808 | /* ACCEPT the FAN request */ | ||
2809 | lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0); | ||
2810 | |||
2811 | if (phba->hba_state == LPFC_LOCAL_CFG_LINK) { | ||
2812 | /* The discovery state machine needs to take a different | ||
2813 | * action if this node has switched fabrics | ||
2814 | */ | ||
2815 | if ((memcmp(&fp->FportName, &phba->fc_fabparam.portName, | ||
2816 | sizeof (struct lpfc_name)) != 0) | ||
2817 | || | ||
2818 | (memcmp(&fp->FnodeName, &phba->fc_fabparam.nodeName, | ||
2819 | sizeof (struct lpfc_name)) != 0)) { | ||
2820 | /* This node has switched fabrics. An FLOGI is required | ||
2821 | * after the timeout | ||
2822 | */ | ||
2823 | return (0); | ||
2824 | } | ||
2825 | |||
2826 | /* Start discovery */ | ||
2827 | lpfc_disc_start(phba); | ||
2828 | } | ||
2829 | |||
2830 | return (0); | ||
2831 | } | ||
2832 | |||
2833 | void | ||
2834 | lpfc_els_timeout(unsigned long ptr) | ||
2835 | { | ||
2836 | struct lpfc_hba *phba; | ||
2837 | unsigned long iflag; | ||
2838 | |||
2839 | phba = (struct lpfc_hba *)ptr; | ||
2840 | if (phba == 0) | ||
2841 | return; | ||
2842 | spin_lock_irqsave(phba->host->host_lock, iflag); | ||
2843 | if (!(phba->work_hba_events & WORKER_ELS_TMO)) { | ||
2844 | phba->work_hba_events |= WORKER_ELS_TMO; | ||
2845 | if (phba->work_wait) | ||
2846 | wake_up(phba->work_wait); | ||
2847 | } | ||
2848 | spin_unlock_irqrestore(phba->host->host_lock, iflag); | ||
2849 | return; | ||
2850 | } | ||
2851 | |||
2852 | void | ||
2853 | lpfc_els_timeout_handler(struct lpfc_hba *phba) | ||
2854 | { | ||
2855 | struct lpfc_sli_ring *pring; | ||
2856 | struct lpfc_iocbq *tmp_iocb, *piocb; | ||
2857 | IOCB_t *cmd = NULL; | ||
2858 | struct lpfc_dmabuf *pcmd; | ||
2859 | struct list_head *dlp; | ||
2860 | uint32_t *elscmd; | ||
2861 | uint32_t els_command; | ||
2862 | uint32_t timeout; | ||
2863 | uint32_t remote_ID; | ||
2864 | |||
2865 | if (phba == 0) | ||
2866 | return; | ||
2867 | spin_lock_irq(phba->host->host_lock); | ||
2868 | /* If the timer is already canceled do nothing */ | ||
2869 | if (!(phba->work_hba_events & WORKER_ELS_TMO)) { | ||
2870 | spin_unlock_irq(phba->host->host_lock); | ||
2871 | return; | ||
2872 | } | ||
2873 | timeout = (uint32_t)(phba->fc_ratov << 1); | ||
2874 | |||
2875 | pring = &phba->sli.ring[LPFC_ELS_RING]; | ||
2876 | dlp = &pring->txcmplq; | ||
2877 | |||
2878 | list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) { | ||
2879 | cmd = &piocb->iocb; | ||
2880 | |||
2881 | if (piocb->iocb_flag & LPFC_IO_LIBDFC) { | ||
2882 | continue; | ||
2883 | } | ||
2884 | pcmd = (struct lpfc_dmabuf *) piocb->context2; | ||
2885 | elscmd = (uint32_t *) (pcmd->virt); | ||
2886 | els_command = *elscmd; | ||
2887 | |||
2888 | if ((els_command == ELS_CMD_FARP) | ||
2889 | || (els_command == ELS_CMD_FARPR)) { | ||
2890 | continue; | ||
2891 | } | ||
2892 | |||
2893 | if (piocb->drvrTimeout > 0) { | ||
2894 | if (piocb->drvrTimeout >= timeout) { | ||
2895 | piocb->drvrTimeout -= timeout; | ||
2896 | } else { | ||
2897 | piocb->drvrTimeout = 0; | ||
2898 | } | ||
2899 | continue; | ||
2900 | } | ||
2901 | |||
2902 | list_del(&piocb->list); | ||
2903 | pring->txcmplq_cnt--; | ||
2904 | |||
2905 | if (cmd->ulpCommand == CMD_GEN_REQUEST64_CR) { | ||
2906 | struct lpfc_nodelist *ndlp; | ||
2907 | |||
2908 | ndlp = lpfc_findnode_rpi(phba, cmd->ulpContext); | ||
2909 | remote_ID = ndlp->nlp_DID; | ||
2910 | if (cmd->un.elsreq64.bdl.ulpIoTag32) { | ||
2911 | lpfc_sli_issue_abort_iotag32(phba, | ||
2912 | pring, piocb); | ||
2913 | } | ||
2914 | } else { | ||
2915 | remote_ID = cmd->un.elsreq64.remoteID; | ||
2916 | } | ||
2917 | |||
2918 | lpfc_printf_log(phba, | ||
2919 | KERN_ERR, | ||
2920 | LOG_ELS, | ||
2921 | "%d:0127 ELS timeout Data: x%x x%x x%x x%x\n", | ||
2922 | phba->brd_no, els_command, | ||
2923 | remote_ID, cmd->ulpCommand, cmd->ulpIoTag); | ||
2924 | |||
2925 | /* | ||
2926 | * The iocb has timed out; abort it. | ||
2927 | */ | ||
2928 | if (piocb->iocb_cmpl) { | ||
2929 | cmd->ulpStatus = IOSTAT_LOCAL_REJECT; | ||
2930 | cmd->un.ulpWord[4] = IOERR_SLI_ABORTED; | ||
2931 | spin_unlock_irq(phba->host->host_lock); | ||
2932 | (piocb->iocb_cmpl) (phba, piocb, piocb); | ||
2933 | spin_lock_irq(phba->host->host_lock); | ||
2934 | } else { | ||
2935 | list_add_tail(&piocb->list, &phba->lpfc_iocb_list); | ||
2936 | } | ||
2937 | } | ||
2938 | if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt) { | ||
2939 | phba->els_tmofunc.expires = jiffies + HZ * timeout; | ||
2940 | add_timer(&phba->els_tmofunc); | ||
2941 | } | ||
2942 | spin_unlock_irq(phba->host->host_lock); | ||
2943 | } | ||
2944 | |||
2945 | void | ||
2946 | lpfc_els_flush_cmd(struct lpfc_hba * phba) | ||
2947 | { | ||
2948 | struct lpfc_sli_ring *pring; | ||
2949 | struct lpfc_iocbq *tmp_iocb, *piocb; | ||
2950 | IOCB_t *cmd = NULL; | ||
2951 | struct lpfc_dmabuf *pcmd; | ||
2952 | uint32_t *elscmd; | ||
2953 | uint32_t els_command; | ||
2954 | uint32_t remote_ID; | ||
2955 | |||
2956 | pring = &phba->sli.ring[LPFC_ELS_RING]; | ||
2957 | spin_lock_irq(phba->host->host_lock); | ||
2958 | list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) { | ||
2959 | cmd = &piocb->iocb; | ||
2960 | |||
2961 | if (piocb->iocb_flag & LPFC_IO_LIBDFC) { | ||
2962 | continue; | ||
2963 | } | ||
2964 | |||
2965 | /* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */ | ||
2966 | if ((cmd->ulpCommand == CMD_QUE_RING_BUF_CN) || | ||
2967 | (cmd->ulpCommand == CMD_QUE_RING_BUF64_CN) || | ||
2968 | (cmd->ulpCommand == CMD_CLOSE_XRI_CN) || | ||
2969 | (cmd->ulpCommand == CMD_ABORT_XRI_CN)) { | ||
2970 | continue; | ||
2971 | } | ||
2972 | |||
2973 | pcmd = (struct lpfc_dmabuf *) piocb->context2; | ||
2974 | elscmd = (uint32_t *) (pcmd->virt); | ||
2975 | els_command = *elscmd; | ||
2976 | |||
2977 | if (cmd->ulpCommand == CMD_GEN_REQUEST64_CR) { | ||
2978 | struct lpfc_nodelist *ndlp; | ||
2979 | |||
2980 | ndlp = lpfc_findnode_rpi(phba, cmd->ulpContext); | ||
2981 | remote_ID = ndlp->nlp_DID; | ||
2982 | if (phba->hba_state == LPFC_HBA_READY) { | ||
2983 | continue; | ||
2984 | } | ||
2985 | } else { | ||
2986 | remote_ID = cmd->un.elsreq64.remoteID; | ||
2987 | } | ||
2988 | |||
2989 | list_del(&piocb->list); | ||
2990 | pring->txcmplq_cnt--; | ||
2991 | |||
2992 | cmd->ulpStatus = IOSTAT_LOCAL_REJECT; | ||
2993 | cmd->un.ulpWord[4] = IOERR_SLI_ABORTED; | ||
2994 | |||
2995 | if (piocb->iocb_cmpl) { | ||
2996 | spin_unlock_irq(phba->host->host_lock); | ||
2997 | (piocb->iocb_cmpl) (phba, piocb, piocb); | ||
2998 | spin_lock_irq(phba->host->host_lock); | ||
2999 | } | ||
3000 | else | ||
3001 | list_add_tail(&piocb->list, &phba->lpfc_iocb_list); | ||
3002 | } | ||
3003 | |||
3004 | list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) { | ||
3005 | cmd = &piocb->iocb; | ||
3006 | |||
3007 | if (piocb->iocb_flag & LPFC_IO_LIBDFC) { | ||
3008 | continue; | ||
3009 | } | ||
3010 | pcmd = (struct lpfc_dmabuf *) piocb->context2; | ||
3011 | elscmd = (uint32_t *) (pcmd->virt); | ||
3012 | els_command = *elscmd; | ||
3013 | |||
3014 | if (cmd->ulpCommand == CMD_GEN_REQUEST64_CR) { | ||
3015 | struct lpfc_nodelist *ndlp; | ||
3016 | |||
3017 | ndlp = lpfc_findnode_rpi(phba, cmd->ulpContext); | ||
3018 | remote_ID = ndlp->nlp_DID; | ||
3019 | if (phba->hba_state == LPFC_HBA_READY) { | ||
3020 | continue; | ||
3021 | } | ||
3022 | } else { | ||
3023 | remote_ID = cmd->un.elsreq64.remoteID; | ||
3024 | } | ||
3025 | |||
3026 | list_del(&piocb->list); | ||
3027 | pring->txcmplq_cnt--; | ||
3028 | |||
3029 | cmd->ulpStatus = IOSTAT_LOCAL_REJECT; | ||
3030 | cmd->un.ulpWord[4] = IOERR_SLI_ABORTED; | ||
3031 | |||
3032 | if (piocb->iocb_cmpl) { | ||
3033 | spin_unlock_irq(phba->host->host_lock); | ||
3034 | (piocb->iocb_cmpl) (phba, piocb, piocb); | ||
3035 | spin_lock_irq(phba->host->host_lock); | ||
3036 | } | ||
3037 | else | ||
3038 | list_add_tail(&piocb->list, &phba->lpfc_iocb_list); | ||
3039 | } | ||
3040 | spin_unlock_irq(phba->host->host_lock); | ||
3041 | return; | ||
3042 | } | ||
3043 | |||
3044 | void | ||
3045 | lpfc_els_unsol_event(struct lpfc_hba * phba, | ||
3046 | struct lpfc_sli_ring * pring, struct lpfc_iocbq * elsiocb) | ||
3047 | { | ||
3048 | struct lpfc_sli *psli; | ||
3049 | struct lpfc_nodelist *ndlp; | ||
3050 | struct lpfc_dmabuf *mp; | ||
3051 | uint32_t *lp; | ||
3052 | IOCB_t *icmd; | ||
3053 | struct ls_rjt stat; | ||
3054 | uint32_t cmd; | ||
3055 | uint32_t did; | ||
3056 | uint32_t newnode; | ||
3057 | uint32_t drop_cmd = 0; /* by default do NOT drop received cmd */ | ||
3058 | uint32_t rjt_err = 0; | ||
3059 | |||
3060 | psli = &phba->sli; | ||
3061 | icmd = &elsiocb->iocb; | ||
3062 | |||
3063 | if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) && | ||
3064 | ((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) { | ||
3065 | /* Not enough posted buffers; Try posting more buffers */ | ||
3066 | phba->fc_stat.NoRcvBuf++; | ||
3067 | lpfc_post_buffer(phba, pring, 0, 1); | ||
3068 | return; | ||
3069 | } | ||
3070 | |||
3071 | /* If there are no BDEs associated with this IOCB, | ||
3072 | * there is nothing to do. | ||
3073 | */ | ||
3074 | if (icmd->ulpBdeCount == 0) | ||
3075 | return; | ||
3076 | |||
3077 | /* type of ELS cmd is first 32bit word in packet */ | ||
3078 | mp = lpfc_sli_ringpostbuf_get(phba, pring, getPaddr(icmd->un. | ||
3079 | cont64[0]. | ||
3080 | addrHigh, | ||
3081 | icmd->un. | ||
3082 | cont64[0].addrLow)); | ||
3083 | if (mp == 0) { | ||
3084 | drop_cmd = 1; | ||
3085 | goto dropit; | ||
3086 | } | ||
3087 | |||
3088 | newnode = 0; | ||
3089 | lp = (uint32_t *) mp->virt; | ||
3090 | cmd = *lp++; | ||
3091 | lpfc_post_buffer(phba, &psli->ring[LPFC_ELS_RING], 1, 1); | ||
3092 | |||
3093 | if (icmd->ulpStatus) { | ||
3094 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | ||
3095 | kfree(mp); | ||
3096 | drop_cmd = 1; | ||
3097 | goto dropit; | ||
3098 | } | ||
3099 | |||
3100 | /* Check to see if link went down during discovery */ | ||
3101 | if (lpfc_els_chk_latt(phba)) { | ||
3102 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | ||
3103 | kfree(mp); | ||
3104 | drop_cmd = 1; | ||
3105 | goto dropit; | ||
3106 | } | ||
3107 | |||
3108 | did = icmd->un.rcvels.remoteID; | ||
3109 | if ((ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, did)) == 0) { | ||
3110 | /* Cannot find existing Fabric ndlp, so allocate a new one */ | ||
3111 | if ((ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL)) | ||
3112 | == 0) { | ||
3113 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | ||
3114 | kfree(mp); | ||
3115 | drop_cmd = 1; | ||
3116 | goto dropit; | ||
3117 | } | ||
3118 | |||
3119 | lpfc_nlp_init(phba, ndlp, did); | ||
3120 | newnode = 1; | ||
3121 | if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) { | ||
3122 | ndlp->nlp_type |= NLP_FABRIC; | ||
3123 | } | ||
3124 | } | ||
3125 | |||
3126 | phba->fc_stat.elsRcvFrame++; | ||
3127 | elsiocb->context1 = ndlp; | ||
3128 | elsiocb->context2 = mp; | ||
3129 | |||
3130 | if ((cmd & ELS_CMD_MASK) == ELS_CMD_RSCN) { | ||
3131 | cmd &= ELS_CMD_MASK; | ||
3132 | } | ||
3133 | /* ELS command <elsCmd> received from NPORT <did> */ | ||
3134 | lpfc_printf_log(phba, KERN_INFO, LOG_ELS, | ||
3135 | "%d:0112 ELS command x%x received from NPORT x%x " | ||
3136 | "Data: x%x\n", phba->brd_no, cmd, did, phba->hba_state); | ||
3137 | |||
3138 | switch (cmd) { | ||
3139 | case ELS_CMD_PLOGI: | ||
3140 | phba->fc_stat.elsRcvPLOGI++; | ||
3141 | if (phba->hba_state < LPFC_DISC_AUTH) { | ||
3142 | rjt_err = LSEXP_NOTHING_MORE; | ||
3143 | break; | ||
3144 | } | ||
3145 | lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PLOGI); | ||
3146 | break; | ||
3147 | case ELS_CMD_FLOGI: | ||
3148 | phba->fc_stat.elsRcvFLOGI++; | ||
3149 | lpfc_els_rcv_flogi(phba, elsiocb, ndlp, newnode); | ||
3150 | if (newnode) { | ||
3151 | mempool_free( ndlp, phba->nlp_mem_pool); | ||
3152 | } | ||
3153 | break; | ||
3154 | case ELS_CMD_LOGO: | ||
3155 | phba->fc_stat.elsRcvLOGO++; | ||
3156 | if (phba->hba_state < LPFC_DISC_AUTH) { | ||
3157 | rjt_err = LSEXP_NOTHING_MORE; | ||
3158 | break; | ||
3159 | } | ||
3160 | lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_LOGO); | ||
3161 | break; | ||
3162 | case ELS_CMD_PRLO: | ||
3163 | phba->fc_stat.elsRcvPRLO++; | ||
3164 | if (phba->hba_state < LPFC_DISC_AUTH) { | ||
3165 | rjt_err = LSEXP_NOTHING_MORE; | ||
3166 | break; | ||
3167 | } | ||
3168 | lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PRLO); | ||
3169 | break; | ||
3170 | case ELS_CMD_RSCN: | ||
3171 | phba->fc_stat.elsRcvRSCN++; | ||
3172 | lpfc_els_rcv_rscn(phba, elsiocb, ndlp, newnode); | ||
3173 | if (newnode) { | ||
3174 | mempool_free( ndlp, phba->nlp_mem_pool); | ||
3175 | } | ||
3176 | break; | ||
3177 | case ELS_CMD_ADISC: | ||
3178 | phba->fc_stat.elsRcvADISC++; | ||
3179 | if (phba->hba_state < LPFC_DISC_AUTH) { | ||
3180 | rjt_err = LSEXP_NOTHING_MORE; | ||
3181 | break; | ||
3182 | } | ||
3183 | lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_ADISC); | ||
3184 | break; | ||
3185 | case ELS_CMD_PDISC: | ||
3186 | phba->fc_stat.elsRcvPDISC++; | ||
3187 | if (phba->hba_state < LPFC_DISC_AUTH) { | ||
3188 | rjt_err = LSEXP_NOTHING_MORE; | ||
3189 | break; | ||
3190 | } | ||
3191 | lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PDISC); | ||
3192 | break; | ||
3193 | case ELS_CMD_FARPR: | ||
3194 | phba->fc_stat.elsRcvFARPR++; | ||
3195 | lpfc_els_rcv_farpr(phba, elsiocb, ndlp); | ||
3196 | break; | ||
3197 | case ELS_CMD_FARP: | ||
3198 | phba->fc_stat.elsRcvFARP++; | ||
3199 | lpfc_els_rcv_farp(phba, elsiocb, ndlp); | ||
3200 | break; | ||
3201 | case ELS_CMD_FAN: | ||
3202 | phba->fc_stat.elsRcvFAN++; | ||
3203 | lpfc_els_rcv_fan(phba, elsiocb, ndlp); | ||
3204 | break; | ||
3205 | case ELS_CMD_RRQ: | ||
3206 | phba->fc_stat.elsRcvRRQ++; | ||
3207 | lpfc_els_rcv_rrq(phba, elsiocb, ndlp); | ||
3208 | break; | ||
3209 | case ELS_CMD_PRLI: | ||
3210 | phba->fc_stat.elsRcvPRLI++; | ||
3211 | if (phba->hba_state < LPFC_DISC_AUTH) { | ||
3212 | rjt_err = LSEXP_NOTHING_MORE; | ||
3213 | break; | ||
3214 | } | ||
3215 | lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PRLI); | ||
3216 | break; | ||
3217 | case ELS_CMD_RNID: | ||
3218 | phba->fc_stat.elsRcvRNID++; | ||
3219 | lpfc_els_rcv_rnid(phba, elsiocb, ndlp); | ||
3220 | break; | ||
3221 | default: | ||
3222 | /* Unsupported ELS command, reject */ | ||
3223 | rjt_err = LSEXP_NOTHING_MORE; | ||
3224 | |||
3225 | /* Unknown ELS command <elsCmd> received from NPORT <did> */ | ||
3226 | lpfc_printf_log(phba, KERN_ERR, LOG_ELS, | ||
3227 | "%d:0115 Unknown ELS command x%x received from " | ||
3228 | "NPORT x%x\n", phba->brd_no, cmd, did); | ||
3229 | if (newnode) { | ||
3230 | mempool_free( ndlp, phba->nlp_mem_pool); | ||
3231 | } | ||
3232 | break; | ||
3233 | } | ||
3234 | |||
3235 | /* check if need to LS_RJT received ELS cmd */ | ||
3236 | if (rjt_err) { | ||
3237 | stat.un.b.lsRjtRsvd0 = 0; | ||
3238 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; | ||
3239 | stat.un.b.lsRjtRsnCodeExp = rjt_err; | ||
3240 | stat.un.b.vendorUnique = 0; | ||
3241 | lpfc_els_rsp_reject(phba, stat.un.lsRjtError, elsiocb, ndlp); | ||
3242 | } | ||
3243 | |||
3244 | if (elsiocb->context2) { | ||
3245 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | ||
3246 | kfree(mp); | ||
3247 | } | ||
3248 | dropit: | ||
3249 | /* check if need to drop received ELS cmd */ | ||
3250 | if (drop_cmd == 1) { | ||
3251 | lpfc_printf_log(phba, KERN_ERR, LOG_ELS, | ||
3252 | "%d:0111 Dropping received ELS cmd " | ||
3253 | "Data: x%x x%x\n", phba->brd_no, | ||
3254 | icmd->ulpStatus, icmd->un.ulpWord[4]); | ||
3255 | phba->fc_stat.elsRcvDrop++; | ||
3256 | } | ||
3257 | return; | ||
3258 | } | ||