blob: d48247b3b654dd4c89775ab99ad0f59e97397a2c [file] [log] [blame]
dea31012005-04-17 16:05:31 -05001/*******************************************************************
2 * This file is part of the Emulex Linux Device Driver for *
James.Smart@Emulex.Comc44ce172005-06-25 10:34:39 -04003 * Fibre Channel Host Bus Adapters. *
James Smart9413aff2007-04-25 09:53:35 -04004 * Copyright (C) 2004-2007 Emulex. All rights reserved. *
James.Smart@Emulex.Comc44ce172005-06-25 10:34:39 -04005 * EMULEX and SLI are trademarks of Emulex. *
dea31012005-04-17 16:05:31 -05006 * www.emulex.com *
James.Smart@Emulex.Comc44ce172005-06-25 10:34:39 -04007 * Portions Copyright (C) 2004-2005 Christoph Hellwig *
dea31012005-04-17 16:05:31 -05008 * *
9 * This program is free software; you can redistribute it and/or *
James.Smart@Emulex.Comc44ce172005-06-25 10:34:39 -040010 * modify it under the terms of version 2 of the GNU General *
11 * Public License as published by the Free Software Foundation. *
12 * This program is distributed in the hope that it will be useful. *
13 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
14 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
15 * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
16 * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
17 * TO BE LEGALLY INVALID. See the GNU General Public License for *
18 * more details, a copy of which can be found in the file COPYING *
19 * included with this package. *
dea31012005-04-17 16:05:31 -050020 *******************************************************************/
21
dea31012005-04-17 16:05:31 -050022#include <linux/blkdev.h>
23#include <linux/pci.h>
24#include <linux/interrupt.h>
25
James.Smart@Emulex.Com91886522005-08-10 15:03:09 -040026#include <scsi/scsi.h>
dea31012005-04-17 16:05:31 -050027#include <scsi/scsi_device.h>
28#include <scsi/scsi_host.h>
29#include <scsi/scsi_transport_fc.h>
30
31#include "lpfc_hw.h"
32#include "lpfc_sli.h"
33#include "lpfc_disc.h"
34#include "lpfc_scsi.h"
35#include "lpfc.h"
36#include "lpfc_logmsg.h"
37#include "lpfc_crtn.h"
38
39static int lpfc_els_retry(struct lpfc_hba *, struct lpfc_iocbq *,
40 struct lpfc_iocbq *);
41static int lpfc_max_els_tries = 3;
42
43static int
James Smart2e0fef82007-06-17 19:56:36 -050044lpfc_els_chk_latt(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -050045{
James Smart2e0fef82007-06-17 19:56:36 -050046 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
47 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -050048 uint32_t ha_copy;
dea31012005-04-17 16:05:31 -050049
James Smart2e0fef82007-06-17 19:56:36 -050050 if (vport->port_state >= LPFC_VPORT_READY ||
51 phba->link_state == LPFC_LINK_DOWN)
dea31012005-04-17 16:05:31 -050052 return 0;
53
54 /* Read the HBA Host Attention Register */
dea31012005-04-17 16:05:31 -050055 ha_copy = readl(phba->HAregaddr);
dea31012005-04-17 16:05:31 -050056
57 if (!(ha_copy & HA_LATT))
58 return 0;
59
60 /* Pending Link Event during Discovery */
61 lpfc_printf_log(phba, KERN_WARNING, LOG_DISCOVERY,
62 "%d:0237 Pending Link Event during "
63 "Discovery: State x%x\n",
James Smart2e0fef82007-06-17 19:56:36 -050064 phba->brd_no, phba->pport->port_state);
dea31012005-04-17 16:05:31 -050065
66 /* CLEAR_LA should re-enable link attention events and
67 * we should then imediately take a LATT event. The
68 * LATT processing should call lpfc_linkdown() which
69 * will cleanup any left over in-progress discovery
70 * events.
71 */
James Smart2e0fef82007-06-17 19:56:36 -050072 spin_lock_irq(shost->host_lock);
73 vport->fc_flag |= FC_ABORT_DISCOVERY;
74 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -050075
James Smart2e0fef82007-06-17 19:56:36 -050076 if (phba->link_state != LPFC_CLEAR_LA) {
James Smarted957682007-06-17 19:56:37 -050077 lpfc_issue_clear_la(phba, vport);
dea31012005-04-17 16:05:31 -050078 }
79
Jamie Wellnitzc9f87352006-02-28 19:25:23 -050080 return 1;
dea31012005-04-17 16:05:31 -050081
82}
83
84static struct lpfc_iocbq *
James Smart2e0fef82007-06-17 19:56:36 -050085lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
86 uint16_t cmdSize, uint8_t retry,
87 struct lpfc_nodelist *ndlp, uint32_t did,
88 uint32_t elscmd)
dea31012005-04-17 16:05:31 -050089{
James Smart2e0fef82007-06-17 19:56:36 -050090 struct lpfc_hba *phba = vport->phba;
James.Smart@Emulex.Com0bd4ca22005-10-28 20:30:02 -040091 struct lpfc_iocbq *elsiocb;
dea31012005-04-17 16:05:31 -050092 struct lpfc_dmabuf *pcmd, *prsp, *pbuflist;
93 struct ulp_bde64 *bpl;
94 IOCB_t *icmd;
95
dea31012005-04-17 16:05:31 -050096
James Smart2e0fef82007-06-17 19:56:36 -050097 if (!lpfc_is_link_up(phba))
98 return NULL;
dea31012005-04-17 16:05:31 -050099
dea31012005-04-17 16:05:31 -0500100 /* Allocate buffer for command iocb */
James.Smart@Emulex.Com0bd4ca22005-10-28 20:30:02 -0400101 elsiocb = lpfc_sli_get_iocbq(phba);
dea31012005-04-17 16:05:31 -0500102
103 if (elsiocb == NULL)
104 return NULL;
dea31012005-04-17 16:05:31 -0500105 icmd = &elsiocb->iocb;
106
107 /* fill in BDEs for command */
108 /* Allocate buffer for command payload */
109 if (((pcmd = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == 0) ||
110 ((pcmd->virt = lpfc_mbuf_alloc(phba,
111 MEM_PRI, &(pcmd->phys))) == 0)) {
Jesper Juhlc9475cb2005-11-07 01:01:26 -0800112 kfree(pcmd);
dea31012005-04-17 16:05:31 -0500113
James Bottomley604a3e32005-10-29 10:28:33 -0500114 lpfc_sli_release_iocbq(phba, elsiocb);
dea31012005-04-17 16:05:31 -0500115 return NULL;
116 }
117
118 INIT_LIST_HEAD(&pcmd->list);
119
120 /* Allocate buffer for response payload */
121 if (expectRsp) {
122 prsp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
123 if (prsp)
124 prsp->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
125 &prsp->phys);
126 if (prsp == 0 || prsp->virt == 0) {
Jesper Juhlc9475cb2005-11-07 01:01:26 -0800127 kfree(prsp);
dea31012005-04-17 16:05:31 -0500128 lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
129 kfree(pcmd);
James Bottomley604a3e32005-10-29 10:28:33 -0500130 lpfc_sli_release_iocbq(phba, elsiocb);
dea31012005-04-17 16:05:31 -0500131 return NULL;
132 }
133 INIT_LIST_HEAD(&prsp->list);
134 } else {
135 prsp = NULL;
136 }
137
138 /* Allocate buffer for Buffer ptr list */
139 pbuflist = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
140 if (pbuflist)
James Smarted957682007-06-17 19:56:37 -0500141 pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
142 &pbuflist->phys);
dea31012005-04-17 16:05:31 -0500143 if (pbuflist == 0 || pbuflist->virt == 0) {
James Bottomley604a3e32005-10-29 10:28:33 -0500144 lpfc_sli_release_iocbq(phba, elsiocb);
dea31012005-04-17 16:05:31 -0500145 lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
146 lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
147 kfree(pcmd);
148 kfree(prsp);
Jesper Juhlc9475cb2005-11-07 01:01:26 -0800149 kfree(pbuflist);
dea31012005-04-17 16:05:31 -0500150 return NULL;
151 }
152
153 INIT_LIST_HEAD(&pbuflist->list);
154
155 icmd->un.elsreq64.bdl.addrHigh = putPaddrHigh(pbuflist->phys);
156 icmd->un.elsreq64.bdl.addrLow = putPaddrLow(pbuflist->phys);
157 icmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BDL;
James Smart2e0fef82007-06-17 19:56:36 -0500158 icmd->un.elsreq64.remoteID = did; /* DID */
dea31012005-04-17 16:05:31 -0500159 if (expectRsp) {
160 icmd->un.elsreq64.bdl.bdeSize = (2 * sizeof (struct ulp_bde64));
dea31012005-04-17 16:05:31 -0500161 icmd->ulpCommand = CMD_ELS_REQUEST64_CR;
James Smart2680eea2007-04-25 09:52:55 -0400162 icmd->ulpTimeout = phba->fc_ratov * 2;
dea31012005-04-17 16:05:31 -0500163 } else {
164 icmd->un.elsreq64.bdl.bdeSize = sizeof (struct ulp_bde64);
165 icmd->ulpCommand = CMD_XMIT_ELS_RSP64_CX;
166 }
167
168 icmd->ulpBdeCount = 1;
169 icmd->ulpLe = 1;
170 icmd->ulpClass = CLASS3;
171
172 bpl = (struct ulp_bde64 *) pbuflist->virt;
173 bpl->addrLow = le32_to_cpu(putPaddrLow(pcmd->phys));
174 bpl->addrHigh = le32_to_cpu(putPaddrHigh(pcmd->phys));
175 bpl->tus.f.bdeSize = cmdSize;
176 bpl->tus.f.bdeFlags = 0;
177 bpl->tus.w = le32_to_cpu(bpl->tus.w);
178
179 if (expectRsp) {
180 bpl++;
181 bpl->addrLow = le32_to_cpu(putPaddrLow(prsp->phys));
182 bpl->addrHigh = le32_to_cpu(putPaddrHigh(prsp->phys));
183 bpl->tus.f.bdeSize = FCELSSIZE;
184 bpl->tus.f.bdeFlags = BUFF_USE_RCV;
185 bpl->tus.w = le32_to_cpu(bpl->tus.w);
186 }
187
188 /* Save for completion so we can release these resources */
James Smart329f9bc2007-04-25 09:53:01 -0400189 elsiocb->context1 = lpfc_nlp_get(ndlp);
190 elsiocb->context2 = pcmd;
191 elsiocb->context3 = pbuflist;
dea31012005-04-17 16:05:31 -0500192 elsiocb->retry = retry;
James Smart2e0fef82007-06-17 19:56:36 -0500193 elsiocb->vport = vport;
dea31012005-04-17 16:05:31 -0500194 elsiocb->drvrTimeout = (phba->fc_ratov << 1) + LPFC_DRVR_TIMEOUT;
195
196 if (prsp) {
197 list_add(&prsp->list, &pcmd->list);
198 }
199
200 if (expectRsp) {
201 /* Xmit ELS command <elsCmd> to remote NPORT <did> */
202 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
203 "%d:0116 Xmit ELS command x%x to remote "
James Smart2e0fef82007-06-17 19:56:36 -0500204 "NPORT x%x I/O tag: x%x, port state: x%x\n",
205 phba->brd_no, elscmd, did,
206 elsiocb->iotag, vport->port_state);
dea31012005-04-17 16:05:31 -0500207 } else {
208 /* Xmit ELS response <elsCmd> to remote NPORT <did> */
209 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
210 "%d:0117 Xmit ELS response x%x to remote "
James Smart1dcb58e2007-04-25 09:51:30 -0400211 "NPORT x%x I/O tag: x%x, size: x%x\n",
dea31012005-04-17 16:05:31 -0500212 phba->brd_no, elscmd,
James Smart1dcb58e2007-04-25 09:51:30 -0400213 ndlp->nlp_DID, elsiocb->iotag, cmdSize);
dea31012005-04-17 16:05:31 -0500214 }
215
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500216 return elsiocb;
dea31012005-04-17 16:05:31 -0500217}
218
219
220static int
James Smart2e0fef82007-06-17 19:56:36 -0500221lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
222 struct serv_parm *sp, IOCB_t *irsp)
dea31012005-04-17 16:05:31 -0500223{
James Smart2e0fef82007-06-17 19:56:36 -0500224 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
225 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500226 LPFC_MBOXQ_t *mbox;
James Smart14691152006-12-02 13:34:28 -0500227 struct lpfc_dmabuf *mp;
dea31012005-04-17 16:05:31 -0500228 int rc;
229
James Smart2e0fef82007-06-17 19:56:36 -0500230 spin_lock_irq(shost->host_lock);
231 vport->fc_flag |= FC_FABRIC;
232 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500233
234 phba->fc_edtov = be32_to_cpu(sp->cmn.e_d_tov);
235 if (sp->cmn.edtovResolution) /* E_D_TOV ticks are in nanoseconds */
236 phba->fc_edtov = (phba->fc_edtov + 999999) / 1000000;
237
238 phba->fc_ratov = (be32_to_cpu(sp->cmn.w2.r_a_tov) + 999) / 1000;
239
240 if (phba->fc_topology == TOPOLOGY_LOOP) {
James Smart2e0fef82007-06-17 19:56:36 -0500241 spin_lock_irq(shost->host_lock);
242 vport->fc_flag |= FC_PUBLIC_LOOP;
243 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500244 } else {
245 /*
246 * If we are a N-port connected to a Fabric, fixup sparam's so
247 * logins to devices on remote loops work.
248 */
James Smart2e0fef82007-06-17 19:56:36 -0500249 vport->fc_sparam.cmn.altBbCredit = 1;
dea31012005-04-17 16:05:31 -0500250 }
251
James Smart2e0fef82007-06-17 19:56:36 -0500252 vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID;
dea31012005-04-17 16:05:31 -0500253 memcpy(&ndlp->nlp_portname, &sp->portName, sizeof(struct lpfc_name));
254 memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof (struct lpfc_name));
255 ndlp->nlp_class_sup = 0;
256 if (sp->cls1.classValid)
257 ndlp->nlp_class_sup |= FC_COS_CLASS1;
258 if (sp->cls2.classValid)
259 ndlp->nlp_class_sup |= FC_COS_CLASS2;
260 if (sp->cls3.classValid)
261 ndlp->nlp_class_sup |= FC_COS_CLASS3;
262 if (sp->cls4.classValid)
263 ndlp->nlp_class_sup |= FC_COS_CLASS4;
264 ndlp->nlp_maxframe = ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) |
265 sp->cmn.bbRcvSizeLsb;
266 memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
267
James Smart2e0fef82007-06-17 19:56:36 -0500268 ndlp->nlp_sid = irsp->un.ulpWord[4] & Mask_DID;
269
dea31012005-04-17 16:05:31 -0500270 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
271 if (!mbox)
272 goto fail;
273
James Smart2e0fef82007-06-17 19:56:36 -0500274 vport->port_state = LPFC_FABRIC_CFG_LINK;
dea31012005-04-17 16:05:31 -0500275 lpfc_config_link(phba, mbox);
276 mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
James Smarted957682007-06-17 19:56:37 -0500277 mbox->vport = vport;
dea31012005-04-17 16:05:31 -0500278
279 rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
280 if (rc == MBX_NOT_FINISHED)
281 goto fail_free_mbox;
282
283 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
284 if (!mbox)
285 goto fail;
James Smart2e0fef82007-06-17 19:56:36 -0500286 rc = lpfc_reg_login(phba, Fabric_DID, (uint8_t *) sp, mbox, 0);
287 if (rc)
dea31012005-04-17 16:05:31 -0500288 goto fail_free_mbox;
289
dea31012005-04-17 16:05:31 -0500290 mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login;
James Smart2e0fef82007-06-17 19:56:36 -0500291 mbox->vport = vport;
James Smart329f9bc2007-04-25 09:53:01 -0400292 mbox->context2 = lpfc_nlp_get(ndlp);
dea31012005-04-17 16:05:31 -0500293
294 rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
295 if (rc == MBX_NOT_FINISHED)
James Smart14691152006-12-02 13:34:28 -0500296 goto fail_issue_reg_login;
dea31012005-04-17 16:05:31 -0500297
298 return 0;
299
James Smart14691152006-12-02 13:34:28 -0500300 fail_issue_reg_login:
James Smart329f9bc2007-04-25 09:53:01 -0400301 lpfc_nlp_put(ndlp);
James Smart14691152006-12-02 13:34:28 -0500302 mp = (struct lpfc_dmabuf *) mbox->context1;
303 lpfc_mbuf_free(phba, mp->virt, mp->phys);
304 kfree(mp);
dea31012005-04-17 16:05:31 -0500305 fail_free_mbox:
306 mempool_free(mbox, phba->mbox_mem_pool);
307 fail:
308 return -ENXIO;
309}
310
311/*
312 * We FLOGIed into an NPort, initiate pt2pt protocol
313 */
314static int
James Smart2e0fef82007-06-17 19:56:36 -0500315lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
316 struct serv_parm *sp)
dea31012005-04-17 16:05:31 -0500317{
James Smart2e0fef82007-06-17 19:56:36 -0500318 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
319 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500320 LPFC_MBOXQ_t *mbox;
321 int rc;
322
James Smart2e0fef82007-06-17 19:56:36 -0500323 spin_lock_irq(shost->host_lock);
324 vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
325 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500326
327 phba->fc_edtov = FF_DEF_EDTOV;
328 phba->fc_ratov = FF_DEF_RATOV;
James Smart2e0fef82007-06-17 19:56:36 -0500329 rc = memcmp(&vport->fc_portname, &sp->portName,
dea31012005-04-17 16:05:31 -0500330 sizeof(struct lpfc_name));
331 if (rc >= 0) {
332 /* This side will initiate the PLOGI */
James Smart2e0fef82007-06-17 19:56:36 -0500333 spin_lock_irq(shost->host_lock);
334 vport->fc_flag |= FC_PT2PT_PLOGI;
335 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500336
337 /*
338 * N_Port ID cannot be 0, set our to LocalID the other
339 * side will be RemoteID.
340 */
341
342 /* not equal */
343 if (rc)
James Smart2e0fef82007-06-17 19:56:36 -0500344 vport->fc_myDID = PT2PT_LocalID;
dea31012005-04-17 16:05:31 -0500345
346 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
347 if (!mbox)
348 goto fail;
349
350 lpfc_config_link(phba, mbox);
351
352 mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
James Smarted957682007-06-17 19:56:37 -0500353 mbox->vport = vport;
dea31012005-04-17 16:05:31 -0500354 rc = lpfc_sli_issue_mbox(phba, mbox,
355 MBX_NOWAIT | MBX_STOP_IOCB);
356 if (rc == MBX_NOT_FINISHED) {
357 mempool_free(mbox, phba->mbox_mem_pool);
358 goto fail;
359 }
James Smart329f9bc2007-04-25 09:53:01 -0400360 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -0500361
James Smart2e0fef82007-06-17 19:56:36 -0500362 ndlp = lpfc_findnode_did(vport, PT2PT_RemoteID);
dea31012005-04-17 16:05:31 -0500363 if (!ndlp) {
364 /*
365 * Cannot find existing Fabric ndlp, so allocate a
366 * new one
367 */
368 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
369 if (!ndlp)
370 goto fail;
371
James Smart2e0fef82007-06-17 19:56:36 -0500372 lpfc_nlp_init(vport, ndlp, PT2PT_RemoteID);
dea31012005-04-17 16:05:31 -0500373 }
374
375 memcpy(&ndlp->nlp_portname, &sp->portName,
James Smart2e0fef82007-06-17 19:56:36 -0500376 sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -0500377 memcpy(&ndlp->nlp_nodename, &sp->nodeName,
James Smart2e0fef82007-06-17 19:56:36 -0500378 sizeof(struct lpfc_name));
379 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
380 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500381 ndlp->nlp_flag |= NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -0500382 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500383 } else {
384 /* This side will wait for the PLOGI */
James Smart329f9bc2007-04-25 09:53:01 -0400385 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -0500386 }
387
James Smart2e0fef82007-06-17 19:56:36 -0500388 spin_lock_irq(shost->host_lock);
389 vport->fc_flag |= FC_PT2PT;
390 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500391
392 /* Start discovery - this should just do CLEAR_LA */
James Smart2e0fef82007-06-17 19:56:36 -0500393 lpfc_disc_start(vport);
dea31012005-04-17 16:05:31 -0500394 return 0;
395 fail:
396 return -ENXIO;
397}
398
399static void
James Smart329f9bc2007-04-25 09:53:01 -0400400lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
401 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -0500402{
James Smart2e0fef82007-06-17 19:56:36 -0500403 struct lpfc_vport *vport = cmdiocb->vport;
404 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -0500405 IOCB_t *irsp = &rspiocb->iocb;
406 struct lpfc_nodelist *ndlp = cmdiocb->context1;
407 struct lpfc_dmabuf *pcmd = cmdiocb->context2, *prsp;
408 struct serv_parm *sp;
409 int rc;
410
411 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -0500412 if (lpfc_els_chk_latt(vport)) {
James Smart329f9bc2007-04-25 09:53:01 -0400413 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -0500414 goto out;
415 }
416
417 if (irsp->ulpStatus) {
418 /* Check for retry */
James Smart2e0fef82007-06-17 19:56:36 -0500419 if (lpfc_els_retry(phba, cmdiocb, rspiocb))
dea31012005-04-17 16:05:31 -0500420 goto out;
James Smart2e0fef82007-06-17 19:56:36 -0500421
dea31012005-04-17 16:05:31 -0500422 /* FLOGI failed, so there is no fabric */
James Smart2e0fef82007-06-17 19:56:36 -0500423 spin_lock_irq(shost->host_lock);
424 vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
425 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500426
James Smart329f9bc2007-04-25 09:53:01 -0400427 /* If private loop, then allow max outstanding els to be
dea31012005-04-17 16:05:31 -0500428 * LPFC_MAX_DISC_THREADS (32). Scanning in the case of no
429 * alpa map would take too long otherwise.
430 */
431 if (phba->alpa_map[0] == 0) {
James Smart329f9bc2007-04-25 09:53:01 -0400432 phba->cfg_discovery_threads = LPFC_MAX_DISC_THREADS;
dea31012005-04-17 16:05:31 -0500433 }
434
435 /* FLOGI failure */
436 lpfc_printf_log(phba,
437 KERN_INFO,
438 LOG_ELS,
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500439 "%d:0100 FLOGI failure Data: x%x x%x x%x\n",
dea31012005-04-17 16:05:31 -0500440 phba->brd_no,
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500441 irsp->ulpStatus, irsp->un.ulpWord[4],
442 irsp->ulpTimeout);
dea31012005-04-17 16:05:31 -0500443 goto flogifail;
444 }
445
446 /*
447 * The FLogI succeeded. Sync the data for the CPU before
448 * accessing it.
449 */
450 prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list);
451
452 sp = prsp->virt + sizeof(uint32_t);
453
454 /* FLOGI completes successfully */
455 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
456 "%d:0101 FLOGI completes sucessfully "
457 "Data: x%x x%x x%x x%x\n",
458 phba->brd_no,
459 irsp->un.ulpWord[4], sp->cmn.e_d_tov,
460 sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution);
461
James Smart2e0fef82007-06-17 19:56:36 -0500462 if (vport->port_state == LPFC_FLOGI) {
dea31012005-04-17 16:05:31 -0500463 /*
464 * If Common Service Parameters indicate Nport
465 * we are point to point, if Fport we are Fabric.
466 */
467 if (sp->cmn.fPort)
James Smart2e0fef82007-06-17 19:56:36 -0500468 rc = lpfc_cmpl_els_flogi_fabric(vport, ndlp, sp, irsp);
dea31012005-04-17 16:05:31 -0500469 else
James Smart2e0fef82007-06-17 19:56:36 -0500470 rc = lpfc_cmpl_els_flogi_nport(vport, ndlp, sp);
dea31012005-04-17 16:05:31 -0500471
472 if (!rc)
473 goto out;
474 }
475
476flogifail:
James Smart329f9bc2007-04-25 09:53:01 -0400477 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -0500478
479 if (irsp->ulpStatus != IOSTAT_LOCAL_REJECT ||
480 (irsp->un.ulpWord[4] != IOERR_SLI_ABORTED &&
481 irsp->un.ulpWord[4] != IOERR_SLI_DOWN)) {
482 /* FLOGI failed, so just use loop map to make discovery list */
James Smart2e0fef82007-06-17 19:56:36 -0500483 lpfc_disc_list_loopmap(vport);
dea31012005-04-17 16:05:31 -0500484
485 /* Start discovery */
James Smart2e0fef82007-06-17 19:56:36 -0500486 lpfc_disc_start(vport);
dea31012005-04-17 16:05:31 -0500487 }
488
489out:
490 lpfc_els_free_iocb(phba, cmdiocb);
491}
492
493static int
James Smart2e0fef82007-06-17 19:56:36 -0500494lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
dea31012005-04-17 16:05:31 -0500495 uint8_t retry)
496{
James Smart2e0fef82007-06-17 19:56:36 -0500497 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500498 struct serv_parm *sp;
499 IOCB_t *icmd;
500 struct lpfc_iocbq *elsiocb;
501 struct lpfc_sli_ring *pring;
502 uint8_t *pcmd;
503 uint16_t cmdsize;
504 uint32_t tmo;
505 int rc;
506
507 pring = &phba->sli.ring[LPFC_ELS_RING];
508
509 cmdsize = (sizeof (uint32_t) + sizeof (struct serv_parm));
James Smart2e0fef82007-06-17 19:56:36 -0500510 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
511 ndlp->nlp_DID, ELS_CMD_FLOGI);
James Smart488d1462006-03-07 15:02:37 -0500512 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500513 return 1;
dea31012005-04-17 16:05:31 -0500514
515 icmd = &elsiocb->iocb;
516 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
517
518 /* For FLOGI request, remainder of payload is service parameters */
519 *((uint32_t *) (pcmd)) = ELS_CMD_FLOGI;
520 pcmd += sizeof (uint32_t);
James Smart2e0fef82007-06-17 19:56:36 -0500521 memcpy(pcmd, &vport->fc_sparam, sizeof (struct serv_parm));
dea31012005-04-17 16:05:31 -0500522 sp = (struct serv_parm *) pcmd;
523
524 /* Setup CSPs accordingly for Fabric */
525 sp->cmn.e_d_tov = 0;
526 sp->cmn.w2.r_a_tov = 0;
527 sp->cls1.classValid = 0;
528 sp->cls2.seqDelivery = 1;
529 sp->cls3.seqDelivery = 1;
530 if (sp->cmn.fcphLow < FC_PH3)
531 sp->cmn.fcphLow = FC_PH3;
532 if (sp->cmn.fcphHigh < FC_PH3)
533 sp->cmn.fcphHigh = FC_PH3;
534
535 tmo = phba->fc_ratov;
536 phba->fc_ratov = LPFC_DISC_FLOGI_TMO;
James Smart2e0fef82007-06-17 19:56:36 -0500537 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -0500538 phba->fc_ratov = tmo;
539
540 phba->fc_stat.elsXmitFLOGI++;
541 elsiocb->iocb_cmpl = lpfc_cmpl_els_flogi;
dea31012005-04-17 16:05:31 -0500542 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
dea31012005-04-17 16:05:31 -0500543 if (rc == IOCB_ERROR) {
544 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500545 return 1;
dea31012005-04-17 16:05:31 -0500546 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500547 return 0;
dea31012005-04-17 16:05:31 -0500548}
549
550int
James Smart2e0fef82007-06-17 19:56:36 -0500551lpfc_els_abort_flogi(struct lpfc_hba *phba)
dea31012005-04-17 16:05:31 -0500552{
553 struct lpfc_sli_ring *pring;
554 struct lpfc_iocbq *iocb, *next_iocb;
555 struct lpfc_nodelist *ndlp;
556 IOCB_t *icmd;
557
558 /* Abort outstanding I/O on NPort <nlp_DID> */
559 lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
560 "%d:0201 Abort outstanding I/O on NPort x%x\n",
561 phba->brd_no, Fabric_DID);
562
563 pring = &phba->sli.ring[LPFC_ELS_RING];
564
565 /*
566 * Check the txcmplq for an iocb that matches the nport the driver is
567 * searching for.
568 */
James Smart2e0fef82007-06-17 19:56:36 -0500569 spin_lock_irq(&phba->hbalock);
dea31012005-04-17 16:05:31 -0500570 list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
571 icmd = &iocb->iocb;
James Smart2e0fef82007-06-17 19:56:36 -0500572 if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR &&
573 icmd->un.elsreq64.bdl.ulpIoTag32) {
dea31012005-04-17 16:05:31 -0500574 ndlp = (struct lpfc_nodelist *)(iocb->context1);
James Smart07951072007-04-25 09:51:38 -0400575 if (ndlp && (ndlp->nlp_DID == Fabric_DID))
576 lpfc_sli_issue_abort_iotag(phba, pring, iocb);
dea31012005-04-17 16:05:31 -0500577 }
578 }
James Smart2e0fef82007-06-17 19:56:36 -0500579 spin_unlock_irq(&phba->hbalock);
dea31012005-04-17 16:05:31 -0500580
581 return 0;
582}
583
584int
James Smart2e0fef82007-06-17 19:56:36 -0500585lpfc_initial_flogi(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -0500586{
James Smart2e0fef82007-06-17 19:56:36 -0500587 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500588 struct lpfc_nodelist *ndlp;
589
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500590 /* First look for the Fabric ndlp */
James Smart2e0fef82007-06-17 19:56:36 -0500591 ndlp = lpfc_findnode_did(vport, Fabric_DID);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500592 if (!ndlp) {
dea31012005-04-17 16:05:31 -0500593 /* Cannot find existing Fabric ndlp, so allocate a new one */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500594 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
595 if (!ndlp)
596 return 0;
James Smart2e0fef82007-06-17 19:56:36 -0500597 lpfc_nlp_init(vport, ndlp, Fabric_DID);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500598 } else {
James Smart2e0fef82007-06-17 19:56:36 -0500599 lpfc_dequeue_node(vport, ndlp);
dea31012005-04-17 16:05:31 -0500600 }
James Smart2e0fef82007-06-17 19:56:36 -0500601 if (lpfc_issue_els_flogi(vport, ndlp, 0)) {
James Smart329f9bc2007-04-25 09:53:01 -0400602 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -0500603 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500604 return 1;
dea31012005-04-17 16:05:31 -0500605}
606
607static void
James Smart2e0fef82007-06-17 19:56:36 -0500608lpfc_more_plogi(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -0500609{
610 int sentplogi;
James Smart2e0fef82007-06-17 19:56:36 -0500611 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500612
James Smart2e0fef82007-06-17 19:56:36 -0500613 if (vport->num_disc_nodes)
614 vport->num_disc_nodes--;
dea31012005-04-17 16:05:31 -0500615
616 /* Continue discovery with <num_disc_nodes> PLOGIs to go */
617 lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
618 "%d:0232 Continue discovery with %d PLOGIs to go "
619 "Data: x%x x%x x%x\n",
James Smart2e0fef82007-06-17 19:56:36 -0500620 phba->brd_no, vport->num_disc_nodes,
621 vport->fc_plogi_cnt, vport->fc_flag, vport->port_state);
dea31012005-04-17 16:05:31 -0500622
623 /* Check to see if there are more PLOGIs to be sent */
James Smart2e0fef82007-06-17 19:56:36 -0500624 if (vport->fc_flag & FC_NLP_MORE)
625 /* go thru NPR nodes and issue any remaining ELS PLOGIs */
626 sentplogi = lpfc_els_disc_plogi(vport);
627
dea31012005-04-17 16:05:31 -0500628 return;
629}
630
James Smart488d1462006-03-07 15:02:37 -0500631static struct lpfc_nodelist *
James Smart685f0bf2007-04-25 09:53:08 -0400632lpfc_plogi_confirm_nport(struct lpfc_hba *phba, struct lpfc_dmabuf *prsp,
James Smart488d1462006-03-07 15:02:37 -0500633 struct lpfc_nodelist *ndlp)
634{
James Smart2e0fef82007-06-17 19:56:36 -0500635 struct lpfc_vport *vport = ndlp->vport;
James Smart488d1462006-03-07 15:02:37 -0500636 struct lpfc_nodelist *new_ndlp;
James Smart488d1462006-03-07 15:02:37 -0500637 uint32_t *lp;
638 struct serv_parm *sp;
639 uint8_t name[sizeof (struct lpfc_name)];
640 uint32_t rc;
641
James Smart2fb9bd82006-12-02 13:33:57 -0500642 /* Fabric nodes can have the same WWPN so we don't bother searching
643 * by WWPN. Just return the ndlp that was given to us.
644 */
645 if (ndlp->nlp_type & NLP_FABRIC)
646 return ndlp;
647
James Smart488d1462006-03-07 15:02:37 -0500648 lp = (uint32_t *) prsp->virt;
649 sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
James Smart685f0bf2007-04-25 09:53:08 -0400650 memset(name, 0, sizeof(struct lpfc_name));
James Smart488d1462006-03-07 15:02:37 -0500651
James Smart685f0bf2007-04-25 09:53:08 -0400652 /* Now we find out if the NPort we are logging into, matches the WWPN
James Smart488d1462006-03-07 15:02:37 -0500653 * we have for that ndlp. If not, we have some work to do.
654 */
James Smart2e0fef82007-06-17 19:56:36 -0500655 new_ndlp = lpfc_findnode_wwpn(vport, &sp->portName);
James Smart488d1462006-03-07 15:02:37 -0500656
James Smart92795652006-07-06 15:50:02 -0400657 if (new_ndlp == ndlp)
James Smart488d1462006-03-07 15:02:37 -0500658 return ndlp;
James Smart488d1462006-03-07 15:02:37 -0500659
660 if (!new_ndlp) {
James Smart2e0fef82007-06-17 19:56:36 -0500661 rc = memcmp(&ndlp->nlp_portname, name,
662 sizeof(struct lpfc_name));
James Smart92795652006-07-06 15:50:02 -0400663 if (!rc)
664 return ndlp;
James Smart488d1462006-03-07 15:02:37 -0500665 new_ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC);
666 if (!new_ndlp)
667 return ndlp;
668
James Smart2e0fef82007-06-17 19:56:36 -0500669 lpfc_nlp_init(vport, new_ndlp, ndlp->nlp_DID);
James Smart488d1462006-03-07 15:02:37 -0500670 }
671
James Smart2e0fef82007-06-17 19:56:36 -0500672 lpfc_unreg_rpi(vport, new_ndlp);
James Smart488d1462006-03-07 15:02:37 -0500673 new_ndlp->nlp_DID = ndlp->nlp_DID;
James Smart92795652006-07-06 15:50:02 -0400674 new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
James Smart2e0fef82007-06-17 19:56:36 -0500675 lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state);
James Smart488d1462006-03-07 15:02:37 -0500676
James Smart2e0fef82007-06-17 19:56:36 -0500677 /* Move this back to NPR state */
James Smartde0c5b32007-04-25 09:52:27 -0400678 if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0)
James Smart2e0fef82007-06-17 19:56:36 -0500679 lpfc_drop_node(vport, ndlp);
James Smart92795652006-07-06 15:50:02 -0400680 else {
James Smart2e0fef82007-06-17 19:56:36 -0500681 lpfc_unreg_rpi(vport, ndlp);
James Smart92795652006-07-06 15:50:02 -0400682 ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
James Smart2e0fef82007-06-17 19:56:36 -0500683 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
James Smart92795652006-07-06 15:50:02 -0400684 }
James Smart488d1462006-03-07 15:02:37 -0500685 return new_ndlp;
686}
687
dea31012005-04-17 16:05:31 -0500688static void
James Smart2e0fef82007-06-17 19:56:36 -0500689lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
690 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -0500691{
James Smart2e0fef82007-06-17 19:56:36 -0500692 struct lpfc_vport *vport = cmdiocb->vport;
693 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -0500694 IOCB_t *irsp;
dea31012005-04-17 16:05:31 -0500695 struct lpfc_nodelist *ndlp;
James Smart92795652006-07-06 15:50:02 -0400696 struct lpfc_dmabuf *prsp;
dea31012005-04-17 16:05:31 -0500697 int disc, rc, did, type;
698
dea31012005-04-17 16:05:31 -0500699 /* we pass cmdiocb to state machine which needs rspiocb as well */
700 cmdiocb->context_un.rsp_iocb = rspiocb;
701
702 irsp = &rspiocb->iocb;
James Smart2e0fef82007-06-17 19:56:36 -0500703 ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID);
James Smarted957682007-06-17 19:56:37 -0500704
705 if (!ndlp) {
James Smart488d1462006-03-07 15:02:37 -0500706 goto out;
James Smarted957682007-06-17 19:56:37 -0500707 }
dea31012005-04-17 16:05:31 -0500708
709 /* Since ndlp can be freed in the disc state machine, note if this node
710 * is being used during discovery.
711 */
James Smart2e0fef82007-06-17 19:56:36 -0500712 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500713 disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
James Smart488d1462006-03-07 15:02:37 -0500714 ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -0500715 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500716 rc = 0;
717
718 /* PLOGI completes to NPort <nlp_DID> */
719 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
720 "%d:0102 PLOGI completes to NPort x%x "
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500721 "Data: x%x x%x x%x x%x x%x\n",
dea31012005-04-17 16:05:31 -0500722 phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus,
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500723 irsp->un.ulpWord[4], irsp->ulpTimeout, disc,
James Smart2e0fef82007-06-17 19:56:36 -0500724 vport->num_disc_nodes);
dea31012005-04-17 16:05:31 -0500725
726 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -0500727 if (lpfc_els_chk_latt(vport)) {
728 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500729 ndlp->nlp_flag |= NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -0500730 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500731 goto out;
732 }
733
734 /* ndlp could be freed in DSM, save these values now */
735 type = ndlp->nlp_type;
736 did = ndlp->nlp_DID;
737
738 if (irsp->ulpStatus) {
739 /* Check for retry */
740 if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
741 /* ELS command is being retried */
742 if (disc) {
James Smart2e0fef82007-06-17 19:56:36 -0500743 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500744 ndlp->nlp_flag |= NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -0500745 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500746 }
747 goto out;
748 }
749
750 /* PLOGI failed */
751 /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
752 if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
753 ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
James.Smart@Emulex.Com6281bfe2005-11-28 11:41:33 -0500754 (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
dea31012005-04-17 16:05:31 -0500755 (irsp->un.ulpWord[4] == IOERR_SLI_DOWN))) {
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500756 rc = NLP_STE_FREED_NODE;
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -0500757 } else {
James Smart2e0fef82007-06-17 19:56:36 -0500758 rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb,
dea31012005-04-17 16:05:31 -0500759 NLP_EVT_CMPL_PLOGI);
760 }
761 } else {
762 /* Good status, call state machine */
James Smart92795652006-07-06 15:50:02 -0400763 prsp = list_entry(((struct lpfc_dmabuf *)
764 cmdiocb->context2)->list.next,
765 struct lpfc_dmabuf, list);
766 ndlp = lpfc_plogi_confirm_nport(phba, prsp, ndlp);
James Smart2e0fef82007-06-17 19:56:36 -0500767 rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb,
dea31012005-04-17 16:05:31 -0500768 NLP_EVT_CMPL_PLOGI);
769 }
770
James Smart2e0fef82007-06-17 19:56:36 -0500771 if (disc && vport->num_disc_nodes) {
dea31012005-04-17 16:05:31 -0500772 /* Check to see if there are more PLOGIs to be sent */
James Smart2e0fef82007-06-17 19:56:36 -0500773 lpfc_more_plogi(vport);
dea31012005-04-17 16:05:31 -0500774
James Smart2e0fef82007-06-17 19:56:36 -0500775 if (vport->num_disc_nodes == 0) {
776 spin_lock_irq(shost->host_lock);
777 vport->fc_flag &= ~FC_NDISC_ACTIVE;
778 spin_unlock_irq(shost->host_lock);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500779
James Smart2e0fef82007-06-17 19:56:36 -0500780 lpfc_can_disctmo(vport);
781 if (vport->fc_flag & FC_RSCN_MODE) {
James Smart10d4e952006-04-15 11:53:15 -0400782 /*
783 * Check to see if more RSCNs came in while
784 * we were processing this one.
785 */
James Smart2e0fef82007-06-17 19:56:36 -0500786 if ((vport->fc_rscn_id_cnt == 0) &&
787 (!(vport->fc_flag & FC_RSCN_DISCOVERY))) {
788 spin_lock_irq(shost->host_lock);
789 vport->fc_flag &= ~FC_RSCN_MODE;
790 spin_unlock_irq(shost->host_lock);
James Smart10d4e952006-04-15 11:53:15 -0400791 } else {
James Smart2e0fef82007-06-17 19:56:36 -0500792 lpfc_els_handle_rscn(vport);
James Smart10d4e952006-04-15 11:53:15 -0400793 }
dea31012005-04-17 16:05:31 -0500794 }
795 }
796 }
797
798out:
799 lpfc_els_free_iocb(phba, cmdiocb);
800 return;
801}
802
803int
James Smart2e0fef82007-06-17 19:56:36 -0500804lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
dea31012005-04-17 16:05:31 -0500805{
James Smart2e0fef82007-06-17 19:56:36 -0500806 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500807 struct serv_parm *sp;
808 IOCB_t *icmd;
809 struct lpfc_iocbq *elsiocb;
810 struct lpfc_sli_ring *pring;
811 struct lpfc_sli *psli;
812 uint8_t *pcmd;
813 uint16_t cmdsize;
814
815 psli = &phba->sli;
816 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
817
818 cmdsize = (sizeof (uint32_t) + sizeof (struct serv_parm));
James Smart2e0fef82007-06-17 19:56:36 -0500819 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, NULL, did,
820 ELS_CMD_PLOGI);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500821 if (!elsiocb)
822 return 1;
dea31012005-04-17 16:05:31 -0500823
824 icmd = &elsiocb->iocb;
825 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
826
827 /* For PLOGI request, remainder of payload is service parameters */
828 *((uint32_t *) (pcmd)) = ELS_CMD_PLOGI;
829 pcmd += sizeof (uint32_t);
James Smart2e0fef82007-06-17 19:56:36 -0500830 memcpy(pcmd, &vport->fc_sparam, sizeof (struct serv_parm));
dea31012005-04-17 16:05:31 -0500831 sp = (struct serv_parm *) pcmd;
832
833 if (sp->cmn.fcphLow < FC_PH_4_3)
834 sp->cmn.fcphLow = FC_PH_4_3;
835
836 if (sp->cmn.fcphHigh < FC_PH3)
837 sp->cmn.fcphHigh = FC_PH3;
838
839 phba->fc_stat.elsXmitPLOGI++;
840 elsiocb->iocb_cmpl = lpfc_cmpl_els_plogi;
dea31012005-04-17 16:05:31 -0500841 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
dea31012005-04-17 16:05:31 -0500842 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500843 return 1;
dea31012005-04-17 16:05:31 -0500844 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500845 return 0;
dea31012005-04-17 16:05:31 -0500846}
847
848static void
James Smart2e0fef82007-06-17 19:56:36 -0500849lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
850 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -0500851{
James Smart2e0fef82007-06-17 19:56:36 -0500852 struct lpfc_vport *vport = cmdiocb->vport;
853 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -0500854 IOCB_t *irsp;
855 struct lpfc_sli *psli;
856 struct lpfc_nodelist *ndlp;
857
858 psli = &phba->sli;
859 /* we pass cmdiocb to state machine which needs rspiocb as well */
860 cmdiocb->context_un.rsp_iocb = rspiocb;
861
862 irsp = &(rspiocb->iocb);
863 ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
James Smart2e0fef82007-06-17 19:56:36 -0500864 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500865 ndlp->nlp_flag &= ~NLP_PRLI_SND;
James Smart2e0fef82007-06-17 19:56:36 -0500866 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500867
868 /* PRLI completes to NPort <nlp_DID> */
869 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
870 "%d:0103 PRLI completes to NPort x%x "
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500871 "Data: x%x x%x x%x x%x\n",
dea31012005-04-17 16:05:31 -0500872 phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus,
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500873 irsp->un.ulpWord[4], irsp->ulpTimeout,
James Smart2e0fef82007-06-17 19:56:36 -0500874 vport->num_disc_nodes);
dea31012005-04-17 16:05:31 -0500875
James Smart2e0fef82007-06-17 19:56:36 -0500876 vport->fc_prli_sent--;
dea31012005-04-17 16:05:31 -0500877 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -0500878 if (lpfc_els_chk_latt(vport))
dea31012005-04-17 16:05:31 -0500879 goto out;
880
881 if (irsp->ulpStatus) {
882 /* Check for retry */
883 if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
884 /* ELS command is being retried */
885 goto out;
886 }
887 /* PRLI failed */
888 /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
889 if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
890 ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
James.Smart@Emulex.Com6281bfe2005-11-28 11:41:33 -0500891 (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
dea31012005-04-17 16:05:31 -0500892 (irsp->un.ulpWord[4] == IOERR_SLI_DOWN))) {
893 goto out;
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -0500894 } else {
James Smart2e0fef82007-06-17 19:56:36 -0500895 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
dea31012005-04-17 16:05:31 -0500896 NLP_EVT_CMPL_PRLI);
897 }
898 } else {
899 /* Good status, call state machine */
James Smart2e0fef82007-06-17 19:56:36 -0500900 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
901 NLP_EVT_CMPL_PRLI);
dea31012005-04-17 16:05:31 -0500902 }
903
904out:
905 lpfc_els_free_iocb(phba, cmdiocb);
906 return;
907}
908
909int
James Smart2e0fef82007-06-17 19:56:36 -0500910lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
dea31012005-04-17 16:05:31 -0500911 uint8_t retry)
912{
James Smart2e0fef82007-06-17 19:56:36 -0500913 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
914 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500915 PRLI *npr;
916 IOCB_t *icmd;
917 struct lpfc_iocbq *elsiocb;
918 struct lpfc_sli_ring *pring;
919 struct lpfc_sli *psli;
920 uint8_t *pcmd;
921 uint16_t cmdsize;
922
923 psli = &phba->sli;
924 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
925
926 cmdsize = (sizeof (uint32_t) + sizeof (PRLI));
James Smart2e0fef82007-06-17 19:56:36 -0500927 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
928 ndlp->nlp_DID, ELS_CMD_PRLI);
James Smart488d1462006-03-07 15:02:37 -0500929 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500930 return 1;
dea31012005-04-17 16:05:31 -0500931
932 icmd = &elsiocb->iocb;
933 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
934
935 /* For PRLI request, remainder of payload is service parameters */
936 memset(pcmd, 0, (sizeof (PRLI) + sizeof (uint32_t)));
937 *((uint32_t *) (pcmd)) = ELS_CMD_PRLI;
938 pcmd += sizeof (uint32_t);
939
940 /* For PRLI, remainder of payload is PRLI parameter page */
941 npr = (PRLI *) pcmd;
942 /*
943 * If our firmware version is 3.20 or later,
944 * set the following bits for FC-TAPE support.
945 */
946 if (phba->vpd.rev.feaLevelHigh >= 0x02) {
947 npr->ConfmComplAllowed = 1;
948 npr->Retry = 1;
949 npr->TaskRetryIdReq = 1;
950 }
951 npr->estabImagePair = 1;
952 npr->readXferRdyDis = 1;
953
954 /* For FCP support */
955 npr->prliType = PRLI_FCP_TYPE;
956 npr->initiatorFunc = 1;
957
958 phba->fc_stat.elsXmitPRLI++;
959 elsiocb->iocb_cmpl = lpfc_cmpl_els_prli;
James Smart2e0fef82007-06-17 19:56:36 -0500960 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500961 ndlp->nlp_flag |= NLP_PRLI_SND;
James Smart2e0fef82007-06-17 19:56:36 -0500962 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500963 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
James Smart2e0fef82007-06-17 19:56:36 -0500964 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500965 ndlp->nlp_flag &= ~NLP_PRLI_SND;
James Smart2e0fef82007-06-17 19:56:36 -0500966 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500967 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500968 return 1;
dea31012005-04-17 16:05:31 -0500969 }
James Smart2e0fef82007-06-17 19:56:36 -0500970 vport->fc_prli_sent++;
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500971 return 0;
dea31012005-04-17 16:05:31 -0500972}
973
974static void
James Smart2e0fef82007-06-17 19:56:36 -0500975lpfc_more_adisc(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -0500976{
977 int sentadisc;
James Smart2e0fef82007-06-17 19:56:36 -0500978 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500979
James Smart2e0fef82007-06-17 19:56:36 -0500980 if (vport->num_disc_nodes)
981 vport->num_disc_nodes--;
dea31012005-04-17 16:05:31 -0500982
983 /* Continue discovery with <num_disc_nodes> ADISCs to go */
984 lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
985 "%d:0210 Continue discovery with %d ADISCs to go "
986 "Data: x%x x%x x%x\n",
James Smart2e0fef82007-06-17 19:56:36 -0500987 phba->brd_no, vport->num_disc_nodes,
988 vport->fc_adisc_cnt, vport->fc_flag, vport->port_state);
dea31012005-04-17 16:05:31 -0500989
990 /* Check to see if there are more ADISCs to be sent */
James Smart2e0fef82007-06-17 19:56:36 -0500991 if (vport->fc_flag & FC_NLP_MORE) {
992 lpfc_set_disctmo(vport);
993 /* go thru NPR nodes and issue any remaining ELS ADISCs */
994 sentadisc = lpfc_els_disc_adisc(vport);
dea31012005-04-17 16:05:31 -0500995 }
996 return;
997}
998
999static void
James Smart2e0fef82007-06-17 19:56:36 -05001000lpfc_rscn_disc(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05001001{
James Smart2e0fef82007-06-17 19:56:36 -05001002 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1003
dea31012005-04-17 16:05:31 -05001004 /* RSCN discovery */
James Smart2e0fef82007-06-17 19:56:36 -05001005 /* go thru NPR nodes and issue ELS PLOGIs */
1006 if (vport->fc_npr_cnt)
1007 if (lpfc_els_disc_plogi(vport))
dea31012005-04-17 16:05:31 -05001008 return;
James Smart2e0fef82007-06-17 19:56:36 -05001009
1010 if (vport->fc_flag & FC_RSCN_MODE) {
dea31012005-04-17 16:05:31 -05001011 /* Check to see if more RSCNs came in while we were
1012 * processing this one.
1013 */
James Smart2e0fef82007-06-17 19:56:36 -05001014 if ((vport->fc_rscn_id_cnt == 0) &&
1015 (!(vport->fc_flag & FC_RSCN_DISCOVERY))) {
1016 spin_lock_irq(shost->host_lock);
1017 vport->fc_flag &= ~FC_RSCN_MODE;
1018 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001019 } else {
James Smart2e0fef82007-06-17 19:56:36 -05001020 lpfc_els_handle_rscn(vport);
dea31012005-04-17 16:05:31 -05001021 }
1022 }
1023}
1024
1025static void
James Smart2e0fef82007-06-17 19:56:36 -05001026lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1027 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05001028{
James Smart2e0fef82007-06-17 19:56:36 -05001029 struct lpfc_vport *vport = cmdiocb->vport;
1030 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05001031 IOCB_t *irsp;
dea31012005-04-17 16:05:31 -05001032 struct lpfc_nodelist *ndlp;
James Smart2e0fef82007-06-17 19:56:36 -05001033 int disc;
dea31012005-04-17 16:05:31 -05001034
1035 /* we pass cmdiocb to state machine which needs rspiocb as well */
1036 cmdiocb->context_un.rsp_iocb = rspiocb;
1037
1038 irsp = &(rspiocb->iocb);
1039 ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
dea31012005-04-17 16:05:31 -05001040
1041 /* Since ndlp can be freed in the disc state machine, note if this node
1042 * is being used during discovery.
1043 */
James Smart2e0fef82007-06-17 19:56:36 -05001044 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001045 disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001046 ndlp->nlp_flag &= ~(NLP_ADISC_SND | NLP_NPR_2B_DISC);
James Smart2e0fef82007-06-17 19:56:36 -05001047 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001048
1049 /* ADISC completes to NPort <nlp_DID> */
1050 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
1051 "%d:0104 ADISC completes to NPort x%x "
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001052 "Data: x%x x%x x%x x%x x%x\n",
dea31012005-04-17 16:05:31 -05001053 phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus,
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001054 irsp->un.ulpWord[4], irsp->ulpTimeout, disc,
James Smart2e0fef82007-06-17 19:56:36 -05001055 vport->num_disc_nodes);
dea31012005-04-17 16:05:31 -05001056
1057 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -05001058 if (lpfc_els_chk_latt(vport)) {
1059 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001060 ndlp->nlp_flag |= NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -05001061 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001062 goto out;
1063 }
1064
1065 if (irsp->ulpStatus) {
1066 /* Check for retry */
1067 if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
1068 /* ELS command is being retried */
1069 if (disc) {
James Smart2e0fef82007-06-17 19:56:36 -05001070 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001071 ndlp->nlp_flag |= NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -05001072 spin_unlock_irq(shost->host_lock);
1073 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -05001074 }
1075 goto out;
1076 }
1077 /* ADISC failed */
1078 /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001079 if ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
1080 ((irsp->un.ulpWord[4] != IOERR_SLI_ABORTED) &&
1081 (irsp->un.ulpWord[4] != IOERR_LINK_DOWN) &&
1082 (irsp->un.ulpWord[4] != IOERR_SLI_DOWN))) {
James Smart2e0fef82007-06-17 19:56:36 -05001083 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
dea31012005-04-17 16:05:31 -05001084 NLP_EVT_CMPL_ADISC);
1085 }
1086 } else {
1087 /* Good status, call state machine */
James Smart2e0fef82007-06-17 19:56:36 -05001088 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
dea31012005-04-17 16:05:31 -05001089 NLP_EVT_CMPL_ADISC);
1090 }
1091
James Smart2e0fef82007-06-17 19:56:36 -05001092 if (disc && vport->num_disc_nodes) {
dea31012005-04-17 16:05:31 -05001093 /* Check to see if there are more ADISCs to be sent */
James Smart2e0fef82007-06-17 19:56:36 -05001094 lpfc_more_adisc(vport);
dea31012005-04-17 16:05:31 -05001095
1096 /* Check to see if we are done with ADISC authentication */
James Smart2e0fef82007-06-17 19:56:36 -05001097 if (vport->num_disc_nodes == 0) {
1098 lpfc_can_disctmo(vport);
dea31012005-04-17 16:05:31 -05001099 /* If we get here, there is nothing left to wait for */
James Smart2e0fef82007-06-17 19:56:36 -05001100 if (vport->port_state < LPFC_VPORT_READY &&
1101 phba->link_state != LPFC_CLEAR_LA) {
James Smarted957682007-06-17 19:56:37 -05001102 if (vport->port_type == LPFC_PHYSICAL_PORT)
James Smart2e0fef82007-06-17 19:56:36 -05001103 lpfc_issue_clear_la(phba, vport);
dea31012005-04-17 16:05:31 -05001104 } else {
James Smart2e0fef82007-06-17 19:56:36 -05001105 lpfc_rscn_disc(vport);
dea31012005-04-17 16:05:31 -05001106 }
1107 }
1108 }
dea31012005-04-17 16:05:31 -05001109out:
1110 lpfc_els_free_iocb(phba, cmdiocb);
1111 return;
1112}
1113
1114int
James Smart2e0fef82007-06-17 19:56:36 -05001115lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
dea31012005-04-17 16:05:31 -05001116 uint8_t retry)
1117{
James Smart2e0fef82007-06-17 19:56:36 -05001118 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1119 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001120 ADISC *ap;
1121 IOCB_t *icmd;
1122 struct lpfc_iocbq *elsiocb;
James Smart2e0fef82007-06-17 19:56:36 -05001123 struct lpfc_sli *psli = &phba->sli;
1124 struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
dea31012005-04-17 16:05:31 -05001125 uint8_t *pcmd;
1126 uint16_t cmdsize;
1127
dea31012005-04-17 16:05:31 -05001128 cmdsize = (sizeof (uint32_t) + sizeof (ADISC));
James Smart2e0fef82007-06-17 19:56:36 -05001129 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
1130 ndlp->nlp_DID, ELS_CMD_ADISC);
James Smart488d1462006-03-07 15:02:37 -05001131 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001132 return 1;
dea31012005-04-17 16:05:31 -05001133
1134 icmd = &elsiocb->iocb;
1135 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1136
1137 /* For ADISC request, remainder of payload is service parameters */
1138 *((uint32_t *) (pcmd)) = ELS_CMD_ADISC;
1139 pcmd += sizeof (uint32_t);
1140
1141 /* Fill in ADISC payload */
1142 ap = (ADISC *) pcmd;
1143 ap->hardAL_PA = phba->fc_pref_ALPA;
James Smart2e0fef82007-06-17 19:56:36 -05001144 memcpy(&ap->portName, &vport->fc_portname, sizeof (struct lpfc_name));
1145 memcpy(&ap->nodeName, &vport->fc_nodename, sizeof (struct lpfc_name));
1146 ap->DID = be32_to_cpu(vport->fc_myDID);
dea31012005-04-17 16:05:31 -05001147
1148 phba->fc_stat.elsXmitADISC++;
1149 elsiocb->iocb_cmpl = lpfc_cmpl_els_adisc;
James Smart2e0fef82007-06-17 19:56:36 -05001150 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001151 ndlp->nlp_flag |= NLP_ADISC_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001152 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001153 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
James Smart2e0fef82007-06-17 19:56:36 -05001154 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001155 ndlp->nlp_flag &= ~NLP_ADISC_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001156 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001157 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001158 return 1;
dea31012005-04-17 16:05:31 -05001159 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001160 return 0;
dea31012005-04-17 16:05:31 -05001161}
1162
1163static void
James Smart2e0fef82007-06-17 19:56:36 -05001164lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1165 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05001166{
James Smart2e0fef82007-06-17 19:56:36 -05001167 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
1168 struct lpfc_vport *vport = ndlp->vport;
1169 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05001170 IOCB_t *irsp;
1171 struct lpfc_sli *psli;
dea31012005-04-17 16:05:31 -05001172
1173 psli = &phba->sli;
1174 /* we pass cmdiocb to state machine which needs rspiocb as well */
1175 cmdiocb->context_un.rsp_iocb = rspiocb;
1176
1177 irsp = &(rspiocb->iocb);
James Smart2e0fef82007-06-17 19:56:36 -05001178 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001179 ndlp->nlp_flag &= ~NLP_LOGO_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001180 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001181
1182 /* LOGO completes to NPort <nlp_DID> */
1183 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
1184 "%d:0105 LOGO completes to NPort x%x "
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001185 "Data: x%x x%x x%x x%x\n",
dea31012005-04-17 16:05:31 -05001186 phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus,
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001187 irsp->un.ulpWord[4], irsp->ulpTimeout,
James Smart2e0fef82007-06-17 19:56:36 -05001188 vport->num_disc_nodes);
dea31012005-04-17 16:05:31 -05001189
1190 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -05001191 if (lpfc_els_chk_latt(vport))
dea31012005-04-17 16:05:31 -05001192 goto out;
1193
1194 if (irsp->ulpStatus) {
1195 /* Check for retry */
James Smart2e0fef82007-06-17 19:56:36 -05001196 if (lpfc_els_retry(phba, cmdiocb, rspiocb))
dea31012005-04-17 16:05:31 -05001197 /* ELS command is being retried */
1198 goto out;
dea31012005-04-17 16:05:31 -05001199 /* LOGO failed */
1200 /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
1201 if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
1202 ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
James.Smart@Emulex.Com6281bfe2005-11-28 11:41:33 -05001203 (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
dea31012005-04-17 16:05:31 -05001204 (irsp->un.ulpWord[4] == IOERR_SLI_DOWN))) {
1205 goto out;
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05001206 } else {
James Smart2e0fef82007-06-17 19:56:36 -05001207 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
dea31012005-04-17 16:05:31 -05001208 NLP_EVT_CMPL_LOGO);
1209 }
1210 } else {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001211 /* Good status, call state machine.
1212 * This will unregister the rpi if needed.
1213 */
James Smart2e0fef82007-06-17 19:56:36 -05001214 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
1215 NLP_EVT_CMPL_LOGO);
dea31012005-04-17 16:05:31 -05001216 }
1217
1218out:
1219 lpfc_els_free_iocb(phba, cmdiocb);
1220 return;
1221}
1222
1223int
James Smart2e0fef82007-06-17 19:56:36 -05001224lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
dea31012005-04-17 16:05:31 -05001225 uint8_t retry)
1226{
James Smart2e0fef82007-06-17 19:56:36 -05001227 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1228 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001229 IOCB_t *icmd;
1230 struct lpfc_iocbq *elsiocb;
1231 struct lpfc_sli_ring *pring;
1232 struct lpfc_sli *psli;
1233 uint8_t *pcmd;
1234 uint16_t cmdsize;
1235
1236 psli = &phba->sli;
1237 pring = &psli->ring[LPFC_ELS_RING];
1238
James Smart10d4e952006-04-15 11:53:15 -04001239 cmdsize = (2 * sizeof (uint32_t)) + sizeof (struct lpfc_name);
James Smart2e0fef82007-06-17 19:56:36 -05001240 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
1241 ndlp->nlp_DID, ELS_CMD_LOGO);
James Smart488d1462006-03-07 15:02:37 -05001242 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001243 return 1;
dea31012005-04-17 16:05:31 -05001244
1245 icmd = &elsiocb->iocb;
1246 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1247 *((uint32_t *) (pcmd)) = ELS_CMD_LOGO;
1248 pcmd += sizeof (uint32_t);
1249
1250 /* Fill in LOGO payload */
James Smart2e0fef82007-06-17 19:56:36 -05001251 *((uint32_t *) (pcmd)) = be32_to_cpu(vport->fc_myDID);
dea31012005-04-17 16:05:31 -05001252 pcmd += sizeof (uint32_t);
James Smart2e0fef82007-06-17 19:56:36 -05001253 memcpy(pcmd, &vport->fc_portname, sizeof (struct lpfc_name));
dea31012005-04-17 16:05:31 -05001254
1255 phba->fc_stat.elsXmitLOGO++;
1256 elsiocb->iocb_cmpl = lpfc_cmpl_els_logo;
James Smart2e0fef82007-06-17 19:56:36 -05001257 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001258 ndlp->nlp_flag |= NLP_LOGO_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001259 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001260 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
James Smart2e0fef82007-06-17 19:56:36 -05001261 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001262 ndlp->nlp_flag &= ~NLP_LOGO_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001263 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001264 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001265 return 1;
dea31012005-04-17 16:05:31 -05001266 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001267 return 0;
dea31012005-04-17 16:05:31 -05001268}
1269
1270static void
James Smart2e0fef82007-06-17 19:56:36 -05001271lpfc_cmpl_els_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1272 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05001273{
James Smart2e0fef82007-06-17 19:56:36 -05001274 struct lpfc_vport *vport = cmdiocb->vport;
dea31012005-04-17 16:05:31 -05001275 IOCB_t *irsp;
1276
1277 irsp = &rspiocb->iocb;
1278
1279 /* ELS cmd tag <ulpIoTag> completes */
1280 lpfc_printf_log(phba,
1281 KERN_INFO,
1282 LOG_ELS,
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001283 "%d:0106 ELS cmd tag x%x completes Data: x%x x%x x%x\n",
dea31012005-04-17 16:05:31 -05001284 phba->brd_no,
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001285 irsp->ulpIoTag, irsp->ulpStatus,
1286 irsp->un.ulpWord[4], irsp->ulpTimeout);
dea31012005-04-17 16:05:31 -05001287
1288 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -05001289 lpfc_els_chk_latt(vport);
dea31012005-04-17 16:05:31 -05001290 lpfc_els_free_iocb(phba, cmdiocb);
1291 return;
1292}
1293
1294int
James Smart2e0fef82007-06-17 19:56:36 -05001295lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
dea31012005-04-17 16:05:31 -05001296{
James Smart2e0fef82007-06-17 19:56:36 -05001297 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001298 IOCB_t *icmd;
1299 struct lpfc_iocbq *elsiocb;
1300 struct lpfc_sli_ring *pring;
1301 struct lpfc_sli *psli;
1302 uint8_t *pcmd;
1303 uint16_t cmdsize;
1304 struct lpfc_nodelist *ndlp;
1305
1306 psli = &phba->sli;
1307 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
1308 cmdsize = (sizeof (uint32_t) + sizeof (SCR));
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001309 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
1310 if (!ndlp)
1311 return 1;
dea31012005-04-17 16:05:31 -05001312
James Smart2e0fef82007-06-17 19:56:36 -05001313 lpfc_nlp_init(vport, ndlp, nportid);
dea31012005-04-17 16:05:31 -05001314
James Smart2e0fef82007-06-17 19:56:36 -05001315 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
1316 ndlp->nlp_DID, ELS_CMD_SCR);
1317
James Smart488d1462006-03-07 15:02:37 -05001318 if (!elsiocb) {
James Smart329f9bc2007-04-25 09:53:01 -04001319 lpfc_nlp_put(ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001320 return 1;
dea31012005-04-17 16:05:31 -05001321 }
1322
1323 icmd = &elsiocb->iocb;
1324 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1325
1326 *((uint32_t *) (pcmd)) = ELS_CMD_SCR;
1327 pcmd += sizeof (uint32_t);
1328
1329 /* For SCR, remainder of payload is SCR parameter page */
1330 memset(pcmd, 0, sizeof (SCR));
1331 ((SCR *) pcmd)->Function = SCR_FUNC_FULL;
1332
1333 phba->fc_stat.elsXmitSCR++;
1334 elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
dea31012005-04-17 16:05:31 -05001335 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
James Smart329f9bc2007-04-25 09:53:01 -04001336 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05001337 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001338 return 1;
dea31012005-04-17 16:05:31 -05001339 }
James Smart329f9bc2007-04-25 09:53:01 -04001340 lpfc_nlp_put(ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001341 return 0;
dea31012005-04-17 16:05:31 -05001342}
1343
1344static int
James Smart2e0fef82007-06-17 19:56:36 -05001345lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
dea31012005-04-17 16:05:31 -05001346{
James Smart2e0fef82007-06-17 19:56:36 -05001347 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001348 IOCB_t *icmd;
1349 struct lpfc_iocbq *elsiocb;
1350 struct lpfc_sli_ring *pring;
1351 struct lpfc_sli *psli;
1352 FARP *fp;
1353 uint8_t *pcmd;
1354 uint32_t *lp;
1355 uint16_t cmdsize;
1356 struct lpfc_nodelist *ondlp;
1357 struct lpfc_nodelist *ndlp;
1358
1359 psli = &phba->sli;
1360 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
1361 cmdsize = (sizeof (uint32_t) + sizeof (FARP));
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001362 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
1363 if (!ndlp)
1364 return 1;
dea31012005-04-17 16:05:31 -05001365
James Smart2e0fef82007-06-17 19:56:36 -05001366 lpfc_nlp_init(vport, ndlp, nportid);
1367
1368 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
1369 ndlp->nlp_DID, ELS_CMD_RNID);
James Smart488d1462006-03-07 15:02:37 -05001370 if (!elsiocb) {
James Smart329f9bc2007-04-25 09:53:01 -04001371 lpfc_nlp_put(ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001372 return 1;
dea31012005-04-17 16:05:31 -05001373 }
1374
1375 icmd = &elsiocb->iocb;
1376 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1377
1378 *((uint32_t *) (pcmd)) = ELS_CMD_FARPR;
1379 pcmd += sizeof (uint32_t);
1380
1381 /* Fill in FARPR payload */
1382 fp = (FARP *) (pcmd);
1383 memset(fp, 0, sizeof (FARP));
1384 lp = (uint32_t *) pcmd;
1385 *lp++ = be32_to_cpu(nportid);
James Smart2e0fef82007-06-17 19:56:36 -05001386 *lp++ = be32_to_cpu(vport->fc_myDID);
dea31012005-04-17 16:05:31 -05001387 fp->Rflags = 0;
1388 fp->Mflags = (FARP_MATCH_PORT | FARP_MATCH_NODE);
1389
James Smart2e0fef82007-06-17 19:56:36 -05001390 memcpy(&fp->RportName, &vport->fc_portname, sizeof (struct lpfc_name));
1391 memcpy(&fp->RnodeName, &vport->fc_nodename, sizeof (struct lpfc_name));
1392 ondlp = lpfc_findnode_did(vport, nportid);
1393 if (ondlp) {
dea31012005-04-17 16:05:31 -05001394 memcpy(&fp->OportName, &ondlp->nlp_portname,
1395 sizeof (struct lpfc_name));
1396 memcpy(&fp->OnodeName, &ondlp->nlp_nodename,
1397 sizeof (struct lpfc_name));
1398 }
1399
1400 phba->fc_stat.elsXmitFARPR++;
1401 elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
dea31012005-04-17 16:05:31 -05001402 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
James Smart329f9bc2007-04-25 09:53:01 -04001403 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05001404 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001405 return 1;
dea31012005-04-17 16:05:31 -05001406 }
James Smart329f9bc2007-04-25 09:53:01 -04001407 lpfc_nlp_put(ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001408 return 0;
dea31012005-04-17 16:05:31 -05001409}
1410
James Smarted957682007-06-17 19:56:37 -05001411static void
1412lpfc_end_rscn(struct lpfc_vport *vport)
1413{
1414 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1415
1416 if (vport->fc_flag & FC_RSCN_MODE) {
1417 /*
1418 * Check to see if more RSCNs came in while we were
1419 * processing this one.
1420 */
1421 if (vport->fc_rscn_id_cnt ||
1422 (vport->fc_flag & FC_RSCN_DISCOVERY) != 0)
1423 lpfc_els_handle_rscn(vport);
1424 else {
1425 spin_lock_irq(shost->host_lock);
1426 vport->fc_flag &= ~FC_RSCN_MODE;
1427 spin_unlock_irq(shost->host_lock);
1428 }
1429 }
1430}
1431
dea31012005-04-17 16:05:31 -05001432void
James Smart2e0fef82007-06-17 19:56:36 -05001433lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp)
James Smartfdcebe22006-03-07 15:04:01 -05001434{
James Smart2e0fef82007-06-17 19:56:36 -05001435 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1436
1437 spin_lock_irq(shost->host_lock);
James Smartfdcebe22006-03-07 15:04:01 -05001438 nlp->nlp_flag &= ~NLP_DELAY_TMO;
James Smart2e0fef82007-06-17 19:56:36 -05001439 spin_unlock_irq(shost->host_lock);
James Smartfdcebe22006-03-07 15:04:01 -05001440 del_timer_sync(&nlp->nlp_delayfunc);
1441 nlp->nlp_last_elscmd = 0;
1442
1443 if (!list_empty(&nlp->els_retry_evt.evt_listp))
1444 list_del_init(&nlp->els_retry_evt.evt_listp);
1445
1446 if (nlp->nlp_flag & NLP_NPR_2B_DISC) {
James Smart2e0fef82007-06-17 19:56:36 -05001447 spin_lock_irq(shost->host_lock);
James Smartfdcebe22006-03-07 15:04:01 -05001448 nlp->nlp_flag &= ~NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -05001449 spin_unlock_irq(shost->host_lock);
1450 if (vport->num_disc_nodes) {
James Smartfdcebe22006-03-07 15:04:01 -05001451 /* Check to see if there are more
1452 * PLOGIs to be sent
1453 */
James Smart2e0fef82007-06-17 19:56:36 -05001454 lpfc_more_plogi(vport);
James Smartfdcebe22006-03-07 15:04:01 -05001455
James Smart2e0fef82007-06-17 19:56:36 -05001456 if (vport->num_disc_nodes == 0) {
1457 spin_lock_irq(shost->host_lock);
1458 vport->fc_flag &= ~FC_NDISC_ACTIVE;
1459 spin_unlock_irq(shost->host_lock);
1460 lpfc_can_disctmo(vport);
James Smarted957682007-06-17 19:56:37 -05001461 lpfc_end_rscn(vport);
James Smartfdcebe22006-03-07 15:04:01 -05001462 }
1463 }
1464 }
1465 return;
1466}
1467
1468void
dea31012005-04-17 16:05:31 -05001469lpfc_els_retry_delay(unsigned long ptr)
1470{
James Smart2e0fef82007-06-17 19:56:36 -05001471 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) ptr;
1472 struct lpfc_vport *vport = ndlp->vport;
1473 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1474 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001475 unsigned long iflag;
James Smart2e0fef82007-06-17 19:56:36 -05001476 struct lpfc_work_evt *evtp = &ndlp->els_retry_evt;
dea31012005-04-17 16:05:31 -05001477
James Smart2e0fef82007-06-17 19:56:36 -05001478 ndlp = (struct lpfc_nodelist *) ptr;
1479 phba = ndlp->vport->phba;
dea31012005-04-17 16:05:31 -05001480 evtp = &ndlp->els_retry_evt;
1481
James Smart2e0fef82007-06-17 19:56:36 -05001482 spin_lock_irqsave(shost->host_lock, iflag);
dea31012005-04-17 16:05:31 -05001483 if (!list_empty(&evtp->evt_listp)) {
James Smart2e0fef82007-06-17 19:56:36 -05001484 spin_unlock_irqrestore(shost->host_lock, iflag);
dea31012005-04-17 16:05:31 -05001485 return;
1486 }
1487
1488 evtp->evt_arg1 = ndlp;
1489 evtp->evt = LPFC_EVT_ELS_RETRY;
1490 list_add_tail(&evtp->evt_listp, &phba->work_list);
1491 if (phba->work_wait)
1492 wake_up(phba->work_wait);
1493
James Smart2e0fef82007-06-17 19:56:36 -05001494 spin_unlock_irqrestore(shost->host_lock, iflag);
dea31012005-04-17 16:05:31 -05001495 return;
1496}
1497
1498void
1499lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp)
1500{
James Smart2e0fef82007-06-17 19:56:36 -05001501 struct lpfc_vport *vport = ndlp->vport;
1502 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1503 uint32_t cmd, did, retry;
dea31012005-04-17 16:05:31 -05001504
James Smart2e0fef82007-06-17 19:56:36 -05001505 spin_lock_irq(shost->host_lock);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001506 did = ndlp->nlp_DID;
1507 cmd = ndlp->nlp_last_elscmd;
1508 ndlp->nlp_last_elscmd = 0;
dea31012005-04-17 16:05:31 -05001509
1510 if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
James Smart2e0fef82007-06-17 19:56:36 -05001511 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001512 return;
1513 }
1514
1515 ndlp->nlp_flag &= ~NLP_DELAY_TMO;
James Smart2e0fef82007-06-17 19:56:36 -05001516 spin_unlock_irq(shost->host_lock);
James Smart1a169682006-03-07 15:04:06 -05001517 /*
1518 * If a discovery event readded nlp_delayfunc after timer
1519 * firing and before processing the timer, cancel the
1520 * nlp_delayfunc.
1521 */
1522 del_timer_sync(&ndlp->nlp_delayfunc);
dea31012005-04-17 16:05:31 -05001523 retry = ndlp->nlp_retry;
1524
1525 switch (cmd) {
1526 case ELS_CMD_FLOGI:
James Smart2e0fef82007-06-17 19:56:36 -05001527 lpfc_issue_els_flogi(vport, ndlp, retry);
dea31012005-04-17 16:05:31 -05001528 break;
1529 case ELS_CMD_PLOGI:
James Smart2e0fef82007-06-17 19:56:36 -05001530 if (!lpfc_issue_els_plogi(vport, ndlp->nlp_DID, retry)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001531 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001532 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
Jamie Wellnitz6ad42532006-02-28 19:25:16 -05001533 }
dea31012005-04-17 16:05:31 -05001534 break;
1535 case ELS_CMD_ADISC:
James Smart2e0fef82007-06-17 19:56:36 -05001536 if (!lpfc_issue_els_adisc(vport, ndlp, retry)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001537 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001538 lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
Jamie Wellnitz6ad42532006-02-28 19:25:16 -05001539 }
dea31012005-04-17 16:05:31 -05001540 break;
1541 case ELS_CMD_PRLI:
James Smart2e0fef82007-06-17 19:56:36 -05001542 if (!lpfc_issue_els_prli(vport, ndlp, retry)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001543 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001544 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
Jamie Wellnitz6ad42532006-02-28 19:25:16 -05001545 }
dea31012005-04-17 16:05:31 -05001546 break;
1547 case ELS_CMD_LOGO:
James Smart2e0fef82007-06-17 19:56:36 -05001548 if (!lpfc_issue_els_logo(vport, ndlp, retry)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001549 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001550 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
Jamie Wellnitz6ad42532006-02-28 19:25:16 -05001551 }
dea31012005-04-17 16:05:31 -05001552 break;
1553 }
1554 return;
1555}
1556
1557static int
James Smart2e0fef82007-06-17 19:56:36 -05001558lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1559 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05001560{
James Smart2e0fef82007-06-17 19:56:36 -05001561 struct lpfc_vport *vport = cmdiocb->vport;
1562 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1563 IOCB_t *irsp = &rspiocb->iocb;
1564 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
1565 struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
dea31012005-04-17 16:05:31 -05001566 uint32_t *elscmd;
1567 struct ls_rjt stat;
James Smart2e0fef82007-06-17 19:56:36 -05001568 int retry = 0, maxretry = lpfc_max_els_tries, delay = 0;
1569 uint32_t cmd = 0;
James Smart488d1462006-03-07 15:02:37 -05001570 uint32_t did;
dea31012005-04-17 16:05:31 -05001571
James Smart488d1462006-03-07 15:02:37 -05001572
dea31012005-04-17 16:05:31 -05001573 /* Note: context2 may be 0 for internal driver abort
1574 * of delays ELS command.
1575 */
1576
1577 if (pcmd && pcmd->virt) {
1578 elscmd = (uint32_t *) (pcmd->virt);
1579 cmd = *elscmd++;
1580 }
1581
James Smart329f9bc2007-04-25 09:53:01 -04001582 if (ndlp)
James Smart488d1462006-03-07 15:02:37 -05001583 did = ndlp->nlp_DID;
1584 else {
1585 /* We should only hit this case for retrying PLOGI */
1586 did = irsp->un.elsreq64.remoteID;
James Smart2e0fef82007-06-17 19:56:36 -05001587 ndlp = lpfc_findnode_did(vport, did);
James Smart488d1462006-03-07 15:02:37 -05001588 if (!ndlp && (cmd != ELS_CMD_PLOGI))
1589 return 1;
1590 }
1591
dea31012005-04-17 16:05:31 -05001592 switch (irsp->ulpStatus) {
1593 case IOSTAT_FCP_RSP_ERROR:
1594 case IOSTAT_REMOTE_STOP:
1595 break;
1596
1597 case IOSTAT_LOCAL_REJECT:
1598 switch ((irsp->un.ulpWord[4] & 0xff)) {
1599 case IOERR_LOOP_OPEN_FAILURE:
James Smart2e0fef82007-06-17 19:56:36 -05001600 if (cmd == ELS_CMD_PLOGI && cmdiocb->retry == 0)
dea31012005-04-17 16:05:31 -05001601 delay = 1;
dea31012005-04-17 16:05:31 -05001602 retry = 1;
1603 break;
1604
1605 case IOERR_SEQUENCE_TIMEOUT:
1606 retry = 1;
dea31012005-04-17 16:05:31 -05001607 break;
1608
1609 case IOERR_NO_RESOURCES:
James Smart2e0fef82007-06-17 19:56:36 -05001610 if (cmd == ELS_CMD_PLOGI)
dea31012005-04-17 16:05:31 -05001611 delay = 1;
dea31012005-04-17 16:05:31 -05001612 retry = 1;
1613 break;
1614
1615 case IOERR_INVALID_RPI:
1616 retry = 1;
1617 break;
1618 }
1619 break;
1620
1621 case IOSTAT_NPORT_RJT:
1622 case IOSTAT_FABRIC_RJT:
1623 if (irsp->un.ulpWord[4] & RJT_UNAVAIL_TEMP) {
1624 retry = 1;
1625 break;
1626 }
1627 break;
1628
1629 case IOSTAT_NPORT_BSY:
1630 case IOSTAT_FABRIC_BSY:
1631 retry = 1;
1632 break;
1633
1634 case IOSTAT_LS_RJT:
1635 stat.un.lsRjtError = be32_to_cpu(irsp->un.ulpWord[4]);
1636 /* Added for Vendor specifc support
1637 * Just keep retrying for these Rsn / Exp codes
1638 */
1639 switch (stat.un.b.lsRjtRsnCode) {
1640 case LSRJT_UNABLE_TPC:
1641 if (stat.un.b.lsRjtRsnCodeExp ==
1642 LSEXP_CMD_IN_PROGRESS) {
1643 if (cmd == ELS_CMD_PLOGI) {
1644 delay = 1;
1645 maxretry = 48;
1646 }
1647 retry = 1;
1648 break;
1649 }
1650 if (cmd == ELS_CMD_PLOGI) {
1651 delay = 1;
1652 maxretry = lpfc_max_els_tries + 1;
1653 retry = 1;
1654 break;
1655 }
1656 break;
1657
1658 case LSRJT_LOGICAL_BSY:
1659 if (cmd == ELS_CMD_PLOGI) {
1660 delay = 1;
1661 maxretry = 48;
1662 }
1663 retry = 1;
1664 break;
1665 }
1666 break;
1667
1668 case IOSTAT_INTERMED_RSP:
1669 case IOSTAT_BA_RJT:
1670 break;
1671
1672 default:
1673 break;
1674 }
1675
James Smart488d1462006-03-07 15:02:37 -05001676 if (did == FDMI_DID)
dea31012005-04-17 16:05:31 -05001677 retry = 1;
dea31012005-04-17 16:05:31 -05001678
1679 if ((++cmdiocb->retry) >= maxretry) {
1680 phba->fc_stat.elsRetryExceeded++;
1681 retry = 0;
1682 }
1683
James Smarted957682007-06-17 19:56:37 -05001684 if ((vport->load_flag & FC_UNLOADING) != 0)
1685 retry = 0;
1686
dea31012005-04-17 16:05:31 -05001687 if (retry) {
1688
1689 /* Retry ELS command <elsCmd> to remote NPORT <did> */
1690 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
1691 "%d:0107 Retry ELS command x%x to remote "
1692 "NPORT x%x Data: x%x x%x\n",
1693 phba->brd_no,
James Smart488d1462006-03-07 15:02:37 -05001694 cmd, did, cmdiocb->retry, delay);
dea31012005-04-17 16:05:31 -05001695
1696 if ((cmd == ELS_CMD_PLOGI) || (cmd == ELS_CMD_ADISC)) {
1697 /* If discovery / RSCN timer is running, reset it */
James Smart2e0fef82007-06-17 19:56:36 -05001698 if (timer_pending(&vport->fc_disctmo) ||
1699 (vport->fc_flag & FC_RSCN_MODE))
1700 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -05001701 }
1702
1703 phba->fc_stat.elsXmitRetry++;
James Smart488d1462006-03-07 15:02:37 -05001704 if (ndlp && delay) {
dea31012005-04-17 16:05:31 -05001705 phba->fc_stat.elsDelayRetry++;
1706 ndlp->nlp_retry = cmdiocb->retry;
1707
1708 mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
James Smart2e0fef82007-06-17 19:56:36 -05001709 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001710 ndlp->nlp_flag |= NLP_DELAY_TMO;
James Smart2e0fef82007-06-17 19:56:36 -05001711 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001712
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001713 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001714 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
dea31012005-04-17 16:05:31 -05001715 ndlp->nlp_last_elscmd = cmd;
1716
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001717 return 1;
dea31012005-04-17 16:05:31 -05001718 }
1719 switch (cmd) {
1720 case ELS_CMD_FLOGI:
James Smart2e0fef82007-06-17 19:56:36 -05001721 lpfc_issue_els_flogi(vport, ndlp, cmdiocb->retry);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001722 return 1;
dea31012005-04-17 16:05:31 -05001723 case ELS_CMD_PLOGI:
James Smart488d1462006-03-07 15:02:37 -05001724 if (ndlp) {
1725 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001726 lpfc_nlp_set_state(vport, ndlp,
James Smartde0c5b32007-04-25 09:52:27 -04001727 NLP_STE_PLOGI_ISSUE);
James Smart488d1462006-03-07 15:02:37 -05001728 }
James Smart2e0fef82007-06-17 19:56:36 -05001729 lpfc_issue_els_plogi(vport, did, cmdiocb->retry);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001730 return 1;
dea31012005-04-17 16:05:31 -05001731 case ELS_CMD_ADISC:
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001732 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001733 lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
1734 lpfc_issue_els_adisc(vport, ndlp, cmdiocb->retry);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001735 return 1;
dea31012005-04-17 16:05:31 -05001736 case ELS_CMD_PRLI:
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001737 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001738 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
1739 lpfc_issue_els_prli(vport, ndlp, cmdiocb->retry);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001740 return 1;
dea31012005-04-17 16:05:31 -05001741 case ELS_CMD_LOGO:
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001742 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001743 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
1744 lpfc_issue_els_logo(vport, ndlp, cmdiocb->retry);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001745 return 1;
dea31012005-04-17 16:05:31 -05001746 }
1747 }
1748
1749 /* No retry ELS command <elsCmd> to remote NPORT <did> */
1750 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
1751 "%d:0108 No retry ELS command x%x to remote NPORT x%x "
James Smart488d1462006-03-07 15:02:37 -05001752 "Data: x%x\n",
dea31012005-04-17 16:05:31 -05001753 phba->brd_no,
James Smart488d1462006-03-07 15:02:37 -05001754 cmd, did, cmdiocb->retry);
dea31012005-04-17 16:05:31 -05001755
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001756 return 0;
dea31012005-04-17 16:05:31 -05001757}
1758
1759int
James Smart329f9bc2007-04-25 09:53:01 -04001760lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
dea31012005-04-17 16:05:31 -05001761{
1762 struct lpfc_dmabuf *buf_ptr, *buf_ptr1;
1763
James Smart329f9bc2007-04-25 09:53:01 -04001764 if (elsiocb->context1) {
1765 lpfc_nlp_put(elsiocb->context1);
1766 elsiocb->context1 = NULL;
1767 }
dea31012005-04-17 16:05:31 -05001768 /* context2 = cmd, context2->next = rsp, context3 = bpl */
1769 if (elsiocb->context2) {
1770 buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
1771 /* Free the response before processing the command. */
1772 if (!list_empty(&buf_ptr1->list)) {
1773 list_remove_head(&buf_ptr1->list, buf_ptr,
1774 struct lpfc_dmabuf,
1775 list);
1776 lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
1777 kfree(buf_ptr);
1778 }
1779 lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys);
1780 kfree(buf_ptr1);
1781 }
1782
1783 if (elsiocb->context3) {
1784 buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3;
1785 lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
1786 kfree(buf_ptr);
1787 }
James Bottomley604a3e32005-10-29 10:28:33 -05001788 lpfc_sli_release_iocbq(phba, elsiocb);
dea31012005-04-17 16:05:31 -05001789 return 0;
1790}
1791
1792static void
James Smart2e0fef82007-06-17 19:56:36 -05001793lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1794 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05001795{
James Smart2e0fef82007-06-17 19:56:36 -05001796 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
1797 struct lpfc_vport *vport = cmdiocb->vport;
dea31012005-04-17 16:05:31 -05001798
1799 /* ACC to LOGO completes to NPort <nlp_DID> */
1800 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
1801 "%d:0109 ACC to LOGO completes to NPort x%x "
1802 "Data: x%x x%x x%x\n",
1803 phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag,
1804 ndlp->nlp_state, ndlp->nlp_rpi);
1805
dea31012005-04-17 16:05:31 -05001806 switch (ndlp->nlp_state) {
1807 case NLP_STE_UNUSED_NODE: /* node is just allocated */
James Smart2e0fef82007-06-17 19:56:36 -05001808 lpfc_drop_node(vport, ndlp);
dea31012005-04-17 16:05:31 -05001809 break;
1810 case NLP_STE_NPR_NODE: /* NPort Recovery mode */
James Smart2e0fef82007-06-17 19:56:36 -05001811 lpfc_unreg_rpi(vport, ndlp);
dea31012005-04-17 16:05:31 -05001812 break;
1813 default:
1814 break;
1815 }
1816 lpfc_els_free_iocb(phba, cmdiocb);
1817 return;
1818}
1819
1820static void
James Smart329f9bc2007-04-25 09:53:01 -04001821lpfc_cmpl_els_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1822 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05001823{
James Smart2e0fef82007-06-17 19:56:36 -05001824 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
1825 struct lpfc_vport *vport = ndlp ? ndlp->vport : NULL;
1826 struct Scsi_Host *shost = vport ? lpfc_shost_from_vport(vport) : NULL;
James Smart33ccf8d2006-08-17 11:57:58 -04001827 IOCB_t *irsp;
dea31012005-04-17 16:05:31 -05001828 LPFC_MBOXQ_t *mbox = NULL;
James Smart2e0fef82007-06-17 19:56:36 -05001829 struct lpfc_dmabuf *mp = NULL;
dea31012005-04-17 16:05:31 -05001830
James Smart33ccf8d2006-08-17 11:57:58 -04001831 irsp = &rspiocb->iocb;
1832
dea31012005-04-17 16:05:31 -05001833 if (cmdiocb->context_un.mbox)
1834 mbox = cmdiocb->context_un.mbox;
1835
dea31012005-04-17 16:05:31 -05001836 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -05001837 if (!ndlp || lpfc_els_chk_latt(vport)) {
dea31012005-04-17 16:05:31 -05001838 if (mbox) {
James Smart14691152006-12-02 13:34:28 -05001839 mp = (struct lpfc_dmabuf *) mbox->context1;
1840 if (mp) {
1841 lpfc_mbuf_free(phba, mp->virt, mp->phys);
1842 kfree(mp);
1843 }
James Smart329f9bc2007-04-25 09:53:01 -04001844 mempool_free(mbox, phba->mbox_mem_pool);
dea31012005-04-17 16:05:31 -05001845 }
1846 goto out;
1847 }
1848
1849 /* ELS response tag <ulpIoTag> completes */
1850 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
1851 "%d:0110 ELS response tag x%x completes "
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001852 "Data: x%x x%x x%x x%x x%x x%x x%x\n",
dea31012005-04-17 16:05:31 -05001853 phba->brd_no,
1854 cmdiocb->iocb.ulpIoTag, rspiocb->iocb.ulpStatus,
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001855 rspiocb->iocb.un.ulpWord[4], rspiocb->iocb.ulpTimeout,
James Smart2e0fef82007-06-17 19:56:36 -05001856 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001857 ndlp->nlp_rpi);
dea31012005-04-17 16:05:31 -05001858
1859 if (mbox) {
1860 if ((rspiocb->iocb.ulpStatus == 0)
1861 && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) {
James Smart2e0fef82007-06-17 19:56:36 -05001862 lpfc_unreg_rpi(vport, ndlp);
dea31012005-04-17 16:05:31 -05001863 mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
James Smart329f9bc2007-04-25 09:53:01 -04001864 mbox->context2 = lpfc_nlp_get(ndlp);
James Smart2e0fef82007-06-17 19:56:36 -05001865 mbox->vport = vport;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001866 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001867 lpfc_nlp_set_state(vport, ndlp,
1868 NLP_STE_REG_LOGIN_ISSUE);
dea31012005-04-17 16:05:31 -05001869 if (lpfc_sli_issue_mbox(phba, mbox,
1870 (MBX_NOWAIT | MBX_STOP_IOCB))
1871 != MBX_NOT_FINISHED) {
1872 goto out;
1873 }
James Smart329f9bc2007-04-25 09:53:01 -04001874 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05001875 /* NOTE: we should have messages for unsuccessful
1876 reglogin */
dea31012005-04-17 16:05:31 -05001877 } else {
James Smart33ccf8d2006-08-17 11:57:58 -04001878 /* Do not call NO_LIST for lpfc_els_abort'ed ELS cmds */
1879 if (!((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
1880 ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
1881 (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
1882 (irsp->un.ulpWord[4] == IOERR_SLI_DOWN)))) {
1883 if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
James Smart2e0fef82007-06-17 19:56:36 -05001884 lpfc_drop_node(vport, ndlp);
James Smart33ccf8d2006-08-17 11:57:58 -04001885 ndlp = NULL;
1886 }
dea31012005-04-17 16:05:31 -05001887 }
1888 }
James Smart14691152006-12-02 13:34:28 -05001889 mp = (struct lpfc_dmabuf *) mbox->context1;
1890 if (mp) {
1891 lpfc_mbuf_free(phba, mp->virt, mp->phys);
1892 kfree(mp);
1893 }
1894 mempool_free(mbox, phba->mbox_mem_pool);
dea31012005-04-17 16:05:31 -05001895 }
1896out:
1897 if (ndlp) {
James Smart2e0fef82007-06-17 19:56:36 -05001898 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001899 ndlp->nlp_flag &= ~NLP_ACC_REGLOGIN;
James Smart2e0fef82007-06-17 19:56:36 -05001900 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001901 }
1902 lpfc_els_free_iocb(phba, cmdiocb);
1903 return;
1904}
1905
1906int
James Smart2e0fef82007-06-17 19:56:36 -05001907lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
1908 struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp,
1909 LPFC_MBOXQ_t *mbox, uint8_t newnode)
dea31012005-04-17 16:05:31 -05001910{
James Smart2e0fef82007-06-17 19:56:36 -05001911 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1912 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001913 IOCB_t *icmd;
1914 IOCB_t *oldcmd;
1915 struct lpfc_iocbq *elsiocb;
1916 struct lpfc_sli_ring *pring;
1917 struct lpfc_sli *psli;
1918 uint8_t *pcmd;
1919 uint16_t cmdsize;
1920 int rc;
James Smart82d9a2a2006-04-15 11:53:05 -04001921 ELS_PKT *els_pkt_ptr;
dea31012005-04-17 16:05:31 -05001922
1923 psli = &phba->sli;
1924 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
1925 oldcmd = &oldiocb->iocb;
1926
1927 switch (flag) {
1928 case ELS_CMD_ACC:
1929 cmdsize = sizeof (uint32_t);
James Smart2e0fef82007-06-17 19:56:36 -05001930 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
1931 ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
James Smart488d1462006-03-07 15:02:37 -05001932 if (!elsiocb) {
James Smart2e0fef82007-06-17 19:56:36 -05001933 spin_lock_irq(shost->host_lock);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001934 ndlp->nlp_flag &= ~NLP_LOGO_ACC;
James Smart2e0fef82007-06-17 19:56:36 -05001935 spin_unlock_irq(shost->host_lock);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001936 return 1;
dea31012005-04-17 16:05:31 -05001937 }
James Smart2e0fef82007-06-17 19:56:36 -05001938
dea31012005-04-17 16:05:31 -05001939 icmd = &elsiocb->iocb;
1940 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
1941 pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1942 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
1943 pcmd += sizeof (uint32_t);
1944 break;
1945 case ELS_CMD_PLOGI:
1946 cmdsize = (sizeof (struct serv_parm) + sizeof (uint32_t));
James Smart2e0fef82007-06-17 19:56:36 -05001947 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
1948 ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
James Smart488d1462006-03-07 15:02:37 -05001949 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001950 return 1;
James Smart488d1462006-03-07 15:02:37 -05001951
dea31012005-04-17 16:05:31 -05001952 icmd = &elsiocb->iocb;
1953 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
1954 pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1955
1956 if (mbox)
1957 elsiocb->context_un.mbox = mbox;
1958
1959 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
1960 pcmd += sizeof (uint32_t);
James Smart2e0fef82007-06-17 19:56:36 -05001961 memcpy(pcmd, &vport->fc_sparam, sizeof (struct serv_parm));
dea31012005-04-17 16:05:31 -05001962 break;
James Smart82d9a2a2006-04-15 11:53:05 -04001963 case ELS_CMD_PRLO:
1964 cmdsize = sizeof (uint32_t) + sizeof (PRLO);
James Smart2e0fef82007-06-17 19:56:36 -05001965 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
James Smart82d9a2a2006-04-15 11:53:05 -04001966 ndlp, ndlp->nlp_DID, ELS_CMD_PRLO);
1967 if (!elsiocb)
1968 return 1;
1969
1970 icmd = &elsiocb->iocb;
1971 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
1972 pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1973
1974 memcpy(pcmd, ((struct lpfc_dmabuf *) oldiocb->context2)->virt,
1975 sizeof (uint32_t) + sizeof (PRLO));
1976 *((uint32_t *) (pcmd)) = ELS_CMD_PRLO_ACC;
1977 els_pkt_ptr = (ELS_PKT *) pcmd;
1978 els_pkt_ptr->un.prlo.acceptRspCode = PRLO_REQ_EXECUTED;
1979 break;
dea31012005-04-17 16:05:31 -05001980 default:
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001981 return 1;
dea31012005-04-17 16:05:31 -05001982 }
1983
James Smart329f9bc2007-04-25 09:53:01 -04001984 if (newnode) {
1985 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05001986 elsiocb->context1 = NULL;
James Smart329f9bc2007-04-25 09:53:01 -04001987 }
dea31012005-04-17 16:05:31 -05001988
1989 /* Xmit ELS ACC response tag <ulpIoTag> */
1990 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart1dcb58e2007-04-25 09:51:30 -04001991 "%d:0128 Xmit ELS ACC response tag x%x, XRI: x%x, "
1992 "DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x\n",
1993 phba->brd_no, elsiocb->iotag,
dea31012005-04-17 16:05:31 -05001994 elsiocb->iocb.ulpContext, ndlp->nlp_DID,
1995 ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
1996
1997 if (ndlp->nlp_flag & NLP_LOGO_ACC) {
James Smart2e0fef82007-06-17 19:56:36 -05001998 spin_lock_irq(shost->host_lock);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001999 ndlp->nlp_flag &= ~NLP_LOGO_ACC;
James Smart2e0fef82007-06-17 19:56:36 -05002000 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05002001 elsiocb->iocb_cmpl = lpfc_cmpl_els_logo_acc;
2002 } else {
2003 elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
2004 }
2005
2006 phba->fc_stat.elsXmitACC++;
dea31012005-04-17 16:05:31 -05002007 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
dea31012005-04-17 16:05:31 -05002008 if (rc == IOCB_ERROR) {
2009 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002010 return 1;
dea31012005-04-17 16:05:31 -05002011 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002012 return 0;
dea31012005-04-17 16:05:31 -05002013}
2014
2015int
James Smart2e0fef82007-06-17 19:56:36 -05002016lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
2017 struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05002018{
James Smart2e0fef82007-06-17 19:56:36 -05002019 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002020 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 = 2 * sizeof (uint32_t);
James Smart2e0fef82007-06-17 19:56:36 -05002033 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
2034 ndlp->nlp_DID, ELS_CMD_LS_RJT);
James Smart488d1462006-03-07 15:02:37 -05002035 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002036 return 1;
dea31012005-04-17 16:05:31 -05002037
2038 icmd = &elsiocb->iocb;
2039 oldcmd = &oldiocb->iocb;
2040 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
2041 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2042
2043 *((uint32_t *) (pcmd)) = ELS_CMD_LS_RJT;
2044 pcmd += sizeof (uint32_t);
2045 *((uint32_t *) (pcmd)) = rejectError;
2046
2047 /* Xmit ELS RJT <err> response tag <ulpIoTag> */
2048 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart5b8bd0c2007-04-25 09:52:49 -04002049 "%d:0129 Xmit ELS RJT x%x response tag x%x xri x%x, "
2050 "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
2051 phba->brd_no, rejectError, elsiocb->iotag,
dea31012005-04-17 16:05:31 -05002052 elsiocb->iocb.ulpContext, ndlp->nlp_DID,
2053 ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
2054
2055 phba->fc_stat.elsXmitLSRJT++;
2056 elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
dea31012005-04-17 16:05:31 -05002057 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
dea31012005-04-17 16:05:31 -05002058 if (rc == IOCB_ERROR) {
2059 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002060 return 1;
dea31012005-04-17 16:05:31 -05002061 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002062 return 0;
dea31012005-04-17 16:05:31 -05002063}
2064
2065int
James Smart2e0fef82007-06-17 19:56:36 -05002066lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
2067 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05002068{
James Smart2e0fef82007-06-17 19:56:36 -05002069 struct lpfc_hba *phba = vport->phba;
2070 struct lpfc_sli *psli = &phba->sli;
2071 struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
dea31012005-04-17 16:05:31 -05002072 ADISC *ap;
James Smart2e0fef82007-06-17 19:56:36 -05002073 IOCB_t *icmd, *oldcmd;
dea31012005-04-17 16:05:31 -05002074 struct lpfc_iocbq *elsiocb;
dea31012005-04-17 16:05:31 -05002075 uint8_t *pcmd;
2076 uint16_t cmdsize;
2077 int rc;
2078
dea31012005-04-17 16:05:31 -05002079 cmdsize = sizeof (uint32_t) + sizeof (ADISC);
James Smart2e0fef82007-06-17 19:56:36 -05002080 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
2081 ndlp->nlp_DID, ELS_CMD_ACC);
James Smart488d1462006-03-07 15:02:37 -05002082 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002083 return 1;
dea31012005-04-17 16:05:31 -05002084
dea31012005-04-17 16:05:31 -05002085 icmd = &elsiocb->iocb;
2086 oldcmd = &oldiocb->iocb;
2087 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
James Smart5b8bd0c2007-04-25 09:52:49 -04002088
2089 /* Xmit ADISC ACC response tag <ulpIoTag> */
2090 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
2091 "%d:0130 Xmit ADISC ACC response iotag x%x xri: "
2092 "x%x, did x%x, nlp_flag x%x, nlp_state x%x rpi x%x\n",
2093 phba->brd_no, elsiocb->iotag,
2094 elsiocb->iocb.ulpContext, ndlp->nlp_DID,
2095 ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
2096
dea31012005-04-17 16:05:31 -05002097 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2098
2099 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
2100 pcmd += sizeof (uint32_t);
2101
2102 ap = (ADISC *) (pcmd);
2103 ap->hardAL_PA = phba->fc_pref_ALPA;
James Smart2e0fef82007-06-17 19:56:36 -05002104 memcpy(&ap->portName, &vport->fc_portname, sizeof (struct lpfc_name));
2105 memcpy(&ap->nodeName, &vport->fc_nodename, sizeof (struct lpfc_name));
2106 ap->DID = be32_to_cpu(vport->fc_myDID);
dea31012005-04-17 16:05:31 -05002107
2108 phba->fc_stat.elsXmitACC++;
2109 elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
dea31012005-04-17 16:05:31 -05002110 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
dea31012005-04-17 16:05:31 -05002111 if (rc == IOCB_ERROR) {
2112 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002113 return 1;
dea31012005-04-17 16:05:31 -05002114 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002115 return 0;
dea31012005-04-17 16:05:31 -05002116}
2117
2118int
James Smart2e0fef82007-06-17 19:56:36 -05002119lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
James Smart5b8bd0c2007-04-25 09:52:49 -04002120 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05002121{
James Smart2e0fef82007-06-17 19:56:36 -05002122 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002123 PRLI *npr;
2124 lpfc_vpd_t *vpd;
2125 IOCB_t *icmd;
2126 IOCB_t *oldcmd;
2127 struct lpfc_iocbq *elsiocb;
2128 struct lpfc_sli_ring *pring;
2129 struct lpfc_sli *psli;
2130 uint8_t *pcmd;
2131 uint16_t cmdsize;
2132 int rc;
2133
2134 psli = &phba->sli;
2135 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
2136
2137 cmdsize = sizeof (uint32_t) + sizeof (PRLI);
James Smart2e0fef82007-06-17 19:56:36 -05002138 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
James Smarted957682007-06-17 19:56:37 -05002139 ndlp->nlp_DID, (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK)));
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002140 if (!elsiocb)
2141 return 1;
dea31012005-04-17 16:05:31 -05002142
dea31012005-04-17 16:05:31 -05002143 icmd = &elsiocb->iocb;
2144 oldcmd = &oldiocb->iocb;
2145 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
James Smart5b8bd0c2007-04-25 09:52:49 -04002146
2147 /* Xmit PRLI ACC response tag <ulpIoTag> */
2148 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
2149 "%d:0131 Xmit PRLI ACC response tag x%x xri x%x, "
2150 "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
2151 phba->brd_no, elsiocb->iotag,
2152 elsiocb->iocb.ulpContext, ndlp->nlp_DID,
2153 ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
2154
dea31012005-04-17 16:05:31 -05002155 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2156
2157 *((uint32_t *) (pcmd)) = (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK));
2158 pcmd += sizeof (uint32_t);
2159
2160 /* For PRLI, remainder of payload is PRLI parameter page */
2161 memset(pcmd, 0, sizeof (PRLI));
2162
2163 npr = (PRLI *) pcmd;
2164 vpd = &phba->vpd;
2165 /*
2166 * If our firmware version is 3.20 or later,
2167 * set the following bits for FC-TAPE support.
2168 */
2169 if (vpd->rev.feaLevelHigh >= 0x02) {
2170 npr->ConfmComplAllowed = 1;
2171 npr->Retry = 1;
2172 npr->TaskRetryIdReq = 1;
2173 }
2174
2175 npr->acceptRspCode = PRLI_REQ_EXECUTED;
2176 npr->estabImagePair = 1;
2177 npr->readXferRdyDis = 1;
2178 npr->ConfmComplAllowed = 1;
2179
2180 npr->prliType = PRLI_FCP_TYPE;
2181 npr->initiatorFunc = 1;
2182
2183 phba->fc_stat.elsXmitACC++;
2184 elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
2185
dea31012005-04-17 16:05:31 -05002186 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
dea31012005-04-17 16:05:31 -05002187 if (rc == IOCB_ERROR) {
2188 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002189 return 1;
dea31012005-04-17 16:05:31 -05002190 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002191 return 0;
dea31012005-04-17 16:05:31 -05002192}
2193
2194static int
James Smart2e0fef82007-06-17 19:56:36 -05002195lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format,
James Smart329f9bc2007-04-25 09:53:01 -04002196 struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05002197{
James Smart2e0fef82007-06-17 19:56:36 -05002198 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002199 RNID *rn;
James Smart2e0fef82007-06-17 19:56:36 -05002200 IOCB_t *icmd, *oldcmd;
dea31012005-04-17 16:05:31 -05002201 struct lpfc_iocbq *elsiocb;
2202 struct lpfc_sli_ring *pring;
2203 struct lpfc_sli *psli;
2204 uint8_t *pcmd;
2205 uint16_t cmdsize;
2206 int rc;
2207
2208 psli = &phba->sli;
2209 pring = &psli->ring[LPFC_ELS_RING];
2210
2211 cmdsize = sizeof (uint32_t) + sizeof (uint32_t)
2212 + (2 * sizeof (struct lpfc_name));
2213 if (format)
2214 cmdsize += sizeof (RNID_TOP_DISC);
2215
James Smart2e0fef82007-06-17 19:56:36 -05002216 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
2217 ndlp->nlp_DID, ELS_CMD_ACC);
James Smart488d1462006-03-07 15:02:37 -05002218 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002219 return 1;
dea31012005-04-17 16:05:31 -05002220
dea31012005-04-17 16:05:31 -05002221 icmd = &elsiocb->iocb;
2222 oldcmd = &oldiocb->iocb;
2223 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
James Smart5b8bd0c2007-04-25 09:52:49 -04002224
2225 /* Xmit RNID ACC response tag <ulpIoTag> */
2226 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
2227 "%d:0132 Xmit RNID ACC response tag x%x "
2228 "xri x%x\n",
2229 phba->brd_no, elsiocb->iotag,
2230 elsiocb->iocb.ulpContext);
2231
dea31012005-04-17 16:05:31 -05002232 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2233
2234 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
2235 pcmd += sizeof (uint32_t);
2236
2237 memset(pcmd, 0, sizeof (RNID));
2238 rn = (RNID *) (pcmd);
2239 rn->Format = format;
2240 rn->CommonLen = (2 * sizeof (struct lpfc_name));
James Smart2e0fef82007-06-17 19:56:36 -05002241 memcpy(&rn->portName, &vport->fc_portname, sizeof (struct lpfc_name));
2242 memcpy(&rn->nodeName, &vport->fc_nodename, sizeof (struct lpfc_name));
dea31012005-04-17 16:05:31 -05002243 switch (format) {
2244 case 0:
2245 rn->SpecificLen = 0;
2246 break;
2247 case RNID_TOPOLOGY_DISC:
2248 rn->SpecificLen = sizeof (RNID_TOP_DISC);
2249 memcpy(&rn->un.topologyDisc.portName,
James Smart2e0fef82007-06-17 19:56:36 -05002250 &vport->fc_portname, sizeof (struct lpfc_name));
dea31012005-04-17 16:05:31 -05002251 rn->un.topologyDisc.unitType = RNID_HBA;
2252 rn->un.topologyDisc.physPort = 0;
2253 rn->un.topologyDisc.attachedNodes = 0;
2254 break;
2255 default:
2256 rn->CommonLen = 0;
2257 rn->SpecificLen = 0;
2258 break;
2259 }
2260
2261 phba->fc_stat.elsXmitACC++;
2262 elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
James Smart329f9bc2007-04-25 09:53:01 -04002263 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05002264 elsiocb->context1 = NULL; /* Don't need ndlp for cmpl,
2265 * it could be freed */
2266
dea31012005-04-17 16:05:31 -05002267 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
dea31012005-04-17 16:05:31 -05002268 if (rc == IOCB_ERROR) {
2269 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002270 return 1;
dea31012005-04-17 16:05:31 -05002271 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002272 return 0;
dea31012005-04-17 16:05:31 -05002273}
2274
2275int
James Smart2e0fef82007-06-17 19:56:36 -05002276lpfc_els_disc_adisc(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05002277{
James Smart2e0fef82007-06-17 19:56:36 -05002278 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05002279 struct lpfc_nodelist *ndlp, *next_ndlp;
James Smart2e0fef82007-06-17 19:56:36 -05002280 int sentadisc = 0;
dea31012005-04-17 16:05:31 -05002281
James Smart685f0bf2007-04-25 09:53:08 -04002282 /* go thru NPR nodes and issue any remaining ELS ADISCs */
James Smart2e0fef82007-06-17 19:56:36 -05002283 list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
James Smart685f0bf2007-04-25 09:53:08 -04002284 if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
2285 (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
2286 (ndlp->nlp_flag & NLP_NPR_ADISC) != 0) {
James Smart2e0fef82007-06-17 19:56:36 -05002287 spin_lock_irq(shost->host_lock);
James Smart685f0bf2007-04-25 09:53:08 -04002288 ndlp->nlp_flag &= ~NLP_NPR_ADISC;
James Smart2e0fef82007-06-17 19:56:36 -05002289 spin_unlock_irq(shost->host_lock);
James Smart685f0bf2007-04-25 09:53:08 -04002290 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002291 lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
2292 lpfc_issue_els_adisc(vport, ndlp, 0);
James Smart685f0bf2007-04-25 09:53:08 -04002293 sentadisc++;
James Smart2e0fef82007-06-17 19:56:36 -05002294 vport->num_disc_nodes++;
2295 if (vport->num_disc_nodes >=
2296 vport->phba->cfg_discovery_threads) {
2297 spin_lock_irq(shost->host_lock);
2298 vport->fc_flag |= FC_NLP_MORE;
2299 spin_unlock_irq(shost->host_lock);
James Smart685f0bf2007-04-25 09:53:08 -04002300 break;
dea31012005-04-17 16:05:31 -05002301 }
2302 }
2303 }
2304 if (sentadisc == 0) {
James Smart2e0fef82007-06-17 19:56:36 -05002305 spin_lock_irq(shost->host_lock);
2306 vport->fc_flag &= ~FC_NLP_MORE;
2307 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05002308 }
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05002309 return sentadisc;
dea31012005-04-17 16:05:31 -05002310}
2311
2312int
James Smart2e0fef82007-06-17 19:56:36 -05002313lpfc_els_disc_plogi(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05002314{
James Smart2e0fef82007-06-17 19:56:36 -05002315 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05002316 struct lpfc_nodelist *ndlp, *next_ndlp;
James Smart2e0fef82007-06-17 19:56:36 -05002317 int sentplogi = 0;
dea31012005-04-17 16:05:31 -05002318
James Smart2e0fef82007-06-17 19:56:36 -05002319 /* go thru NPR nodes and issue any remaining ELS PLOGIs */
2320 list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
James Smart685f0bf2007-04-25 09:53:08 -04002321 if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
2322 (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
2323 (ndlp->nlp_flag & NLP_DELAY_TMO) == 0 &&
2324 (ndlp->nlp_flag & NLP_NPR_ADISC) == 0) {
2325 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002326 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
2327 lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
James Smart685f0bf2007-04-25 09:53:08 -04002328 sentplogi++;
James Smart2e0fef82007-06-17 19:56:36 -05002329 vport->num_disc_nodes++;
2330 if (vport->num_disc_nodes >=
2331 vport->phba->cfg_discovery_threads) {
2332 spin_lock_irq(shost->host_lock);
2333 vport->fc_flag |= FC_NLP_MORE;
2334 spin_unlock_irq(shost->host_lock);
James Smart685f0bf2007-04-25 09:53:08 -04002335 break;
dea31012005-04-17 16:05:31 -05002336 }
2337 }
2338 }
2339 if (sentplogi == 0) {
James Smart2e0fef82007-06-17 19:56:36 -05002340 spin_lock_irq(shost->host_lock);
2341 vport->fc_flag &= ~FC_NLP_MORE;
2342 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05002343 }
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05002344 return sentplogi;
dea31012005-04-17 16:05:31 -05002345}
2346
2347int
James Smart2e0fef82007-06-17 19:56:36 -05002348lpfc_els_flush_rscn(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05002349{
James Smart2e0fef82007-06-17 19:56:36 -05002350 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
2351 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002352 struct lpfc_dmabuf *mp;
2353 int i;
2354
James Smart2e0fef82007-06-17 19:56:36 -05002355 for (i = 0; i < vport->fc_rscn_id_cnt; i++) {
2356 mp = vport->fc_rscn_id_list[i];
James Smarted957682007-06-17 19:56:37 -05002357 if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
2358 lpfc_sli_hbqbuf_free(phba, mp->virt, mp->phys);
2359 else {
2360 lpfc_mbuf_free(phba, mp->virt, mp->phys);
2361 kfree(mp);
2362 }
James Smart2e0fef82007-06-17 19:56:36 -05002363 vport->fc_rscn_id_list[i] = NULL;
dea31012005-04-17 16:05:31 -05002364 }
James Smart2e0fef82007-06-17 19:56:36 -05002365 spin_lock_irq(shost->host_lock);
2366 vport->fc_rscn_id_cnt = 0;
2367 vport->fc_flag &= ~(FC_RSCN_MODE | FC_RSCN_DISCOVERY);
2368 spin_unlock_irq(shost->host_lock);
2369 lpfc_can_disctmo(vport);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002370 return 0;
dea31012005-04-17 16:05:31 -05002371}
2372
2373int
James Smart2e0fef82007-06-17 19:56:36 -05002374lpfc_rscn_payload_check(struct lpfc_vport *vport, uint32_t did)
dea31012005-04-17 16:05:31 -05002375{
2376 D_ID ns_did;
2377 D_ID rscn_did;
2378 struct lpfc_dmabuf *mp;
2379 uint32_t *lp;
2380 uint32_t payload_len, cmd, i, match;
James Smart2e0fef82007-06-17 19:56:36 -05002381 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002382
2383 ns_did.un.word = did;
2384 match = 0;
2385
2386 /* Never match fabric nodes for RSCNs */
2387 if ((did & Fabric_DID_MASK) == Fabric_DID_MASK)
James Smart2e0fef82007-06-17 19:56:36 -05002388 return 0;
dea31012005-04-17 16:05:31 -05002389
2390 /* If we are doing a FULL RSCN rediscovery, match everything */
James Smart2e0fef82007-06-17 19:56:36 -05002391 if (vport->fc_flag & FC_RSCN_DISCOVERY)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002392 return did;
dea31012005-04-17 16:05:31 -05002393
James Smart2e0fef82007-06-17 19:56:36 -05002394 for (i = 0; i < vport->fc_rscn_id_cnt; i++) {
2395 mp = vport->fc_rscn_id_list[i];
dea31012005-04-17 16:05:31 -05002396 lp = (uint32_t *) mp->virt;
2397 cmd = *lp++;
2398 payload_len = be32_to_cpu(cmd) & 0xffff; /* payload length */
2399 payload_len -= sizeof (uint32_t); /* take off word 0 */
2400 while (payload_len) {
2401 rscn_did.un.word = *lp++;
2402 rscn_did.un.word = be32_to_cpu(rscn_did.un.word);
2403 payload_len -= sizeof (uint32_t);
2404 switch (rscn_did.un.b.resv) {
2405 case 0: /* Single N_Port ID effected */
James Smart2e0fef82007-06-17 19:56:36 -05002406 if (ns_did.un.word == rscn_did.un.word)
dea31012005-04-17 16:05:31 -05002407 match = did;
dea31012005-04-17 16:05:31 -05002408 break;
2409 case 1: /* Whole N_Port Area effected */
2410 if ((ns_did.un.b.domain == rscn_did.un.b.domain)
2411 && (ns_did.un.b.area == rscn_did.un.b.area))
dea31012005-04-17 16:05:31 -05002412 match = did;
dea31012005-04-17 16:05:31 -05002413 break;
2414 case 2: /* Whole N_Port Domain effected */
2415 if (ns_did.un.b.domain == rscn_did.un.b.domain)
dea31012005-04-17 16:05:31 -05002416 match = did;
dea31012005-04-17 16:05:31 -05002417 break;
2418 case 3: /* Whole Fabric effected */
2419 match = did;
2420 break;
2421 default:
James Smart2e0fef82007-06-17 19:56:36 -05002422 /* Unknown Identifier in RSCN node */
dea31012005-04-17 16:05:31 -05002423 lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
2424 "%d:0217 Unknown Identifier in "
2425 "RSCN payload Data: x%x\n",
2426 phba->brd_no, rscn_did.un.word);
2427 break;
2428 }
James Smart2e0fef82007-06-17 19:56:36 -05002429 if (match)
dea31012005-04-17 16:05:31 -05002430 break;
2431 }
2432 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002433 return match;
dea31012005-04-17 16:05:31 -05002434}
2435
2436static int
James Smart2e0fef82007-06-17 19:56:36 -05002437lpfc_rscn_recovery_check(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05002438{
James Smart685f0bf2007-04-25 09:53:08 -04002439 struct lpfc_nodelist *ndlp = NULL;
dea31012005-04-17 16:05:31 -05002440
2441 /* Look at all nodes effected by pending RSCNs and move
James Smart685f0bf2007-04-25 09:53:08 -04002442 * them to NPR state.
dea31012005-04-17 16:05:31 -05002443 */
James Smart685f0bf2007-04-25 09:53:08 -04002444
James Smart2e0fef82007-06-17 19:56:36 -05002445 list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
James Smart685f0bf2007-04-25 09:53:08 -04002446 if (ndlp->nlp_state == NLP_STE_UNUSED_NODE ||
James Smart2e0fef82007-06-17 19:56:36 -05002447 lpfc_rscn_payload_check(vport, ndlp->nlp_DID) == 0)
dea31012005-04-17 16:05:31 -05002448 continue;
2449
James Smart2e0fef82007-06-17 19:56:36 -05002450 lpfc_disc_state_machine(vport, ndlp, NULL,
dea31012005-04-17 16:05:31 -05002451 NLP_EVT_DEVICE_RECOVERY);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05002452
James Smart685f0bf2007-04-25 09:53:08 -04002453 /*
2454 * Make sure NLP_DELAY_TMO is NOT running after a device
2455 * recovery event.
2456 */
2457 if (ndlp->nlp_flag & NLP_DELAY_TMO)
James Smart2e0fef82007-06-17 19:56:36 -05002458 lpfc_cancel_retry_delay_tmo(vport, ndlp);
dea31012005-04-17 16:05:31 -05002459 }
James Smart685f0bf2007-04-25 09:53:08 -04002460
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002461 return 0;
dea31012005-04-17 16:05:31 -05002462}
2463
2464static int
James Smart2e0fef82007-06-17 19:56:36 -05002465lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
2466 struct lpfc_nodelist *ndlp, uint8_t newnode)
dea31012005-04-17 16:05:31 -05002467{
James Smart2e0fef82007-06-17 19:56:36 -05002468 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
2469 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002470 struct lpfc_dmabuf *pcmd;
2471 uint32_t *lp;
2472 IOCB_t *icmd;
2473 uint32_t payload_len, cmd;
James Smartd2873e42006-08-18 17:46:43 -04002474 int i;
dea31012005-04-17 16:05:31 -05002475
2476 icmd = &cmdiocb->iocb;
2477 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
2478 lp = (uint32_t *) pcmd->virt;
2479
2480 cmd = *lp++;
2481 payload_len = be32_to_cpu(cmd) & 0xffff; /* payload length */
2482 payload_len -= sizeof (uint32_t); /* take off word 0 */
2483 cmd &= ELS_CMD_MASK;
2484
2485 /* RSCN received */
James Smarted957682007-06-17 19:56:37 -05002486 lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
dea31012005-04-17 16:05:31 -05002487 "%d:0214 RSCN received Data: x%x x%x x%x x%x\n",
James Smart2e0fef82007-06-17 19:56:36 -05002488 phba->brd_no, vport->fc_flag, payload_len, *lp,
2489 vport->fc_rscn_id_cnt);
dea31012005-04-17 16:05:31 -05002490
James Smartd2873e42006-08-18 17:46:43 -04002491 for (i = 0; i < payload_len/sizeof(uint32_t); i++)
James Smart2e0fef82007-06-17 19:56:36 -05002492 fc_host_post_event(shost, fc_get_event_number(),
James Smartd2873e42006-08-18 17:46:43 -04002493 FCH_EVT_RSCN, lp[i]);
2494
dea31012005-04-17 16:05:31 -05002495 /* If we are about to begin discovery, just ACC the RSCN.
2496 * Discovery processing will satisfy it.
2497 */
James Smart2e0fef82007-06-17 19:56:36 -05002498 if (vport->port_state <= LPFC_NS_QRY) {
2499 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL,
dea31012005-04-17 16:05:31 -05002500 newnode);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002501 return 0;
dea31012005-04-17 16:05:31 -05002502 }
2503
2504 /* If we are already processing an RSCN, save the received
2505 * RSCN payload buffer, cmdiocb->context2 to process later.
2506 */
James Smart2e0fef82007-06-17 19:56:36 -05002507 if (vport->fc_flag & (FC_RSCN_MODE | FC_NDISC_ACTIVE)) {
2508 if ((vport->fc_rscn_id_cnt < FC_MAX_HOLD_RSCN) &&
2509 !(vport->fc_flag & FC_RSCN_DISCOVERY)) {
2510 spin_lock_irq(shost->host_lock);
2511 vport->fc_flag |= FC_RSCN_MODE;
2512 spin_unlock_irq(shost->host_lock);
2513 vport->fc_rscn_id_list[vport->fc_rscn_id_cnt++] = pcmd;
dea31012005-04-17 16:05:31 -05002514
2515 /* If we zero, cmdiocb->context2, the calling
2516 * routine will not try to free it.
2517 */
2518 cmdiocb->context2 = NULL;
2519
2520 /* Deferred RSCN */
2521 lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
2522 "%d:0235 Deferred RSCN "
2523 "Data: x%x x%x x%x\n",
James Smart2e0fef82007-06-17 19:56:36 -05002524 phba->brd_no, vport->fc_rscn_id_cnt,
2525 vport->fc_flag,
2526 vport->port_state);
dea31012005-04-17 16:05:31 -05002527 } else {
James Smart2e0fef82007-06-17 19:56:36 -05002528 spin_lock_irq(shost->host_lock);
2529 vport->fc_flag |= FC_RSCN_DISCOVERY;
2530 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05002531 /* ReDiscovery RSCN */
2532 lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
2533 "%d:0234 ReDiscovery RSCN "
2534 "Data: x%x x%x x%x\n",
James Smart2e0fef82007-06-17 19:56:36 -05002535 phba->brd_no, vport->fc_rscn_id_cnt,
2536 vport->fc_flag,
2537 vport->port_state);
dea31012005-04-17 16:05:31 -05002538 }
2539 /* Send back ACC */
James Smart2e0fef82007-06-17 19:56:36 -05002540 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL,
dea31012005-04-17 16:05:31 -05002541 newnode);
2542
2543 /* send RECOVERY event for ALL nodes that match RSCN payload */
James Smart2e0fef82007-06-17 19:56:36 -05002544 lpfc_rscn_recovery_check(vport);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002545 return 0;
dea31012005-04-17 16:05:31 -05002546 }
2547
James Smart2e0fef82007-06-17 19:56:36 -05002548 spin_lock_irq(shost->host_lock);
2549 vport->fc_flag |= FC_RSCN_MODE;
2550 spin_unlock_irq(shost->host_lock);
2551 vport->fc_rscn_id_list[vport->fc_rscn_id_cnt++] = pcmd;
dea31012005-04-17 16:05:31 -05002552 /*
2553 * If we zero, cmdiocb->context2, the calling routine will
2554 * not try to free it.
2555 */
2556 cmdiocb->context2 = NULL;
2557
James Smart2e0fef82007-06-17 19:56:36 -05002558 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -05002559
2560 /* Send back ACC */
James Smart2e0fef82007-06-17 19:56:36 -05002561 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, newnode);
dea31012005-04-17 16:05:31 -05002562
2563 /* send RECOVERY event for ALL nodes that match RSCN payload */
James Smart2e0fef82007-06-17 19:56:36 -05002564 lpfc_rscn_recovery_check(vport);
dea31012005-04-17 16:05:31 -05002565
James Smart2e0fef82007-06-17 19:56:36 -05002566 return lpfc_els_handle_rscn(vport);
dea31012005-04-17 16:05:31 -05002567}
2568
2569int
James Smart2e0fef82007-06-17 19:56:36 -05002570lpfc_els_handle_rscn(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05002571{
2572 struct lpfc_nodelist *ndlp;
James Smart2e0fef82007-06-17 19:56:36 -05002573 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002574
2575 /* Start timer for RSCN processing */
James Smart2e0fef82007-06-17 19:56:36 -05002576 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -05002577
2578 /* RSCN processed */
James Smarted957682007-06-17 19:56:37 -05002579 lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
dea31012005-04-17 16:05:31 -05002580 "%d:0215 RSCN processed Data: x%x x%x x%x x%x\n",
2581 phba->brd_no,
James Smart2e0fef82007-06-17 19:56:36 -05002582 vport->fc_flag, 0, vport->fc_rscn_id_cnt,
2583 vport->port_state);
dea31012005-04-17 16:05:31 -05002584
2585 /* To process RSCN, first compare RSCN data with NameServer */
James Smart2e0fef82007-06-17 19:56:36 -05002586 vport->fc_ns_retry = 0;
2587 ndlp = lpfc_findnode_did(vport, NameServer_DID);
James Smart685f0bf2007-04-25 09:53:08 -04002588 if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
dea31012005-04-17 16:05:31 -05002589 /* Good ndlp, issue CT Request to NameServer */
James Smart2e0fef82007-06-17 19:56:36 -05002590 if (lpfc_ns_cmd(vport, ndlp, SLI_CTNS_GID_FT) == 0)
dea31012005-04-17 16:05:31 -05002591 /* Wait for NameServer query cmpl before we can
2592 continue */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002593 return 1;
dea31012005-04-17 16:05:31 -05002594 } else {
2595 /* If login to NameServer does not exist, issue one */
2596 /* Good status, issue PLOGI to NameServer */
James Smart2e0fef82007-06-17 19:56:36 -05002597 ndlp = lpfc_findnode_did(vport, NameServer_DID);
2598 if (ndlp)
dea31012005-04-17 16:05:31 -05002599 /* Wait for NameServer login cmpl before we can
2600 continue */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002601 return 1;
James Smart2e0fef82007-06-17 19:56:36 -05002602
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002603 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
2604 if (!ndlp) {
James Smart2e0fef82007-06-17 19:56:36 -05002605 lpfc_els_flush_rscn(vport);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002606 return 0;
dea31012005-04-17 16:05:31 -05002607 } else {
James Smart2e0fef82007-06-17 19:56:36 -05002608 lpfc_nlp_init(vport, ndlp, NameServer_DID);
dea31012005-04-17 16:05:31 -05002609 ndlp->nlp_type |= NLP_FABRIC;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05002610 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002611 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
2612 lpfc_issue_els_plogi(vport, NameServer_DID, 0);
dea31012005-04-17 16:05:31 -05002613 /* Wait for NameServer login cmpl before we can
2614 continue */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002615 return 1;
dea31012005-04-17 16:05:31 -05002616 }
2617 }
2618
James Smart2e0fef82007-06-17 19:56:36 -05002619 lpfc_els_flush_rscn(vport);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002620 return 0;
dea31012005-04-17 16:05:31 -05002621}
2622
2623static int
James Smart2e0fef82007-06-17 19:56:36 -05002624lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
2625 struct lpfc_nodelist *ndlp, uint8_t newnode)
dea31012005-04-17 16:05:31 -05002626{
James Smart2e0fef82007-06-17 19:56:36 -05002627 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
2628 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002629 struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
2630 uint32_t *lp = (uint32_t *) pcmd->virt;
2631 IOCB_t *icmd = &cmdiocb->iocb;
2632 struct serv_parm *sp;
2633 LPFC_MBOXQ_t *mbox;
2634 struct ls_rjt stat;
2635 uint32_t cmd, did;
2636 int rc;
2637
2638 cmd = *lp++;
2639 sp = (struct serv_parm *) lp;
2640
2641 /* FLOGI received */
2642
James Smart2e0fef82007-06-17 19:56:36 -05002643 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -05002644
2645 if (phba->fc_topology == TOPOLOGY_LOOP) {
2646 /* We should never receive a FLOGI in loop mode, ignore it */
2647 did = icmd->un.elsreq64.remoteID;
2648
2649 /* An FLOGI ELS command <elsCmd> was received from DID <did> in
2650 Loop Mode */
2651 lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
2652 "%d:0113 An FLOGI ELS command x%x was received "
2653 "from DID x%x in Loop Mode\n",
2654 phba->brd_no, cmd, did);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002655 return 1;
dea31012005-04-17 16:05:31 -05002656 }
2657
2658 did = Fabric_DID;
2659
James Smart2e0fef82007-06-17 19:56:36 -05002660 if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3))) {
dea31012005-04-17 16:05:31 -05002661 /* For a FLOGI we accept, then if our portname is greater
2662 * then the remote portname we initiate Nport login.
2663 */
2664
James Smart2e0fef82007-06-17 19:56:36 -05002665 rc = memcmp(&vport->fc_portname, &sp->portName,
dea31012005-04-17 16:05:31 -05002666 sizeof (struct lpfc_name));
2667
2668 if (!rc) {
James Smart2e0fef82007-06-17 19:56:36 -05002669 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
2670 if (!mbox)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002671 return 1;
James Smart2e0fef82007-06-17 19:56:36 -05002672
dea31012005-04-17 16:05:31 -05002673 lpfc_linkdown(phba);
2674 lpfc_init_link(phba, mbox,
2675 phba->cfg_topology,
2676 phba->cfg_link_speed);
2677 mbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
2678 mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
James Smarted957682007-06-17 19:56:37 -05002679 mbox->vport = vport;
dea31012005-04-17 16:05:31 -05002680 rc = lpfc_sli_issue_mbox
2681 (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
James Smart5b8bd0c2007-04-25 09:52:49 -04002682 lpfc_set_loopback_flag(phba);
dea31012005-04-17 16:05:31 -05002683 if (rc == MBX_NOT_FINISHED) {
James Smart329f9bc2007-04-25 09:53:01 -04002684 mempool_free(mbox, phba->mbox_mem_pool);
dea31012005-04-17 16:05:31 -05002685 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002686 return 1;
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05002687 } else if (rc > 0) { /* greater than */
James Smart2e0fef82007-06-17 19:56:36 -05002688 spin_lock_irq(shost->host_lock);
2689 vport->fc_flag |= FC_PT2PT_PLOGI;
2690 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05002691 }
James Smart2e0fef82007-06-17 19:56:36 -05002692 spin_lock_irq(shost->host_lock);
2693 vport->fc_flag |= FC_PT2PT;
2694 vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
2695 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05002696 } else {
2697 /* Reject this request because invalid parameters */
2698 stat.un.b.lsRjtRsvd0 = 0;
2699 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
2700 stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
2701 stat.un.b.vendorUnique = 0;
James Smart2e0fef82007-06-17 19:56:36 -05002702 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002703 return 1;
dea31012005-04-17 16:05:31 -05002704 }
2705
2706 /* Send back ACC */
James Smart2e0fef82007-06-17 19:56:36 -05002707 lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL, newnode);
dea31012005-04-17 16:05:31 -05002708
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002709 return 0;
dea31012005-04-17 16:05:31 -05002710}
2711
2712static int
James Smart2e0fef82007-06-17 19:56:36 -05002713lpfc_els_rcv_rnid(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
2714 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05002715{
2716 struct lpfc_dmabuf *pcmd;
2717 uint32_t *lp;
2718 IOCB_t *icmd;
2719 RNID *rn;
2720 struct ls_rjt stat;
2721 uint32_t cmd, did;
2722
2723 icmd = &cmdiocb->iocb;
2724 did = icmd->un.elsreq64.remoteID;
2725 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
2726 lp = (uint32_t *) pcmd->virt;
2727
2728 cmd = *lp++;
2729 rn = (RNID *) lp;
2730
2731 /* RNID received */
2732
2733 switch (rn->Format) {
2734 case 0:
2735 case RNID_TOPOLOGY_DISC:
2736 /* Send back ACC */
James Smart2e0fef82007-06-17 19:56:36 -05002737 lpfc_els_rsp_rnid_acc(vport, rn->Format, cmdiocb, ndlp);
dea31012005-04-17 16:05:31 -05002738 break;
2739 default:
2740 /* Reject this request because format not supported */
2741 stat.un.b.lsRjtRsvd0 = 0;
2742 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
2743 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
2744 stat.un.b.vendorUnique = 0;
James Smart2e0fef82007-06-17 19:56:36 -05002745 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp);
dea31012005-04-17 16:05:31 -05002746 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002747 return 0;
dea31012005-04-17 16:05:31 -05002748}
2749
2750static int
James Smart2e0fef82007-06-17 19:56:36 -05002751lpfc_els_rcv_lirr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
2752 struct lpfc_nodelist *ndlp)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002753{
2754 struct ls_rjt stat;
2755
2756 /* For now, unconditionally reject this command */
2757 stat.un.b.lsRjtRsvd0 = 0;
2758 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
2759 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
2760 stat.un.b.vendorUnique = 0;
James Smart2e0fef82007-06-17 19:56:36 -05002761 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002762 return 0;
2763}
2764
Jamie Wellnitz082c0262006-02-28 19:25:30 -05002765static void
James Smart329f9bc2007-04-25 09:53:01 -04002766lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002767{
James Smart2e0fef82007-06-17 19:56:36 -05002768 struct lpfc_sli *psli = &phba->sli;
2769 struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002770 MAILBOX_t *mb;
2771 IOCB_t *icmd;
2772 RPS_RSP *rps_rsp;
2773 uint8_t *pcmd;
2774 struct lpfc_iocbq *elsiocb;
2775 struct lpfc_nodelist *ndlp;
2776 uint16_t xri, status;
2777 uint32_t cmdsize;
2778
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002779 mb = &pmb->mb;
2780
2781 ndlp = (struct lpfc_nodelist *) pmb->context2;
2782 xri = (uint16_t) ((unsigned long)(pmb->context1));
Randy Dunlap041976f2006-06-25 01:58:51 -07002783 pmb->context1 = NULL;
2784 pmb->context2 = NULL;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002785
2786 if (mb->mbxStatus) {
James Smart329f9bc2007-04-25 09:53:01 -04002787 mempool_free(pmb, phba->mbox_mem_pool);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002788 return;
2789 }
2790
2791 cmdsize = sizeof(RPS_RSP) + sizeof(uint32_t);
James Smart329f9bc2007-04-25 09:53:01 -04002792 mempool_free(pmb, phba->mbox_mem_pool);
James Smart2e0fef82007-06-17 19:56:36 -05002793 elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize,
2794 lpfc_max_els_tries, ndlp,
2795 ndlp->nlp_DID, ELS_CMD_ACC);
James Smart329f9bc2007-04-25 09:53:01 -04002796 lpfc_nlp_put(ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002797 if (!elsiocb)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002798 return;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002799
2800 icmd = &elsiocb->iocb;
2801 icmd->ulpContext = xri;
2802
2803 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2804 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
2805 pcmd += sizeof (uint32_t); /* Skip past command */
2806 rps_rsp = (RPS_RSP *)pcmd;
2807
2808 if (phba->fc_topology != TOPOLOGY_LOOP)
2809 status = 0x10;
2810 else
2811 status = 0x8;
James Smart2e0fef82007-06-17 19:56:36 -05002812 if (phba->pport->fc_flag & FC_FABRIC)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002813 status |= 0x4;
2814
2815 rps_rsp->rsvd1 = 0;
2816 rps_rsp->portStatus = be16_to_cpu(status);
2817 rps_rsp->linkFailureCnt = be32_to_cpu(mb->un.varRdLnk.linkFailureCnt);
2818 rps_rsp->lossSyncCnt = be32_to_cpu(mb->un.varRdLnk.lossSyncCnt);
2819 rps_rsp->lossSignalCnt = be32_to_cpu(mb->un.varRdLnk.lossSignalCnt);
2820 rps_rsp->primSeqErrCnt = be32_to_cpu(mb->un.varRdLnk.primSeqErrCnt);
2821 rps_rsp->invalidXmitWord = be32_to_cpu(mb->un.varRdLnk.invalidXmitWord);
2822 rps_rsp->crcCnt = be32_to_cpu(mb->un.varRdLnk.crcCnt);
2823
2824 /* Xmit ELS RPS ACC response tag <ulpIoTag> */
2825 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart5b8bd0c2007-04-25 09:52:49 -04002826 "%d:0118 Xmit ELS RPS ACC response tag x%x xri x%x, "
2827 "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
2828 phba->brd_no, elsiocb->iotag,
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002829 elsiocb->iocb.ulpContext, ndlp->nlp_DID,
2830 ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
2831
2832 elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
2833 phba->fc_stat.elsXmitACC++;
James Smarted957682007-06-17 19:56:37 -05002834 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002835 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002836 return;
2837}
2838
2839static int
James Smart2e0fef82007-06-17 19:56:36 -05002840lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
2841 struct lpfc_nodelist *ndlp)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002842{
James Smart2e0fef82007-06-17 19:56:36 -05002843 struct lpfc_hba *phba = vport->phba;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002844 uint32_t *lp;
2845 uint8_t flag;
2846 LPFC_MBOXQ_t *mbox;
2847 struct lpfc_dmabuf *pcmd;
2848 RPS *rps;
2849 struct ls_rjt stat;
2850
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05002851 if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
2852 (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) {
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002853 stat.un.b.lsRjtRsvd0 = 0;
2854 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
2855 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
2856 stat.un.b.vendorUnique = 0;
James Smart2e0fef82007-06-17 19:56:36 -05002857 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002858 }
2859
2860 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
2861 lp = (uint32_t *) pcmd->virt;
2862 flag = (be32_to_cpu(*lp++) & 0xf);
2863 rps = (RPS *) lp;
2864
2865 if ((flag == 0) ||
2866 ((flag == 1) && (be32_to_cpu(rps->un.portNum) == 0)) ||
James Smart2e0fef82007-06-17 19:56:36 -05002867 ((flag == 2) && (memcmp(&rps->un.portName, &vport->fc_portname,
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002868 sizeof (struct lpfc_name)) == 0))) {
James Smart2e0fef82007-06-17 19:56:36 -05002869
2870 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC);
2871 if (mbox) {
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002872 lpfc_read_lnk_stat(phba, mbox);
2873 mbox->context1 =
2874 (void *)((unsigned long)cmdiocb->iocb.ulpContext);
James Smart329f9bc2007-04-25 09:53:01 -04002875 mbox->context2 = lpfc_nlp_get(ndlp);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002876 mbox->mbox_cmpl = lpfc_els_rsp_rps_acc;
2877 if (lpfc_sli_issue_mbox (phba, mbox,
James Smart2e0fef82007-06-17 19:56:36 -05002878 (MBX_NOWAIT | MBX_STOP_IOCB)) != MBX_NOT_FINISHED)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002879 /* Mbox completion will send ELS Response */
2880 return 0;
James Smart2e0fef82007-06-17 19:56:36 -05002881
James Smart329f9bc2007-04-25 09:53:01 -04002882 lpfc_nlp_put(ndlp);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002883 mempool_free(mbox, phba->mbox_mem_pool);
2884 }
2885 }
2886 stat.un.b.lsRjtRsvd0 = 0;
2887 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
2888 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
2889 stat.un.b.vendorUnique = 0;
James Smart2e0fef82007-06-17 19:56:36 -05002890 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002891 return 0;
2892}
2893
Jamie Wellnitz082c0262006-02-28 19:25:30 -05002894static int
James Smart2e0fef82007-06-17 19:56:36 -05002895lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize,
2896 struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002897{
James Smart2e0fef82007-06-17 19:56:36 -05002898 struct lpfc_hba *phba = vport->phba;
2899 IOCB_t *icmd, *oldcmd;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002900 RPL_RSP rpl_rsp;
2901 struct lpfc_iocbq *elsiocb;
James Smart2e0fef82007-06-17 19:56:36 -05002902 struct lpfc_sli *psli = &phba->sli;
2903 struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002904 uint8_t *pcmd;
2905
James Smart2e0fef82007-06-17 19:56:36 -05002906 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
2907 ndlp->nlp_DID, ELS_CMD_ACC);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002908
James Smart488d1462006-03-07 15:02:37 -05002909 if (!elsiocb)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002910 return 1;
James Smart488d1462006-03-07 15:02:37 -05002911
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002912 icmd = &elsiocb->iocb;
2913 oldcmd = &oldiocb->iocb;
2914 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
2915
2916 pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2917 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
2918 pcmd += sizeof (uint16_t);
2919 *((uint16_t *)(pcmd)) = be16_to_cpu(cmdsize);
2920 pcmd += sizeof(uint16_t);
2921
2922 /* Setup the RPL ACC payload */
2923 rpl_rsp.listLen = be32_to_cpu(1);
2924 rpl_rsp.index = 0;
2925 rpl_rsp.port_num_blk.portNum = 0;
James Smart2e0fef82007-06-17 19:56:36 -05002926 rpl_rsp.port_num_blk.portID = be32_to_cpu(vport->fc_myDID);
2927 memcpy(&rpl_rsp.port_num_blk.portName, &vport->fc_portname,
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002928 sizeof(struct lpfc_name));
2929
2930 memcpy(pcmd, &rpl_rsp, cmdsize - sizeof(uint32_t));
2931
2932
2933 /* Xmit ELS RPL ACC response tag <ulpIoTag> */
2934 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart5b8bd0c2007-04-25 09:52:49 -04002935 "%d:0120 Xmit ELS RPL ACC response tag x%x xri x%x, "
2936 "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
2937 phba->brd_no, elsiocb->iotag,
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002938 elsiocb->iocb.ulpContext, ndlp->nlp_DID,
2939 ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
2940
2941 elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
2942
2943 phba->fc_stat.elsXmitACC++;
2944 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
2945 lpfc_els_free_iocb(phba, elsiocb);
2946 return 1;
2947 }
2948 return 0;
2949}
2950
2951static int
James Smart2e0fef82007-06-17 19:56:36 -05002952lpfc_els_rcv_rpl(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
2953 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05002954{
2955 struct lpfc_dmabuf *pcmd;
2956 uint32_t *lp;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002957 uint32_t maxsize;
2958 uint16_t cmdsize;
2959 RPL *rpl;
2960 struct ls_rjt stat;
dea31012005-04-17 16:05:31 -05002961
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05002962 if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
2963 (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) {
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002964 stat.un.b.lsRjtRsvd0 = 0;
2965 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
2966 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
2967 stat.un.b.vendorUnique = 0;
James Smart2e0fef82007-06-17 19:56:36 -05002968 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp);
dea31012005-04-17 16:05:31 -05002969 }
2970
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002971 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
2972 lp = (uint32_t *) pcmd->virt;
2973 rpl = (RPL *) (lp + 1);
2974
2975 maxsize = be32_to_cpu(rpl->maxsize);
2976
2977 /* We support only one port */
2978 if ((rpl->index == 0) &&
2979 ((maxsize == 0) ||
2980 ((maxsize * sizeof(uint32_t)) >= sizeof(RPL_RSP)))) {
2981 cmdsize = sizeof(uint32_t) + sizeof(RPL_RSP);
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05002982 } else {
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05002983 cmdsize = sizeof(uint32_t) + maxsize * sizeof(uint32_t);
2984 }
James Smart2e0fef82007-06-17 19:56:36 -05002985 lpfc_els_rsp_rpl_acc(vport, cmdsize, cmdiocb, ndlp);
dea31012005-04-17 16:05:31 -05002986
2987 return 0;
2988}
2989
2990static int
James Smart2e0fef82007-06-17 19:56:36 -05002991lpfc_els_rcv_farp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
2992 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05002993{
James Smart2e0fef82007-06-17 19:56:36 -05002994 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002995 struct lpfc_dmabuf *pcmd;
2996 uint32_t *lp;
2997 IOCB_t *icmd;
2998 FARP *fp;
2999 uint32_t cmd, cnt, did;
3000
3001 icmd = &cmdiocb->iocb;
3002 did = icmd->un.elsreq64.remoteID;
3003 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3004 lp = (uint32_t *) pcmd->virt;
3005
3006 cmd = *lp++;
3007 fp = (FARP *) lp;
3008
3009 /* FARP-REQ received from DID <did> */
James Smarted957682007-06-17 19:56:37 -05003010 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
dea31012005-04-17 16:05:31 -05003011 "%d:0601 FARP-REQ received from DID x%x\n",
3012 phba->brd_no, did);
3013
3014 /* We will only support match on WWPN or WWNN */
3015 if (fp->Mflags & ~(FARP_MATCH_NODE | FARP_MATCH_PORT)) {
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003016 return 0;
dea31012005-04-17 16:05:31 -05003017 }
3018
3019 cnt = 0;
3020 /* If this FARP command is searching for my portname */
3021 if (fp->Mflags & FARP_MATCH_PORT) {
James Smart2e0fef82007-06-17 19:56:36 -05003022 if (memcmp(&fp->RportName, &vport->fc_portname,
dea31012005-04-17 16:05:31 -05003023 sizeof (struct lpfc_name)) == 0)
3024 cnt = 1;
3025 }
3026
3027 /* If this FARP command is searching for my nodename */
3028 if (fp->Mflags & FARP_MATCH_NODE) {
James Smart2e0fef82007-06-17 19:56:36 -05003029 if (memcmp(&fp->RnodeName, &vport->fc_nodename,
dea31012005-04-17 16:05:31 -05003030 sizeof (struct lpfc_name)) == 0)
3031 cnt = 1;
3032 }
3033
3034 if (cnt) {
3035 if ((ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) ||
3036 (ndlp->nlp_state == NLP_STE_MAPPED_NODE)) {
3037 /* Log back into the node before sending the FARP. */
3038 if (fp->Rflags & FARP_REQUEST_PLOGI) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003039 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05003040 lpfc_nlp_set_state(vport, ndlp,
James Smartde0c5b32007-04-25 09:52:27 -04003041 NLP_STE_PLOGI_ISSUE);
James Smart2e0fef82007-06-17 19:56:36 -05003042 lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
dea31012005-04-17 16:05:31 -05003043 }
3044
3045 /* Send a FARP response to that node */
James Smart2e0fef82007-06-17 19:56:36 -05003046 if (fp->Rflags & FARP_REQUEST_FARPR)
3047 lpfc_issue_els_farpr(vport, did, 0);
dea31012005-04-17 16:05:31 -05003048 }
3049 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003050 return 0;
dea31012005-04-17 16:05:31 -05003051}
3052
3053static int
James Smart2e0fef82007-06-17 19:56:36 -05003054lpfc_els_rcv_farpr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3055 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05003056{
3057 struct lpfc_dmabuf *pcmd;
3058 uint32_t *lp;
3059 IOCB_t *icmd;
3060 uint32_t cmd, did;
James Smart2e0fef82007-06-17 19:56:36 -05003061 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05003062
3063 icmd = &cmdiocb->iocb;
3064 did = icmd->un.elsreq64.remoteID;
3065 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3066 lp = (uint32_t *) pcmd->virt;
3067
3068 cmd = *lp++;
3069 /* FARP-RSP received from DID <did> */
James Smarted957682007-06-17 19:56:37 -05003070 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
dea31012005-04-17 16:05:31 -05003071 "%d:0600 FARP-RSP received from DID x%x\n",
3072 phba->brd_no, did);
dea31012005-04-17 16:05:31 -05003073 /* ACCEPT the Farp resp request */
James Smart2e0fef82007-06-17 19:56:36 -05003074 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
dea31012005-04-17 16:05:31 -05003075
3076 return 0;
3077}
3078
3079static int
James Smart2e0fef82007-06-17 19:56:36 -05003080lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3081 struct lpfc_nodelist *fan_ndlp)
dea31012005-04-17 16:05:31 -05003082{
3083 struct lpfc_dmabuf *pcmd;
3084 uint32_t *lp;
3085 IOCB_t *icmd;
dea31012005-04-17 16:05:31 -05003086 uint32_t cmd, did;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003087 FAN *fp;
3088 struct lpfc_nodelist *ndlp, *next_ndlp;
James Smart2e0fef82007-06-17 19:56:36 -05003089 struct lpfc_hba *phba = vport->phba;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003090
3091 /* FAN received */
James Smarted957682007-06-17 19:56:37 -05003092 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
3093 "%d:0265 FAN received\n",
3094 phba->brd_no);
dea31012005-04-17 16:05:31 -05003095
3096 icmd = &cmdiocb->iocb;
3097 did = icmd->un.elsreq64.remoteID;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003098 pcmd = (struct lpfc_dmabuf *)cmdiocb->context2;
3099 lp = (uint32_t *)pcmd->virt;
dea31012005-04-17 16:05:31 -05003100
3101 cmd = *lp++;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003102 fp = (FAN *)lp;
dea31012005-04-17 16:05:31 -05003103
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003104 /* FAN received; Fan does not have a reply sequence */
dea31012005-04-17 16:05:31 -05003105
James Smart2e0fef82007-06-17 19:56:36 -05003106 if (phba->pport->port_state == LPFC_LOCAL_CFG_LINK) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003107 if ((memcmp(&phba->fc_fabparam.nodeName, &fp->FnodeName,
3108 sizeof(struct lpfc_name)) != 0) ||
3109 (memcmp(&phba->fc_fabparam.portName, &fp->FportName,
3110 sizeof(struct lpfc_name)) != 0)) {
3111 /*
3112 * This node has switched fabrics. FLOGI is required
3113 * Clean up the old rpi's
dea31012005-04-17 16:05:31 -05003114 */
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003115
3116 list_for_each_entry_safe(ndlp, next_ndlp,
James Smart2e0fef82007-06-17 19:56:36 -05003117 &vport->fc_nodes, nlp_listp) {
James Smart685f0bf2007-04-25 09:53:08 -04003118 if (ndlp->nlp_state != NLP_STE_NPR_NODE)
3119 continue;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003120 if (ndlp->nlp_type & NLP_FABRIC) {
3121 /*
3122 * Clean up old Fabric, Nameserver and
3123 * other NLP_FABRIC logins
3124 */
James Smart2e0fef82007-06-17 19:56:36 -05003125 lpfc_drop_node(vport, ndlp);
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05003126 } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003127 /* Fail outstanding I/O now since this
3128 * device is marked for PLOGI
3129 */
James Smart2e0fef82007-06-17 19:56:36 -05003130 lpfc_unreg_rpi(vport, ndlp);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003131 }
3132 }
3133
James Smart2e0fef82007-06-17 19:56:36 -05003134 vport->port_state = LPFC_FLOGI;
3135 lpfc_set_disctmo(vport);
3136 lpfc_initial_flogi(vport);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003137 return 0;
dea31012005-04-17 16:05:31 -05003138 }
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003139 /* Discovery not needed,
3140 * move the nodes to their original state.
3141 */
James Smart2e0fef82007-06-17 19:56:36 -05003142 list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
James Smart685f0bf2007-04-25 09:53:08 -04003143 nlp_listp) {
3144 if (ndlp->nlp_state != NLP_STE_NPR_NODE)
3145 continue;
dea31012005-04-17 16:05:31 -05003146
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003147 switch (ndlp->nlp_prev_state) {
3148 case NLP_STE_UNMAPPED_NODE:
3149 ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
James Smart2e0fef82007-06-17 19:56:36 -05003150 lpfc_nlp_set_state(vport, ndlp,
James Smartde0c5b32007-04-25 09:52:27 -04003151 NLP_STE_UNMAPPED_NODE);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003152 break;
3153
3154 case NLP_STE_MAPPED_NODE:
3155 ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
James Smart2e0fef82007-06-17 19:56:36 -05003156 lpfc_nlp_set_state(vport, ndlp,
James Smartde0c5b32007-04-25 09:52:27 -04003157 NLP_STE_MAPPED_NODE);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003158 break;
3159
3160 default:
3161 break;
3162 }
3163 }
3164
3165 /* Start discovery - this should just do CLEAR_LA */
James Smart2e0fef82007-06-17 19:56:36 -05003166 lpfc_disc_start(vport);
dea31012005-04-17 16:05:31 -05003167 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003168 return 0;
dea31012005-04-17 16:05:31 -05003169}
3170
3171void
3172lpfc_els_timeout(unsigned long ptr)
3173{
James Smart2e0fef82007-06-17 19:56:36 -05003174 struct lpfc_vport *vport = (struct lpfc_vport *) ptr;
3175 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05003176 unsigned long iflag;
3177
James Smart2e0fef82007-06-17 19:56:36 -05003178 spin_lock_irqsave(&vport->work_port_lock, iflag);
3179 if ((vport->work_port_events & WORKER_ELS_TMO) == 0) {
3180 vport->work_port_events |= WORKER_ELS_TMO;
dea31012005-04-17 16:05:31 -05003181 if (phba->work_wait)
3182 wake_up(phba->work_wait);
3183 }
James Smart2e0fef82007-06-17 19:56:36 -05003184 spin_unlock_irqrestore(&vport->work_port_lock, iflag);
dea31012005-04-17 16:05:31 -05003185 return;
3186}
3187
3188void
James Smart2e0fef82007-06-17 19:56:36 -05003189lpfc_els_timeout_handler(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05003190{
James Smart2e0fef82007-06-17 19:56:36 -05003191 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05003192 struct lpfc_sli_ring *pring;
3193 struct lpfc_iocbq *tmp_iocb, *piocb;
3194 IOCB_t *cmd = NULL;
3195 struct lpfc_dmabuf *pcmd;
James Smart2e0fef82007-06-17 19:56:36 -05003196 uint32_t els_command = 0;
dea31012005-04-17 16:05:31 -05003197 uint32_t timeout;
James Smart2e0fef82007-06-17 19:56:36 -05003198 uint32_t remote_ID = 0xffffffff;
dea31012005-04-17 16:05:31 -05003199
dea31012005-04-17 16:05:31 -05003200 /* If the timer is already canceled do nothing */
James Smart2e0fef82007-06-17 19:56:36 -05003201 if ((vport->work_port_events & WORKER_ELS_TMO) == 0) {
dea31012005-04-17 16:05:31 -05003202 return;
3203 }
James Smart2e0fef82007-06-17 19:56:36 -05003204 spin_lock_irq(&phba->hbalock);
dea31012005-04-17 16:05:31 -05003205 timeout = (uint32_t)(phba->fc_ratov << 1);
3206
3207 pring = &phba->sli.ring[LPFC_ELS_RING];
dea31012005-04-17 16:05:31 -05003208
3209 list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
3210 cmd = &piocb->iocb;
3211
James Smart2e0fef82007-06-17 19:56:36 -05003212 if ((piocb->iocb_flag & LPFC_IO_LIBDFC) != 0 ||
3213 piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN ||
3214 piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)
dea31012005-04-17 16:05:31 -05003215 continue;
James Smart2e0fef82007-06-17 19:56:36 -05003216
3217 if (piocb->vport != vport)
3218 continue;
3219
dea31012005-04-17 16:05:31 -05003220 pcmd = (struct lpfc_dmabuf *) piocb->context2;
James Smart2e0fef82007-06-17 19:56:36 -05003221 if (pcmd)
3222 els_command = *(uint32_t *) (pcmd->virt);
dea31012005-04-17 16:05:31 -05003223
3224 if ((els_command == ELS_CMD_FARP)
3225 || (els_command == ELS_CMD_FARPR)) {
3226 continue;
3227 }
3228
3229 if (piocb->drvrTimeout > 0) {
3230 if (piocb->drvrTimeout >= timeout) {
3231 piocb->drvrTimeout -= timeout;
3232 } else {
3233 piocb->drvrTimeout = 0;
3234 }
3235 continue;
3236 }
3237
James Smart2e0fef82007-06-17 19:56:36 -05003238 remote_ID = 0xffffffff;
3239 if (cmd->ulpCommand != CMD_GEN_REQUEST64_CR)
dea31012005-04-17 16:05:31 -05003240 remote_ID = cmd->un.elsreq64.remoteID;
James Smart2e0fef82007-06-17 19:56:36 -05003241 else {
3242 struct lpfc_nodelist *ndlp;
3243 ndlp = __lpfc_findnode_rpi(vport, cmd->ulpContext);
3244 if (ndlp)
3245 remote_ID = ndlp->nlp_DID;
dea31012005-04-17 16:05:31 -05003246 }
3247
3248 lpfc_printf_log(phba,
3249 KERN_ERR,
3250 LOG_ELS,
3251 "%d:0127 ELS timeout Data: x%x x%x x%x x%x\n",
3252 phba->brd_no, els_command,
3253 remote_ID, cmd->ulpCommand, cmd->ulpIoTag);
3254
James Smart07951072007-04-25 09:51:38 -04003255 lpfc_sli_issue_abort_iotag(phba, pring, piocb);
dea31012005-04-17 16:05:31 -05003256 }
James Smart2e0fef82007-06-17 19:56:36 -05003257 spin_unlock_irq(&phba->hbalock);
James Smart5a0e3262006-07-06 15:49:16 -04003258
James Smart2e0fef82007-06-17 19:56:36 -05003259 if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt)
3260 mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout);
dea31012005-04-17 16:05:31 -05003261}
3262
3263void
James Smart2e0fef82007-06-17 19:56:36 -05003264lpfc_els_flush_cmd(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05003265{
James Smart2534ba72007-04-25 09:52:20 -04003266 LIST_HEAD(completions);
James Smart2e0fef82007-06-17 19:56:36 -05003267 struct lpfc_hba *phba = vport->phba;
James Smart329f9bc2007-04-25 09:53:01 -04003268 struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
dea31012005-04-17 16:05:31 -05003269 struct lpfc_iocbq *tmp_iocb, *piocb;
3270 IOCB_t *cmd = NULL;
dea31012005-04-17 16:05:31 -05003271
James Smart2e0fef82007-06-17 19:56:36 -05003272 spin_lock_irq(&phba->hbalock);
dea31012005-04-17 16:05:31 -05003273 list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
3274 cmd = &piocb->iocb;
3275
3276 if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
3277 continue;
3278 }
3279
3280 /* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */
James Smart329f9bc2007-04-25 09:53:01 -04003281 if (cmd->ulpCommand == CMD_QUE_RING_BUF_CN ||
3282 cmd->ulpCommand == CMD_QUE_RING_BUF64_CN ||
3283 cmd->ulpCommand == CMD_CLOSE_XRI_CN ||
3284 cmd->ulpCommand == CMD_ABORT_XRI_CN)
dea31012005-04-17 16:05:31 -05003285 continue;
dea31012005-04-17 16:05:31 -05003286
James Smart2e0fef82007-06-17 19:56:36 -05003287 if (piocb->vport != vport)
3288 continue;
3289
James Smart2534ba72007-04-25 09:52:20 -04003290 list_move_tail(&piocb->list, &completions);
James Smart1dcb58e2007-04-25 09:51:30 -04003291 pring->txq_cnt--;
dea31012005-04-17 16:05:31 -05003292 }
3293
3294 list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
dea31012005-04-17 16:05:31 -05003295 if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
3296 continue;
3297 }
dea31012005-04-17 16:05:31 -05003298
James Smart2e0fef82007-06-17 19:56:36 -05003299 if (piocb->vport != vport)
3300 continue;
3301
James Smart07951072007-04-25 09:51:38 -04003302 lpfc_sli_issue_abort_iotag(phba, pring, piocb);
dea31012005-04-17 16:05:31 -05003303 }
James Smart2e0fef82007-06-17 19:56:36 -05003304 spin_unlock_irq(&phba->hbalock);
James Smart2534ba72007-04-25 09:52:20 -04003305
James Smart2e0fef82007-06-17 19:56:36 -05003306 while (!list_empty(&completions)) {
James Smart2534ba72007-04-25 09:52:20 -04003307 piocb = list_get_first(&completions, struct lpfc_iocbq, list);
3308 cmd = &piocb->iocb;
3309 list_del(&piocb->list);
3310
James Smart2e0fef82007-06-17 19:56:36 -05003311 if (!piocb->iocb_cmpl)
3312 lpfc_sli_release_iocbq(phba, piocb);
3313 else {
James Smart2534ba72007-04-25 09:52:20 -04003314 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
3315 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
3316 (piocb->iocb_cmpl) (phba, piocb, piocb);
James Smart2e0fef82007-06-17 19:56:36 -05003317 }
James Smart2534ba72007-04-25 09:52:20 -04003318 }
3319
dea31012005-04-17 16:05:31 -05003320 return;
3321}
3322
James Smarted957682007-06-17 19:56:37 -05003323static void
3324lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
3325 struct lpfc_vport *vport, struct lpfc_dmabuf *mp,
3326 struct lpfc_iocbq *elsiocb)
dea31012005-04-17 16:05:31 -05003327{
dea31012005-04-17 16:05:31 -05003328 struct lpfc_nodelist *ndlp;
dea31012005-04-17 16:05:31 -05003329 struct ls_rjt stat;
James Smarted957682007-06-17 19:56:37 -05003330 uint32_t *lp;
James Smart2e0fef82007-06-17 19:56:36 -05003331 uint32_t cmd, did, newnode, rjt_err = 0;
James Smarted957682007-06-17 19:56:37 -05003332 IOCB_t *icmd = &elsiocb->iocb;
dea31012005-04-17 16:05:31 -05003333
James Smarted957682007-06-17 19:56:37 -05003334 if (!vport || !mp)
dea31012005-04-17 16:05:31 -05003335 goto dropit;
James Smart2e0fef82007-06-17 19:56:36 -05003336
dea31012005-04-17 16:05:31 -05003337 newnode = 0;
3338 lp = (uint32_t *) mp->virt;
3339 cmd = *lp++;
James Smarted957682007-06-17 19:56:37 -05003340 if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) == 0)
3341 lpfc_post_buffer(phba, pring, 1, 1);
dea31012005-04-17 16:05:31 -05003342
James Smarted957682007-06-17 19:56:37 -05003343 if (icmd->ulpStatus)
dea31012005-04-17 16:05:31 -05003344 goto dropit;
dea31012005-04-17 16:05:31 -05003345
3346 /* Check to see if link went down during discovery */
James Smarted957682007-06-17 19:56:37 -05003347 if (lpfc_els_chk_latt(vport))
dea31012005-04-17 16:05:31 -05003348 goto dropit;
dea31012005-04-17 16:05:31 -05003349
3350 did = icmd->un.rcvels.remoteID;
James Smart2e0fef82007-06-17 19:56:36 -05003351 ndlp = lpfc_findnode_did(vport, did);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003352 if (!ndlp) {
dea31012005-04-17 16:05:31 -05003353 /* Cannot find existing Fabric ndlp, so allocate a new one */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003354 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
James Smarted957682007-06-17 19:56:37 -05003355 if (!ndlp)
dea31012005-04-17 16:05:31 -05003356 goto dropit;
dea31012005-04-17 16:05:31 -05003357
James Smart2e0fef82007-06-17 19:56:36 -05003358 lpfc_nlp_init(vport, ndlp, did);
dea31012005-04-17 16:05:31 -05003359 newnode = 1;
3360 if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) {
3361 ndlp->nlp_type |= NLP_FABRIC;
3362 }
James Smart2e0fef82007-06-17 19:56:36 -05003363 lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
dea31012005-04-17 16:05:31 -05003364 }
3365
3366 phba->fc_stat.elsRcvFrame++;
James Smart329f9bc2007-04-25 09:53:01 -04003367 if (elsiocb->context1)
3368 lpfc_nlp_put(elsiocb->context1);
3369 elsiocb->context1 = lpfc_nlp_get(ndlp);
dea31012005-04-17 16:05:31 -05003370 elsiocb->context2 = mp;
James Smart2e0fef82007-06-17 19:56:36 -05003371 elsiocb->vport = vport;
dea31012005-04-17 16:05:31 -05003372
3373 if ((cmd & ELS_CMD_MASK) == ELS_CMD_RSCN) {
3374 cmd &= ELS_CMD_MASK;
3375 }
3376 /* ELS command <elsCmd> received from NPORT <did> */
3377 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
3378 "%d:0112 ELS command x%x received from NPORT x%x "
James Smart2e0fef82007-06-17 19:56:36 -05003379 "Data: x%x\n", phba->brd_no, cmd, did,
James Smarted957682007-06-17 19:56:37 -05003380 vport->port_state);
dea31012005-04-17 16:05:31 -05003381
3382 switch (cmd) {
3383 case ELS_CMD_PLOGI:
3384 phba->fc_stat.elsRcvPLOGI++;
James Smart2e0fef82007-06-17 19:56:36 -05003385 if (vport->port_state < LPFC_DISC_AUTH) {
James.Smart@Emulex.Com1f679ca2005-06-25 10:34:27 -04003386 rjt_err = 1;
dea31012005-04-17 16:05:31 -05003387 break;
3388 }
James Smart92795652006-07-06 15:50:02 -04003389 ndlp = lpfc_plogi_confirm_nport(phba, mp, ndlp);
James Smart2e0fef82007-06-17 19:56:36 -05003390 lpfc_disc_state_machine(vport, ndlp, elsiocb,
3391 NLP_EVT_RCV_PLOGI);
dea31012005-04-17 16:05:31 -05003392 break;
3393 case ELS_CMD_FLOGI:
3394 phba->fc_stat.elsRcvFLOGI++;
James Smart2e0fef82007-06-17 19:56:36 -05003395 lpfc_els_rcv_flogi(vport, elsiocb, ndlp, newnode);
James Smartde0c5b32007-04-25 09:52:27 -04003396 if (newnode)
James Smart2e0fef82007-06-17 19:56:36 -05003397 lpfc_drop_node(vport, ndlp);
dea31012005-04-17 16:05:31 -05003398 break;
3399 case ELS_CMD_LOGO:
3400 phba->fc_stat.elsRcvLOGO++;
James Smart2e0fef82007-06-17 19:56:36 -05003401 if (vport->port_state < LPFC_DISC_AUTH) {
James.Smart@Emulex.Com1f679ca2005-06-25 10:34:27 -04003402 rjt_err = 1;
dea31012005-04-17 16:05:31 -05003403 break;
3404 }
James Smart2e0fef82007-06-17 19:56:36 -05003405 lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_LOGO);
dea31012005-04-17 16:05:31 -05003406 break;
3407 case ELS_CMD_PRLO:
3408 phba->fc_stat.elsRcvPRLO++;
James Smart2e0fef82007-06-17 19:56:36 -05003409 if (vport->port_state < LPFC_DISC_AUTH) {
James.Smart@Emulex.Com1f679ca2005-06-25 10:34:27 -04003410 rjt_err = 1;
dea31012005-04-17 16:05:31 -05003411 break;
3412 }
James Smart2e0fef82007-06-17 19:56:36 -05003413 lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PRLO);
dea31012005-04-17 16:05:31 -05003414 break;
3415 case ELS_CMD_RSCN:
3416 phba->fc_stat.elsRcvRSCN++;
James Smart2e0fef82007-06-17 19:56:36 -05003417 lpfc_els_rcv_rscn(vport, elsiocb, ndlp, newnode);
James Smartde0c5b32007-04-25 09:52:27 -04003418 if (newnode)
James Smart2e0fef82007-06-17 19:56:36 -05003419 lpfc_drop_node(vport, ndlp);
dea31012005-04-17 16:05:31 -05003420 break;
3421 case ELS_CMD_ADISC:
3422 phba->fc_stat.elsRcvADISC++;
James Smart2e0fef82007-06-17 19:56:36 -05003423 if (vport->port_state < LPFC_DISC_AUTH) {
James.Smart@Emulex.Com1f679ca2005-06-25 10:34:27 -04003424 rjt_err = 1;
dea31012005-04-17 16:05:31 -05003425 break;
3426 }
James Smart2e0fef82007-06-17 19:56:36 -05003427 lpfc_disc_state_machine(vport, ndlp, elsiocb,
3428 NLP_EVT_RCV_ADISC);
dea31012005-04-17 16:05:31 -05003429 break;
3430 case ELS_CMD_PDISC:
3431 phba->fc_stat.elsRcvPDISC++;
James Smart2e0fef82007-06-17 19:56:36 -05003432 if (vport->port_state < LPFC_DISC_AUTH) {
James.Smart@Emulex.Com1f679ca2005-06-25 10:34:27 -04003433 rjt_err = 1;
dea31012005-04-17 16:05:31 -05003434 break;
3435 }
James Smart2e0fef82007-06-17 19:56:36 -05003436 lpfc_disc_state_machine(vport, ndlp, elsiocb,
3437 NLP_EVT_RCV_PDISC);
dea31012005-04-17 16:05:31 -05003438 break;
3439 case ELS_CMD_FARPR:
3440 phba->fc_stat.elsRcvFARPR++;
James Smart2e0fef82007-06-17 19:56:36 -05003441 lpfc_els_rcv_farpr(vport, elsiocb, ndlp);
dea31012005-04-17 16:05:31 -05003442 break;
3443 case ELS_CMD_FARP:
3444 phba->fc_stat.elsRcvFARP++;
James Smart2e0fef82007-06-17 19:56:36 -05003445 lpfc_els_rcv_farp(vport, elsiocb, ndlp);
dea31012005-04-17 16:05:31 -05003446 break;
3447 case ELS_CMD_FAN:
3448 phba->fc_stat.elsRcvFAN++;
James Smart2e0fef82007-06-17 19:56:36 -05003449 lpfc_els_rcv_fan(vport, elsiocb, ndlp);
dea31012005-04-17 16:05:31 -05003450 break;
dea31012005-04-17 16:05:31 -05003451 case ELS_CMD_PRLI:
3452 phba->fc_stat.elsRcvPRLI++;
James Smart2e0fef82007-06-17 19:56:36 -05003453 if (vport->port_state < LPFC_DISC_AUTH) {
James.Smart@Emulex.Com1f679ca2005-06-25 10:34:27 -04003454 rjt_err = 1;
dea31012005-04-17 16:05:31 -05003455 break;
3456 }
James Smart2e0fef82007-06-17 19:56:36 -05003457 lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PRLI);
dea31012005-04-17 16:05:31 -05003458 break;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003459 case ELS_CMD_LIRR:
3460 phba->fc_stat.elsRcvLIRR++;
James Smart2e0fef82007-06-17 19:56:36 -05003461 lpfc_els_rcv_lirr(vport, elsiocb, ndlp);
James Smartde0c5b32007-04-25 09:52:27 -04003462 if (newnode)
James Smart2e0fef82007-06-17 19:56:36 -05003463 lpfc_drop_node(vport, ndlp);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003464 break;
3465 case ELS_CMD_RPS:
3466 phba->fc_stat.elsRcvRPS++;
James Smart2e0fef82007-06-17 19:56:36 -05003467 lpfc_els_rcv_rps(vport, elsiocb, ndlp);
James Smartde0c5b32007-04-25 09:52:27 -04003468 if (newnode)
James Smart2e0fef82007-06-17 19:56:36 -05003469 lpfc_drop_node(vport, ndlp);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003470 break;
3471 case ELS_CMD_RPL:
3472 phba->fc_stat.elsRcvRPL++;
James Smart2e0fef82007-06-17 19:56:36 -05003473 lpfc_els_rcv_rpl(vport, elsiocb, ndlp);
James Smartde0c5b32007-04-25 09:52:27 -04003474 if (newnode)
James Smart2e0fef82007-06-17 19:56:36 -05003475 lpfc_drop_node(vport, ndlp);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003476 break;
dea31012005-04-17 16:05:31 -05003477 case ELS_CMD_RNID:
3478 phba->fc_stat.elsRcvRNID++;
James Smart2e0fef82007-06-17 19:56:36 -05003479 lpfc_els_rcv_rnid(vport, elsiocb, ndlp);
James Smartde0c5b32007-04-25 09:52:27 -04003480 if (newnode)
James Smart2e0fef82007-06-17 19:56:36 -05003481 lpfc_drop_node(vport, ndlp);
dea31012005-04-17 16:05:31 -05003482 break;
3483 default:
3484 /* Unsupported ELS command, reject */
James.Smart@Emulex.Com1f679ca2005-06-25 10:34:27 -04003485 rjt_err = 1;
dea31012005-04-17 16:05:31 -05003486
3487 /* Unknown ELS command <elsCmd> received from NPORT <did> */
3488 lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
James Smarted957682007-06-17 19:56:37 -05003489 "%d:0115 Unknown ELS command x%x "
3490 "received from NPORT x%x\n",
3491 phba->brd_no, cmd, did);
James Smartde0c5b32007-04-25 09:52:27 -04003492 if (newnode)
James Smart2e0fef82007-06-17 19:56:36 -05003493 lpfc_drop_node(vport, ndlp);
dea31012005-04-17 16:05:31 -05003494 break;
3495 }
3496
3497 /* check if need to LS_RJT received ELS cmd */
3498 if (rjt_err) {
3499 stat.un.b.lsRjtRsvd0 = 0;
3500 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
James.Smart@Emulex.Com1f679ca2005-06-25 10:34:27 -04003501 stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
dea31012005-04-17 16:05:31 -05003502 stat.un.b.vendorUnique = 0;
James Smart2e0fef82007-06-17 19:56:36 -05003503 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, elsiocb, ndlp);
dea31012005-04-17 16:05:31 -05003504 }
3505
James Smarted957682007-06-17 19:56:37 -05003506 return;
3507
3508dropit:
3509 lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
3510 "%d:0111 Dropping received ELS cmd "
3511 "Data: x%x x%x x%x\n",
3512 phba->brd_no,
3513 icmd->ulpStatus, icmd->un.ulpWord[4],
3514 icmd->ulpTimeout);
3515 phba->fc_stat.elsRcvDrop++;
3516}
3517
3518
3519void
3520lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
3521 struct lpfc_iocbq *elsiocb)
3522{
3523 struct lpfc_vport *vport = phba->pport;
3524 struct lpfc_dmabuf *mp = NULL;
3525 IOCB_t *icmd = &elsiocb->iocb;
3526 struct hbq_dmabuf *sp = NULL;
3527 dma_addr_t paddr;
3528
3529 if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) &&
3530 ((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) {
3531 phba->fc_stat.NoRcvBuf++;
3532 /* Not enough posted buffers; Try posting more buffers */
3533 if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
3534 lpfc_sli_hbqbuf_fill_hbq(phba);
3535 else
3536 lpfc_post_buffer(phba, pring, 0, 1);
3537 return;
3538 }
3539
3540 /* If there are no BDEs associated with this IOCB,
3541 * there is nothing to do.
3542 */
3543 if (icmd->ulpBdeCount == 0)
3544 return;
3545
3546 /* type of ELS cmd is first 32bit word in packet */
3547 if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
3548 paddr = getPaddr(icmd->un.cont64[0].addrHigh,
3549 icmd->un.cont64[0].addrLow);
3550 sp = lpfc_sli_hbqbuf_find(phba, icmd->un.ulpWord[3]);
3551 if (sp)
3552 phba->hbq_buff_count--;
3553 mp = sp ? &sp->dbuf : NULL;
3554 } else {
3555 paddr = getPaddr(icmd->un.cont64[0].addrHigh,
3556 icmd->un.cont64[0].addrLow);
3557 mp = lpfc_sli_ringpostbuf_get(phba, pring, paddr);
3558 }
3559
3560 lpfc_els_unsol_buffer(phba, pring, vport, mp, elsiocb);
3561
James Smart329f9bc2007-04-25 09:53:01 -04003562 lpfc_nlp_put(elsiocb->context1);
3563 elsiocb->context1 = NULL;
dea31012005-04-17 16:05:31 -05003564 if (elsiocb->context2) {
James Smarted957682007-06-17 19:56:37 -05003565 if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
3566 lpfc_sli_free_hbq(phba, sp);
3567 else {
3568 lpfc_mbuf_free(phba, mp->virt, mp->phys);
3569 kfree(mp);
3570 }
dea31012005-04-17 16:05:31 -05003571 }
James Smarted957682007-06-17 19:56:37 -05003572
3573 /* RCV_ELS64_CX provide for 2 BDEs - process 2nd if included */
3574 if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) != 0 &&
3575 icmd->ulpBdeCount == 2) {
3576 sp = lpfc_sli_hbqbuf_find(phba, icmd->un.ulpWord[15]);
3577 if (sp)
3578 phba->hbq_buff_count--;
3579 mp = sp ? &sp->dbuf : NULL;
3580 lpfc_els_unsol_buffer(phba, pring, vport, mp, elsiocb);
3581 /* free mp if we are done with it */
3582 if (elsiocb->context2) {
3583 if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
3584 lpfc_sli_free_hbq(phba, sp);
3585 else {
3586 lpfc_mbuf_free(phba, mp->virt, mp->phys);
3587 kfree(mp);
3588 }
3589 }
dea31012005-04-17 16:05:31 -05003590 }
dea31012005-04-17 16:05:31 -05003591}