blob: 33fbc166694678a2f5ed82f62575197e95eb32cd [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"
James Smart92d7f7b2007-06-17 19:56:38 -050038#include "lpfc_vport.h"
James Smart858c9f62007-06-17 19:56:39 -050039#include "lpfc_debugfs.h"
dea31012005-04-17 16:05:31 -050040
41static int lpfc_els_retry(struct lpfc_hba *, struct lpfc_iocbq *,
42 struct lpfc_iocbq *);
James Smart92d7f7b2007-06-17 19:56:38 -050043static void lpfc_cmpl_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *,
44 struct lpfc_iocbq *);
45
dea31012005-04-17 16:05:31 -050046static int lpfc_max_els_tries = 3;
47
James Smart858c9f62007-06-17 19:56:39 -050048int
James Smart2e0fef82007-06-17 19:56:36 -050049lpfc_els_chk_latt(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -050050{
James Smart2e0fef82007-06-17 19:56:36 -050051 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
52 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -050053 uint32_t ha_copy;
dea31012005-04-17 16:05:31 -050054
James Smart2e0fef82007-06-17 19:56:36 -050055 if (vport->port_state >= LPFC_VPORT_READY ||
56 phba->link_state == LPFC_LINK_DOWN)
dea31012005-04-17 16:05:31 -050057 return 0;
58
59 /* Read the HBA Host Attention Register */
dea31012005-04-17 16:05:31 -050060 ha_copy = readl(phba->HAregaddr);
dea31012005-04-17 16:05:31 -050061
62 if (!(ha_copy & HA_LATT))
63 return 0;
64
65 /* Pending Link Event during Discovery */
James Smart92d7f7b2007-06-17 19:56:38 -050066 lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
67 "%d (%d):0237 Pending Link Event during "
dea31012005-04-17 16:05:31 -050068 "Discovery: State x%x\n",
James Smart92d7f7b2007-06-17 19:56:38 -050069 phba->brd_no, vport->vpi, phba->pport->port_state);
dea31012005-04-17 16:05:31 -050070
71 /* CLEAR_LA should re-enable link attention events and
72 * we should then imediately take a LATT event. The
73 * LATT processing should call lpfc_linkdown() which
74 * will cleanup any left over in-progress discovery
75 * events.
76 */
James Smart2e0fef82007-06-17 19:56:36 -050077 spin_lock_irq(shost->host_lock);
78 vport->fc_flag |= FC_ABORT_DISCOVERY;
79 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -050080
James Smart92d7f7b2007-06-17 19:56:38 -050081 if (phba->link_state != LPFC_CLEAR_LA)
James Smarted957682007-06-17 19:56:37 -050082 lpfc_issue_clear_la(phba, vport);
dea31012005-04-17 16:05:31 -050083
Jamie Wellnitzc9f87352006-02-28 19:25:23 -050084 return 1;
dea31012005-04-17 16:05:31 -050085}
86
87static struct lpfc_iocbq *
James Smart2e0fef82007-06-17 19:56:36 -050088lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
89 uint16_t cmdSize, uint8_t retry,
90 struct lpfc_nodelist *ndlp, uint32_t did,
91 uint32_t elscmd)
dea31012005-04-17 16:05:31 -050092{
James Smart2e0fef82007-06-17 19:56:36 -050093 struct lpfc_hba *phba = vport->phba;
James.Smart@Emulex.Com0bd4ca22005-10-28 20:30:02 -040094 struct lpfc_iocbq *elsiocb;
dea31012005-04-17 16:05:31 -050095 struct lpfc_dmabuf *pcmd, *prsp, *pbuflist;
96 struct ulp_bde64 *bpl;
97 IOCB_t *icmd;
98
dea31012005-04-17 16:05:31 -050099
James Smart2e0fef82007-06-17 19:56:36 -0500100 if (!lpfc_is_link_up(phba))
101 return NULL;
dea31012005-04-17 16:05:31 -0500102
dea31012005-04-17 16:05:31 -0500103 /* Allocate buffer for command iocb */
James.Smart@Emulex.Com0bd4ca22005-10-28 20:30:02 -0400104 elsiocb = lpfc_sli_get_iocbq(phba);
dea31012005-04-17 16:05:31 -0500105
106 if (elsiocb == NULL)
107 return NULL;
dea31012005-04-17 16:05:31 -0500108 icmd = &elsiocb->iocb;
109
110 /* fill in BDEs for command */
111 /* Allocate buffer for command payload */
James Smart92d7f7b2007-06-17 19:56:38 -0500112 if (((pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL)) == 0) ||
dea31012005-04-17 16:05:31 -0500113 ((pcmd->virt = lpfc_mbuf_alloc(phba,
114 MEM_PRI, &(pcmd->phys))) == 0)) {
Jesper Juhlc9475cb2005-11-07 01:01:26 -0800115 kfree(pcmd);
dea31012005-04-17 16:05:31 -0500116
James Bottomley604a3e32005-10-29 10:28:33 -0500117 lpfc_sli_release_iocbq(phba, elsiocb);
dea31012005-04-17 16:05:31 -0500118 return NULL;
119 }
120
121 INIT_LIST_HEAD(&pcmd->list);
122
123 /* Allocate buffer for response payload */
124 if (expectRsp) {
James Smart92d7f7b2007-06-17 19:56:38 -0500125 prsp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
dea31012005-04-17 16:05:31 -0500126 if (prsp)
127 prsp->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
128 &prsp->phys);
129 if (prsp == 0 || prsp->virt == 0) {
Jesper Juhlc9475cb2005-11-07 01:01:26 -0800130 kfree(prsp);
dea31012005-04-17 16:05:31 -0500131 lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
132 kfree(pcmd);
James Bottomley604a3e32005-10-29 10:28:33 -0500133 lpfc_sli_release_iocbq(phba, elsiocb);
dea31012005-04-17 16:05:31 -0500134 return NULL;
135 }
136 INIT_LIST_HEAD(&prsp->list);
137 } else {
138 prsp = NULL;
139 }
140
141 /* Allocate buffer for Buffer ptr list */
James Smart92d7f7b2007-06-17 19:56:38 -0500142 pbuflist = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
dea31012005-04-17 16:05:31 -0500143 if (pbuflist)
James Smarted957682007-06-17 19:56:37 -0500144 pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
145 &pbuflist->phys);
dea31012005-04-17 16:05:31 -0500146 if (pbuflist == 0 || pbuflist->virt == 0) {
James Bottomley604a3e32005-10-29 10:28:33 -0500147 lpfc_sli_release_iocbq(phba, elsiocb);
dea31012005-04-17 16:05:31 -0500148 lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
149 lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
150 kfree(pcmd);
151 kfree(prsp);
Jesper Juhlc9475cb2005-11-07 01:01:26 -0800152 kfree(pbuflist);
dea31012005-04-17 16:05:31 -0500153 return NULL;
154 }
155
156 INIT_LIST_HEAD(&pbuflist->list);
157
158 icmd->un.elsreq64.bdl.addrHigh = putPaddrHigh(pbuflist->phys);
159 icmd->un.elsreq64.bdl.addrLow = putPaddrLow(pbuflist->phys);
160 icmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BDL;
James Smart2e0fef82007-06-17 19:56:36 -0500161 icmd->un.elsreq64.remoteID = did; /* DID */
dea31012005-04-17 16:05:31 -0500162 if (expectRsp) {
James Smart92d7f7b2007-06-17 19:56:38 -0500163 icmd->un.elsreq64.bdl.bdeSize = (2 * sizeof(struct ulp_bde64));
dea31012005-04-17 16:05:31 -0500164 icmd->ulpCommand = CMD_ELS_REQUEST64_CR;
James Smart2680eea2007-04-25 09:52:55 -0400165 icmd->ulpTimeout = phba->fc_ratov * 2;
dea31012005-04-17 16:05:31 -0500166 } else {
James Smart92d7f7b2007-06-17 19:56:38 -0500167 icmd->un.elsreq64.bdl.bdeSize = sizeof(struct ulp_bde64);
dea31012005-04-17 16:05:31 -0500168 icmd->ulpCommand = CMD_XMIT_ELS_RSP64_CX;
169 }
dea31012005-04-17 16:05:31 -0500170 icmd->ulpBdeCount = 1;
171 icmd->ulpLe = 1;
172 icmd->ulpClass = CLASS3;
173
James Smart92d7f7b2007-06-17 19:56:38 -0500174 if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
175 icmd->un.elsreq64.myID = vport->fc_myDID;
176
177 /* For ELS_REQUEST64_CR, use the VPI by default */
178 icmd->ulpContext = vport->vpi;
179 icmd->ulpCt_h = 0;
180 icmd->ulpCt_l = 1;
181 }
182
dea31012005-04-17 16:05:31 -0500183 bpl = (struct ulp_bde64 *) pbuflist->virt;
184 bpl->addrLow = le32_to_cpu(putPaddrLow(pcmd->phys));
185 bpl->addrHigh = le32_to_cpu(putPaddrHigh(pcmd->phys));
186 bpl->tus.f.bdeSize = cmdSize;
187 bpl->tus.f.bdeFlags = 0;
188 bpl->tus.w = le32_to_cpu(bpl->tus.w);
189
190 if (expectRsp) {
191 bpl++;
192 bpl->addrLow = le32_to_cpu(putPaddrLow(prsp->phys));
193 bpl->addrHigh = le32_to_cpu(putPaddrHigh(prsp->phys));
194 bpl->tus.f.bdeSize = FCELSSIZE;
195 bpl->tus.f.bdeFlags = BUFF_USE_RCV;
196 bpl->tus.w = le32_to_cpu(bpl->tus.w);
197 }
198
199 /* Save for completion so we can release these resources */
James Smart92d7f7b2007-06-17 19:56:38 -0500200 if (elscmd != ELS_CMD_LS_RJT)
201 elsiocb->context1 = lpfc_nlp_get(ndlp);
James Smart329f9bc2007-04-25 09:53:01 -0400202 elsiocb->context2 = pcmd;
203 elsiocb->context3 = pbuflist;
dea31012005-04-17 16:05:31 -0500204 elsiocb->retry = retry;
James Smart2e0fef82007-06-17 19:56:36 -0500205 elsiocb->vport = vport;
dea31012005-04-17 16:05:31 -0500206 elsiocb->drvrTimeout = (phba->fc_ratov << 1) + LPFC_DRVR_TIMEOUT;
207
208 if (prsp) {
209 list_add(&prsp->list, &pcmd->list);
210 }
211
212 if (expectRsp) {
213 /* Xmit ELS command <elsCmd> to remote NPORT <did> */
214 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart92d7f7b2007-06-17 19:56:38 -0500215 "%d (%d):0116 Xmit ELS command x%x to remote "
James Smart2e0fef82007-06-17 19:56:36 -0500216 "NPORT x%x I/O tag: x%x, port state: x%x\n",
James Smart92d7f7b2007-06-17 19:56:38 -0500217 phba->brd_no, vport->vpi, elscmd, did,
James Smart2e0fef82007-06-17 19:56:36 -0500218 elsiocb->iotag, vport->port_state);
dea31012005-04-17 16:05:31 -0500219 } else {
220 /* Xmit ELS response <elsCmd> to remote NPORT <did> */
221 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart92d7f7b2007-06-17 19:56:38 -0500222 "%d (%d):0117 Xmit ELS response x%x to remote "
James Smart1dcb58e2007-04-25 09:51:30 -0400223 "NPORT x%x I/O tag: x%x, size: x%x\n",
James Smart92d7f7b2007-06-17 19:56:38 -0500224 phba->brd_no, vport->vpi, elscmd,
James Smart1dcb58e2007-04-25 09:51:30 -0400225 ndlp->nlp_DID, elsiocb->iotag, cmdSize);
dea31012005-04-17 16:05:31 -0500226 }
227
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500228 return elsiocb;
dea31012005-04-17 16:05:31 -0500229}
230
231
232static int
James Smart92d7f7b2007-06-17 19:56:38 -0500233lpfc_issue_fabric_reglogin(struct lpfc_vport *vport)
234{
235 struct lpfc_hba *phba = vport->phba;
236 LPFC_MBOXQ_t *mbox;
237 struct lpfc_dmabuf *mp;
238 struct lpfc_nodelist *ndlp;
239 struct serv_parm *sp;
240 int rc;
241
242 sp = &phba->fc_fabparam;
243 ndlp = lpfc_findnode_did(vport, Fabric_DID);
244 if (!ndlp)
245 goto fail;
246
247 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
248 if (!mbox)
249 goto fail;
250
251 vport->port_state = LPFC_FABRIC_CFG_LINK;
252 lpfc_config_link(phba, mbox);
253 mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
254 mbox->vport = vport;
255
256 rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
257 if (rc == MBX_NOT_FINISHED)
258 goto fail_free_mbox;
259
260 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
261 if (!mbox)
262 goto fail;
263 rc = lpfc_reg_login(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox,
264 0);
265 if (rc)
266 goto fail_free_mbox;
267
268 mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login;
269 mbox->vport = vport;
270 mbox->context2 = lpfc_nlp_get(ndlp);
271
272 rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
273 if (rc == MBX_NOT_FINISHED)
274 goto fail_issue_reg_login;
275
276 return 0;
277
278fail_issue_reg_login:
279 lpfc_nlp_put(ndlp);
280 mp = (struct lpfc_dmabuf *) mbox->context1;
281 lpfc_mbuf_free(phba, mp->virt, mp->phys);
282 kfree(mp);
283fail_free_mbox:
284 mempool_free(mbox, phba->mbox_mem_pool);
285
286fail:
287 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
288 lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
289 "%d (%d):0249 Cannot issue Register Fabric login\n",
290 phba->brd_no, vport->vpi);
291 return -ENXIO;
292}
293
294static int
James Smart2e0fef82007-06-17 19:56:36 -0500295lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
296 struct serv_parm *sp, IOCB_t *irsp)
dea31012005-04-17 16:05:31 -0500297{
James Smart2e0fef82007-06-17 19:56:36 -0500298 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
299 struct lpfc_hba *phba = vport->phba;
James Smart92d7f7b2007-06-17 19:56:38 -0500300 struct lpfc_nodelist *np;
301 struct lpfc_nodelist *next_np;
dea31012005-04-17 16:05:31 -0500302
James Smart2e0fef82007-06-17 19:56:36 -0500303 spin_lock_irq(shost->host_lock);
304 vport->fc_flag |= FC_FABRIC;
305 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500306
307 phba->fc_edtov = be32_to_cpu(sp->cmn.e_d_tov);
308 if (sp->cmn.edtovResolution) /* E_D_TOV ticks are in nanoseconds */
309 phba->fc_edtov = (phba->fc_edtov + 999999) / 1000000;
310
311 phba->fc_ratov = (be32_to_cpu(sp->cmn.w2.r_a_tov) + 999) / 1000;
312
313 if (phba->fc_topology == TOPOLOGY_LOOP) {
James Smart2e0fef82007-06-17 19:56:36 -0500314 spin_lock_irq(shost->host_lock);
315 vport->fc_flag |= FC_PUBLIC_LOOP;
316 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500317 } else {
318 /*
319 * If we are a N-port connected to a Fabric, fixup sparam's so
320 * logins to devices on remote loops work.
321 */
James Smart2e0fef82007-06-17 19:56:36 -0500322 vport->fc_sparam.cmn.altBbCredit = 1;
dea31012005-04-17 16:05:31 -0500323 }
324
James Smart2e0fef82007-06-17 19:56:36 -0500325 vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID;
dea31012005-04-17 16:05:31 -0500326 memcpy(&ndlp->nlp_portname, &sp->portName, sizeof(struct lpfc_name));
James Smart92d7f7b2007-06-17 19:56:38 -0500327 memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -0500328 ndlp->nlp_class_sup = 0;
329 if (sp->cls1.classValid)
330 ndlp->nlp_class_sup |= FC_COS_CLASS1;
331 if (sp->cls2.classValid)
332 ndlp->nlp_class_sup |= FC_COS_CLASS2;
333 if (sp->cls3.classValid)
334 ndlp->nlp_class_sup |= FC_COS_CLASS3;
335 if (sp->cls4.classValid)
336 ndlp->nlp_class_sup |= FC_COS_CLASS4;
337 ndlp->nlp_maxframe = ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) |
338 sp->cmn.bbRcvSizeLsb;
339 memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
340
James Smart92d7f7b2007-06-17 19:56:38 -0500341 if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
342 if (sp->cmn.response_multiple_NPort) {
343 lpfc_printf_log(phba, KERN_WARNING, LOG_ELS | LOG_VPORT,
344 "%d:1816 FLOGI NPIV supported, "
345 "response data 0x%x\n",
346 phba->brd_no,
347 sp->cmn.response_multiple_NPort);
348 phba->link_flag |= LS_NPIV_FAB_SUPPORTED;
349
350 } else {
351 /* Because we asked f/w for NPIV it still expects us
352 to call reg_vnpid atleast for the physcial host */
353 lpfc_printf_log(phba, KERN_WARNING, LOG_ELS | LOG_VPORT,
354 "%d:1817 Fabric does not support NPIV "
355 "- configuring single port mode.\n",
356 phba->brd_no);
James Smart92d7f7b2007-06-17 19:56:38 -0500357 phba->link_flag &= ~LS_NPIV_FAB_SUPPORTED;
358 }
359 }
360
361 if ((vport->fc_prevDID != vport->fc_myDID) &&
362 !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) {
363
364 /* If our NportID changed, we need to ensure all
365 * remaining NPORTs get unreg_login'ed.
366 */
367 list_for_each_entry_safe(np, next_np,
368 &vport->fc_nodes, nlp_listp) {
369 if ((np->nlp_state != NLP_STE_NPR_NODE) ||
370 !(np->nlp_flag & NLP_NPR_ADISC))
371 continue;
372 spin_lock_irq(shost->host_lock);
373 np->nlp_flag &= ~NLP_NPR_ADISC;
374 spin_unlock_irq(shost->host_lock);
375 lpfc_unreg_rpi(vport, np);
376 }
377 if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
378 lpfc_mbx_unreg_vpi(vport);
379 vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
380 }
381 }
382
James Smart2e0fef82007-06-17 19:56:36 -0500383 ndlp->nlp_sid = irsp->un.ulpWord[4] & Mask_DID;
James Smart92d7f7b2007-06-17 19:56:38 -0500384 lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE);
James Smart2e0fef82007-06-17 19:56:36 -0500385
James Smart92d7f7b2007-06-17 19:56:38 -0500386 if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED &&
387 vport->fc_flag & FC_VPORT_NEEDS_REG_VPI) {
388 lpfc_register_new_vport(phba, vport, ndlp);
389 return 0;
390 }
391 lpfc_issue_fabric_reglogin(vport);
dea31012005-04-17 16:05:31 -0500392 return 0;
dea31012005-04-17 16:05:31 -0500393}
394
395/*
396 * We FLOGIed into an NPort, initiate pt2pt protocol
397 */
398static int
James Smart2e0fef82007-06-17 19:56:36 -0500399lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
400 struct serv_parm *sp)
dea31012005-04-17 16:05:31 -0500401{
James Smart2e0fef82007-06-17 19:56:36 -0500402 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
403 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500404 LPFC_MBOXQ_t *mbox;
405 int rc;
406
James Smart2e0fef82007-06-17 19:56:36 -0500407 spin_lock_irq(shost->host_lock);
408 vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
409 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500410
411 phba->fc_edtov = FF_DEF_EDTOV;
412 phba->fc_ratov = FF_DEF_RATOV;
James Smart2e0fef82007-06-17 19:56:36 -0500413 rc = memcmp(&vport->fc_portname, &sp->portName,
James Smart92d7f7b2007-06-17 19:56:38 -0500414 sizeof(vport->fc_portname));
dea31012005-04-17 16:05:31 -0500415 if (rc >= 0) {
416 /* This side will initiate the PLOGI */
James Smart2e0fef82007-06-17 19:56:36 -0500417 spin_lock_irq(shost->host_lock);
418 vport->fc_flag |= FC_PT2PT_PLOGI;
419 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500420
421 /*
422 * N_Port ID cannot be 0, set our to LocalID the other
423 * side will be RemoteID.
424 */
425
426 /* not equal */
427 if (rc)
James Smart2e0fef82007-06-17 19:56:36 -0500428 vport->fc_myDID = PT2PT_LocalID;
dea31012005-04-17 16:05:31 -0500429
430 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
431 if (!mbox)
432 goto fail;
433
434 lpfc_config_link(phba, mbox);
435
436 mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
James Smarted957682007-06-17 19:56:37 -0500437 mbox->vport = vport;
dea31012005-04-17 16:05:31 -0500438 rc = lpfc_sli_issue_mbox(phba, mbox,
James Smart92d7f7b2007-06-17 19:56:38 -0500439 MBX_NOWAIT | MBX_STOP_IOCB);
dea31012005-04-17 16:05:31 -0500440 if (rc == MBX_NOT_FINISHED) {
441 mempool_free(mbox, phba->mbox_mem_pool);
442 goto fail;
443 }
James Smart329f9bc2007-04-25 09:53:01 -0400444 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -0500445
James Smart2e0fef82007-06-17 19:56:36 -0500446 ndlp = lpfc_findnode_did(vport, PT2PT_RemoteID);
dea31012005-04-17 16:05:31 -0500447 if (!ndlp) {
448 /*
449 * Cannot find existing Fabric ndlp, so allocate a
450 * new one
451 */
452 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
453 if (!ndlp)
454 goto fail;
455
James Smart2e0fef82007-06-17 19:56:36 -0500456 lpfc_nlp_init(vport, ndlp, PT2PT_RemoteID);
dea31012005-04-17 16:05:31 -0500457 }
458
459 memcpy(&ndlp->nlp_portname, &sp->portName,
James Smart2e0fef82007-06-17 19:56:36 -0500460 sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -0500461 memcpy(&ndlp->nlp_nodename, &sp->nodeName,
James Smart2e0fef82007-06-17 19:56:36 -0500462 sizeof(struct lpfc_name));
463 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
464 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500465 ndlp->nlp_flag |= NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -0500466 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500467 } else {
468 /* This side will wait for the PLOGI */
James Smart329f9bc2007-04-25 09:53:01 -0400469 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -0500470 }
471
James Smart2e0fef82007-06-17 19:56:36 -0500472 spin_lock_irq(shost->host_lock);
473 vport->fc_flag |= FC_PT2PT;
474 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500475
476 /* Start discovery - this should just do CLEAR_LA */
James Smart2e0fef82007-06-17 19:56:36 -0500477 lpfc_disc_start(vport);
dea31012005-04-17 16:05:31 -0500478 return 0;
James Smart92d7f7b2007-06-17 19:56:38 -0500479fail:
dea31012005-04-17 16:05:31 -0500480 return -ENXIO;
481}
482
483static void
James Smart329f9bc2007-04-25 09:53:01 -0400484lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
485 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -0500486{
James Smart2e0fef82007-06-17 19:56:36 -0500487 struct lpfc_vport *vport = cmdiocb->vport;
488 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -0500489 IOCB_t *irsp = &rspiocb->iocb;
490 struct lpfc_nodelist *ndlp = cmdiocb->context1;
491 struct lpfc_dmabuf *pcmd = cmdiocb->context2, *prsp;
492 struct serv_parm *sp;
493 int rc;
494
495 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -0500496 if (lpfc_els_chk_latt(vport)) {
James Smart329f9bc2007-04-25 09:53:01 -0400497 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -0500498 goto out;
499 }
500
James Smart858c9f62007-06-17 19:56:39 -0500501 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
502 "FLOGI cmpl: status:x%x/x%x state:x%x",
503 irsp->ulpStatus, irsp->un.ulpWord[4],
504 vport->port_state);
505
dea31012005-04-17 16:05:31 -0500506 if (irsp->ulpStatus) {
507 /* Check for retry */
James Smart2e0fef82007-06-17 19:56:36 -0500508 if (lpfc_els_retry(phba, cmdiocb, rspiocb))
dea31012005-04-17 16:05:31 -0500509 goto out;
James Smart2e0fef82007-06-17 19:56:36 -0500510
dea31012005-04-17 16:05:31 -0500511 /* FLOGI failed, so there is no fabric */
James Smart2e0fef82007-06-17 19:56:36 -0500512 spin_lock_irq(shost->host_lock);
513 vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
514 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500515
James Smart329f9bc2007-04-25 09:53:01 -0400516 /* If private loop, then allow max outstanding els to be
dea31012005-04-17 16:05:31 -0500517 * LPFC_MAX_DISC_THREADS (32). Scanning in the case of no
518 * alpa map would take too long otherwise.
519 */
520 if (phba->alpa_map[0] == 0) {
James Smart329f9bc2007-04-25 09:53:01 -0400521 phba->cfg_discovery_threads = LPFC_MAX_DISC_THREADS;
dea31012005-04-17 16:05:31 -0500522 }
523
524 /* FLOGI failure */
James Smart92d7f7b2007-06-17 19:56:38 -0500525 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
526 "%d (%d):0100 FLOGI failure Data: x%x x%x "
527 "x%x\n",
528 phba->brd_no, vport->vpi,
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500529 irsp->ulpStatus, irsp->un.ulpWord[4],
530 irsp->ulpTimeout);
dea31012005-04-17 16:05:31 -0500531 goto flogifail;
532 }
533
534 /*
535 * The FLogI succeeded. Sync the data for the CPU before
536 * accessing it.
537 */
538 prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list);
539
540 sp = prsp->virt + sizeof(uint32_t);
541
542 /* FLOGI completes successfully */
543 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart92d7f7b2007-06-17 19:56:38 -0500544 "%d (%d):0101 FLOGI completes sucessfully "
dea31012005-04-17 16:05:31 -0500545 "Data: x%x x%x x%x x%x\n",
James Smart92d7f7b2007-06-17 19:56:38 -0500546 phba->brd_no, vport->vpi,
dea31012005-04-17 16:05:31 -0500547 irsp->un.ulpWord[4], sp->cmn.e_d_tov,
548 sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution);
549
James Smart2e0fef82007-06-17 19:56:36 -0500550 if (vport->port_state == LPFC_FLOGI) {
dea31012005-04-17 16:05:31 -0500551 /*
552 * If Common Service Parameters indicate Nport
553 * we are point to point, if Fport we are Fabric.
554 */
555 if (sp->cmn.fPort)
James Smart2e0fef82007-06-17 19:56:36 -0500556 rc = lpfc_cmpl_els_flogi_fabric(vport, ndlp, sp, irsp);
dea31012005-04-17 16:05:31 -0500557 else
James Smart2e0fef82007-06-17 19:56:36 -0500558 rc = lpfc_cmpl_els_flogi_nport(vport, ndlp, sp);
dea31012005-04-17 16:05:31 -0500559
560 if (!rc)
561 goto out;
562 }
563
564flogifail:
James Smart329f9bc2007-04-25 09:53:01 -0400565 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -0500566
James Smart858c9f62007-06-17 19:56:39 -0500567 if (!lpfc_error_lost_link(irsp)) {
dea31012005-04-17 16:05:31 -0500568 /* FLOGI failed, so just use loop map to make discovery list */
James Smart2e0fef82007-06-17 19:56:36 -0500569 lpfc_disc_list_loopmap(vport);
dea31012005-04-17 16:05:31 -0500570
571 /* Start discovery */
James Smart2e0fef82007-06-17 19:56:36 -0500572 lpfc_disc_start(vport);
dea31012005-04-17 16:05:31 -0500573 }
574
575out:
576 lpfc_els_free_iocb(phba, cmdiocb);
577}
578
579static int
James Smart2e0fef82007-06-17 19:56:36 -0500580lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
dea31012005-04-17 16:05:31 -0500581 uint8_t retry)
582{
James Smart2e0fef82007-06-17 19:56:36 -0500583 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500584 struct serv_parm *sp;
585 IOCB_t *icmd;
586 struct lpfc_iocbq *elsiocb;
587 struct lpfc_sli_ring *pring;
588 uint8_t *pcmd;
589 uint16_t cmdsize;
590 uint32_t tmo;
591 int rc;
592
593 pring = &phba->sli.ring[LPFC_ELS_RING];
594
James Smart92d7f7b2007-06-17 19:56:38 -0500595 cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
James Smart2e0fef82007-06-17 19:56:36 -0500596 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
597 ndlp->nlp_DID, ELS_CMD_FLOGI);
James Smart92d7f7b2007-06-17 19:56:38 -0500598
James Smart488d1462006-03-07 15:02:37 -0500599 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500600 return 1;
dea31012005-04-17 16:05:31 -0500601
602 icmd = &elsiocb->iocb;
603 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
604
605 /* For FLOGI request, remainder of payload is service parameters */
606 *((uint32_t *) (pcmd)) = ELS_CMD_FLOGI;
James Smart92d7f7b2007-06-17 19:56:38 -0500607 pcmd += sizeof(uint32_t);
608 memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
dea31012005-04-17 16:05:31 -0500609 sp = (struct serv_parm *) pcmd;
610
611 /* Setup CSPs accordingly for Fabric */
612 sp->cmn.e_d_tov = 0;
613 sp->cmn.w2.r_a_tov = 0;
614 sp->cls1.classValid = 0;
615 sp->cls2.seqDelivery = 1;
616 sp->cls3.seqDelivery = 1;
617 if (sp->cmn.fcphLow < FC_PH3)
618 sp->cmn.fcphLow = FC_PH3;
619 if (sp->cmn.fcphHigh < FC_PH3)
620 sp->cmn.fcphHigh = FC_PH3;
621
James Smart92d7f7b2007-06-17 19:56:38 -0500622 if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
623 sp->cmn.request_multiple_Nport = 1;
624
625 /* For FLOGI, Let FLOGI rsp set the NPortID for VPI 0 */
626 icmd->ulpCt_h = 1;
627 icmd->ulpCt_l = 0;
628 }
629
James Smart858c9f62007-06-17 19:56:39 -0500630 if (phba->fc_topology != TOPOLOGY_LOOP) {
631 icmd->un.elsreq64.myID = 0;
632 icmd->un.elsreq64.fl = 1;
633 }
634
dea31012005-04-17 16:05:31 -0500635 tmo = phba->fc_ratov;
636 phba->fc_ratov = LPFC_DISC_FLOGI_TMO;
James Smart2e0fef82007-06-17 19:56:36 -0500637 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -0500638 phba->fc_ratov = tmo;
639
640 phba->fc_stat.elsXmitFLOGI++;
641 elsiocb->iocb_cmpl = lpfc_cmpl_els_flogi;
James Smart858c9f62007-06-17 19:56:39 -0500642
643 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
644 "Issue FLOGI: opt:x%x",
645 phba->sli3_options, 0, 0);
646
James Smart92d7f7b2007-06-17 19:56:38 -0500647 rc = lpfc_issue_fabric_iocb(phba, elsiocb);
dea31012005-04-17 16:05:31 -0500648 if (rc == IOCB_ERROR) {
649 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500650 return 1;
dea31012005-04-17 16:05:31 -0500651 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500652 return 0;
dea31012005-04-17 16:05:31 -0500653}
654
655int
James Smart2e0fef82007-06-17 19:56:36 -0500656lpfc_els_abort_flogi(struct lpfc_hba *phba)
dea31012005-04-17 16:05:31 -0500657{
658 struct lpfc_sli_ring *pring;
659 struct lpfc_iocbq *iocb, *next_iocb;
660 struct lpfc_nodelist *ndlp;
661 IOCB_t *icmd;
662
663 /* Abort outstanding I/O on NPort <nlp_DID> */
664 lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
665 "%d:0201 Abort outstanding I/O on NPort x%x\n",
666 phba->brd_no, Fabric_DID);
667
668 pring = &phba->sli.ring[LPFC_ELS_RING];
669
670 /*
671 * Check the txcmplq for an iocb that matches the nport the driver is
672 * searching for.
673 */
James Smart2e0fef82007-06-17 19:56:36 -0500674 spin_lock_irq(&phba->hbalock);
dea31012005-04-17 16:05:31 -0500675 list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
676 icmd = &iocb->iocb;
James Smart2e0fef82007-06-17 19:56:36 -0500677 if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR &&
678 icmd->un.elsreq64.bdl.ulpIoTag32) {
dea31012005-04-17 16:05:31 -0500679 ndlp = (struct lpfc_nodelist *)(iocb->context1);
James Smart92d7f7b2007-06-17 19:56:38 -0500680 if (ndlp && (ndlp->nlp_DID == Fabric_DID)) {
James Smart07951072007-04-25 09:51:38 -0400681 lpfc_sli_issue_abort_iotag(phba, pring, iocb);
James Smart92d7f7b2007-06-17 19:56:38 -0500682 }
dea31012005-04-17 16:05:31 -0500683 }
684 }
James Smart2e0fef82007-06-17 19:56:36 -0500685 spin_unlock_irq(&phba->hbalock);
dea31012005-04-17 16:05:31 -0500686
687 return 0;
688}
689
690int
James Smart2e0fef82007-06-17 19:56:36 -0500691lpfc_initial_flogi(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -0500692{
James Smart2e0fef82007-06-17 19:56:36 -0500693 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500694 struct lpfc_nodelist *ndlp;
695
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500696 /* First look for the Fabric ndlp */
James Smart2e0fef82007-06-17 19:56:36 -0500697 ndlp = lpfc_findnode_did(vport, Fabric_DID);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500698 if (!ndlp) {
dea31012005-04-17 16:05:31 -0500699 /* Cannot find existing Fabric ndlp, so allocate a new one */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500700 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
701 if (!ndlp)
702 return 0;
James Smart2e0fef82007-06-17 19:56:36 -0500703 lpfc_nlp_init(vport, ndlp, Fabric_DID);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500704 } else {
James Smart2e0fef82007-06-17 19:56:36 -0500705 lpfc_dequeue_node(vport, ndlp);
dea31012005-04-17 16:05:31 -0500706 }
James Smart2e0fef82007-06-17 19:56:36 -0500707 if (lpfc_issue_els_flogi(vport, ndlp, 0)) {
James Smart329f9bc2007-04-25 09:53:01 -0400708 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -0500709 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500710 return 1;
dea31012005-04-17 16:05:31 -0500711}
712
James Smart92d7f7b2007-06-17 19:56:38 -0500713int
714lpfc_initial_fdisc(struct lpfc_vport *vport)
715{
716 struct lpfc_hba *phba = vport->phba;
717 struct lpfc_nodelist *ndlp;
718
719 /* First look for the Fabric ndlp */
720 ndlp = lpfc_findnode_did(vport, Fabric_DID);
721 if (!ndlp) {
722 /* Cannot find existing Fabric ndlp, so allocate a new one */
723 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
724 if (!ndlp)
725 return 0;
726 lpfc_nlp_init(vport, ndlp, Fabric_DID);
727 } else {
728 lpfc_dequeue_node(vport, ndlp);
729 }
730 if (lpfc_issue_els_fdisc(vport, ndlp, 0)) {
731 lpfc_nlp_put(ndlp);
732 }
733 return 1;
734}
dea31012005-04-17 16:05:31 -0500735static void
James Smart2e0fef82007-06-17 19:56:36 -0500736lpfc_more_plogi(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -0500737{
738 int sentplogi;
James Smart2e0fef82007-06-17 19:56:36 -0500739 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500740
James Smart2e0fef82007-06-17 19:56:36 -0500741 if (vport->num_disc_nodes)
742 vport->num_disc_nodes--;
dea31012005-04-17 16:05:31 -0500743
744 /* Continue discovery with <num_disc_nodes> PLOGIs to go */
745 lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
James Smart92d7f7b2007-06-17 19:56:38 -0500746 "%d (%d):0232 Continue discovery with %d PLOGIs to go "
dea31012005-04-17 16:05:31 -0500747 "Data: x%x x%x x%x\n",
James Smart92d7f7b2007-06-17 19:56:38 -0500748 phba->brd_no, vport->vpi, vport->num_disc_nodes,
James Smart2e0fef82007-06-17 19:56:36 -0500749 vport->fc_plogi_cnt, vport->fc_flag, vport->port_state);
dea31012005-04-17 16:05:31 -0500750
751 /* Check to see if there are more PLOGIs to be sent */
James Smart2e0fef82007-06-17 19:56:36 -0500752 if (vport->fc_flag & FC_NLP_MORE)
753 /* go thru NPR nodes and issue any remaining ELS PLOGIs */
754 sentplogi = lpfc_els_disc_plogi(vport);
755
dea31012005-04-17 16:05:31 -0500756 return;
757}
758
James Smart488d1462006-03-07 15:02:37 -0500759static struct lpfc_nodelist *
James Smart92d7f7b2007-06-17 19:56:38 -0500760lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
James Smart488d1462006-03-07 15:02:37 -0500761 struct lpfc_nodelist *ndlp)
762{
James Smart2e0fef82007-06-17 19:56:36 -0500763 struct lpfc_vport *vport = ndlp->vport;
James Smart488d1462006-03-07 15:02:37 -0500764 struct lpfc_nodelist *new_ndlp;
James Smart488d1462006-03-07 15:02:37 -0500765 struct serv_parm *sp;
James Smart92d7f7b2007-06-17 19:56:38 -0500766 uint8_t name[sizeof(struct lpfc_name)];
James Smart488d1462006-03-07 15:02:37 -0500767 uint32_t rc;
768
James Smart2fb9bd82006-12-02 13:33:57 -0500769 /* Fabric nodes can have the same WWPN so we don't bother searching
770 * by WWPN. Just return the ndlp that was given to us.
771 */
772 if (ndlp->nlp_type & NLP_FABRIC)
773 return ndlp;
774
James Smart92d7f7b2007-06-17 19:56:38 -0500775 sp = (struct serv_parm *) ((uint8_t *) prsp + sizeof(uint32_t));
James Smart685f0bf2007-04-25 09:53:08 -0400776 memset(name, 0, sizeof(struct lpfc_name));
James Smart488d1462006-03-07 15:02:37 -0500777
James Smart685f0bf2007-04-25 09:53:08 -0400778 /* Now we find out if the NPort we are logging into, matches the WWPN
James Smart488d1462006-03-07 15:02:37 -0500779 * we have for that ndlp. If not, we have some work to do.
780 */
James Smart2e0fef82007-06-17 19:56:36 -0500781 new_ndlp = lpfc_findnode_wwpn(vport, &sp->portName);
James Smart488d1462006-03-07 15:02:37 -0500782
James Smart92795652006-07-06 15:50:02 -0400783 if (new_ndlp == ndlp)
James Smart488d1462006-03-07 15:02:37 -0500784 return ndlp;
James Smart488d1462006-03-07 15:02:37 -0500785
786 if (!new_ndlp) {
James Smart2e0fef82007-06-17 19:56:36 -0500787 rc = memcmp(&ndlp->nlp_portname, name,
788 sizeof(struct lpfc_name));
James Smart92795652006-07-06 15:50:02 -0400789 if (!rc)
790 return ndlp;
James Smart488d1462006-03-07 15:02:37 -0500791 new_ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC);
792 if (!new_ndlp)
793 return ndlp;
794
James Smart2e0fef82007-06-17 19:56:36 -0500795 lpfc_nlp_init(vport, new_ndlp, ndlp->nlp_DID);
James Smart488d1462006-03-07 15:02:37 -0500796 }
797
James Smart2e0fef82007-06-17 19:56:36 -0500798 lpfc_unreg_rpi(vport, new_ndlp);
James Smart488d1462006-03-07 15:02:37 -0500799 new_ndlp->nlp_DID = ndlp->nlp_DID;
James Smart92795652006-07-06 15:50:02 -0400800 new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
James Smart2e0fef82007-06-17 19:56:36 -0500801 lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state);
James Smart488d1462006-03-07 15:02:37 -0500802
James Smart2e0fef82007-06-17 19:56:36 -0500803 /* Move this back to NPR state */
James Smartde0c5b32007-04-25 09:52:27 -0400804 if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0)
James Smart2e0fef82007-06-17 19:56:36 -0500805 lpfc_drop_node(vport, ndlp);
James Smart92795652006-07-06 15:50:02 -0400806 else {
James Smart2e0fef82007-06-17 19:56:36 -0500807 lpfc_unreg_rpi(vport, ndlp);
James Smart92795652006-07-06 15:50:02 -0400808 ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
James Smart2e0fef82007-06-17 19:56:36 -0500809 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
James Smart92795652006-07-06 15:50:02 -0400810 }
James Smart488d1462006-03-07 15:02:37 -0500811 return new_ndlp;
812}
813
dea31012005-04-17 16:05:31 -0500814static void
James Smart2e0fef82007-06-17 19:56:36 -0500815lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
816 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -0500817{
James Smart2e0fef82007-06-17 19:56:36 -0500818 struct lpfc_vport *vport = cmdiocb->vport;
819 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -0500820 IOCB_t *irsp;
dea31012005-04-17 16:05:31 -0500821 struct lpfc_nodelist *ndlp;
James Smart92795652006-07-06 15:50:02 -0400822 struct lpfc_dmabuf *prsp;
dea31012005-04-17 16:05:31 -0500823 int disc, rc, did, type;
824
dea31012005-04-17 16:05:31 -0500825 /* we pass cmdiocb to state machine which needs rspiocb as well */
826 cmdiocb->context_un.rsp_iocb = rspiocb;
827
828 irsp = &rspiocb->iocb;
James Smart858c9f62007-06-17 19:56:39 -0500829 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
830 "PLOGI cmpl: status:x%x/x%x did:x%x",
831 irsp->ulpStatus, irsp->un.ulpWord[4],
832 irsp->un.elsreq64.remoteID);
833
James Smart2e0fef82007-06-17 19:56:36 -0500834 ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID);
James Smarted957682007-06-17 19:56:37 -0500835 if (!ndlp) {
James Smart92d7f7b2007-06-17 19:56:38 -0500836 lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
837 "%d (%d):0136 PLOGI completes to NPort x%x "
838 "with no ndlp. Data: x%x x%x x%x\n",
839 phba->brd_no, vport->vpi, irsp->un.elsreq64.remoteID,
840 irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpIoTag);
James Smart488d1462006-03-07 15:02:37 -0500841 goto out;
James Smarted957682007-06-17 19:56:37 -0500842 }
dea31012005-04-17 16:05:31 -0500843
844 /* Since ndlp can be freed in the disc state machine, note if this node
845 * is being used during discovery.
846 */
James Smart2e0fef82007-06-17 19:56:36 -0500847 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500848 disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
James Smart488d1462006-03-07 15:02:37 -0500849 ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -0500850 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500851 rc = 0;
852
853 /* PLOGI completes to NPort <nlp_DID> */
854 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart92d7f7b2007-06-17 19:56:38 -0500855 "%d (%d):0102 PLOGI completes to NPort x%x "
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500856 "Data: x%x x%x x%x x%x x%x\n",
James Smart92d7f7b2007-06-17 19:56:38 -0500857 phba->brd_no, vport->vpi, ndlp->nlp_DID,
858 irsp->ulpStatus, irsp->un.ulpWord[4],
859 irsp->ulpTimeout, disc, vport->num_disc_nodes);
dea31012005-04-17 16:05:31 -0500860
861 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -0500862 if (lpfc_els_chk_latt(vport)) {
863 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500864 ndlp->nlp_flag |= NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -0500865 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500866 goto out;
867 }
868
869 /* ndlp could be freed in DSM, save these values now */
870 type = ndlp->nlp_type;
871 did = ndlp->nlp_DID;
872
873 if (irsp->ulpStatus) {
874 /* Check for retry */
875 if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
876 /* ELS command is being retried */
877 if (disc) {
James Smart2e0fef82007-06-17 19:56:36 -0500878 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500879 ndlp->nlp_flag |= NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -0500880 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500881 }
882 goto out;
883 }
884
885 /* PLOGI failed */
James Smart92d7f7b2007-06-17 19:56:38 -0500886 if (ndlp->nlp_DID == NameServer_DID) {
887 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
888 lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
889 "%d (%d):0250 Nameserver login error: "
890 "0x%x / 0x%x\n",
891 phba->brd_no, vport->vpi,
892 irsp->ulpStatus, irsp->un.ulpWord[4]);
893 }
894
dea31012005-04-17 16:05:31 -0500895 /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
James Smart858c9f62007-06-17 19:56:39 -0500896 if (lpfc_error_lost_link(irsp)) {
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500897 rc = NLP_STE_FREED_NODE;
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -0500898 } else {
James Smart2e0fef82007-06-17 19:56:36 -0500899 rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart92d7f7b2007-06-17 19:56:38 -0500900 NLP_EVT_CMPL_PLOGI);
dea31012005-04-17 16:05:31 -0500901 }
902 } else {
903 /* Good status, call state machine */
James Smart92795652006-07-06 15:50:02 -0400904 prsp = list_entry(((struct lpfc_dmabuf *)
James Smart92d7f7b2007-06-17 19:56:38 -0500905 cmdiocb->context2)->list.next,
906 struct lpfc_dmabuf, list);
907 ndlp = lpfc_plogi_confirm_nport(phba, prsp->virt, ndlp);
James Smart2e0fef82007-06-17 19:56:36 -0500908 rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart92d7f7b2007-06-17 19:56:38 -0500909 NLP_EVT_CMPL_PLOGI);
dea31012005-04-17 16:05:31 -0500910 }
911
James Smart2e0fef82007-06-17 19:56:36 -0500912 if (disc && vport->num_disc_nodes) {
dea31012005-04-17 16:05:31 -0500913 /* Check to see if there are more PLOGIs to be sent */
James Smart2e0fef82007-06-17 19:56:36 -0500914 lpfc_more_plogi(vport);
dea31012005-04-17 16:05:31 -0500915
James Smart2e0fef82007-06-17 19:56:36 -0500916 if (vport->num_disc_nodes == 0) {
917 spin_lock_irq(shost->host_lock);
918 vport->fc_flag &= ~FC_NDISC_ACTIVE;
919 spin_unlock_irq(shost->host_lock);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500920
James Smart2e0fef82007-06-17 19:56:36 -0500921 lpfc_can_disctmo(vport);
922 if (vport->fc_flag & FC_RSCN_MODE) {
James Smart10d4e952006-04-15 11:53:15 -0400923 /*
924 * Check to see if more RSCNs came in while
925 * we were processing this one.
926 */
James Smart2e0fef82007-06-17 19:56:36 -0500927 if ((vport->fc_rscn_id_cnt == 0) &&
928 (!(vport->fc_flag & FC_RSCN_DISCOVERY))) {
929 spin_lock_irq(shost->host_lock);
930 vport->fc_flag &= ~FC_RSCN_MODE;
931 spin_unlock_irq(shost->host_lock);
James Smart10d4e952006-04-15 11:53:15 -0400932 } else {
James Smart2e0fef82007-06-17 19:56:36 -0500933 lpfc_els_handle_rscn(vport);
James Smart10d4e952006-04-15 11:53:15 -0400934 }
dea31012005-04-17 16:05:31 -0500935 }
936 }
937 }
938
939out:
940 lpfc_els_free_iocb(phba, cmdiocb);
941 return;
942}
943
944int
James Smart2e0fef82007-06-17 19:56:36 -0500945lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
dea31012005-04-17 16:05:31 -0500946{
James Smart2e0fef82007-06-17 19:56:36 -0500947 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500948 struct serv_parm *sp;
949 IOCB_t *icmd;
950 struct lpfc_iocbq *elsiocb;
951 struct lpfc_sli_ring *pring;
952 struct lpfc_sli *psli;
953 uint8_t *pcmd;
954 uint16_t cmdsize;
James Smart92d7f7b2007-06-17 19:56:38 -0500955 int ret;
dea31012005-04-17 16:05:31 -0500956
957 psli = &phba->sli;
958 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
959
James Smart92d7f7b2007-06-17 19:56:38 -0500960 cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
James Smart2e0fef82007-06-17 19:56:36 -0500961 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, NULL, did,
962 ELS_CMD_PLOGI);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500963 if (!elsiocb)
964 return 1;
dea31012005-04-17 16:05:31 -0500965
966 icmd = &elsiocb->iocb;
967 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
968
969 /* For PLOGI request, remainder of payload is service parameters */
970 *((uint32_t *) (pcmd)) = ELS_CMD_PLOGI;
James Smart92d7f7b2007-06-17 19:56:38 -0500971 pcmd += sizeof(uint32_t);
972 memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
dea31012005-04-17 16:05:31 -0500973 sp = (struct serv_parm *) pcmd;
974
975 if (sp->cmn.fcphLow < FC_PH_4_3)
976 sp->cmn.fcphLow = FC_PH_4_3;
977
978 if (sp->cmn.fcphHigh < FC_PH3)
979 sp->cmn.fcphHigh = FC_PH3;
980
James Smart858c9f62007-06-17 19:56:39 -0500981 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
982 "Issue PLOGI: did:x%x",
983 did, 0, 0);
984
dea31012005-04-17 16:05:31 -0500985 phba->fc_stat.elsXmitPLOGI++;
986 elsiocb->iocb_cmpl = lpfc_cmpl_els_plogi;
James Smart92d7f7b2007-06-17 19:56:38 -0500987 ret = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
988
989 if (ret == IOCB_ERROR) {
dea31012005-04-17 16:05:31 -0500990 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500991 return 1;
dea31012005-04-17 16:05:31 -0500992 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500993 return 0;
dea31012005-04-17 16:05:31 -0500994}
995
996static void
James Smart2e0fef82007-06-17 19:56:36 -0500997lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
998 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -0500999{
James Smart2e0fef82007-06-17 19:56:36 -05001000 struct lpfc_vport *vport = cmdiocb->vport;
1001 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05001002 IOCB_t *irsp;
1003 struct lpfc_sli *psli;
1004 struct lpfc_nodelist *ndlp;
1005
1006 psli = &phba->sli;
1007 /* we pass cmdiocb to state machine which needs rspiocb as well */
1008 cmdiocb->context_un.rsp_iocb = rspiocb;
1009
1010 irsp = &(rspiocb->iocb);
1011 ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
James Smart2e0fef82007-06-17 19:56:36 -05001012 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001013 ndlp->nlp_flag &= ~NLP_PRLI_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001014 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001015
James Smart858c9f62007-06-17 19:56:39 -05001016 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1017 "PRLI cmpl: status:x%x/x%x did:x%x",
1018 irsp->ulpStatus, irsp->un.ulpWord[4],
1019 ndlp->nlp_DID);
1020
dea31012005-04-17 16:05:31 -05001021 /* PRLI completes to NPort <nlp_DID> */
1022 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart92d7f7b2007-06-17 19:56:38 -05001023 "%d (%d):0103 PRLI completes to NPort x%x "
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001024 "Data: x%x x%x x%x x%x\n",
James Smart92d7f7b2007-06-17 19:56:38 -05001025 phba->brd_no, vport->vpi, ndlp->nlp_DID,
1026 irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpTimeout,
James Smart2e0fef82007-06-17 19:56:36 -05001027 vport->num_disc_nodes);
dea31012005-04-17 16:05:31 -05001028
James Smart2e0fef82007-06-17 19:56:36 -05001029 vport->fc_prli_sent--;
dea31012005-04-17 16:05:31 -05001030 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -05001031 if (lpfc_els_chk_latt(vport))
dea31012005-04-17 16:05:31 -05001032 goto out;
1033
1034 if (irsp->ulpStatus) {
1035 /* Check for retry */
1036 if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
1037 /* ELS command is being retried */
1038 goto out;
1039 }
1040 /* PRLI failed */
1041 /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
James Smart858c9f62007-06-17 19:56:39 -05001042 if (lpfc_error_lost_link(irsp)) {
dea31012005-04-17 16:05:31 -05001043 goto out;
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05001044 } else {
James Smart2e0fef82007-06-17 19:56:36 -05001045 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart92d7f7b2007-06-17 19:56:38 -05001046 NLP_EVT_CMPL_PRLI);
dea31012005-04-17 16:05:31 -05001047 }
1048 } else {
1049 /* Good status, call state machine */
James Smart2e0fef82007-06-17 19:56:36 -05001050 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart92d7f7b2007-06-17 19:56:38 -05001051 NLP_EVT_CMPL_PRLI);
dea31012005-04-17 16:05:31 -05001052 }
1053
1054out:
1055 lpfc_els_free_iocb(phba, cmdiocb);
1056 return;
1057}
1058
1059int
James Smart2e0fef82007-06-17 19:56:36 -05001060lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
dea31012005-04-17 16:05:31 -05001061 uint8_t retry)
1062{
James Smart2e0fef82007-06-17 19:56:36 -05001063 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1064 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001065 PRLI *npr;
1066 IOCB_t *icmd;
1067 struct lpfc_iocbq *elsiocb;
1068 struct lpfc_sli_ring *pring;
1069 struct lpfc_sli *psli;
1070 uint8_t *pcmd;
1071 uint16_t cmdsize;
1072
1073 psli = &phba->sli;
1074 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
1075
James Smart92d7f7b2007-06-17 19:56:38 -05001076 cmdsize = (sizeof(uint32_t) + sizeof(PRLI));
James Smart2e0fef82007-06-17 19:56:36 -05001077 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
1078 ndlp->nlp_DID, ELS_CMD_PRLI);
James Smart488d1462006-03-07 15:02:37 -05001079 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001080 return 1;
dea31012005-04-17 16:05:31 -05001081
1082 icmd = &elsiocb->iocb;
1083 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1084
1085 /* For PRLI request, remainder of payload is service parameters */
James Smart92d7f7b2007-06-17 19:56:38 -05001086 memset(pcmd, 0, (sizeof(PRLI) + sizeof(uint32_t)));
dea31012005-04-17 16:05:31 -05001087 *((uint32_t *) (pcmd)) = ELS_CMD_PRLI;
James Smart92d7f7b2007-06-17 19:56:38 -05001088 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05001089
1090 /* For PRLI, remainder of payload is PRLI parameter page */
1091 npr = (PRLI *) pcmd;
1092 /*
1093 * If our firmware version is 3.20 or later,
1094 * set the following bits for FC-TAPE support.
1095 */
1096 if (phba->vpd.rev.feaLevelHigh >= 0x02) {
1097 npr->ConfmComplAllowed = 1;
1098 npr->Retry = 1;
1099 npr->TaskRetryIdReq = 1;
1100 }
1101 npr->estabImagePair = 1;
1102 npr->readXferRdyDis = 1;
1103
1104 /* For FCP support */
1105 npr->prliType = PRLI_FCP_TYPE;
1106 npr->initiatorFunc = 1;
1107
James Smart858c9f62007-06-17 19:56:39 -05001108 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1109 "Issue PRLI: did:x%x",
1110 ndlp->nlp_DID, 0, 0);
1111
dea31012005-04-17 16:05:31 -05001112 phba->fc_stat.elsXmitPRLI++;
1113 elsiocb->iocb_cmpl = lpfc_cmpl_els_prli;
James Smart2e0fef82007-06-17 19:56:36 -05001114 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001115 ndlp->nlp_flag |= NLP_PRLI_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001116 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001117 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
James Smart2e0fef82007-06-17 19:56:36 -05001118 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001119 ndlp->nlp_flag &= ~NLP_PRLI_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001120 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001121 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001122 return 1;
dea31012005-04-17 16:05:31 -05001123 }
James Smart2e0fef82007-06-17 19:56:36 -05001124 vport->fc_prli_sent++;
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001125 return 0;
dea31012005-04-17 16:05:31 -05001126}
1127
1128static void
James Smart2e0fef82007-06-17 19:56:36 -05001129lpfc_more_adisc(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05001130{
1131 int sentadisc;
James Smart2e0fef82007-06-17 19:56:36 -05001132 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001133
James Smart2e0fef82007-06-17 19:56:36 -05001134 if (vport->num_disc_nodes)
1135 vport->num_disc_nodes--;
dea31012005-04-17 16:05:31 -05001136
1137 /* Continue discovery with <num_disc_nodes> ADISCs to go */
1138 lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
James Smart92d7f7b2007-06-17 19:56:38 -05001139 "%d (%d):0210 Continue discovery with %d ADISCs to go "
dea31012005-04-17 16:05:31 -05001140 "Data: x%x x%x x%x\n",
James Smart92d7f7b2007-06-17 19:56:38 -05001141 phba->brd_no, vport->vpi, vport->num_disc_nodes,
James Smart2e0fef82007-06-17 19:56:36 -05001142 vport->fc_adisc_cnt, vport->fc_flag, vport->port_state);
dea31012005-04-17 16:05:31 -05001143
1144 /* Check to see if there are more ADISCs to be sent */
James Smart2e0fef82007-06-17 19:56:36 -05001145 if (vport->fc_flag & FC_NLP_MORE) {
1146 lpfc_set_disctmo(vport);
1147 /* go thru NPR nodes and issue any remaining ELS ADISCs */
1148 sentadisc = lpfc_els_disc_adisc(vport);
dea31012005-04-17 16:05:31 -05001149 }
1150 return;
1151}
1152
1153static void
James Smart2e0fef82007-06-17 19:56:36 -05001154lpfc_rscn_disc(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05001155{
James Smart2e0fef82007-06-17 19:56:36 -05001156 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1157
James Smart858c9f62007-06-17 19:56:39 -05001158 lpfc_can_disctmo(vport);
1159
dea31012005-04-17 16:05:31 -05001160 /* RSCN discovery */
James Smart2e0fef82007-06-17 19:56:36 -05001161 /* go thru NPR nodes and issue ELS PLOGIs */
1162 if (vport->fc_npr_cnt)
1163 if (lpfc_els_disc_plogi(vport))
dea31012005-04-17 16:05:31 -05001164 return;
James Smart2e0fef82007-06-17 19:56:36 -05001165
1166 if (vport->fc_flag & FC_RSCN_MODE) {
dea31012005-04-17 16:05:31 -05001167 /* Check to see if more RSCNs came in while we were
1168 * processing this one.
1169 */
James Smart2e0fef82007-06-17 19:56:36 -05001170 if ((vport->fc_rscn_id_cnt == 0) &&
1171 (!(vport->fc_flag & FC_RSCN_DISCOVERY))) {
1172 spin_lock_irq(shost->host_lock);
1173 vport->fc_flag &= ~FC_RSCN_MODE;
1174 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001175 } else {
James Smart2e0fef82007-06-17 19:56:36 -05001176 lpfc_els_handle_rscn(vport);
dea31012005-04-17 16:05:31 -05001177 }
1178 }
1179}
1180
1181static void
James Smart2e0fef82007-06-17 19:56:36 -05001182lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1183 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05001184{
James Smart2e0fef82007-06-17 19:56:36 -05001185 struct lpfc_vport *vport = cmdiocb->vport;
1186 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05001187 IOCB_t *irsp;
dea31012005-04-17 16:05:31 -05001188 struct lpfc_nodelist *ndlp;
James Smart2e0fef82007-06-17 19:56:36 -05001189 int disc;
dea31012005-04-17 16:05:31 -05001190
1191 /* we pass cmdiocb to state machine which needs rspiocb as well */
1192 cmdiocb->context_un.rsp_iocb = rspiocb;
1193
1194 irsp = &(rspiocb->iocb);
1195 ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
dea31012005-04-17 16:05:31 -05001196
James Smart858c9f62007-06-17 19:56:39 -05001197 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1198 "ADISC cmpl: status:x%x/x%x did:x%x",
1199 irsp->ulpStatus, irsp->un.ulpWord[4],
1200 ndlp->nlp_DID);
1201
dea31012005-04-17 16:05:31 -05001202 /* Since ndlp can be freed in the disc state machine, note if this node
1203 * is being used during discovery.
1204 */
James Smart2e0fef82007-06-17 19:56:36 -05001205 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001206 disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001207 ndlp->nlp_flag &= ~(NLP_ADISC_SND | NLP_NPR_2B_DISC);
James Smart2e0fef82007-06-17 19:56:36 -05001208 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001209
1210 /* ADISC completes to NPort <nlp_DID> */
1211 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart92d7f7b2007-06-17 19:56:38 -05001212 "%d (%d):0104 ADISC completes to NPort x%x "
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001213 "Data: x%x x%x x%x x%x x%x\n",
James Smart92d7f7b2007-06-17 19:56:38 -05001214 phba->brd_no, vport->vpi, ndlp->nlp_DID,
1215 irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpTimeout,
1216 disc, vport->num_disc_nodes);
dea31012005-04-17 16:05:31 -05001217
1218 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -05001219 if (lpfc_els_chk_latt(vport)) {
1220 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001221 ndlp->nlp_flag |= NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -05001222 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001223 goto out;
1224 }
1225
1226 if (irsp->ulpStatus) {
1227 /* Check for retry */
1228 if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
1229 /* ELS command is being retried */
1230 if (disc) {
James Smart2e0fef82007-06-17 19:56:36 -05001231 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001232 ndlp->nlp_flag |= NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -05001233 spin_unlock_irq(shost->host_lock);
1234 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -05001235 }
1236 goto out;
1237 }
1238 /* ADISC failed */
1239 /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
James Smart858c9f62007-06-17 19:56:39 -05001240 if (!lpfc_error_lost_link(irsp)) {
James Smart2e0fef82007-06-17 19:56:36 -05001241 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart858c9f62007-06-17 19:56:39 -05001242 NLP_EVT_CMPL_ADISC);
dea31012005-04-17 16:05:31 -05001243 }
1244 } else {
1245 /* Good status, call state machine */
James Smart2e0fef82007-06-17 19:56:36 -05001246 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
dea31012005-04-17 16:05:31 -05001247 NLP_EVT_CMPL_ADISC);
1248 }
1249
James Smart2e0fef82007-06-17 19:56:36 -05001250 if (disc && vport->num_disc_nodes) {
dea31012005-04-17 16:05:31 -05001251 /* Check to see if there are more ADISCs to be sent */
James Smart2e0fef82007-06-17 19:56:36 -05001252 lpfc_more_adisc(vport);
dea31012005-04-17 16:05:31 -05001253
1254 /* Check to see if we are done with ADISC authentication */
James Smart2e0fef82007-06-17 19:56:36 -05001255 if (vport->num_disc_nodes == 0) {
James Smart92d7f7b2007-06-17 19:56:38 -05001256 /* If we get here, there is nothing left to ADISC */
1257 /*
1258 * For NPIV, cmpl_reg_vpi will set port_state to READY,
1259 * and continue discovery.
1260 */
1261 if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
1262 !(vport->fc_flag & FC_RSCN_MODE)) {
1263 lpfc_issue_reg_vpi(phba, vport);
1264 goto out;
1265 }
1266 /*
1267 * For SLI2, we need to set port_state to READY
1268 * and continue discovery.
1269 */
1270 if (vport->port_state < LPFC_VPORT_READY) {
1271 /* If we get here, there is nothing to ADISC */
James Smarted957682007-06-17 19:56:37 -05001272 if (vport->port_type == LPFC_PHYSICAL_PORT)
James Smart2e0fef82007-06-17 19:56:36 -05001273 lpfc_issue_clear_la(phba, vport);
James Smart92d7f7b2007-06-17 19:56:38 -05001274
1275 if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) {
1276 vport->num_disc_nodes = 0;
1277 /* go thru NPR list, issue ELS PLOGIs */
1278 if (vport->fc_npr_cnt)
1279 lpfc_els_disc_plogi(vport);
1280
1281 if (!vport->num_disc_nodes) {
1282 spin_lock_irq(shost->host_lock);
1283 vport->fc_flag &=
1284 ~FC_NDISC_ACTIVE;
1285 spin_unlock_irq(
1286 shost->host_lock);
1287 lpfc_can_disctmo(vport);
1288 }
1289 }
1290 vport->port_state = LPFC_VPORT_READY;
dea31012005-04-17 16:05:31 -05001291 } else {
James Smart2e0fef82007-06-17 19:56:36 -05001292 lpfc_rscn_disc(vport);
dea31012005-04-17 16:05:31 -05001293 }
1294 }
1295 }
dea31012005-04-17 16:05:31 -05001296out:
1297 lpfc_els_free_iocb(phba, cmdiocb);
1298 return;
1299}
1300
1301int
James Smart2e0fef82007-06-17 19:56:36 -05001302lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
dea31012005-04-17 16:05:31 -05001303 uint8_t retry)
1304{
James Smart2e0fef82007-06-17 19:56:36 -05001305 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1306 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001307 ADISC *ap;
1308 IOCB_t *icmd;
1309 struct lpfc_iocbq *elsiocb;
James Smart2e0fef82007-06-17 19:56:36 -05001310 struct lpfc_sli *psli = &phba->sli;
1311 struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
dea31012005-04-17 16:05:31 -05001312 uint8_t *pcmd;
1313 uint16_t cmdsize;
1314
James Smart92d7f7b2007-06-17 19:56:38 -05001315 cmdsize = (sizeof(uint32_t) + sizeof(ADISC));
James Smart2e0fef82007-06-17 19:56:36 -05001316 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
1317 ndlp->nlp_DID, ELS_CMD_ADISC);
James Smart488d1462006-03-07 15:02:37 -05001318 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001319 return 1;
dea31012005-04-17 16:05:31 -05001320
1321 icmd = &elsiocb->iocb;
1322 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1323
1324 /* For ADISC request, remainder of payload is service parameters */
1325 *((uint32_t *) (pcmd)) = ELS_CMD_ADISC;
James Smart92d7f7b2007-06-17 19:56:38 -05001326 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05001327
1328 /* Fill in ADISC payload */
1329 ap = (ADISC *) pcmd;
1330 ap->hardAL_PA = phba->fc_pref_ALPA;
James Smart92d7f7b2007-06-17 19:56:38 -05001331 memcpy(&ap->portName, &vport->fc_portname, sizeof(struct lpfc_name));
1332 memcpy(&ap->nodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
James Smart2e0fef82007-06-17 19:56:36 -05001333 ap->DID = be32_to_cpu(vport->fc_myDID);
dea31012005-04-17 16:05:31 -05001334
James Smart858c9f62007-06-17 19:56:39 -05001335 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1336 "Issue ADISC: did:x%x",
1337 ndlp->nlp_DID, 0, 0);
1338
dea31012005-04-17 16:05:31 -05001339 phba->fc_stat.elsXmitADISC++;
1340 elsiocb->iocb_cmpl = lpfc_cmpl_els_adisc;
James Smart2e0fef82007-06-17 19:56:36 -05001341 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001342 ndlp->nlp_flag |= NLP_ADISC_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001343 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001344 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
James Smart2e0fef82007-06-17 19:56:36 -05001345 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001346 ndlp->nlp_flag &= ~NLP_ADISC_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001347 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001348 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001349 return 1;
dea31012005-04-17 16:05:31 -05001350 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001351 return 0;
dea31012005-04-17 16:05:31 -05001352}
1353
1354static void
James Smart2e0fef82007-06-17 19:56:36 -05001355lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1356 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05001357{
James Smart2e0fef82007-06-17 19:56:36 -05001358 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
1359 struct lpfc_vport *vport = ndlp->vport;
1360 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05001361 IOCB_t *irsp;
1362 struct lpfc_sli *psli;
dea31012005-04-17 16:05:31 -05001363
1364 psli = &phba->sli;
1365 /* we pass cmdiocb to state machine which needs rspiocb as well */
1366 cmdiocb->context_un.rsp_iocb = rspiocb;
1367
1368 irsp = &(rspiocb->iocb);
James Smart2e0fef82007-06-17 19:56:36 -05001369 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001370 ndlp->nlp_flag &= ~NLP_LOGO_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001371 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001372
James Smart858c9f62007-06-17 19:56:39 -05001373 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1374 "LOGO cmpl: status:x%x/x%x did:x%x",
1375 irsp->ulpStatus, irsp->un.ulpWord[4],
1376 ndlp->nlp_DID);
1377
dea31012005-04-17 16:05:31 -05001378 /* LOGO completes to NPort <nlp_DID> */
1379 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart92d7f7b2007-06-17 19:56:38 -05001380 "%d (%d):0105 LOGO completes to NPort x%x "
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001381 "Data: x%x x%x x%x x%x\n",
James Smart92d7f7b2007-06-17 19:56:38 -05001382 phba->brd_no, vport->vpi, ndlp->nlp_DID,
1383 irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpTimeout,
James Smart2e0fef82007-06-17 19:56:36 -05001384 vport->num_disc_nodes);
dea31012005-04-17 16:05:31 -05001385
1386 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -05001387 if (lpfc_els_chk_latt(vport))
dea31012005-04-17 16:05:31 -05001388 goto out;
1389
James Smart92d7f7b2007-06-17 19:56:38 -05001390 if (ndlp->nlp_flag & NLP_TARGET_REMOVE) {
1391 /* NLP_EVT_DEVICE_RM should unregister the RPI
1392 * which should abort all outstanding IOs.
1393 */
1394 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
1395 NLP_EVT_DEVICE_RM);
1396 goto out;
1397 }
1398
dea31012005-04-17 16:05:31 -05001399 if (irsp->ulpStatus) {
1400 /* Check for retry */
James Smart2e0fef82007-06-17 19:56:36 -05001401 if (lpfc_els_retry(phba, cmdiocb, rspiocb))
dea31012005-04-17 16:05:31 -05001402 /* ELS command is being retried */
1403 goto out;
dea31012005-04-17 16:05:31 -05001404 /* LOGO failed */
1405 /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
James Smart858c9f62007-06-17 19:56:39 -05001406 if (lpfc_error_lost_link(irsp))
dea31012005-04-17 16:05:31 -05001407 goto out;
James Smart858c9f62007-06-17 19:56:39 -05001408 else
James Smart2e0fef82007-06-17 19:56:36 -05001409 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart92d7f7b2007-06-17 19:56:38 -05001410 NLP_EVT_CMPL_LOGO);
dea31012005-04-17 16:05:31 -05001411 } else {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001412 /* Good status, call state machine.
1413 * This will unregister the rpi if needed.
1414 */
James Smart2e0fef82007-06-17 19:56:36 -05001415 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart92d7f7b2007-06-17 19:56:38 -05001416 NLP_EVT_CMPL_LOGO);
dea31012005-04-17 16:05:31 -05001417 }
1418
1419out:
1420 lpfc_els_free_iocb(phba, cmdiocb);
1421 return;
1422}
1423
1424int
James Smart2e0fef82007-06-17 19:56:36 -05001425lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
dea31012005-04-17 16:05:31 -05001426 uint8_t retry)
1427{
James Smart2e0fef82007-06-17 19:56:36 -05001428 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1429 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001430 IOCB_t *icmd;
1431 struct lpfc_iocbq *elsiocb;
1432 struct lpfc_sli_ring *pring;
1433 struct lpfc_sli *psli;
1434 uint8_t *pcmd;
1435 uint16_t cmdsize;
James Smart92d7f7b2007-06-17 19:56:38 -05001436 int rc;
dea31012005-04-17 16:05:31 -05001437
1438 psli = &phba->sli;
1439 pring = &psli->ring[LPFC_ELS_RING];
1440
James Smart92d7f7b2007-06-17 19:56:38 -05001441 cmdsize = (2 * sizeof(uint32_t)) + sizeof(struct lpfc_name);
James Smart2e0fef82007-06-17 19:56:36 -05001442 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
1443 ndlp->nlp_DID, ELS_CMD_LOGO);
James Smart488d1462006-03-07 15:02:37 -05001444 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001445 return 1;
dea31012005-04-17 16:05:31 -05001446
1447 icmd = &elsiocb->iocb;
1448 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1449 *((uint32_t *) (pcmd)) = ELS_CMD_LOGO;
James Smart92d7f7b2007-06-17 19:56:38 -05001450 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05001451
1452 /* Fill in LOGO payload */
James Smart2e0fef82007-06-17 19:56:36 -05001453 *((uint32_t *) (pcmd)) = be32_to_cpu(vport->fc_myDID);
James Smart92d7f7b2007-06-17 19:56:38 -05001454 pcmd += sizeof(uint32_t);
1455 memcpy(pcmd, &vport->fc_portname, sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05001456
James Smart858c9f62007-06-17 19:56:39 -05001457 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1458 "Issue LOGO: did:x%x",
1459 ndlp->nlp_DID, 0, 0);
1460
dea31012005-04-17 16:05:31 -05001461 phba->fc_stat.elsXmitLOGO++;
1462 elsiocb->iocb_cmpl = lpfc_cmpl_els_logo;
James Smart2e0fef82007-06-17 19:56:36 -05001463 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001464 ndlp->nlp_flag |= NLP_LOGO_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001465 spin_unlock_irq(shost->host_lock);
James Smart92d7f7b2007-06-17 19:56:38 -05001466 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
1467
1468 if (rc == IOCB_ERROR) {
James Smart2e0fef82007-06-17 19:56:36 -05001469 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001470 ndlp->nlp_flag &= ~NLP_LOGO_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001471 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001472 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001473 return 1;
dea31012005-04-17 16:05:31 -05001474 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001475 return 0;
dea31012005-04-17 16:05:31 -05001476}
1477
1478static void
James Smart2e0fef82007-06-17 19:56:36 -05001479lpfc_cmpl_els_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1480 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05001481{
James Smart2e0fef82007-06-17 19:56:36 -05001482 struct lpfc_vport *vport = cmdiocb->vport;
dea31012005-04-17 16:05:31 -05001483 IOCB_t *irsp;
1484
1485 irsp = &rspiocb->iocb;
1486
James Smart858c9f62007-06-17 19:56:39 -05001487 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1488 "ELS cmd cmpl: status:x%x/x%x did:x%x",
1489 irsp->ulpStatus, irsp->un.ulpWord[4],
1490 irsp->un.elsreq64.remoteID);
1491
dea31012005-04-17 16:05:31 -05001492 /* ELS cmd tag <ulpIoTag> completes */
James Smart92d7f7b2007-06-17 19:56:38 -05001493 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
1494 "%d (%d):0106 ELS cmd tag x%x completes Data: x%x x%x "
1495 "x%x\n",
1496 phba->brd_no, vport->vpi,
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001497 irsp->ulpIoTag, irsp->ulpStatus,
1498 irsp->un.ulpWord[4], irsp->ulpTimeout);
dea31012005-04-17 16:05:31 -05001499
1500 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -05001501 lpfc_els_chk_latt(vport);
dea31012005-04-17 16:05:31 -05001502 lpfc_els_free_iocb(phba, cmdiocb);
1503 return;
1504}
1505
1506int
James Smart2e0fef82007-06-17 19:56:36 -05001507lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
dea31012005-04-17 16:05:31 -05001508{
James Smart2e0fef82007-06-17 19:56:36 -05001509 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001510 IOCB_t *icmd;
1511 struct lpfc_iocbq *elsiocb;
1512 struct lpfc_sli_ring *pring;
1513 struct lpfc_sli *psli;
1514 uint8_t *pcmd;
1515 uint16_t cmdsize;
1516 struct lpfc_nodelist *ndlp;
1517
1518 psli = &phba->sli;
1519 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
James Smart92d7f7b2007-06-17 19:56:38 -05001520 cmdsize = (sizeof(uint32_t) + sizeof(SCR));
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001521 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
1522 if (!ndlp)
1523 return 1;
dea31012005-04-17 16:05:31 -05001524
James Smart2e0fef82007-06-17 19:56:36 -05001525 lpfc_nlp_init(vport, ndlp, nportid);
dea31012005-04-17 16:05:31 -05001526
James Smart2e0fef82007-06-17 19:56:36 -05001527 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
1528 ndlp->nlp_DID, ELS_CMD_SCR);
1529
James Smart488d1462006-03-07 15:02:37 -05001530 if (!elsiocb) {
James Smart329f9bc2007-04-25 09:53:01 -04001531 lpfc_nlp_put(ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001532 return 1;
dea31012005-04-17 16:05:31 -05001533 }
1534
1535 icmd = &elsiocb->iocb;
1536 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1537
1538 *((uint32_t *) (pcmd)) = ELS_CMD_SCR;
James Smart92d7f7b2007-06-17 19:56:38 -05001539 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05001540
1541 /* For SCR, remainder of payload is SCR parameter page */
James Smart92d7f7b2007-06-17 19:56:38 -05001542 memset(pcmd, 0, sizeof(SCR));
dea31012005-04-17 16:05:31 -05001543 ((SCR *) pcmd)->Function = SCR_FUNC_FULL;
1544
James Smart858c9f62007-06-17 19:56:39 -05001545 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1546 "Issue SCR: did:x%x",
1547 ndlp->nlp_DID, 0, 0);
1548
dea31012005-04-17 16:05:31 -05001549 phba->fc_stat.elsXmitSCR++;
1550 elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
dea31012005-04-17 16:05:31 -05001551 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
James Smart329f9bc2007-04-25 09:53:01 -04001552 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05001553 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001554 return 1;
dea31012005-04-17 16:05:31 -05001555 }
James Smart329f9bc2007-04-25 09:53:01 -04001556 lpfc_nlp_put(ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001557 return 0;
dea31012005-04-17 16:05:31 -05001558}
1559
1560static int
James Smart2e0fef82007-06-17 19:56:36 -05001561lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
dea31012005-04-17 16:05:31 -05001562{
James Smart2e0fef82007-06-17 19:56:36 -05001563 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001564 IOCB_t *icmd;
1565 struct lpfc_iocbq *elsiocb;
1566 struct lpfc_sli_ring *pring;
1567 struct lpfc_sli *psli;
1568 FARP *fp;
1569 uint8_t *pcmd;
1570 uint32_t *lp;
1571 uint16_t cmdsize;
1572 struct lpfc_nodelist *ondlp;
1573 struct lpfc_nodelist *ndlp;
1574
1575 psli = &phba->sli;
1576 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
James Smart92d7f7b2007-06-17 19:56:38 -05001577 cmdsize = (sizeof(uint32_t) + sizeof(FARP));
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001578 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
1579 if (!ndlp)
1580 return 1;
dea31012005-04-17 16:05:31 -05001581
James Smart2e0fef82007-06-17 19:56:36 -05001582 lpfc_nlp_init(vport, ndlp, nportid);
1583
1584 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
1585 ndlp->nlp_DID, ELS_CMD_RNID);
James Smart488d1462006-03-07 15:02:37 -05001586 if (!elsiocb) {
James Smart329f9bc2007-04-25 09:53:01 -04001587 lpfc_nlp_put(ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001588 return 1;
dea31012005-04-17 16:05:31 -05001589 }
1590
1591 icmd = &elsiocb->iocb;
1592 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1593
1594 *((uint32_t *) (pcmd)) = ELS_CMD_FARPR;
James Smart92d7f7b2007-06-17 19:56:38 -05001595 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05001596
1597 /* Fill in FARPR payload */
1598 fp = (FARP *) (pcmd);
James Smart92d7f7b2007-06-17 19:56:38 -05001599 memset(fp, 0, sizeof(FARP));
dea31012005-04-17 16:05:31 -05001600 lp = (uint32_t *) pcmd;
1601 *lp++ = be32_to_cpu(nportid);
James Smart2e0fef82007-06-17 19:56:36 -05001602 *lp++ = be32_to_cpu(vport->fc_myDID);
dea31012005-04-17 16:05:31 -05001603 fp->Rflags = 0;
1604 fp->Mflags = (FARP_MATCH_PORT | FARP_MATCH_NODE);
1605
James Smart92d7f7b2007-06-17 19:56:38 -05001606 memcpy(&fp->RportName, &vport->fc_portname, sizeof(struct lpfc_name));
1607 memcpy(&fp->RnodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
James Smart2e0fef82007-06-17 19:56:36 -05001608 ondlp = lpfc_findnode_did(vport, nportid);
1609 if (ondlp) {
dea31012005-04-17 16:05:31 -05001610 memcpy(&fp->OportName, &ondlp->nlp_portname,
James Smart92d7f7b2007-06-17 19:56:38 -05001611 sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05001612 memcpy(&fp->OnodeName, &ondlp->nlp_nodename,
James Smart92d7f7b2007-06-17 19:56:38 -05001613 sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05001614 }
1615
James Smart858c9f62007-06-17 19:56:39 -05001616 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1617 "Issue FARPR: did:x%x",
1618 ndlp->nlp_DID, 0, 0);
1619
dea31012005-04-17 16:05:31 -05001620 phba->fc_stat.elsXmitFARPR++;
1621 elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
dea31012005-04-17 16:05:31 -05001622 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
James Smart329f9bc2007-04-25 09:53:01 -04001623 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05001624 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001625 return 1;
dea31012005-04-17 16:05:31 -05001626 }
James Smart329f9bc2007-04-25 09:53:01 -04001627 lpfc_nlp_put(ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001628 return 0;
dea31012005-04-17 16:05:31 -05001629}
1630
James Smarted957682007-06-17 19:56:37 -05001631static void
1632lpfc_end_rscn(struct lpfc_vport *vport)
1633{
1634 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1635
1636 if (vport->fc_flag & FC_RSCN_MODE) {
1637 /*
1638 * Check to see if more RSCNs came in while we were
1639 * processing this one.
1640 */
1641 if (vport->fc_rscn_id_cnt ||
1642 (vport->fc_flag & FC_RSCN_DISCOVERY) != 0)
1643 lpfc_els_handle_rscn(vport);
1644 else {
1645 spin_lock_irq(shost->host_lock);
1646 vport->fc_flag &= ~FC_RSCN_MODE;
1647 spin_unlock_irq(shost->host_lock);
1648 }
1649 }
1650}
1651
dea31012005-04-17 16:05:31 -05001652void
James Smart2e0fef82007-06-17 19:56:36 -05001653lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp)
James Smartfdcebe22006-03-07 15:04:01 -05001654{
James Smart2e0fef82007-06-17 19:56:36 -05001655 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1656
1657 spin_lock_irq(shost->host_lock);
James Smartfdcebe22006-03-07 15:04:01 -05001658 nlp->nlp_flag &= ~NLP_DELAY_TMO;
James Smart2e0fef82007-06-17 19:56:36 -05001659 spin_unlock_irq(shost->host_lock);
James Smartfdcebe22006-03-07 15:04:01 -05001660 del_timer_sync(&nlp->nlp_delayfunc);
1661 nlp->nlp_last_elscmd = 0;
1662
1663 if (!list_empty(&nlp->els_retry_evt.evt_listp))
1664 list_del_init(&nlp->els_retry_evt.evt_listp);
1665
1666 if (nlp->nlp_flag & NLP_NPR_2B_DISC) {
James Smart2e0fef82007-06-17 19:56:36 -05001667 spin_lock_irq(shost->host_lock);
James Smartfdcebe22006-03-07 15:04:01 -05001668 nlp->nlp_flag &= ~NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -05001669 spin_unlock_irq(shost->host_lock);
1670 if (vport->num_disc_nodes) {
James Smartfdcebe22006-03-07 15:04:01 -05001671 /* Check to see if there are more
1672 * PLOGIs to be sent
1673 */
James Smart2e0fef82007-06-17 19:56:36 -05001674 lpfc_more_plogi(vport);
James Smartfdcebe22006-03-07 15:04:01 -05001675
James Smart2e0fef82007-06-17 19:56:36 -05001676 if (vport->num_disc_nodes == 0) {
1677 spin_lock_irq(shost->host_lock);
1678 vport->fc_flag &= ~FC_NDISC_ACTIVE;
1679 spin_unlock_irq(shost->host_lock);
1680 lpfc_can_disctmo(vport);
James Smarted957682007-06-17 19:56:37 -05001681 lpfc_end_rscn(vport);
James Smartfdcebe22006-03-07 15:04:01 -05001682 }
1683 }
1684 }
1685 return;
1686}
1687
1688void
dea31012005-04-17 16:05:31 -05001689lpfc_els_retry_delay(unsigned long ptr)
1690{
James Smart2e0fef82007-06-17 19:56:36 -05001691 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) ptr;
1692 struct lpfc_vport *vport = ndlp->vport;
James Smart2e0fef82007-06-17 19:56:36 -05001693 struct lpfc_hba *phba = vport->phba;
James Smart92d7f7b2007-06-17 19:56:38 -05001694 unsigned long flags;
James Smart2e0fef82007-06-17 19:56:36 -05001695 struct lpfc_work_evt *evtp = &ndlp->els_retry_evt;
dea31012005-04-17 16:05:31 -05001696
James Smart2e0fef82007-06-17 19:56:36 -05001697 ndlp = (struct lpfc_nodelist *) ptr;
1698 phba = ndlp->vport->phba;
dea31012005-04-17 16:05:31 -05001699 evtp = &ndlp->els_retry_evt;
1700
James Smart92d7f7b2007-06-17 19:56:38 -05001701 spin_lock_irqsave(&phba->hbalock, flags);
dea31012005-04-17 16:05:31 -05001702 if (!list_empty(&evtp->evt_listp)) {
James Smart92d7f7b2007-06-17 19:56:38 -05001703 spin_unlock_irqrestore(&phba->hbalock, flags);
dea31012005-04-17 16:05:31 -05001704 return;
1705 }
1706
1707 evtp->evt_arg1 = ndlp;
1708 evtp->evt = LPFC_EVT_ELS_RETRY;
1709 list_add_tail(&evtp->evt_listp, &phba->work_list);
1710 if (phba->work_wait)
James Smart92d7f7b2007-06-17 19:56:38 -05001711 lpfc_worker_wake_up(phba);
dea31012005-04-17 16:05:31 -05001712
James Smart92d7f7b2007-06-17 19:56:38 -05001713 spin_unlock_irqrestore(&phba->hbalock, flags);
dea31012005-04-17 16:05:31 -05001714 return;
1715}
1716
1717void
1718lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp)
1719{
James Smart2e0fef82007-06-17 19:56:36 -05001720 struct lpfc_vport *vport = ndlp->vport;
1721 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1722 uint32_t cmd, did, retry;
dea31012005-04-17 16:05:31 -05001723
James Smart2e0fef82007-06-17 19:56:36 -05001724 spin_lock_irq(shost->host_lock);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001725 did = ndlp->nlp_DID;
1726 cmd = ndlp->nlp_last_elscmd;
1727 ndlp->nlp_last_elscmd = 0;
dea31012005-04-17 16:05:31 -05001728
1729 if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
James Smart2e0fef82007-06-17 19:56:36 -05001730 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001731 return;
1732 }
1733
1734 ndlp->nlp_flag &= ~NLP_DELAY_TMO;
James Smart2e0fef82007-06-17 19:56:36 -05001735 spin_unlock_irq(shost->host_lock);
James Smart1a169682006-03-07 15:04:06 -05001736 /*
1737 * If a discovery event readded nlp_delayfunc after timer
1738 * firing and before processing the timer, cancel the
1739 * nlp_delayfunc.
1740 */
1741 del_timer_sync(&ndlp->nlp_delayfunc);
dea31012005-04-17 16:05:31 -05001742 retry = ndlp->nlp_retry;
1743
1744 switch (cmd) {
1745 case ELS_CMD_FLOGI:
James Smart2e0fef82007-06-17 19:56:36 -05001746 lpfc_issue_els_flogi(vport, ndlp, retry);
dea31012005-04-17 16:05:31 -05001747 break;
1748 case ELS_CMD_PLOGI:
James Smart2e0fef82007-06-17 19:56:36 -05001749 if (!lpfc_issue_els_plogi(vport, ndlp->nlp_DID, retry)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001750 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001751 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
Jamie Wellnitz6ad42532006-02-28 19:25:16 -05001752 }
dea31012005-04-17 16:05:31 -05001753 break;
1754 case ELS_CMD_ADISC:
James Smart2e0fef82007-06-17 19:56:36 -05001755 if (!lpfc_issue_els_adisc(vport, ndlp, retry)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001756 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001757 lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
Jamie Wellnitz6ad42532006-02-28 19:25:16 -05001758 }
dea31012005-04-17 16:05:31 -05001759 break;
1760 case ELS_CMD_PRLI:
James Smart2e0fef82007-06-17 19:56:36 -05001761 if (!lpfc_issue_els_prli(vport, ndlp, retry)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001762 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001763 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
Jamie Wellnitz6ad42532006-02-28 19:25:16 -05001764 }
dea31012005-04-17 16:05:31 -05001765 break;
1766 case ELS_CMD_LOGO:
James Smart2e0fef82007-06-17 19:56:36 -05001767 if (!lpfc_issue_els_logo(vport, ndlp, retry)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001768 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001769 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
Jamie Wellnitz6ad42532006-02-28 19:25:16 -05001770 }
dea31012005-04-17 16:05:31 -05001771 break;
James Smart92d7f7b2007-06-17 19:56:38 -05001772 case ELS_CMD_FDISC:
1773 lpfc_issue_els_fdisc(vport, ndlp, retry);
1774 break;
dea31012005-04-17 16:05:31 -05001775 }
1776 return;
1777}
1778
1779static int
James Smart2e0fef82007-06-17 19:56:36 -05001780lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1781 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05001782{
James Smart2e0fef82007-06-17 19:56:36 -05001783 struct lpfc_vport *vport = cmdiocb->vport;
1784 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1785 IOCB_t *irsp = &rspiocb->iocb;
1786 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
1787 struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
dea31012005-04-17 16:05:31 -05001788 uint32_t *elscmd;
1789 struct ls_rjt stat;
James Smart2e0fef82007-06-17 19:56:36 -05001790 int retry = 0, maxretry = lpfc_max_els_tries, delay = 0;
1791 uint32_t cmd = 0;
James Smart488d1462006-03-07 15:02:37 -05001792 uint32_t did;
dea31012005-04-17 16:05:31 -05001793
James Smart488d1462006-03-07 15:02:37 -05001794
dea31012005-04-17 16:05:31 -05001795 /* Note: context2 may be 0 for internal driver abort
1796 * of delays ELS command.
1797 */
1798
1799 if (pcmd && pcmd->virt) {
1800 elscmd = (uint32_t *) (pcmd->virt);
1801 cmd = *elscmd++;
1802 }
1803
James Smart329f9bc2007-04-25 09:53:01 -04001804 if (ndlp)
James Smart488d1462006-03-07 15:02:37 -05001805 did = ndlp->nlp_DID;
1806 else {
1807 /* We should only hit this case for retrying PLOGI */
1808 did = irsp->un.elsreq64.remoteID;
James Smart2e0fef82007-06-17 19:56:36 -05001809 ndlp = lpfc_findnode_did(vport, did);
James Smart488d1462006-03-07 15:02:37 -05001810 if (!ndlp && (cmd != ELS_CMD_PLOGI))
1811 return 1;
1812 }
1813
James Smart858c9f62007-06-17 19:56:39 -05001814 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1815 "Retry ELS: wd7:x%x wd4:x%x did:x%x",
1816 *(((uint32_t *) irsp) + 7), irsp->un.ulpWord[4], ndlp->nlp_DID);
1817
dea31012005-04-17 16:05:31 -05001818 switch (irsp->ulpStatus) {
1819 case IOSTAT_FCP_RSP_ERROR:
1820 case IOSTAT_REMOTE_STOP:
1821 break;
1822
1823 case IOSTAT_LOCAL_REJECT:
1824 switch ((irsp->un.ulpWord[4] & 0xff)) {
1825 case IOERR_LOOP_OPEN_FAILURE:
James Smart2e0fef82007-06-17 19:56:36 -05001826 if (cmd == ELS_CMD_PLOGI && cmdiocb->retry == 0)
James Smart92d7f7b2007-06-17 19:56:38 -05001827 delay = 1000;
dea31012005-04-17 16:05:31 -05001828 retry = 1;
1829 break;
1830
James Smart92d7f7b2007-06-17 19:56:38 -05001831 case IOERR_ILLEGAL_COMMAND:
1832 if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) &&
1833 (cmd == ELS_CMD_FDISC)) {
1834 lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
1835 "%d (%d):0124 FDISC failed (3/6) retrying...\n",
1836 phba->brd_no, vport->vpi);
1837 lpfc_mbx_unreg_vpi(vport);
1838 retry = 1;
1839 /* Always retry for this case */
1840 cmdiocb->retry = 0;
1841 }
1842 break;
1843
dea31012005-04-17 16:05:31 -05001844 case IOERR_NO_RESOURCES:
James Smart858c9f62007-06-17 19:56:39 -05001845 retry = 1;
1846 if (cmdiocb->retry > 100)
1847 delay = 100;
1848 maxretry = 250;
1849 break;
1850
1851 case IOERR_ILLEGAL_FRAME:
James Smart92d7f7b2007-06-17 19:56:38 -05001852 delay = 100;
dea31012005-04-17 16:05:31 -05001853 retry = 1;
1854 break;
1855
James Smart858c9f62007-06-17 19:56:39 -05001856 case IOERR_SEQUENCE_TIMEOUT:
dea31012005-04-17 16:05:31 -05001857 case IOERR_INVALID_RPI:
1858 retry = 1;
1859 break;
1860 }
1861 break;
1862
1863 case IOSTAT_NPORT_RJT:
1864 case IOSTAT_FABRIC_RJT:
1865 if (irsp->un.ulpWord[4] & RJT_UNAVAIL_TEMP) {
1866 retry = 1;
1867 break;
1868 }
1869 break;
1870
1871 case IOSTAT_NPORT_BSY:
1872 case IOSTAT_FABRIC_BSY:
1873 retry = 1;
1874 break;
1875
1876 case IOSTAT_LS_RJT:
1877 stat.un.lsRjtError = be32_to_cpu(irsp->un.ulpWord[4]);
1878 /* Added for Vendor specifc support
1879 * Just keep retrying for these Rsn / Exp codes
1880 */
1881 switch (stat.un.b.lsRjtRsnCode) {
1882 case LSRJT_UNABLE_TPC:
1883 if (stat.un.b.lsRjtRsnCodeExp ==
1884 LSEXP_CMD_IN_PROGRESS) {
1885 if (cmd == ELS_CMD_PLOGI) {
James Smart92d7f7b2007-06-17 19:56:38 -05001886 delay = 1000;
dea31012005-04-17 16:05:31 -05001887 maxretry = 48;
1888 }
1889 retry = 1;
1890 break;
1891 }
1892 if (cmd == ELS_CMD_PLOGI) {
James Smart92d7f7b2007-06-17 19:56:38 -05001893 delay = 1000;
dea31012005-04-17 16:05:31 -05001894 maxretry = lpfc_max_els_tries + 1;
1895 retry = 1;
1896 break;
1897 }
James Smart92d7f7b2007-06-17 19:56:38 -05001898 if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
1899 (cmd == ELS_CMD_FDISC) &&
1900 (stat.un.b.lsRjtRsnCodeExp == LSEXP_OUT_OF_RESOURCE)){
1901 lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
1902 "%d (%d):0125 FDISC Failed (x%x)."
1903 " Fabric out of resources\n",
1904 phba->brd_no, vport->vpi, stat.un.lsRjtError);
1905 lpfc_vport_set_state(vport,
1906 FC_VPORT_NO_FABRIC_RSCS);
1907 }
dea31012005-04-17 16:05:31 -05001908 break;
1909
1910 case LSRJT_LOGICAL_BSY:
James Smart858c9f62007-06-17 19:56:39 -05001911 if ((cmd == ELS_CMD_PLOGI) ||
1912 (cmd == ELS_CMD_PRLI)) {
James Smart92d7f7b2007-06-17 19:56:38 -05001913 delay = 1000;
dea31012005-04-17 16:05:31 -05001914 maxretry = 48;
James Smart92d7f7b2007-06-17 19:56:38 -05001915 } else if (cmd == ELS_CMD_FDISC) {
1916 /* Always retry for this case */
1917 cmdiocb->retry = 0;
dea31012005-04-17 16:05:31 -05001918 }
1919 retry = 1;
1920 break;
James Smart92d7f7b2007-06-17 19:56:38 -05001921
1922 case LSRJT_LOGICAL_ERR:
1923 case LSRJT_PROTOCOL_ERR:
1924 if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
1925 (cmd == ELS_CMD_FDISC) &&
1926 ((stat.un.b.lsRjtRsnCodeExp == LSEXP_INVALID_PNAME) ||
1927 (stat.un.b.lsRjtRsnCodeExp == LSEXP_INVALID_NPORT_ID))
1928 ) {
1929 lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
1930 "%d (%d):0123 FDISC Failed (x%x)."
1931 " Fabric Detected Bad WWN\n",
1932 phba->brd_no, vport->vpi, stat.un.lsRjtError);
1933 lpfc_vport_set_state(vport,
1934 FC_VPORT_FABRIC_REJ_WWN);
1935 }
1936 break;
dea31012005-04-17 16:05:31 -05001937 }
1938 break;
1939
1940 case IOSTAT_INTERMED_RSP:
1941 case IOSTAT_BA_RJT:
1942 break;
1943
1944 default:
1945 break;
1946 }
1947
James Smart488d1462006-03-07 15:02:37 -05001948 if (did == FDMI_DID)
dea31012005-04-17 16:05:31 -05001949 retry = 1;
dea31012005-04-17 16:05:31 -05001950
1951 if ((++cmdiocb->retry) >= maxretry) {
1952 phba->fc_stat.elsRetryExceeded++;
1953 retry = 0;
1954 }
1955
James Smarted957682007-06-17 19:56:37 -05001956 if ((vport->load_flag & FC_UNLOADING) != 0)
1957 retry = 0;
1958
dea31012005-04-17 16:05:31 -05001959 if (retry) {
1960
1961 /* Retry ELS command <elsCmd> to remote NPORT <did> */
1962 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart92d7f7b2007-06-17 19:56:38 -05001963 "%d (%d):0107 Retry ELS command x%x to remote "
dea31012005-04-17 16:05:31 -05001964 "NPORT x%x Data: x%x x%x\n",
James Smart92d7f7b2007-06-17 19:56:38 -05001965 phba->brd_no, vport->vpi,
James Smart488d1462006-03-07 15:02:37 -05001966 cmd, did, cmdiocb->retry, delay);
dea31012005-04-17 16:05:31 -05001967
James Smart858c9f62007-06-17 19:56:39 -05001968 if (((cmd == ELS_CMD_PLOGI) || (cmd == ELS_CMD_ADISC)) &&
1969 ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
1970 ((irsp->un.ulpWord[4] & 0xff) != IOERR_NO_RESOURCES))) {
1971 /* Don't reset timer for no resources */
1972
dea31012005-04-17 16:05:31 -05001973 /* If discovery / RSCN timer is running, reset it */
James Smart2e0fef82007-06-17 19:56:36 -05001974 if (timer_pending(&vport->fc_disctmo) ||
James Smart92d7f7b2007-06-17 19:56:38 -05001975 (vport->fc_flag & FC_RSCN_MODE))
James Smart2e0fef82007-06-17 19:56:36 -05001976 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -05001977 }
1978
1979 phba->fc_stat.elsXmitRetry++;
James Smart488d1462006-03-07 15:02:37 -05001980 if (ndlp && delay) {
dea31012005-04-17 16:05:31 -05001981 phba->fc_stat.elsDelayRetry++;
1982 ndlp->nlp_retry = cmdiocb->retry;
1983
James Smart92d7f7b2007-06-17 19:56:38 -05001984 /* delay is specified in milliseconds */
1985 mod_timer(&ndlp->nlp_delayfunc,
1986 jiffies + msecs_to_jiffies(delay));
James Smart2e0fef82007-06-17 19:56:36 -05001987 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001988 ndlp->nlp_flag |= NLP_DELAY_TMO;
James Smart2e0fef82007-06-17 19:56:36 -05001989 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001990
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001991 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart858c9f62007-06-17 19:56:39 -05001992 if (cmd == ELS_CMD_PRLI)
1993 lpfc_nlp_set_state(vport, ndlp,
1994 NLP_STE_REG_LOGIN_ISSUE);
1995 else
1996 lpfc_nlp_set_state(vport, ndlp,
1997 NLP_STE_NPR_NODE);
dea31012005-04-17 16:05:31 -05001998 ndlp->nlp_last_elscmd = cmd;
1999
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002000 return 1;
dea31012005-04-17 16:05:31 -05002001 }
2002 switch (cmd) {
2003 case ELS_CMD_FLOGI:
James Smart2e0fef82007-06-17 19:56:36 -05002004 lpfc_issue_els_flogi(vport, ndlp, cmdiocb->retry);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002005 return 1;
James Smart92d7f7b2007-06-17 19:56:38 -05002006 case ELS_CMD_FDISC:
2007 lpfc_issue_els_fdisc(vport, ndlp, cmdiocb->retry);
2008 return 1;
dea31012005-04-17 16:05:31 -05002009 case ELS_CMD_PLOGI:
James Smart488d1462006-03-07 15:02:37 -05002010 if (ndlp) {
2011 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002012 lpfc_nlp_set_state(vport, ndlp,
James Smartde0c5b32007-04-25 09:52:27 -04002013 NLP_STE_PLOGI_ISSUE);
James Smart488d1462006-03-07 15:02:37 -05002014 }
James Smart2e0fef82007-06-17 19:56:36 -05002015 lpfc_issue_els_plogi(vport, did, cmdiocb->retry);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002016 return 1;
dea31012005-04-17 16:05:31 -05002017 case ELS_CMD_ADISC:
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05002018 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002019 lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
2020 lpfc_issue_els_adisc(vport, ndlp, cmdiocb->retry);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002021 return 1;
dea31012005-04-17 16:05:31 -05002022 case ELS_CMD_PRLI:
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05002023 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002024 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
2025 lpfc_issue_els_prli(vport, ndlp, cmdiocb->retry);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002026 return 1;
dea31012005-04-17 16:05:31 -05002027 case ELS_CMD_LOGO:
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05002028 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002029 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
2030 lpfc_issue_els_logo(vport, ndlp, cmdiocb->retry);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002031 return 1;
dea31012005-04-17 16:05:31 -05002032 }
2033 }
2034
2035 /* No retry ELS command <elsCmd> to remote NPORT <did> */
2036 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart92d7f7b2007-06-17 19:56:38 -05002037 "%d (%d):0108 No retry ELS command x%x to remote "
2038 "NPORT x%x Data: x%x\n",
2039 phba->brd_no, vport->vpi,
James Smart488d1462006-03-07 15:02:37 -05002040 cmd, did, cmdiocb->retry);
dea31012005-04-17 16:05:31 -05002041
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002042 return 0;
dea31012005-04-17 16:05:31 -05002043}
2044
2045int
James Smart329f9bc2007-04-25 09:53:01 -04002046lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
dea31012005-04-17 16:05:31 -05002047{
2048 struct lpfc_dmabuf *buf_ptr, *buf_ptr1;
2049
James Smart329f9bc2007-04-25 09:53:01 -04002050 if (elsiocb->context1) {
2051 lpfc_nlp_put(elsiocb->context1);
2052 elsiocb->context1 = NULL;
2053 }
dea31012005-04-17 16:05:31 -05002054 /* context2 = cmd, context2->next = rsp, context3 = bpl */
2055 if (elsiocb->context2) {
2056 buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
2057 /* Free the response before processing the command. */
2058 if (!list_empty(&buf_ptr1->list)) {
2059 list_remove_head(&buf_ptr1->list, buf_ptr,
2060 struct lpfc_dmabuf,
2061 list);
2062 lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
2063 kfree(buf_ptr);
2064 }
2065 lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys);
2066 kfree(buf_ptr1);
2067 }
2068
2069 if (elsiocb->context3) {
2070 buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3;
2071 lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
2072 kfree(buf_ptr);
2073 }
James Bottomley604a3e32005-10-29 10:28:33 -05002074 lpfc_sli_release_iocbq(phba, elsiocb);
dea31012005-04-17 16:05:31 -05002075 return 0;
2076}
2077
2078static void
James Smart2e0fef82007-06-17 19:56:36 -05002079lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
2080 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05002081{
James Smart2e0fef82007-06-17 19:56:36 -05002082 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
2083 struct lpfc_vport *vport = cmdiocb->vport;
James Smart858c9f62007-06-17 19:56:39 -05002084 IOCB_t *irsp;
2085
2086 irsp = &rspiocb->iocb;
2087 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2088 "ACC LOGO cmpl: status:x%x/x%x did:x%x",
2089 irsp->ulpStatus, irsp->un.ulpWord[4], ndlp->nlp_DID);
dea31012005-04-17 16:05:31 -05002090
2091 /* ACC to LOGO completes to NPort <nlp_DID> */
2092 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart92d7f7b2007-06-17 19:56:38 -05002093 "%d (%d):0109 ACC to LOGO completes to NPort x%x "
dea31012005-04-17 16:05:31 -05002094 "Data: x%x x%x x%x\n",
James Smart92d7f7b2007-06-17 19:56:38 -05002095 phba->brd_no, vport->vpi, ndlp->nlp_DID,
2096 ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
dea31012005-04-17 16:05:31 -05002097
dea31012005-04-17 16:05:31 -05002098 switch (ndlp->nlp_state) {
2099 case NLP_STE_UNUSED_NODE: /* node is just allocated */
James Smart2e0fef82007-06-17 19:56:36 -05002100 lpfc_drop_node(vport, ndlp);
dea31012005-04-17 16:05:31 -05002101 break;
2102 case NLP_STE_NPR_NODE: /* NPort Recovery mode */
James Smart2e0fef82007-06-17 19:56:36 -05002103 lpfc_unreg_rpi(vport, ndlp);
dea31012005-04-17 16:05:31 -05002104 break;
2105 default:
2106 break;
2107 }
2108 lpfc_els_free_iocb(phba, cmdiocb);
2109 return;
2110}
2111
James Smart858c9f62007-06-17 19:56:39 -05002112void
2113lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
2114{
2115 struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
2116 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
2117
2118 pmb->context1 = NULL;
2119 lpfc_mbuf_free(phba, mp->virt, mp->phys);
2120 kfree(mp);
2121 mempool_free(pmb, phba->mbox_mem_pool);
2122 lpfc_nlp_put(ndlp);
2123 return;
2124}
2125
dea31012005-04-17 16:05:31 -05002126static void
James Smart858c9f62007-06-17 19:56:39 -05002127lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
James Smart329f9bc2007-04-25 09:53:01 -04002128 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05002129{
James Smart2e0fef82007-06-17 19:56:36 -05002130 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
2131 struct lpfc_vport *vport = ndlp ? ndlp->vport : NULL;
2132 struct Scsi_Host *shost = vport ? lpfc_shost_from_vport(vport) : NULL;
James Smart33ccf8d2006-08-17 11:57:58 -04002133 IOCB_t *irsp;
dea31012005-04-17 16:05:31 -05002134 LPFC_MBOXQ_t *mbox = NULL;
James Smart2e0fef82007-06-17 19:56:36 -05002135 struct lpfc_dmabuf *mp = NULL;
dea31012005-04-17 16:05:31 -05002136
James Smart33ccf8d2006-08-17 11:57:58 -04002137 irsp = &rspiocb->iocb;
2138
dea31012005-04-17 16:05:31 -05002139 if (cmdiocb->context_un.mbox)
2140 mbox = cmdiocb->context_un.mbox;
2141
dea31012005-04-17 16:05:31 -05002142 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -05002143 if (!ndlp || lpfc_els_chk_latt(vport)) {
dea31012005-04-17 16:05:31 -05002144 if (mbox) {
James Smart14691152006-12-02 13:34:28 -05002145 mp = (struct lpfc_dmabuf *) mbox->context1;
2146 if (mp) {
2147 lpfc_mbuf_free(phba, mp->virt, mp->phys);
2148 kfree(mp);
2149 }
James Smart329f9bc2007-04-25 09:53:01 -04002150 mempool_free(mbox, phba->mbox_mem_pool);
dea31012005-04-17 16:05:31 -05002151 }
2152 goto out;
2153 }
2154
James Smart858c9f62007-06-17 19:56:39 -05002155 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2156 "ACC cmpl: status:x%x/x%x did:x%x",
2157 irsp->ulpStatus, irsp->un.ulpWord[4],
2158 irsp->un.rcvels.remoteID);
2159
dea31012005-04-17 16:05:31 -05002160 /* ELS response tag <ulpIoTag> completes */
2161 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart92d7f7b2007-06-17 19:56:38 -05002162 "%d (%d):0110 ELS response tag x%x completes "
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002163 "Data: x%x x%x x%x x%x x%x x%x x%x\n",
James Smart92d7f7b2007-06-17 19:56:38 -05002164 phba->brd_no, vport->vpi,
dea31012005-04-17 16:05:31 -05002165 cmdiocb->iocb.ulpIoTag, rspiocb->iocb.ulpStatus,
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002166 rspiocb->iocb.un.ulpWord[4], rspiocb->iocb.ulpTimeout,
James Smart2e0fef82007-06-17 19:56:36 -05002167 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002168 ndlp->nlp_rpi);
dea31012005-04-17 16:05:31 -05002169
2170 if (mbox) {
2171 if ((rspiocb->iocb.ulpStatus == 0)
2172 && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) {
James Smart2e0fef82007-06-17 19:56:36 -05002173 lpfc_unreg_rpi(vport, ndlp);
James Smart329f9bc2007-04-25 09:53:01 -04002174 mbox->context2 = lpfc_nlp_get(ndlp);
James Smart2e0fef82007-06-17 19:56:36 -05002175 mbox->vport = vport;
James Smart858c9f62007-06-17 19:56:39 -05002176 if (ndlp->nlp_flag & NLP_RM_DFLT_RPI) {
2177 mbox->mbox_flag |= LPFC_MBX_IMED_UNREG;
2178 mbox->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;
2179 }
2180 else {
2181 mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
2182 ndlp->nlp_prev_state = ndlp->nlp_state;
2183 lpfc_nlp_set_state(vport, ndlp,
James Smart2e0fef82007-06-17 19:56:36 -05002184 NLP_STE_REG_LOGIN_ISSUE);
James Smart858c9f62007-06-17 19:56:39 -05002185 }
dea31012005-04-17 16:05:31 -05002186 if (lpfc_sli_issue_mbox(phba, mbox,
2187 (MBX_NOWAIT | MBX_STOP_IOCB))
2188 != MBX_NOT_FINISHED) {
2189 goto out;
2190 }
James Smart329f9bc2007-04-25 09:53:01 -04002191 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05002192 /* NOTE: we should have messages for unsuccessful
2193 reglogin */
dea31012005-04-17 16:05:31 -05002194 } else {
James Smart858c9f62007-06-17 19:56:39 -05002195 /* Do not drop node for lpfc_els_abort'ed ELS cmds */
2196 if (!lpfc_error_lost_link(irsp) &&
2197 ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
2198 lpfc_drop_node(vport, ndlp);
2199 ndlp = NULL;
dea31012005-04-17 16:05:31 -05002200 }
2201 }
James Smart14691152006-12-02 13:34:28 -05002202 mp = (struct lpfc_dmabuf *) mbox->context1;
2203 if (mp) {
2204 lpfc_mbuf_free(phba, mp->virt, mp->phys);
2205 kfree(mp);
2206 }
2207 mempool_free(mbox, phba->mbox_mem_pool);
dea31012005-04-17 16:05:31 -05002208 }
2209out:
2210 if (ndlp) {
James Smart2e0fef82007-06-17 19:56:36 -05002211 spin_lock_irq(shost->host_lock);
James Smart858c9f62007-06-17 19:56:39 -05002212 ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI);
James Smart2e0fef82007-06-17 19:56:36 -05002213 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05002214 }
2215 lpfc_els_free_iocb(phba, cmdiocb);
2216 return;
2217}
2218
2219int
James Smart2e0fef82007-06-17 19:56:36 -05002220lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
2221 struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp,
2222 LPFC_MBOXQ_t *mbox, uint8_t newnode)
dea31012005-04-17 16:05:31 -05002223{
James Smart2e0fef82007-06-17 19:56:36 -05002224 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
2225 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002226 IOCB_t *icmd;
2227 IOCB_t *oldcmd;
2228 struct lpfc_iocbq *elsiocb;
2229 struct lpfc_sli_ring *pring;
2230 struct lpfc_sli *psli;
2231 uint8_t *pcmd;
2232 uint16_t cmdsize;
2233 int rc;
James Smart82d9a2a2006-04-15 11:53:05 -04002234 ELS_PKT *els_pkt_ptr;
dea31012005-04-17 16:05:31 -05002235
2236 psli = &phba->sli;
2237 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
2238 oldcmd = &oldiocb->iocb;
2239
2240 switch (flag) {
2241 case ELS_CMD_ACC:
James Smart92d7f7b2007-06-17 19:56:38 -05002242 cmdsize = sizeof(uint32_t);
James Smart2e0fef82007-06-17 19:56:36 -05002243 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
2244 ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
James Smart488d1462006-03-07 15:02:37 -05002245 if (!elsiocb) {
James Smart2e0fef82007-06-17 19:56:36 -05002246 spin_lock_irq(shost->host_lock);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05002247 ndlp->nlp_flag &= ~NLP_LOGO_ACC;
James Smart2e0fef82007-06-17 19:56:36 -05002248 spin_unlock_irq(shost->host_lock);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002249 return 1;
dea31012005-04-17 16:05:31 -05002250 }
James Smart2e0fef82007-06-17 19:56:36 -05002251
dea31012005-04-17 16:05:31 -05002252 icmd = &elsiocb->iocb;
2253 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
2254 pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2255 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
James Smart92d7f7b2007-06-17 19:56:38 -05002256 pcmd += sizeof(uint32_t);
James Smart858c9f62007-06-17 19:56:39 -05002257
2258 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2259 "Issue ACC: did:x%x flg:x%x",
2260 ndlp->nlp_DID, ndlp->nlp_flag, 0);
dea31012005-04-17 16:05:31 -05002261 break;
2262 case ELS_CMD_PLOGI:
James Smart92d7f7b2007-06-17 19:56:38 -05002263 cmdsize = (sizeof(struct serv_parm) + sizeof(uint32_t));
James Smart2e0fef82007-06-17 19:56:36 -05002264 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
2265 ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
James Smart488d1462006-03-07 15:02:37 -05002266 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002267 return 1;
James Smart488d1462006-03-07 15:02:37 -05002268
dea31012005-04-17 16:05:31 -05002269 icmd = &elsiocb->iocb;
2270 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
2271 pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2272
2273 if (mbox)
2274 elsiocb->context_un.mbox = mbox;
2275
2276 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
James Smart92d7f7b2007-06-17 19:56:38 -05002277 pcmd += sizeof(uint32_t);
2278 memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
James Smart858c9f62007-06-17 19:56:39 -05002279
2280 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2281 "Issue ACC PLOGI: did:x%x flg:x%x",
2282 ndlp->nlp_DID, ndlp->nlp_flag, 0);
dea31012005-04-17 16:05:31 -05002283 break;
James Smart82d9a2a2006-04-15 11:53:05 -04002284 case ELS_CMD_PRLO:
James Smart92d7f7b2007-06-17 19:56:38 -05002285 cmdsize = sizeof(uint32_t) + sizeof(PRLO);
James Smart2e0fef82007-06-17 19:56:36 -05002286 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
James Smart82d9a2a2006-04-15 11:53:05 -04002287 ndlp, ndlp->nlp_DID, ELS_CMD_PRLO);
2288 if (!elsiocb)
2289 return 1;
2290
2291 icmd = &elsiocb->iocb;
2292 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
2293 pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2294
2295 memcpy(pcmd, ((struct lpfc_dmabuf *) oldiocb->context2)->virt,
James Smart92d7f7b2007-06-17 19:56:38 -05002296 sizeof(uint32_t) + sizeof(PRLO));
James Smart82d9a2a2006-04-15 11:53:05 -04002297 *((uint32_t *) (pcmd)) = ELS_CMD_PRLO_ACC;
2298 els_pkt_ptr = (ELS_PKT *) pcmd;
2299 els_pkt_ptr->un.prlo.acceptRspCode = PRLO_REQ_EXECUTED;
James Smart858c9f62007-06-17 19:56:39 -05002300
2301 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2302 "Issue ACC PRLO: did:x%x flg:x%x",
2303 ndlp->nlp_DID, ndlp->nlp_flag, 0);
James Smart82d9a2a2006-04-15 11:53:05 -04002304 break;
dea31012005-04-17 16:05:31 -05002305 default:
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002306 return 1;
dea31012005-04-17 16:05:31 -05002307 }
2308
James Smart329f9bc2007-04-25 09:53:01 -04002309 if (newnode) {
2310 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05002311 elsiocb->context1 = NULL;
James Smart329f9bc2007-04-25 09:53:01 -04002312 }
dea31012005-04-17 16:05:31 -05002313
2314 /* Xmit ELS ACC response tag <ulpIoTag> */
2315 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart92d7f7b2007-06-17 19:56:38 -05002316 "%d (%d):0128 Xmit ELS ACC response tag x%x, XRI: x%x, "
James Smart1dcb58e2007-04-25 09:51:30 -04002317 "DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x\n",
James Smart92d7f7b2007-06-17 19:56:38 -05002318 phba->brd_no, vport->vpi, elsiocb->iotag,
dea31012005-04-17 16:05:31 -05002319 elsiocb->iocb.ulpContext, ndlp->nlp_DID,
2320 ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
2321
2322 if (ndlp->nlp_flag & NLP_LOGO_ACC) {
James Smart2e0fef82007-06-17 19:56:36 -05002323 spin_lock_irq(shost->host_lock);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002324 ndlp->nlp_flag &= ~NLP_LOGO_ACC;
James Smart2e0fef82007-06-17 19:56:36 -05002325 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05002326 elsiocb->iocb_cmpl = lpfc_cmpl_els_logo_acc;
2327 } else {
James Smart858c9f62007-06-17 19:56:39 -05002328 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
dea31012005-04-17 16:05:31 -05002329 }
2330
2331 phba->fc_stat.elsXmitACC++;
dea31012005-04-17 16:05:31 -05002332 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
dea31012005-04-17 16:05:31 -05002333 if (rc == IOCB_ERROR) {
2334 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002335 return 1;
dea31012005-04-17 16:05:31 -05002336 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002337 return 0;
dea31012005-04-17 16:05:31 -05002338}
2339
2340int
James Smart2e0fef82007-06-17 19:56:36 -05002341lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
James Smart858c9f62007-06-17 19:56:39 -05002342 struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp,
2343 LPFC_MBOXQ_t *mbox)
dea31012005-04-17 16:05:31 -05002344{
James Smart2e0fef82007-06-17 19:56:36 -05002345 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002346 IOCB_t *icmd;
2347 IOCB_t *oldcmd;
2348 struct lpfc_iocbq *elsiocb;
2349 struct lpfc_sli_ring *pring;
2350 struct lpfc_sli *psli;
2351 uint8_t *pcmd;
2352 uint16_t cmdsize;
2353 int rc;
2354
2355 psli = &phba->sli;
2356 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
2357
James Smart92d7f7b2007-06-17 19:56:38 -05002358 cmdsize = 2 * sizeof(uint32_t);
James Smart2e0fef82007-06-17 19:56:36 -05002359 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
2360 ndlp->nlp_DID, ELS_CMD_LS_RJT);
James Smart488d1462006-03-07 15:02:37 -05002361 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002362 return 1;
dea31012005-04-17 16:05:31 -05002363
2364 icmd = &elsiocb->iocb;
2365 oldcmd = &oldiocb->iocb;
2366 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
2367 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2368
2369 *((uint32_t *) (pcmd)) = ELS_CMD_LS_RJT;
James Smart92d7f7b2007-06-17 19:56:38 -05002370 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05002371 *((uint32_t *) (pcmd)) = rejectError;
2372
James Smart858c9f62007-06-17 19:56:39 -05002373 if (mbox) {
2374 elsiocb->context_un.mbox = mbox;
2375 elsiocb->context1 = lpfc_nlp_get(ndlp);
2376 }
2377
dea31012005-04-17 16:05:31 -05002378 /* Xmit ELS RJT <err> response tag <ulpIoTag> */
2379 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart92d7f7b2007-06-17 19:56:38 -05002380 "%d (%d):0129 Xmit ELS RJT x%x response tag x%x "
2381 "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, "
2382 "rpi x%x\n",
2383 phba->brd_no, vport->vpi, rejectError, elsiocb->iotag,
dea31012005-04-17 16:05:31 -05002384 elsiocb->iocb.ulpContext, ndlp->nlp_DID,
2385 ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
2386
James Smart858c9f62007-06-17 19:56:39 -05002387 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2388 "Issue LS_RJT: did:x%x flg:x%x err:x%x",
2389 ndlp->nlp_DID, ndlp->nlp_flag, rejectError);
2390
dea31012005-04-17 16:05:31 -05002391 phba->fc_stat.elsXmitLSRJT++;
James Smart858c9f62007-06-17 19:56:39 -05002392 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
dea31012005-04-17 16:05:31 -05002393 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
dea31012005-04-17 16:05:31 -05002394 if (rc == IOCB_ERROR) {
2395 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002396 return 1;
dea31012005-04-17 16:05:31 -05002397 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002398 return 0;
dea31012005-04-17 16:05:31 -05002399}
2400
2401int
James Smart2e0fef82007-06-17 19:56:36 -05002402lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
2403 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05002404{
James Smart2e0fef82007-06-17 19:56:36 -05002405 struct lpfc_hba *phba = vport->phba;
2406 struct lpfc_sli *psli = &phba->sli;
2407 struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
dea31012005-04-17 16:05:31 -05002408 ADISC *ap;
James Smart2e0fef82007-06-17 19:56:36 -05002409 IOCB_t *icmd, *oldcmd;
dea31012005-04-17 16:05:31 -05002410 struct lpfc_iocbq *elsiocb;
dea31012005-04-17 16:05:31 -05002411 uint8_t *pcmd;
2412 uint16_t cmdsize;
2413 int rc;
2414
James Smart92d7f7b2007-06-17 19:56:38 -05002415 cmdsize = sizeof(uint32_t) + sizeof(ADISC);
James Smart2e0fef82007-06-17 19:56:36 -05002416 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
2417 ndlp->nlp_DID, ELS_CMD_ACC);
James Smart488d1462006-03-07 15:02:37 -05002418 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002419 return 1;
dea31012005-04-17 16:05:31 -05002420
dea31012005-04-17 16:05:31 -05002421 icmd = &elsiocb->iocb;
2422 oldcmd = &oldiocb->iocb;
2423 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
James Smart5b8bd0c2007-04-25 09:52:49 -04002424
2425 /* Xmit ADISC ACC response tag <ulpIoTag> */
2426 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart92d7f7b2007-06-17 19:56:38 -05002427 "%d (%d):0130 Xmit ADISC ACC response iotag x%x xri: "
James Smart5b8bd0c2007-04-25 09:52:49 -04002428 "x%x, did x%x, nlp_flag x%x, nlp_state x%x rpi x%x\n",
James Smart92d7f7b2007-06-17 19:56:38 -05002429 phba->brd_no, vport->vpi, elsiocb->iotag,
James Smart5b8bd0c2007-04-25 09:52:49 -04002430 elsiocb->iocb.ulpContext, ndlp->nlp_DID,
2431 ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
2432
dea31012005-04-17 16:05:31 -05002433 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2434
2435 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
James Smart92d7f7b2007-06-17 19:56:38 -05002436 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05002437
2438 ap = (ADISC *) (pcmd);
2439 ap->hardAL_PA = phba->fc_pref_ALPA;
James Smart92d7f7b2007-06-17 19:56:38 -05002440 memcpy(&ap->portName, &vport->fc_portname, sizeof(struct lpfc_name));
2441 memcpy(&ap->nodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
James Smart2e0fef82007-06-17 19:56:36 -05002442 ap->DID = be32_to_cpu(vport->fc_myDID);
dea31012005-04-17 16:05:31 -05002443
James Smart858c9f62007-06-17 19:56:39 -05002444 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2445 "Issue ACC ADISC: did:x%x flg:x%x",
2446 ndlp->nlp_DID, ndlp->nlp_flag, 0);
2447
dea31012005-04-17 16:05:31 -05002448 phba->fc_stat.elsXmitACC++;
James Smart858c9f62007-06-17 19:56:39 -05002449 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
dea31012005-04-17 16:05:31 -05002450 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
dea31012005-04-17 16:05:31 -05002451 if (rc == IOCB_ERROR) {
2452 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002453 return 1;
dea31012005-04-17 16:05:31 -05002454 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002455 return 0;
dea31012005-04-17 16:05:31 -05002456}
2457
2458int
James Smart2e0fef82007-06-17 19:56:36 -05002459lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
James Smart5b8bd0c2007-04-25 09:52:49 -04002460 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05002461{
James Smart2e0fef82007-06-17 19:56:36 -05002462 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002463 PRLI *npr;
2464 lpfc_vpd_t *vpd;
2465 IOCB_t *icmd;
2466 IOCB_t *oldcmd;
2467 struct lpfc_iocbq *elsiocb;
2468 struct lpfc_sli_ring *pring;
2469 struct lpfc_sli *psli;
2470 uint8_t *pcmd;
2471 uint16_t cmdsize;
2472 int rc;
2473
2474 psli = &phba->sli;
2475 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
2476
James Smart92d7f7b2007-06-17 19:56:38 -05002477 cmdsize = sizeof(uint32_t) + sizeof(PRLI);
James Smart2e0fef82007-06-17 19:56:36 -05002478 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
James Smart92d7f7b2007-06-17 19:56:38 -05002479 ndlp->nlp_DID, (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK)));
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002480 if (!elsiocb)
2481 return 1;
dea31012005-04-17 16:05:31 -05002482
dea31012005-04-17 16:05:31 -05002483 icmd = &elsiocb->iocb;
2484 oldcmd = &oldiocb->iocb;
2485 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
James Smart5b8bd0c2007-04-25 09:52:49 -04002486
2487 /* Xmit PRLI ACC response tag <ulpIoTag> */
2488 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart92d7f7b2007-06-17 19:56:38 -05002489 "%d (%d):0131 Xmit PRLI ACC response tag x%x xri x%x, "
James Smart5b8bd0c2007-04-25 09:52:49 -04002490 "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
James Smart92d7f7b2007-06-17 19:56:38 -05002491 phba->brd_no, vport->vpi, elsiocb->iotag,
James Smart5b8bd0c2007-04-25 09:52:49 -04002492 elsiocb->iocb.ulpContext, ndlp->nlp_DID,
2493 ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
2494
dea31012005-04-17 16:05:31 -05002495 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2496
2497 *((uint32_t *) (pcmd)) = (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK));
James Smart92d7f7b2007-06-17 19:56:38 -05002498 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05002499
2500 /* For PRLI, remainder of payload is PRLI parameter page */
James Smart92d7f7b2007-06-17 19:56:38 -05002501 memset(pcmd, 0, sizeof(PRLI));
dea31012005-04-17 16:05:31 -05002502
2503 npr = (PRLI *) pcmd;
2504 vpd = &phba->vpd;
2505 /*
2506 * If our firmware version is 3.20 or later,
2507 * set the following bits for FC-TAPE support.
2508 */
2509 if (vpd->rev.feaLevelHigh >= 0x02) {
2510 npr->ConfmComplAllowed = 1;
2511 npr->Retry = 1;
2512 npr->TaskRetryIdReq = 1;
2513 }
2514
2515 npr->acceptRspCode = PRLI_REQ_EXECUTED;
2516 npr->estabImagePair = 1;
2517 npr->readXferRdyDis = 1;
2518 npr->ConfmComplAllowed = 1;
2519
2520 npr->prliType = PRLI_FCP_TYPE;
2521 npr->initiatorFunc = 1;
2522
James Smart858c9f62007-06-17 19:56:39 -05002523 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2524 "Issue ACC PRLI: did:x%x flg:x%x",
2525 ndlp->nlp_DID, ndlp->nlp_flag, 0);
2526
dea31012005-04-17 16:05:31 -05002527 phba->fc_stat.elsXmitACC++;
James Smart858c9f62007-06-17 19:56:39 -05002528 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
dea31012005-04-17 16:05:31 -05002529
dea31012005-04-17 16:05:31 -05002530 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
dea31012005-04-17 16:05:31 -05002531 if (rc == IOCB_ERROR) {
2532 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002533 return 1;
dea31012005-04-17 16:05:31 -05002534 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002535 return 0;
dea31012005-04-17 16:05:31 -05002536}
2537
2538static int
James Smart2e0fef82007-06-17 19:56:36 -05002539lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format,
James Smart329f9bc2007-04-25 09:53:01 -04002540 struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05002541{
James Smart2e0fef82007-06-17 19:56:36 -05002542 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002543 RNID *rn;
James Smart2e0fef82007-06-17 19:56:36 -05002544 IOCB_t *icmd, *oldcmd;
dea31012005-04-17 16:05:31 -05002545 struct lpfc_iocbq *elsiocb;
2546 struct lpfc_sli_ring *pring;
2547 struct lpfc_sli *psli;
2548 uint8_t *pcmd;
2549 uint16_t cmdsize;
2550 int rc;
2551
2552 psli = &phba->sli;
2553 pring = &psli->ring[LPFC_ELS_RING];
2554
James Smart92d7f7b2007-06-17 19:56:38 -05002555 cmdsize = sizeof(uint32_t) + sizeof(uint32_t)
2556 + (2 * sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05002557 if (format)
James Smart92d7f7b2007-06-17 19:56:38 -05002558 cmdsize += sizeof(RNID_TOP_DISC);
dea31012005-04-17 16:05:31 -05002559
James Smart2e0fef82007-06-17 19:56:36 -05002560 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
2561 ndlp->nlp_DID, ELS_CMD_ACC);
James Smart488d1462006-03-07 15:02:37 -05002562 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002563 return 1;
dea31012005-04-17 16:05:31 -05002564
dea31012005-04-17 16:05:31 -05002565 icmd = &elsiocb->iocb;
2566 oldcmd = &oldiocb->iocb;
2567 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
James Smart5b8bd0c2007-04-25 09:52:49 -04002568
2569 /* Xmit RNID ACC response tag <ulpIoTag> */
2570 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart92d7f7b2007-06-17 19:56:38 -05002571 "%d (%d):0132 Xmit RNID ACC response tag x%x "
James Smart5b8bd0c2007-04-25 09:52:49 -04002572 "xri x%x\n",
James Smart92d7f7b2007-06-17 19:56:38 -05002573 phba->brd_no, vport->vpi, elsiocb->iotag,
James Smart5b8bd0c2007-04-25 09:52:49 -04002574 elsiocb->iocb.ulpContext);
2575
dea31012005-04-17 16:05:31 -05002576 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2577
2578 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
James Smart92d7f7b2007-06-17 19:56:38 -05002579 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05002580
James Smart92d7f7b2007-06-17 19:56:38 -05002581 memset(pcmd, 0, sizeof(RNID));
dea31012005-04-17 16:05:31 -05002582 rn = (RNID *) (pcmd);
2583 rn->Format = format;
James Smart92d7f7b2007-06-17 19:56:38 -05002584 rn->CommonLen = (2 * sizeof(struct lpfc_name));
2585 memcpy(&rn->portName, &vport->fc_portname, sizeof(struct lpfc_name));
2586 memcpy(&rn->nodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05002587 switch (format) {
2588 case 0:
2589 rn->SpecificLen = 0;
2590 break;
2591 case RNID_TOPOLOGY_DISC:
James Smart92d7f7b2007-06-17 19:56:38 -05002592 rn->SpecificLen = sizeof(RNID_TOP_DISC);
dea31012005-04-17 16:05:31 -05002593 memcpy(&rn->un.topologyDisc.portName,
James Smart92d7f7b2007-06-17 19:56:38 -05002594 &vport->fc_portname, sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05002595 rn->un.topologyDisc.unitType = RNID_HBA;
2596 rn->un.topologyDisc.physPort = 0;
2597 rn->un.topologyDisc.attachedNodes = 0;
2598 break;
2599 default:
2600 rn->CommonLen = 0;
2601 rn->SpecificLen = 0;
2602 break;
2603 }
2604
James Smart858c9f62007-06-17 19:56:39 -05002605 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2606 "Issue ACC RNID: did:x%x flg:x%x",
2607 ndlp->nlp_DID, ndlp->nlp_flag, 0);
2608
dea31012005-04-17 16:05:31 -05002609 phba->fc_stat.elsXmitACC++;
James Smart858c9f62007-06-17 19:56:39 -05002610 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
James Smart329f9bc2007-04-25 09:53:01 -04002611 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05002612 elsiocb->context1 = NULL; /* Don't need ndlp for cmpl,
2613 * it could be freed */
2614
dea31012005-04-17 16:05:31 -05002615 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
dea31012005-04-17 16:05:31 -05002616 if (rc == IOCB_ERROR) {
2617 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002618 return 1;
dea31012005-04-17 16:05:31 -05002619 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002620 return 0;
dea31012005-04-17 16:05:31 -05002621}
2622
2623int
James Smart2e0fef82007-06-17 19:56:36 -05002624lpfc_els_disc_adisc(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05002625{
James Smart2e0fef82007-06-17 19:56:36 -05002626 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05002627 struct lpfc_nodelist *ndlp, *next_ndlp;
James Smart2e0fef82007-06-17 19:56:36 -05002628 int sentadisc = 0;
dea31012005-04-17 16:05:31 -05002629
James Smart685f0bf2007-04-25 09:53:08 -04002630 /* go thru NPR nodes and issue any remaining ELS ADISCs */
James Smart2e0fef82007-06-17 19:56:36 -05002631 list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
James Smart685f0bf2007-04-25 09:53:08 -04002632 if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
2633 (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
2634 (ndlp->nlp_flag & NLP_NPR_ADISC) != 0) {
James Smart2e0fef82007-06-17 19:56:36 -05002635 spin_lock_irq(shost->host_lock);
James Smart685f0bf2007-04-25 09:53:08 -04002636 ndlp->nlp_flag &= ~NLP_NPR_ADISC;
James Smart2e0fef82007-06-17 19:56:36 -05002637 spin_unlock_irq(shost->host_lock);
James Smart685f0bf2007-04-25 09:53:08 -04002638 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002639 lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
2640 lpfc_issue_els_adisc(vport, ndlp, 0);
James Smart685f0bf2007-04-25 09:53:08 -04002641 sentadisc++;
James Smart2e0fef82007-06-17 19:56:36 -05002642 vport->num_disc_nodes++;
2643 if (vport->num_disc_nodes >=
2644 vport->phba->cfg_discovery_threads) {
2645 spin_lock_irq(shost->host_lock);
2646 vport->fc_flag |= FC_NLP_MORE;
2647 spin_unlock_irq(shost->host_lock);
James Smart685f0bf2007-04-25 09:53:08 -04002648 break;
dea31012005-04-17 16:05:31 -05002649 }
2650 }
2651 }
2652 if (sentadisc == 0) {
James Smart2e0fef82007-06-17 19:56:36 -05002653 spin_lock_irq(shost->host_lock);
2654 vport->fc_flag &= ~FC_NLP_MORE;
2655 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05002656 }
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05002657 return sentadisc;
dea31012005-04-17 16:05:31 -05002658}
2659
2660int
James Smart2e0fef82007-06-17 19:56:36 -05002661lpfc_els_disc_plogi(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05002662{
James Smart2e0fef82007-06-17 19:56:36 -05002663 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05002664 struct lpfc_nodelist *ndlp, *next_ndlp;
James Smart2e0fef82007-06-17 19:56:36 -05002665 int sentplogi = 0;
dea31012005-04-17 16:05:31 -05002666
James Smart2e0fef82007-06-17 19:56:36 -05002667 /* go thru NPR nodes and issue any remaining ELS PLOGIs */
2668 list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
James Smart685f0bf2007-04-25 09:53:08 -04002669 if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
2670 (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
2671 (ndlp->nlp_flag & NLP_DELAY_TMO) == 0 &&
2672 (ndlp->nlp_flag & NLP_NPR_ADISC) == 0) {
2673 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002674 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
2675 lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
James Smart685f0bf2007-04-25 09:53:08 -04002676 sentplogi++;
James Smart2e0fef82007-06-17 19:56:36 -05002677 vport->num_disc_nodes++;
2678 if (vport->num_disc_nodes >=
2679 vport->phba->cfg_discovery_threads) {
2680 spin_lock_irq(shost->host_lock);
2681 vport->fc_flag |= FC_NLP_MORE;
2682 spin_unlock_irq(shost->host_lock);
James Smart685f0bf2007-04-25 09:53:08 -04002683 break;
dea31012005-04-17 16:05:31 -05002684 }
2685 }
2686 }
2687 if (sentplogi == 0) {
James Smart2e0fef82007-06-17 19:56:36 -05002688 spin_lock_irq(shost->host_lock);
2689 vport->fc_flag &= ~FC_NLP_MORE;
2690 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05002691 }
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05002692 return sentplogi;
dea31012005-04-17 16:05:31 -05002693}
2694
James Smart92d7f7b2007-06-17 19:56:38 -05002695void
James Smart2e0fef82007-06-17 19:56:36 -05002696lpfc_els_flush_rscn(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05002697{
James Smart2e0fef82007-06-17 19:56:36 -05002698 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
2699 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002700 int i;
2701
James Smart2e0fef82007-06-17 19:56:36 -05002702 for (i = 0; i < vport->fc_rscn_id_cnt; i++) {
James Smart92d7f7b2007-06-17 19:56:38 -05002703 lpfc_in_buf_free(phba, vport->fc_rscn_id_list[i]);
James Smart2e0fef82007-06-17 19:56:36 -05002704 vport->fc_rscn_id_list[i] = NULL;
dea31012005-04-17 16:05:31 -05002705 }
James Smart2e0fef82007-06-17 19:56:36 -05002706 spin_lock_irq(shost->host_lock);
2707 vport->fc_rscn_id_cnt = 0;
2708 vport->fc_flag &= ~(FC_RSCN_MODE | FC_RSCN_DISCOVERY);
2709 spin_unlock_irq(shost->host_lock);
2710 lpfc_can_disctmo(vport);
dea31012005-04-17 16:05:31 -05002711}
2712
2713int
James Smart2e0fef82007-06-17 19:56:36 -05002714lpfc_rscn_payload_check(struct lpfc_vport *vport, uint32_t did)
dea31012005-04-17 16:05:31 -05002715{
2716 D_ID ns_did;
2717 D_ID rscn_did;
dea31012005-04-17 16:05:31 -05002718 uint32_t *lp;
James Smart92d7f7b2007-06-17 19:56:38 -05002719 uint32_t payload_len, i;
James Smart2e0fef82007-06-17 19:56:36 -05002720 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002721
2722 ns_did.un.word = did;
dea31012005-04-17 16:05:31 -05002723
2724 /* Never match fabric nodes for RSCNs */
2725 if ((did & Fabric_DID_MASK) == Fabric_DID_MASK)
James Smart2e0fef82007-06-17 19:56:36 -05002726 return 0;
dea31012005-04-17 16:05:31 -05002727
2728 /* If we are doing a FULL RSCN rediscovery, match everything */
James Smart2e0fef82007-06-17 19:56:36 -05002729 if (vport->fc_flag & FC_RSCN_DISCOVERY)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002730 return did;
dea31012005-04-17 16:05:31 -05002731
James Smart2e0fef82007-06-17 19:56:36 -05002732 for (i = 0; i < vport->fc_rscn_id_cnt; i++) {
James Smart92d7f7b2007-06-17 19:56:38 -05002733 lp = vport->fc_rscn_id_list[i]->virt;
2734 payload_len = be32_to_cpu(*lp++ & ~ELS_CMD_MASK);
2735 payload_len -= sizeof(uint32_t); /* take off word 0 */
dea31012005-04-17 16:05:31 -05002736 while (payload_len) {
James Smart92d7f7b2007-06-17 19:56:38 -05002737 rscn_did.un.word = be32_to_cpu(*lp++);
2738 payload_len -= sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05002739 switch (rscn_did.un.b.resv) {
2740 case 0: /* Single N_Port ID effected */
James Smart2e0fef82007-06-17 19:56:36 -05002741 if (ns_did.un.word == rscn_did.un.word)
James Smart92d7f7b2007-06-17 19:56:38 -05002742 return did;
dea31012005-04-17 16:05:31 -05002743 break;
2744 case 1: /* Whole N_Port Area effected */
2745 if ((ns_did.un.b.domain == rscn_did.un.b.domain)
2746 && (ns_did.un.b.area == rscn_did.un.b.area))
James Smart92d7f7b2007-06-17 19:56:38 -05002747 return did;
dea31012005-04-17 16:05:31 -05002748 break;
2749 case 2: /* Whole N_Port Domain effected */
2750 if (ns_did.un.b.domain == rscn_did.un.b.domain)
James Smart92d7f7b2007-06-17 19:56:38 -05002751 return did;
dea31012005-04-17 16:05:31 -05002752 break;
2753 default:
James Smart2e0fef82007-06-17 19:56:36 -05002754 /* Unknown Identifier in RSCN node */
dea31012005-04-17 16:05:31 -05002755 lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
James Smart92d7f7b2007-06-17 19:56:38 -05002756 "%d (%d):0217 Unknown "
2757 "Identifier in RSCN payload "
2758 "Data: x%x\n",
2759 phba->brd_no, vport->vpi,
2760 rscn_did.un.word);
2761 case 3: /* Whole Fabric effected */
2762 return did;
dea31012005-04-17 16:05:31 -05002763 }
2764 }
James Smart92d7f7b2007-06-17 19:56:38 -05002765 }
2766 return 0;
dea31012005-04-17 16:05:31 -05002767}
2768
2769static int
James Smart2e0fef82007-06-17 19:56:36 -05002770lpfc_rscn_recovery_check(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05002771{
James Smart685f0bf2007-04-25 09:53:08 -04002772 struct lpfc_nodelist *ndlp = NULL;
dea31012005-04-17 16:05:31 -05002773
2774 /* Look at all nodes effected by pending RSCNs and move
James Smart685f0bf2007-04-25 09:53:08 -04002775 * them to NPR state.
dea31012005-04-17 16:05:31 -05002776 */
James Smart685f0bf2007-04-25 09:53:08 -04002777
James Smart2e0fef82007-06-17 19:56:36 -05002778 list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
James Smart685f0bf2007-04-25 09:53:08 -04002779 if (ndlp->nlp_state == NLP_STE_UNUSED_NODE ||
James Smart2e0fef82007-06-17 19:56:36 -05002780 lpfc_rscn_payload_check(vport, ndlp->nlp_DID) == 0)
dea31012005-04-17 16:05:31 -05002781 continue;
2782
James Smart2e0fef82007-06-17 19:56:36 -05002783 lpfc_disc_state_machine(vport, ndlp, NULL,
James Smart92d7f7b2007-06-17 19:56:38 -05002784 NLP_EVT_DEVICE_RECOVERY);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05002785
James Smart685f0bf2007-04-25 09:53:08 -04002786 /*
2787 * Make sure NLP_DELAY_TMO is NOT running after a device
2788 * recovery event.
2789 */
2790 if (ndlp->nlp_flag & NLP_DELAY_TMO)
James Smart2e0fef82007-06-17 19:56:36 -05002791 lpfc_cancel_retry_delay_tmo(vport, ndlp);
dea31012005-04-17 16:05:31 -05002792 }
James Smart685f0bf2007-04-25 09:53:08 -04002793
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002794 return 0;
dea31012005-04-17 16:05:31 -05002795}
2796
2797static int
James Smart2e0fef82007-06-17 19:56:36 -05002798lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
2799 struct lpfc_nodelist *ndlp, uint8_t newnode)
dea31012005-04-17 16:05:31 -05002800{
James Smart2e0fef82007-06-17 19:56:36 -05002801 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
2802 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002803 struct lpfc_dmabuf *pcmd;
James Smart92d7f7b2007-06-17 19:56:38 -05002804 struct lpfc_vport *next_vport;
2805 uint32_t *lp, *datap;
dea31012005-04-17 16:05:31 -05002806 IOCB_t *icmd;
James Smart92d7f7b2007-06-17 19:56:38 -05002807 uint32_t payload_len, length, nportid, *cmd;
2808 int rscn_cnt = vport->fc_rscn_id_cnt;
2809 int rscn_id = 0, hba_id = 0;
James Smartd2873e42006-08-18 17:46:43 -04002810 int i;
dea31012005-04-17 16:05:31 -05002811
2812 icmd = &cmdiocb->iocb;
2813 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
2814 lp = (uint32_t *) pcmd->virt;
2815
James Smart92d7f7b2007-06-17 19:56:38 -05002816 payload_len = be32_to_cpu(*lp++ & ~ELS_CMD_MASK);
2817 payload_len -= sizeof(uint32_t); /* take off word 0 */
dea31012005-04-17 16:05:31 -05002818
2819 /* RSCN received */
James Smarted957682007-06-17 19:56:37 -05002820 lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
James Smart92d7f7b2007-06-17 19:56:38 -05002821 "%d (%d):0214 RSCN received Data: x%x x%x x%x x%x\n",
2822 phba->brd_no, vport->vpi, vport->fc_flag, payload_len,
2823 *lp, rscn_cnt);
dea31012005-04-17 16:05:31 -05002824
James Smartd2873e42006-08-18 17:46:43 -04002825 for (i = 0; i < payload_len/sizeof(uint32_t); i++)
James Smart2e0fef82007-06-17 19:56:36 -05002826 fc_host_post_event(shost, fc_get_event_number(),
James Smartd2873e42006-08-18 17:46:43 -04002827 FCH_EVT_RSCN, lp[i]);
2828
dea31012005-04-17 16:05:31 -05002829 /* If we are about to begin discovery, just ACC the RSCN.
2830 * Discovery processing will satisfy it.
2831 */
James Smart2e0fef82007-06-17 19:56:36 -05002832 if (vport->port_state <= LPFC_NS_QRY) {
James Smart858c9f62007-06-17 19:56:39 -05002833 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
2834 "RCV RSCN ignore: did:x%x/ste:x%x flg:x%x",
2835 ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
2836
James Smart2e0fef82007-06-17 19:56:36 -05002837 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL,
James Smart92d7f7b2007-06-17 19:56:38 -05002838 newnode);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002839 return 0;
dea31012005-04-17 16:05:31 -05002840 }
2841
James Smart92d7f7b2007-06-17 19:56:38 -05002842 /* If this RSCN just contains NPortIDs for other vports on this HBA,
2843 * just ACC and ignore it.
2844 */
2845 if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
2846 !(phba->cfg_peer_port_login)) {
2847 i = payload_len;
2848 datap = lp;
2849 while (i > 0) {
2850 nportid = *datap++;
2851 nportid = ((be32_to_cpu(nportid)) & Mask_DID);
2852 i -= sizeof(uint32_t);
2853 rscn_id++;
2854 list_for_each_entry(next_vport, &phba->port_list,
2855 listentry) {
2856 if (nportid == next_vport->fc_myDID) {
2857 hba_id++;
2858 break;
2859 }
2860 }
2861 }
2862 if (rscn_id == hba_id) {
2863 /* ALL NPortIDs in RSCN are on HBA */
2864 lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
2865 "%d (%d):0214 Ignore RSCN Data: x%x x%x x%x x%x\n",
2866 phba->brd_no, vport->vpi, vport->fc_flag, payload_len,
2867 *lp, rscn_cnt);
James Smart858c9f62007-06-17 19:56:39 -05002868
2869 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
2870 "RCV RSCN vport: did:x%x/ste:x%x flg:x%x",
2871 ndlp->nlp_DID, vport->port_state,
2872 ndlp->nlp_flag);
2873
James Smart92d7f7b2007-06-17 19:56:38 -05002874 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb,
2875 ndlp, NULL, newnode);
2876 return 0;
2877 }
2878 }
2879
dea31012005-04-17 16:05:31 -05002880 /* If we are already processing an RSCN, save the received
2881 * RSCN payload buffer, cmdiocb->context2 to process later.
2882 */
James Smart2e0fef82007-06-17 19:56:36 -05002883 if (vport->fc_flag & (FC_RSCN_MODE | FC_NDISC_ACTIVE)) {
James Smart858c9f62007-06-17 19:56:39 -05002884 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
2885 "RCV RSCN defer: did:x%x/ste:x%x flg:x%x",
2886 ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
2887
James Smart92d7f7b2007-06-17 19:56:38 -05002888 vport->fc_flag |= FC_RSCN_DEFERRED;
2889 if ((rscn_cnt < FC_MAX_HOLD_RSCN) &&
James Smart2e0fef82007-06-17 19:56:36 -05002890 !(vport->fc_flag & FC_RSCN_DISCOVERY)) {
2891 spin_lock_irq(shost->host_lock);
2892 vport->fc_flag |= FC_RSCN_MODE;
2893 spin_unlock_irq(shost->host_lock);
James Smart92d7f7b2007-06-17 19:56:38 -05002894 if (rscn_cnt) {
2895 cmd = vport->fc_rscn_id_list[rscn_cnt-1]->virt;
2896 length = be32_to_cpu(*cmd & ~ELS_CMD_MASK);
2897 }
2898 if ((rscn_cnt) &&
2899 (payload_len + length <= LPFC_BPL_SIZE)) {
2900 *cmd &= ELS_CMD_MASK;
2901 *cmd |= be32_to_cpu(payload_len + length);
2902 memcpy(((uint8_t *)cmd) + length, lp,
2903 payload_len);
2904 } else {
2905 vport->fc_rscn_id_list[rscn_cnt] = pcmd;
2906 vport->fc_rscn_id_cnt++;
2907 /* If we zero, cmdiocb->context2, the calling
2908 * routine will not try to free it.
2909 */
2910 cmdiocb->context2 = NULL;
2911 }
dea31012005-04-17 16:05:31 -05002912
2913 /* Deferred RSCN */
2914 lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
James Smart92d7f7b2007-06-17 19:56:38 -05002915 "%d (%d):0235 Deferred RSCN "
dea31012005-04-17 16:05:31 -05002916 "Data: x%x x%x x%x\n",
James Smart92d7f7b2007-06-17 19:56:38 -05002917 phba->brd_no, vport->vpi,
2918 vport->fc_rscn_id_cnt, vport->fc_flag,
James Smart2e0fef82007-06-17 19:56:36 -05002919 vport->port_state);
dea31012005-04-17 16:05:31 -05002920 } else {
James Smart2e0fef82007-06-17 19:56:36 -05002921 spin_lock_irq(shost->host_lock);
2922 vport->fc_flag |= FC_RSCN_DISCOVERY;
2923 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05002924 /* ReDiscovery RSCN */
2925 lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
James Smart92d7f7b2007-06-17 19:56:38 -05002926 "%d (%d):0234 ReDiscovery RSCN "
dea31012005-04-17 16:05:31 -05002927 "Data: x%x x%x x%x\n",
James Smart92d7f7b2007-06-17 19:56:38 -05002928 phba->brd_no, vport->vpi,
2929 vport->fc_rscn_id_cnt, vport->fc_flag,
James Smart2e0fef82007-06-17 19:56:36 -05002930 vport->port_state);
dea31012005-04-17 16:05:31 -05002931 }
2932 /* Send back ACC */
James Smart2e0fef82007-06-17 19:56:36 -05002933 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL,
dea31012005-04-17 16:05:31 -05002934 newnode);
2935
2936 /* send RECOVERY event for ALL nodes that match RSCN payload */
James Smart2e0fef82007-06-17 19:56:36 -05002937 lpfc_rscn_recovery_check(vport);
James Smart92d7f7b2007-06-17 19:56:38 -05002938 vport->fc_flag &= ~FC_RSCN_DEFERRED;
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002939 return 0;
dea31012005-04-17 16:05:31 -05002940 }
2941
James Smart858c9f62007-06-17 19:56:39 -05002942 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
2943 "RCV RSCN: did:x%x/ste:x%x flg:x%x",
2944 ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
2945
James Smart2e0fef82007-06-17 19:56:36 -05002946 spin_lock_irq(shost->host_lock);
2947 vport->fc_flag |= FC_RSCN_MODE;
2948 spin_unlock_irq(shost->host_lock);
2949 vport->fc_rscn_id_list[vport->fc_rscn_id_cnt++] = pcmd;
dea31012005-04-17 16:05:31 -05002950 /*
2951 * If we zero, cmdiocb->context2, the calling routine will
2952 * not try to free it.
2953 */
2954 cmdiocb->context2 = NULL;
2955
James Smart2e0fef82007-06-17 19:56:36 -05002956 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -05002957
2958 /* Send back ACC */
James Smart2e0fef82007-06-17 19:56:36 -05002959 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, newnode);
dea31012005-04-17 16:05:31 -05002960
2961 /* send RECOVERY event for ALL nodes that match RSCN payload */
James Smart2e0fef82007-06-17 19:56:36 -05002962 lpfc_rscn_recovery_check(vport);
dea31012005-04-17 16:05:31 -05002963
James Smart2e0fef82007-06-17 19:56:36 -05002964 return lpfc_els_handle_rscn(vport);
dea31012005-04-17 16:05:31 -05002965}
2966
2967int
James Smart2e0fef82007-06-17 19:56:36 -05002968lpfc_els_handle_rscn(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05002969{
2970 struct lpfc_nodelist *ndlp;
James Smart2e0fef82007-06-17 19:56:36 -05002971 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002972
James Smart92d7f7b2007-06-17 19:56:38 -05002973 /* Ignore RSCN if the port is being torn down. */
2974 if (vport->load_flag & FC_UNLOADING) {
2975 lpfc_els_flush_rscn(vport);
2976 return 0;
2977 }
2978
dea31012005-04-17 16:05:31 -05002979 /* Start timer for RSCN processing */
James Smart2e0fef82007-06-17 19:56:36 -05002980 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -05002981
2982 /* RSCN processed */
James Smarted957682007-06-17 19:56:37 -05002983 lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
James Smart92d7f7b2007-06-17 19:56:38 -05002984 "%d (%d):0215 RSCN processed Data: x%x x%x x%x x%x\n",
2985 phba->brd_no, vport->vpi,
James Smart2e0fef82007-06-17 19:56:36 -05002986 vport->fc_flag, 0, vport->fc_rscn_id_cnt,
2987 vport->port_state);
dea31012005-04-17 16:05:31 -05002988
2989 /* To process RSCN, first compare RSCN data with NameServer */
James Smart2e0fef82007-06-17 19:56:36 -05002990 vport->fc_ns_retry = 0;
2991 ndlp = lpfc_findnode_did(vport, NameServer_DID);
James Smart685f0bf2007-04-25 09:53:08 -04002992 if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
dea31012005-04-17 16:05:31 -05002993 /* Good ndlp, issue CT Request to NameServer */
James Smart92d7f7b2007-06-17 19:56:38 -05002994 if (lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, 0, 0) == 0)
dea31012005-04-17 16:05:31 -05002995 /* Wait for NameServer query cmpl before we can
2996 continue */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002997 return 1;
dea31012005-04-17 16:05:31 -05002998 } else {
2999 /* If login to NameServer does not exist, issue one */
3000 /* Good status, issue PLOGI to NameServer */
James Smart2e0fef82007-06-17 19:56:36 -05003001 ndlp = lpfc_findnode_did(vport, NameServer_DID);
3002 if (ndlp)
dea31012005-04-17 16:05:31 -05003003 /* Wait for NameServer login cmpl before we can
3004 continue */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003005 return 1;
James Smart2e0fef82007-06-17 19:56:36 -05003006
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003007 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
3008 if (!ndlp) {
James Smart2e0fef82007-06-17 19:56:36 -05003009 lpfc_els_flush_rscn(vport);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003010 return 0;
dea31012005-04-17 16:05:31 -05003011 } else {
James Smart2e0fef82007-06-17 19:56:36 -05003012 lpfc_nlp_init(vport, ndlp, NameServer_DID);
dea31012005-04-17 16:05:31 -05003013 ndlp->nlp_type |= NLP_FABRIC;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003014 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05003015 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
3016 lpfc_issue_els_plogi(vport, NameServer_DID, 0);
dea31012005-04-17 16:05:31 -05003017 /* Wait for NameServer login cmpl before we can
3018 continue */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003019 return 1;
dea31012005-04-17 16:05:31 -05003020 }
3021 }
3022
James Smart2e0fef82007-06-17 19:56:36 -05003023 lpfc_els_flush_rscn(vport);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003024 return 0;
dea31012005-04-17 16:05:31 -05003025}
3026
3027static int
James Smart2e0fef82007-06-17 19:56:36 -05003028lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3029 struct lpfc_nodelist *ndlp, uint8_t newnode)
dea31012005-04-17 16:05:31 -05003030{
James Smart2e0fef82007-06-17 19:56:36 -05003031 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
3032 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05003033 struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3034 uint32_t *lp = (uint32_t *) pcmd->virt;
3035 IOCB_t *icmd = &cmdiocb->iocb;
3036 struct serv_parm *sp;
3037 LPFC_MBOXQ_t *mbox;
3038 struct ls_rjt stat;
3039 uint32_t cmd, did;
3040 int rc;
3041
3042 cmd = *lp++;
3043 sp = (struct serv_parm *) lp;
3044
3045 /* FLOGI received */
3046
James Smart2e0fef82007-06-17 19:56:36 -05003047 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -05003048
3049 if (phba->fc_topology == TOPOLOGY_LOOP) {
3050 /* We should never receive a FLOGI in loop mode, ignore it */
3051 did = icmd->un.elsreq64.remoteID;
3052
3053 /* An FLOGI ELS command <elsCmd> was received from DID <did> in
3054 Loop Mode */
3055 lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
James Smart92d7f7b2007-06-17 19:56:38 -05003056 "%d (%d):0113 An FLOGI ELS command x%x was "
3057 "received from DID x%x in Loop Mode\n",
3058 phba->brd_no, vport->vpi, cmd, did);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003059 return 1;
dea31012005-04-17 16:05:31 -05003060 }
3061
3062 did = Fabric_DID;
3063
James Smart2e0fef82007-06-17 19:56:36 -05003064 if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3))) {
dea31012005-04-17 16:05:31 -05003065 /* For a FLOGI we accept, then if our portname is greater
3066 * then the remote portname we initiate Nport login.
3067 */
3068
James Smart2e0fef82007-06-17 19:56:36 -05003069 rc = memcmp(&vport->fc_portname, &sp->portName,
James Smart92d7f7b2007-06-17 19:56:38 -05003070 sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05003071
3072 if (!rc) {
James Smart2e0fef82007-06-17 19:56:36 -05003073 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
3074 if (!mbox)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003075 return 1;
James Smart2e0fef82007-06-17 19:56:36 -05003076
dea31012005-04-17 16:05:31 -05003077 lpfc_linkdown(phba);
3078 lpfc_init_link(phba, mbox,
3079 phba->cfg_topology,
3080 phba->cfg_link_speed);
3081 mbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
3082 mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
James Smarted957682007-06-17 19:56:37 -05003083 mbox->vport = vport;
dea31012005-04-17 16:05:31 -05003084 rc = lpfc_sli_issue_mbox
3085 (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
James Smart5b8bd0c2007-04-25 09:52:49 -04003086 lpfc_set_loopback_flag(phba);
dea31012005-04-17 16:05:31 -05003087 if (rc == MBX_NOT_FINISHED) {
James Smart329f9bc2007-04-25 09:53:01 -04003088 mempool_free(mbox, phba->mbox_mem_pool);
dea31012005-04-17 16:05:31 -05003089 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003090 return 1;
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05003091 } else if (rc > 0) { /* greater than */
James Smart2e0fef82007-06-17 19:56:36 -05003092 spin_lock_irq(shost->host_lock);
3093 vport->fc_flag |= FC_PT2PT_PLOGI;
3094 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05003095 }
James Smart2e0fef82007-06-17 19:56:36 -05003096 spin_lock_irq(shost->host_lock);
3097 vport->fc_flag |= FC_PT2PT;
3098 vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
3099 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05003100 } else {
3101 /* Reject this request because invalid parameters */
3102 stat.un.b.lsRjtRsvd0 = 0;
3103 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
3104 stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
3105 stat.un.b.vendorUnique = 0;
James Smart858c9f62007-06-17 19:56:39 -05003106 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
3107 NULL);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003108 return 1;
dea31012005-04-17 16:05:31 -05003109 }
3110
3111 /* Send back ACC */
James Smart2e0fef82007-06-17 19:56:36 -05003112 lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL, newnode);
dea31012005-04-17 16:05:31 -05003113
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003114 return 0;
dea31012005-04-17 16:05:31 -05003115}
3116
3117static int
James Smart2e0fef82007-06-17 19:56:36 -05003118lpfc_els_rcv_rnid(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3119 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05003120{
3121 struct lpfc_dmabuf *pcmd;
3122 uint32_t *lp;
3123 IOCB_t *icmd;
3124 RNID *rn;
3125 struct ls_rjt stat;
3126 uint32_t cmd, did;
3127
3128 icmd = &cmdiocb->iocb;
3129 did = icmd->un.elsreq64.remoteID;
3130 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3131 lp = (uint32_t *) pcmd->virt;
3132
3133 cmd = *lp++;
3134 rn = (RNID *) lp;
3135
3136 /* RNID received */
3137
3138 switch (rn->Format) {
3139 case 0:
3140 case RNID_TOPOLOGY_DISC:
3141 /* Send back ACC */
James Smart2e0fef82007-06-17 19:56:36 -05003142 lpfc_els_rsp_rnid_acc(vport, rn->Format, cmdiocb, ndlp);
dea31012005-04-17 16:05:31 -05003143 break;
3144 default:
3145 /* Reject this request because format not supported */
3146 stat.un.b.lsRjtRsvd0 = 0;
3147 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
3148 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
3149 stat.un.b.vendorUnique = 0;
James Smart858c9f62007-06-17 19:56:39 -05003150 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
3151 NULL);
dea31012005-04-17 16:05:31 -05003152 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003153 return 0;
dea31012005-04-17 16:05:31 -05003154}
3155
3156static int
James Smart2e0fef82007-06-17 19:56:36 -05003157lpfc_els_rcv_lirr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3158 struct lpfc_nodelist *ndlp)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003159{
3160 struct ls_rjt stat;
3161
3162 /* For now, unconditionally reject this command */
3163 stat.un.b.lsRjtRsvd0 = 0;
3164 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
3165 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
3166 stat.un.b.vendorUnique = 0;
James Smart858c9f62007-06-17 19:56:39 -05003167 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003168 return 0;
3169}
3170
Jamie Wellnitz082c0262006-02-28 19:25:30 -05003171static void
James Smart329f9bc2007-04-25 09:53:01 -04003172lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003173{
James Smart2e0fef82007-06-17 19:56:36 -05003174 struct lpfc_sli *psli = &phba->sli;
3175 struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003176 MAILBOX_t *mb;
3177 IOCB_t *icmd;
3178 RPS_RSP *rps_rsp;
3179 uint8_t *pcmd;
3180 struct lpfc_iocbq *elsiocb;
3181 struct lpfc_nodelist *ndlp;
3182 uint16_t xri, status;
3183 uint32_t cmdsize;
3184
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003185 mb = &pmb->mb;
3186
3187 ndlp = (struct lpfc_nodelist *) pmb->context2;
3188 xri = (uint16_t) ((unsigned long)(pmb->context1));
Randy Dunlap041976f2006-06-25 01:58:51 -07003189 pmb->context1 = NULL;
3190 pmb->context2 = NULL;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003191
3192 if (mb->mbxStatus) {
James Smart329f9bc2007-04-25 09:53:01 -04003193 mempool_free(pmb, phba->mbox_mem_pool);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003194 return;
3195 }
3196
3197 cmdsize = sizeof(RPS_RSP) + sizeof(uint32_t);
James Smart329f9bc2007-04-25 09:53:01 -04003198 mempool_free(pmb, phba->mbox_mem_pool);
James Smart2e0fef82007-06-17 19:56:36 -05003199 elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize,
3200 lpfc_max_els_tries, ndlp,
3201 ndlp->nlp_DID, ELS_CMD_ACC);
James Smart329f9bc2007-04-25 09:53:01 -04003202 lpfc_nlp_put(ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003203 if (!elsiocb)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003204 return;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003205
3206 icmd = &elsiocb->iocb;
3207 icmd->ulpContext = xri;
3208
3209 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
3210 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
James Smart92d7f7b2007-06-17 19:56:38 -05003211 pcmd += sizeof(uint32_t); /* Skip past command */
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003212 rps_rsp = (RPS_RSP *)pcmd;
3213
3214 if (phba->fc_topology != TOPOLOGY_LOOP)
3215 status = 0x10;
3216 else
3217 status = 0x8;
James Smart2e0fef82007-06-17 19:56:36 -05003218 if (phba->pport->fc_flag & FC_FABRIC)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003219 status |= 0x4;
3220
3221 rps_rsp->rsvd1 = 0;
3222 rps_rsp->portStatus = be16_to_cpu(status);
3223 rps_rsp->linkFailureCnt = be32_to_cpu(mb->un.varRdLnk.linkFailureCnt);
3224 rps_rsp->lossSyncCnt = be32_to_cpu(mb->un.varRdLnk.lossSyncCnt);
3225 rps_rsp->lossSignalCnt = be32_to_cpu(mb->un.varRdLnk.lossSignalCnt);
3226 rps_rsp->primSeqErrCnt = be32_to_cpu(mb->un.varRdLnk.primSeqErrCnt);
3227 rps_rsp->invalidXmitWord = be32_to_cpu(mb->un.varRdLnk.invalidXmitWord);
3228 rps_rsp->crcCnt = be32_to_cpu(mb->un.varRdLnk.crcCnt);
3229
3230 /* Xmit ELS RPS ACC response tag <ulpIoTag> */
3231 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart92d7f7b2007-06-17 19:56:38 -05003232 "%d (%d):0118 Xmit ELS RPS ACC response tag x%x "
3233 "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, "
3234 "rpi x%x\n",
3235 phba->brd_no, ndlp->vport->vpi, elsiocb->iotag,
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003236 elsiocb->iocb.ulpContext, ndlp->nlp_DID,
3237 ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
3238
James Smart858c9f62007-06-17 19:56:39 -05003239 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003240 phba->fc_stat.elsXmitACC++;
James Smarted957682007-06-17 19:56:37 -05003241 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003242 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003243 return;
3244}
3245
3246static int
James Smart2e0fef82007-06-17 19:56:36 -05003247lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3248 struct lpfc_nodelist *ndlp)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003249{
James Smart2e0fef82007-06-17 19:56:36 -05003250 struct lpfc_hba *phba = vport->phba;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003251 uint32_t *lp;
3252 uint8_t flag;
3253 LPFC_MBOXQ_t *mbox;
3254 struct lpfc_dmabuf *pcmd;
3255 RPS *rps;
3256 struct ls_rjt stat;
3257
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05003258 if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
3259 (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) {
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003260 stat.un.b.lsRjtRsvd0 = 0;
3261 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
3262 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
3263 stat.un.b.vendorUnique = 0;
James Smart858c9f62007-06-17 19:56:39 -05003264 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
3265 NULL);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003266 }
3267
3268 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3269 lp = (uint32_t *) pcmd->virt;
3270 flag = (be32_to_cpu(*lp++) & 0xf);
3271 rps = (RPS *) lp;
3272
3273 if ((flag == 0) ||
3274 ((flag == 1) && (be32_to_cpu(rps->un.portNum) == 0)) ||
James Smart2e0fef82007-06-17 19:56:36 -05003275 ((flag == 2) && (memcmp(&rps->un.portName, &vport->fc_portname,
James Smart92d7f7b2007-06-17 19:56:38 -05003276 sizeof(struct lpfc_name)) == 0))) {
James Smart2e0fef82007-06-17 19:56:36 -05003277
James Smart92d7f7b2007-06-17 19:56:38 -05003278 printk("Fix me....\n");
3279 dump_stack();
James Smart2e0fef82007-06-17 19:56:36 -05003280 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC);
3281 if (mbox) {
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003282 lpfc_read_lnk_stat(phba, mbox);
3283 mbox->context1 =
James Smart92d7f7b2007-06-17 19:56:38 -05003284 (void *)((unsigned long) cmdiocb->iocb.ulpContext);
James Smart329f9bc2007-04-25 09:53:01 -04003285 mbox->context2 = lpfc_nlp_get(ndlp);
James Smart92d7f7b2007-06-17 19:56:38 -05003286 mbox->vport = vport;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003287 mbox->mbox_cmpl = lpfc_els_rsp_rps_acc;
3288 if (lpfc_sli_issue_mbox (phba, mbox,
James Smart2e0fef82007-06-17 19:56:36 -05003289 (MBX_NOWAIT | MBX_STOP_IOCB)) != MBX_NOT_FINISHED)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003290 /* Mbox completion will send ELS Response */
3291 return 0;
James Smart2e0fef82007-06-17 19:56:36 -05003292
James Smart329f9bc2007-04-25 09:53:01 -04003293 lpfc_nlp_put(ndlp);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003294 mempool_free(mbox, phba->mbox_mem_pool);
3295 }
3296 }
3297 stat.un.b.lsRjtRsvd0 = 0;
3298 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
3299 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
3300 stat.un.b.vendorUnique = 0;
James Smart858c9f62007-06-17 19:56:39 -05003301 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003302 return 0;
3303}
3304
Jamie Wellnitz082c0262006-02-28 19:25:30 -05003305static int
James Smart2e0fef82007-06-17 19:56:36 -05003306lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize,
3307 struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003308{
James Smart2e0fef82007-06-17 19:56:36 -05003309 struct lpfc_hba *phba = vport->phba;
3310 IOCB_t *icmd, *oldcmd;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003311 RPL_RSP rpl_rsp;
3312 struct lpfc_iocbq *elsiocb;
James Smart2e0fef82007-06-17 19:56:36 -05003313 struct lpfc_sli *psli = &phba->sli;
3314 struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003315 uint8_t *pcmd;
3316
James Smart2e0fef82007-06-17 19:56:36 -05003317 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
3318 ndlp->nlp_DID, ELS_CMD_ACC);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003319
James Smart488d1462006-03-07 15:02:37 -05003320 if (!elsiocb)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003321 return 1;
James Smart488d1462006-03-07 15:02:37 -05003322
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003323 icmd = &elsiocb->iocb;
3324 oldcmd = &oldiocb->iocb;
3325 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
3326
3327 pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
3328 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
James Smart92d7f7b2007-06-17 19:56:38 -05003329 pcmd += sizeof(uint16_t);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003330 *((uint16_t *)(pcmd)) = be16_to_cpu(cmdsize);
3331 pcmd += sizeof(uint16_t);
3332
3333 /* Setup the RPL ACC payload */
3334 rpl_rsp.listLen = be32_to_cpu(1);
3335 rpl_rsp.index = 0;
3336 rpl_rsp.port_num_blk.portNum = 0;
James Smart2e0fef82007-06-17 19:56:36 -05003337 rpl_rsp.port_num_blk.portID = be32_to_cpu(vport->fc_myDID);
3338 memcpy(&rpl_rsp.port_num_blk.portName, &vport->fc_portname,
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003339 sizeof(struct lpfc_name));
3340
3341 memcpy(pcmd, &rpl_rsp, cmdsize - sizeof(uint32_t));
3342
3343
3344 /* Xmit ELS RPL ACC response tag <ulpIoTag> */
3345 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart92d7f7b2007-06-17 19:56:38 -05003346 "%d (%d):0120 Xmit ELS RPL ACC response tag x%x "
3347 "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, "
3348 "rpi x%x\n",
3349 phba->brd_no, vport->vpi, elsiocb->iotag,
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003350 elsiocb->iocb.ulpContext, ndlp->nlp_DID,
3351 ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
3352
James Smart858c9f62007-06-17 19:56:39 -05003353 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003354
3355 phba->fc_stat.elsXmitACC++;
3356 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
3357 lpfc_els_free_iocb(phba, elsiocb);
3358 return 1;
3359 }
3360 return 0;
3361}
3362
3363static int
James Smart2e0fef82007-06-17 19:56:36 -05003364lpfc_els_rcv_rpl(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3365 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05003366{
3367 struct lpfc_dmabuf *pcmd;
3368 uint32_t *lp;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003369 uint32_t maxsize;
3370 uint16_t cmdsize;
3371 RPL *rpl;
3372 struct ls_rjt stat;
dea31012005-04-17 16:05:31 -05003373
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05003374 if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
3375 (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) {
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003376 stat.un.b.lsRjtRsvd0 = 0;
3377 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
3378 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
3379 stat.un.b.vendorUnique = 0;
James Smart858c9f62007-06-17 19:56:39 -05003380 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
3381 NULL);
dea31012005-04-17 16:05:31 -05003382 }
3383
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003384 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3385 lp = (uint32_t *) pcmd->virt;
3386 rpl = (RPL *) (lp + 1);
3387
3388 maxsize = be32_to_cpu(rpl->maxsize);
3389
3390 /* We support only one port */
3391 if ((rpl->index == 0) &&
3392 ((maxsize == 0) ||
3393 ((maxsize * sizeof(uint32_t)) >= sizeof(RPL_RSP)))) {
3394 cmdsize = sizeof(uint32_t) + sizeof(RPL_RSP);
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05003395 } else {
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003396 cmdsize = sizeof(uint32_t) + maxsize * sizeof(uint32_t);
3397 }
James Smart2e0fef82007-06-17 19:56:36 -05003398 lpfc_els_rsp_rpl_acc(vport, cmdsize, cmdiocb, ndlp);
dea31012005-04-17 16:05:31 -05003399
3400 return 0;
3401}
3402
3403static int
James Smart2e0fef82007-06-17 19:56:36 -05003404lpfc_els_rcv_farp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3405 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05003406{
James Smart2e0fef82007-06-17 19:56:36 -05003407 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05003408 struct lpfc_dmabuf *pcmd;
3409 uint32_t *lp;
3410 IOCB_t *icmd;
3411 FARP *fp;
3412 uint32_t cmd, cnt, did;
3413
3414 icmd = &cmdiocb->iocb;
3415 did = icmd->un.elsreq64.remoteID;
3416 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3417 lp = (uint32_t *) pcmd->virt;
3418
3419 cmd = *lp++;
3420 fp = (FARP *) lp;
3421
3422 /* FARP-REQ received from DID <did> */
James Smarted957682007-06-17 19:56:37 -05003423 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart92d7f7b2007-06-17 19:56:38 -05003424 "%d (%d):0601 FARP-REQ received from DID x%x\n",
3425 phba->brd_no, vport->vpi, did);
dea31012005-04-17 16:05:31 -05003426
3427 /* We will only support match on WWPN or WWNN */
3428 if (fp->Mflags & ~(FARP_MATCH_NODE | FARP_MATCH_PORT)) {
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003429 return 0;
dea31012005-04-17 16:05:31 -05003430 }
3431
3432 cnt = 0;
3433 /* If this FARP command is searching for my portname */
3434 if (fp->Mflags & FARP_MATCH_PORT) {
James Smart2e0fef82007-06-17 19:56:36 -05003435 if (memcmp(&fp->RportName, &vport->fc_portname,
James Smart92d7f7b2007-06-17 19:56:38 -05003436 sizeof(struct lpfc_name)) == 0)
dea31012005-04-17 16:05:31 -05003437 cnt = 1;
3438 }
3439
3440 /* If this FARP command is searching for my nodename */
3441 if (fp->Mflags & FARP_MATCH_NODE) {
James Smart2e0fef82007-06-17 19:56:36 -05003442 if (memcmp(&fp->RnodeName, &vport->fc_nodename,
James Smart92d7f7b2007-06-17 19:56:38 -05003443 sizeof(struct lpfc_name)) == 0)
dea31012005-04-17 16:05:31 -05003444 cnt = 1;
3445 }
3446
3447 if (cnt) {
3448 if ((ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) ||
3449 (ndlp->nlp_state == NLP_STE_MAPPED_NODE)) {
3450 /* Log back into the node before sending the FARP. */
3451 if (fp->Rflags & FARP_REQUEST_PLOGI) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003452 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05003453 lpfc_nlp_set_state(vport, ndlp,
James Smartde0c5b32007-04-25 09:52:27 -04003454 NLP_STE_PLOGI_ISSUE);
James Smart2e0fef82007-06-17 19:56:36 -05003455 lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
dea31012005-04-17 16:05:31 -05003456 }
3457
3458 /* Send a FARP response to that node */
James Smart2e0fef82007-06-17 19:56:36 -05003459 if (fp->Rflags & FARP_REQUEST_FARPR)
3460 lpfc_issue_els_farpr(vport, did, 0);
dea31012005-04-17 16:05:31 -05003461 }
3462 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003463 return 0;
dea31012005-04-17 16:05:31 -05003464}
3465
3466static int
James Smart2e0fef82007-06-17 19:56:36 -05003467lpfc_els_rcv_farpr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3468 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05003469{
3470 struct lpfc_dmabuf *pcmd;
3471 uint32_t *lp;
3472 IOCB_t *icmd;
3473 uint32_t cmd, did;
James Smart2e0fef82007-06-17 19:56:36 -05003474 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05003475
3476 icmd = &cmdiocb->iocb;
3477 did = icmd->un.elsreq64.remoteID;
3478 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3479 lp = (uint32_t *) pcmd->virt;
3480
3481 cmd = *lp++;
3482 /* FARP-RSP received from DID <did> */
James Smarted957682007-06-17 19:56:37 -05003483 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart92d7f7b2007-06-17 19:56:38 -05003484 "%d (%d):0600 FARP-RSP received from DID x%x\n",
3485 phba->brd_no, vport->vpi, did);
dea31012005-04-17 16:05:31 -05003486 /* ACCEPT the Farp resp request */
James Smart2e0fef82007-06-17 19:56:36 -05003487 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
dea31012005-04-17 16:05:31 -05003488
3489 return 0;
3490}
3491
3492static int
James Smart2e0fef82007-06-17 19:56:36 -05003493lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3494 struct lpfc_nodelist *fan_ndlp)
dea31012005-04-17 16:05:31 -05003495{
3496 struct lpfc_dmabuf *pcmd;
3497 uint32_t *lp;
3498 IOCB_t *icmd;
dea31012005-04-17 16:05:31 -05003499 uint32_t cmd, did;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003500 FAN *fp;
3501 struct lpfc_nodelist *ndlp, *next_ndlp;
James Smart2e0fef82007-06-17 19:56:36 -05003502 struct lpfc_hba *phba = vport->phba;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003503
3504 /* FAN received */
James Smarted957682007-06-17 19:56:37 -05003505 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart92d7f7b2007-06-17 19:56:38 -05003506 "%d (%d):0265 FAN received\n",
3507 phba->brd_no, vport->vpi);
dea31012005-04-17 16:05:31 -05003508
3509 icmd = &cmdiocb->iocb;
3510 did = icmd->un.elsreq64.remoteID;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003511 pcmd = (struct lpfc_dmabuf *)cmdiocb->context2;
3512 lp = (uint32_t *)pcmd->virt;
dea31012005-04-17 16:05:31 -05003513
3514 cmd = *lp++;
James Smart92d7f7b2007-06-17 19:56:38 -05003515 fp = (FAN *) lp;
dea31012005-04-17 16:05:31 -05003516
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003517 /* FAN received; Fan does not have a reply sequence */
dea31012005-04-17 16:05:31 -05003518
James Smart2e0fef82007-06-17 19:56:36 -05003519 if (phba->pport->port_state == LPFC_LOCAL_CFG_LINK) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003520 if ((memcmp(&phba->fc_fabparam.nodeName, &fp->FnodeName,
3521 sizeof(struct lpfc_name)) != 0) ||
3522 (memcmp(&phba->fc_fabparam.portName, &fp->FportName,
3523 sizeof(struct lpfc_name)) != 0)) {
3524 /*
3525 * This node has switched fabrics. FLOGI is required
3526 * Clean up the old rpi's
dea31012005-04-17 16:05:31 -05003527 */
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003528
3529 list_for_each_entry_safe(ndlp, next_ndlp,
James Smart2e0fef82007-06-17 19:56:36 -05003530 &vport->fc_nodes, nlp_listp) {
James Smart685f0bf2007-04-25 09:53:08 -04003531 if (ndlp->nlp_state != NLP_STE_NPR_NODE)
3532 continue;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003533 if (ndlp->nlp_type & NLP_FABRIC) {
3534 /*
3535 * Clean up old Fabric, Nameserver and
3536 * other NLP_FABRIC logins
3537 */
James Smart2e0fef82007-06-17 19:56:36 -05003538 lpfc_drop_node(vport, ndlp);
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05003539 } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003540 /* Fail outstanding I/O now since this
3541 * device is marked for PLOGI
3542 */
James Smart2e0fef82007-06-17 19:56:36 -05003543 lpfc_unreg_rpi(vport, ndlp);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003544 }
3545 }
3546
James Smart2e0fef82007-06-17 19:56:36 -05003547 vport->port_state = LPFC_FLOGI;
3548 lpfc_set_disctmo(vport);
3549 lpfc_initial_flogi(vport);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003550 return 0;
dea31012005-04-17 16:05:31 -05003551 }
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003552 /* Discovery not needed,
3553 * move the nodes to their original state.
3554 */
James Smart2e0fef82007-06-17 19:56:36 -05003555 list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
James Smart685f0bf2007-04-25 09:53:08 -04003556 nlp_listp) {
3557 if (ndlp->nlp_state != NLP_STE_NPR_NODE)
3558 continue;
dea31012005-04-17 16:05:31 -05003559
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003560 switch (ndlp->nlp_prev_state) {
3561 case NLP_STE_UNMAPPED_NODE:
3562 ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
James Smart2e0fef82007-06-17 19:56:36 -05003563 lpfc_nlp_set_state(vport, ndlp,
James Smartde0c5b32007-04-25 09:52:27 -04003564 NLP_STE_UNMAPPED_NODE);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003565 break;
3566
3567 case NLP_STE_MAPPED_NODE:
3568 ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
James Smart2e0fef82007-06-17 19:56:36 -05003569 lpfc_nlp_set_state(vport, ndlp,
James Smartde0c5b32007-04-25 09:52:27 -04003570 NLP_STE_MAPPED_NODE);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003571 break;
3572
3573 default:
3574 break;
3575 }
3576 }
3577
3578 /* Start discovery - this should just do CLEAR_LA */
James Smart2e0fef82007-06-17 19:56:36 -05003579 lpfc_disc_start(vport);
dea31012005-04-17 16:05:31 -05003580 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003581 return 0;
dea31012005-04-17 16:05:31 -05003582}
3583
3584void
3585lpfc_els_timeout(unsigned long ptr)
3586{
James Smart2e0fef82007-06-17 19:56:36 -05003587 struct lpfc_vport *vport = (struct lpfc_vport *) ptr;
3588 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05003589 unsigned long iflag;
3590
James Smart2e0fef82007-06-17 19:56:36 -05003591 spin_lock_irqsave(&vport->work_port_lock, iflag);
3592 if ((vport->work_port_events & WORKER_ELS_TMO) == 0) {
3593 vport->work_port_events |= WORKER_ELS_TMO;
James Smart92d7f7b2007-06-17 19:56:38 -05003594 spin_unlock_irqrestore(&vport->work_port_lock, iflag);
3595
3596 spin_lock_irqsave(&phba->hbalock, iflag);
dea31012005-04-17 16:05:31 -05003597 if (phba->work_wait)
James Smart92d7f7b2007-06-17 19:56:38 -05003598 lpfc_worker_wake_up(phba);
3599 spin_unlock_irqrestore(&phba->hbalock, iflag);
dea31012005-04-17 16:05:31 -05003600 }
James Smart92d7f7b2007-06-17 19:56:38 -05003601 else
3602 spin_unlock_irqrestore(&vport->work_port_lock, iflag);
dea31012005-04-17 16:05:31 -05003603 return;
3604}
3605
3606void
James Smart2e0fef82007-06-17 19:56:36 -05003607lpfc_els_timeout_handler(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05003608{
James Smart2e0fef82007-06-17 19:56:36 -05003609 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05003610 struct lpfc_sli_ring *pring;
3611 struct lpfc_iocbq *tmp_iocb, *piocb;
3612 IOCB_t *cmd = NULL;
3613 struct lpfc_dmabuf *pcmd;
James Smart2e0fef82007-06-17 19:56:36 -05003614 uint32_t els_command = 0;
dea31012005-04-17 16:05:31 -05003615 uint32_t timeout;
James Smart2e0fef82007-06-17 19:56:36 -05003616 uint32_t remote_ID = 0xffffffff;
dea31012005-04-17 16:05:31 -05003617
dea31012005-04-17 16:05:31 -05003618 /* If the timer is already canceled do nothing */
James Smart2e0fef82007-06-17 19:56:36 -05003619 if ((vport->work_port_events & WORKER_ELS_TMO) == 0) {
dea31012005-04-17 16:05:31 -05003620 return;
3621 }
James Smart2e0fef82007-06-17 19:56:36 -05003622 spin_lock_irq(&phba->hbalock);
dea31012005-04-17 16:05:31 -05003623 timeout = (uint32_t)(phba->fc_ratov << 1);
3624
3625 pring = &phba->sli.ring[LPFC_ELS_RING];
dea31012005-04-17 16:05:31 -05003626
3627 list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
3628 cmd = &piocb->iocb;
3629
James Smart2e0fef82007-06-17 19:56:36 -05003630 if ((piocb->iocb_flag & LPFC_IO_LIBDFC) != 0 ||
3631 piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN ||
3632 piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)
dea31012005-04-17 16:05:31 -05003633 continue;
James Smart2e0fef82007-06-17 19:56:36 -05003634
3635 if (piocb->vport != vport)
3636 continue;
3637
dea31012005-04-17 16:05:31 -05003638 pcmd = (struct lpfc_dmabuf *) piocb->context2;
James Smart2e0fef82007-06-17 19:56:36 -05003639 if (pcmd)
3640 els_command = *(uint32_t *) (pcmd->virt);
dea31012005-04-17 16:05:31 -05003641
James Smart92d7f7b2007-06-17 19:56:38 -05003642 if (els_command == ELS_CMD_FARP ||
3643 els_command == ELS_CMD_FARPR ||
3644 els_command == ELS_CMD_FDISC)
dea31012005-04-17 16:05:31 -05003645 continue;
James Smart92d7f7b2007-06-17 19:56:38 -05003646
3647 if (vport != piocb->vport)
3648 continue;
dea31012005-04-17 16:05:31 -05003649
3650 if (piocb->drvrTimeout > 0) {
James Smart92d7f7b2007-06-17 19:56:38 -05003651 if (piocb->drvrTimeout >= timeout)
dea31012005-04-17 16:05:31 -05003652 piocb->drvrTimeout -= timeout;
James Smart92d7f7b2007-06-17 19:56:38 -05003653 else
dea31012005-04-17 16:05:31 -05003654 piocb->drvrTimeout = 0;
dea31012005-04-17 16:05:31 -05003655 continue;
3656 }
3657
James Smart2e0fef82007-06-17 19:56:36 -05003658 remote_ID = 0xffffffff;
3659 if (cmd->ulpCommand != CMD_GEN_REQUEST64_CR)
dea31012005-04-17 16:05:31 -05003660 remote_ID = cmd->un.elsreq64.remoteID;
James Smart2e0fef82007-06-17 19:56:36 -05003661 else {
3662 struct lpfc_nodelist *ndlp;
3663 ndlp = __lpfc_findnode_rpi(vport, cmd->ulpContext);
3664 if (ndlp)
3665 remote_ID = ndlp->nlp_DID;
dea31012005-04-17 16:05:31 -05003666 }
3667
James Smart92d7f7b2007-06-17 19:56:38 -05003668 lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
3669 "%d (%d):0127 ELS timeout Data: x%x x%x x%x "
3670 "x%x\n",
3671 phba->brd_no, vport->vpi, els_command,
dea31012005-04-17 16:05:31 -05003672 remote_ID, cmd->ulpCommand, cmd->ulpIoTag);
3673
James Smart07951072007-04-25 09:51:38 -04003674 lpfc_sli_issue_abort_iotag(phba, pring, piocb);
dea31012005-04-17 16:05:31 -05003675 }
James Smart2e0fef82007-06-17 19:56:36 -05003676 spin_unlock_irq(&phba->hbalock);
James Smart5a0e3262006-07-06 15:49:16 -04003677
James Smart2e0fef82007-06-17 19:56:36 -05003678 if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt)
3679 mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout);
dea31012005-04-17 16:05:31 -05003680}
3681
3682void
James Smart2e0fef82007-06-17 19:56:36 -05003683lpfc_els_flush_cmd(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05003684{
James Smart2534ba72007-04-25 09:52:20 -04003685 LIST_HEAD(completions);
James Smart2e0fef82007-06-17 19:56:36 -05003686 struct lpfc_hba *phba = vport->phba;
James Smart329f9bc2007-04-25 09:53:01 -04003687 struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
dea31012005-04-17 16:05:31 -05003688 struct lpfc_iocbq *tmp_iocb, *piocb;
3689 IOCB_t *cmd = NULL;
James Smart92d7f7b2007-06-17 19:56:38 -05003690
3691 lpfc_fabric_abort_vport(vport);
dea31012005-04-17 16:05:31 -05003692
James Smart2e0fef82007-06-17 19:56:36 -05003693 spin_lock_irq(&phba->hbalock);
dea31012005-04-17 16:05:31 -05003694 list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
3695 cmd = &piocb->iocb;
3696
3697 if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
3698 continue;
3699 }
3700
3701 /* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */
James Smart329f9bc2007-04-25 09:53:01 -04003702 if (cmd->ulpCommand == CMD_QUE_RING_BUF_CN ||
3703 cmd->ulpCommand == CMD_QUE_RING_BUF64_CN ||
3704 cmd->ulpCommand == CMD_CLOSE_XRI_CN ||
3705 cmd->ulpCommand == CMD_ABORT_XRI_CN)
dea31012005-04-17 16:05:31 -05003706 continue;
dea31012005-04-17 16:05:31 -05003707
James Smart2e0fef82007-06-17 19:56:36 -05003708 if (piocb->vport != vport)
3709 continue;
3710
James Smart2534ba72007-04-25 09:52:20 -04003711 list_move_tail(&piocb->list, &completions);
James Smart1dcb58e2007-04-25 09:51:30 -04003712 pring->txq_cnt--;
dea31012005-04-17 16:05:31 -05003713 }
3714
3715 list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
dea31012005-04-17 16:05:31 -05003716 if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
3717 continue;
3718 }
dea31012005-04-17 16:05:31 -05003719
James Smart2e0fef82007-06-17 19:56:36 -05003720 if (piocb->vport != vport)
3721 continue;
3722
James Smart07951072007-04-25 09:51:38 -04003723 lpfc_sli_issue_abort_iotag(phba, pring, piocb);
dea31012005-04-17 16:05:31 -05003724 }
James Smart2e0fef82007-06-17 19:56:36 -05003725 spin_unlock_irq(&phba->hbalock);
James Smart2534ba72007-04-25 09:52:20 -04003726
James Smart2e0fef82007-06-17 19:56:36 -05003727 while (!list_empty(&completions)) {
James Smart2534ba72007-04-25 09:52:20 -04003728 piocb = list_get_first(&completions, struct lpfc_iocbq, list);
3729 cmd = &piocb->iocb;
James Smart92d7f7b2007-06-17 19:56:38 -05003730 list_del_init(&piocb->list);
James Smart2534ba72007-04-25 09:52:20 -04003731
James Smart2e0fef82007-06-17 19:56:36 -05003732 if (!piocb->iocb_cmpl)
3733 lpfc_sli_release_iocbq(phba, piocb);
3734 else {
James Smart2534ba72007-04-25 09:52:20 -04003735 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
3736 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
3737 (piocb->iocb_cmpl) (phba, piocb, piocb);
James Smart2e0fef82007-06-17 19:56:36 -05003738 }
James Smart2534ba72007-04-25 09:52:20 -04003739 }
3740
dea31012005-04-17 16:05:31 -05003741 return;
3742}
3743
James Smarted957682007-06-17 19:56:37 -05003744static void
3745lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
James Smart92d7f7b2007-06-17 19:56:38 -05003746 struct lpfc_vport *vport, struct lpfc_iocbq *elsiocb)
dea31012005-04-17 16:05:31 -05003747{
dea31012005-04-17 16:05:31 -05003748 struct lpfc_nodelist *ndlp;
dea31012005-04-17 16:05:31 -05003749 struct ls_rjt stat;
James Smart92d7f7b2007-06-17 19:56:38 -05003750 uint32_t *payload;
James Smart2e0fef82007-06-17 19:56:36 -05003751 uint32_t cmd, did, newnode, rjt_err = 0;
James Smarted957682007-06-17 19:56:37 -05003752 IOCB_t *icmd = &elsiocb->iocb;
dea31012005-04-17 16:05:31 -05003753
James Smart92d7f7b2007-06-17 19:56:38 -05003754 if (vport == NULL || elsiocb->context2 == NULL)
dea31012005-04-17 16:05:31 -05003755 goto dropit;
James Smart2e0fef82007-06-17 19:56:36 -05003756
dea31012005-04-17 16:05:31 -05003757 newnode = 0;
James Smart92d7f7b2007-06-17 19:56:38 -05003758 payload = ((struct lpfc_dmabuf *)elsiocb->context2)->virt;
3759 cmd = *payload;
James Smarted957682007-06-17 19:56:37 -05003760 if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) == 0)
3761 lpfc_post_buffer(phba, pring, 1, 1);
dea31012005-04-17 16:05:31 -05003762
James Smart858c9f62007-06-17 19:56:39 -05003763 did = icmd->un.rcvels.remoteID;
3764 if (icmd->ulpStatus) {
3765 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3766 "RCV Unsol ELS: status:x%x/x%x did:x%x",
3767 icmd->ulpStatus, icmd->un.ulpWord[4], did);
dea31012005-04-17 16:05:31 -05003768 goto dropit;
James Smart858c9f62007-06-17 19:56:39 -05003769 }
dea31012005-04-17 16:05:31 -05003770
3771 /* Check to see if link went down during discovery */
James Smarted957682007-06-17 19:56:37 -05003772 if (lpfc_els_chk_latt(vport))
dea31012005-04-17 16:05:31 -05003773 goto dropit;
dea31012005-04-17 16:05:31 -05003774
James Smart92d7f7b2007-06-17 19:56:38 -05003775 /* Ignore traffic recevied during vport shutdown. */
3776 if (vport->load_flag & FC_UNLOADING)
3777 goto dropit;
3778
James Smart2e0fef82007-06-17 19:56:36 -05003779 ndlp = lpfc_findnode_did(vport, did);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003780 if (!ndlp) {
dea31012005-04-17 16:05:31 -05003781 /* Cannot find existing Fabric ndlp, so allocate a new one */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003782 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
James Smarted957682007-06-17 19:56:37 -05003783 if (!ndlp)
dea31012005-04-17 16:05:31 -05003784 goto dropit;
dea31012005-04-17 16:05:31 -05003785
James Smart2e0fef82007-06-17 19:56:36 -05003786 lpfc_nlp_init(vport, ndlp, did);
dea31012005-04-17 16:05:31 -05003787 newnode = 1;
3788 if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) {
3789 ndlp->nlp_type |= NLP_FABRIC;
3790 }
James Smart2e0fef82007-06-17 19:56:36 -05003791 lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
dea31012005-04-17 16:05:31 -05003792 }
3793
3794 phba->fc_stat.elsRcvFrame++;
James Smart329f9bc2007-04-25 09:53:01 -04003795 if (elsiocb->context1)
3796 lpfc_nlp_put(elsiocb->context1);
3797 elsiocb->context1 = lpfc_nlp_get(ndlp);
James Smart2e0fef82007-06-17 19:56:36 -05003798 elsiocb->vport = vport;
dea31012005-04-17 16:05:31 -05003799
3800 if ((cmd & ELS_CMD_MASK) == ELS_CMD_RSCN) {
3801 cmd &= ELS_CMD_MASK;
3802 }
3803 /* ELS command <elsCmd> received from NPORT <did> */
3804 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
James Smart92d7f7b2007-06-17 19:56:38 -05003805 "%d (%d):0112 ELS command x%x received from NPORT x%x "
3806 "Data: x%x\n", phba->brd_no, vport->vpi, cmd, did,
James Smarted957682007-06-17 19:56:37 -05003807 vport->port_state);
dea31012005-04-17 16:05:31 -05003808
3809 switch (cmd) {
3810 case ELS_CMD_PLOGI:
James Smart858c9f62007-06-17 19:56:39 -05003811 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3812 "RCV PLOGI: did:x%x/ste:x%x flg:x%x",
3813 did, vport->port_state, ndlp->nlp_flag);
3814
dea31012005-04-17 16:05:31 -05003815 phba->fc_stat.elsRcvPLOGI++;
James Smart858c9f62007-06-17 19:56:39 -05003816 ndlp = lpfc_plogi_confirm_nport(phba, payload, ndlp);
3817
3818 if (vport->port_state < LPFC_DISC_AUTH) {
3819 rjt_err = LSRJT_UNABLE_TPC;
dea31012005-04-17 16:05:31 -05003820 break;
3821 }
James Smart2e0fef82007-06-17 19:56:36 -05003822 lpfc_disc_state_machine(vport, ndlp, elsiocb,
3823 NLP_EVT_RCV_PLOGI);
James Smart858c9f62007-06-17 19:56:39 -05003824
dea31012005-04-17 16:05:31 -05003825 break;
3826 case ELS_CMD_FLOGI:
James Smart858c9f62007-06-17 19:56:39 -05003827 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3828 "RCV FLOGI: did:x%x/ste:x%x flg:x%x",
3829 did, vport->port_state, ndlp->nlp_flag);
3830
dea31012005-04-17 16:05:31 -05003831 phba->fc_stat.elsRcvFLOGI++;
James Smart2e0fef82007-06-17 19:56:36 -05003832 lpfc_els_rcv_flogi(vport, elsiocb, ndlp, newnode);
James Smartde0c5b32007-04-25 09:52:27 -04003833 if (newnode)
James Smart2e0fef82007-06-17 19:56:36 -05003834 lpfc_drop_node(vport, ndlp);
dea31012005-04-17 16:05:31 -05003835 break;
3836 case ELS_CMD_LOGO:
James Smart858c9f62007-06-17 19:56:39 -05003837 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3838 "RCV LOGO: did:x%x/ste:x%x flg:x%x",
3839 did, vport->port_state, ndlp->nlp_flag);
3840
dea31012005-04-17 16:05:31 -05003841 phba->fc_stat.elsRcvLOGO++;
James Smart2e0fef82007-06-17 19:56:36 -05003842 if (vport->port_state < LPFC_DISC_AUTH) {
James Smart858c9f62007-06-17 19:56:39 -05003843 rjt_err = LSRJT_UNABLE_TPC;
dea31012005-04-17 16:05:31 -05003844 break;
3845 }
James Smart2e0fef82007-06-17 19:56:36 -05003846 lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_LOGO);
dea31012005-04-17 16:05:31 -05003847 break;
3848 case ELS_CMD_PRLO:
James Smart858c9f62007-06-17 19:56:39 -05003849 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3850 "RCV PRLO: did:x%x/ste:x%x flg:x%x",
3851 did, vport->port_state, ndlp->nlp_flag);
3852
dea31012005-04-17 16:05:31 -05003853 phba->fc_stat.elsRcvPRLO++;
James Smart2e0fef82007-06-17 19:56:36 -05003854 if (vport->port_state < LPFC_DISC_AUTH) {
James Smart858c9f62007-06-17 19:56:39 -05003855 rjt_err = LSRJT_UNABLE_TPC;
dea31012005-04-17 16:05:31 -05003856 break;
3857 }
James Smart2e0fef82007-06-17 19:56:36 -05003858 lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PRLO);
dea31012005-04-17 16:05:31 -05003859 break;
3860 case ELS_CMD_RSCN:
3861 phba->fc_stat.elsRcvRSCN++;
James Smart2e0fef82007-06-17 19:56:36 -05003862 lpfc_els_rcv_rscn(vport, elsiocb, ndlp, newnode);
James Smartde0c5b32007-04-25 09:52:27 -04003863 if (newnode)
James Smart2e0fef82007-06-17 19:56:36 -05003864 lpfc_drop_node(vport, ndlp);
dea31012005-04-17 16:05:31 -05003865 break;
3866 case ELS_CMD_ADISC:
James Smart858c9f62007-06-17 19:56:39 -05003867 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3868 "RCV ADISC: did:x%x/ste:x%x flg:x%x",
3869 did, vport->port_state, ndlp->nlp_flag);
3870
dea31012005-04-17 16:05:31 -05003871 phba->fc_stat.elsRcvADISC++;
James Smart2e0fef82007-06-17 19:56:36 -05003872 if (vport->port_state < LPFC_DISC_AUTH) {
James Smart858c9f62007-06-17 19:56:39 -05003873 rjt_err = LSRJT_UNABLE_TPC;
dea31012005-04-17 16:05:31 -05003874 break;
3875 }
James Smart2e0fef82007-06-17 19:56:36 -05003876 lpfc_disc_state_machine(vport, ndlp, elsiocb,
3877 NLP_EVT_RCV_ADISC);
dea31012005-04-17 16:05:31 -05003878 break;
3879 case ELS_CMD_PDISC:
James Smart858c9f62007-06-17 19:56:39 -05003880 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3881 "RCV PDISC: did:x%x/ste:x%x flg:x%x",
3882 did, vport->port_state, ndlp->nlp_flag);
3883
dea31012005-04-17 16:05:31 -05003884 phba->fc_stat.elsRcvPDISC++;
James Smart2e0fef82007-06-17 19:56:36 -05003885 if (vport->port_state < LPFC_DISC_AUTH) {
James Smart858c9f62007-06-17 19:56:39 -05003886 rjt_err = LSRJT_UNABLE_TPC;
dea31012005-04-17 16:05:31 -05003887 break;
3888 }
James Smart2e0fef82007-06-17 19:56:36 -05003889 lpfc_disc_state_machine(vport, ndlp, elsiocb,
3890 NLP_EVT_RCV_PDISC);
dea31012005-04-17 16:05:31 -05003891 break;
3892 case ELS_CMD_FARPR:
James Smart858c9f62007-06-17 19:56:39 -05003893 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3894 "RCV FARPR: did:x%x/ste:x%x flg:x%x",
3895 did, vport->port_state, ndlp->nlp_flag);
3896
dea31012005-04-17 16:05:31 -05003897 phba->fc_stat.elsRcvFARPR++;
James Smart2e0fef82007-06-17 19:56:36 -05003898 lpfc_els_rcv_farpr(vport, elsiocb, ndlp);
dea31012005-04-17 16:05:31 -05003899 break;
3900 case ELS_CMD_FARP:
James Smart858c9f62007-06-17 19:56:39 -05003901 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3902 "RCV FARP: did:x%x/ste:x%x flg:x%x",
3903 did, vport->port_state, ndlp->nlp_flag);
3904
dea31012005-04-17 16:05:31 -05003905 phba->fc_stat.elsRcvFARP++;
James Smart2e0fef82007-06-17 19:56:36 -05003906 lpfc_els_rcv_farp(vport, elsiocb, ndlp);
dea31012005-04-17 16:05:31 -05003907 break;
3908 case ELS_CMD_FAN:
James Smart858c9f62007-06-17 19:56:39 -05003909 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3910 "RCV FAN: did:x%x/ste:x%x flg:x%x",
3911 did, vport->port_state, ndlp->nlp_flag);
3912
dea31012005-04-17 16:05:31 -05003913 phba->fc_stat.elsRcvFAN++;
James Smart2e0fef82007-06-17 19:56:36 -05003914 lpfc_els_rcv_fan(vport, elsiocb, ndlp);
dea31012005-04-17 16:05:31 -05003915 break;
dea31012005-04-17 16:05:31 -05003916 case ELS_CMD_PRLI:
James Smart858c9f62007-06-17 19:56:39 -05003917 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3918 "RCV PRLI: did:x%x/ste:x%x flg:x%x",
3919 did, vport->port_state, ndlp->nlp_flag);
3920
dea31012005-04-17 16:05:31 -05003921 phba->fc_stat.elsRcvPRLI++;
James Smart2e0fef82007-06-17 19:56:36 -05003922 if (vport->port_state < LPFC_DISC_AUTH) {
James Smart858c9f62007-06-17 19:56:39 -05003923 rjt_err = LSRJT_UNABLE_TPC;
dea31012005-04-17 16:05:31 -05003924 break;
3925 }
James Smart2e0fef82007-06-17 19:56:36 -05003926 lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PRLI);
dea31012005-04-17 16:05:31 -05003927 break;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003928 case ELS_CMD_LIRR:
James Smart858c9f62007-06-17 19:56:39 -05003929 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3930 "RCV LIRR: did:x%x/ste:x%x flg:x%x",
3931 did, vport->port_state, ndlp->nlp_flag);
3932
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003933 phba->fc_stat.elsRcvLIRR++;
James Smart2e0fef82007-06-17 19:56:36 -05003934 lpfc_els_rcv_lirr(vport, elsiocb, ndlp);
James Smartde0c5b32007-04-25 09:52:27 -04003935 if (newnode)
James Smart2e0fef82007-06-17 19:56:36 -05003936 lpfc_drop_node(vport, ndlp);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003937 break;
3938 case ELS_CMD_RPS:
James Smart858c9f62007-06-17 19:56:39 -05003939 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3940 "RCV RPS: did:x%x/ste:x%x flg:x%x",
3941 did, vport->port_state, ndlp->nlp_flag);
3942
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003943 phba->fc_stat.elsRcvRPS++;
James Smart2e0fef82007-06-17 19:56:36 -05003944 lpfc_els_rcv_rps(vport, elsiocb, ndlp);
James Smartde0c5b32007-04-25 09:52:27 -04003945 if (newnode)
James Smart2e0fef82007-06-17 19:56:36 -05003946 lpfc_drop_node(vport, ndlp);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003947 break;
3948 case ELS_CMD_RPL:
James Smart858c9f62007-06-17 19:56:39 -05003949 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3950 "RCV RPL: did:x%x/ste:x%x flg:x%x",
3951 did, vport->port_state, ndlp->nlp_flag);
3952
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003953 phba->fc_stat.elsRcvRPL++;
James Smart2e0fef82007-06-17 19:56:36 -05003954 lpfc_els_rcv_rpl(vport, elsiocb, ndlp);
James Smartde0c5b32007-04-25 09:52:27 -04003955 if (newnode)
James Smart2e0fef82007-06-17 19:56:36 -05003956 lpfc_drop_node(vport, ndlp);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003957 break;
dea31012005-04-17 16:05:31 -05003958 case ELS_CMD_RNID:
James Smart858c9f62007-06-17 19:56:39 -05003959 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3960 "RCV RNID: did:x%x/ste:x%x flg:x%x",
3961 did, vport->port_state, ndlp->nlp_flag);
3962
dea31012005-04-17 16:05:31 -05003963 phba->fc_stat.elsRcvRNID++;
James Smart2e0fef82007-06-17 19:56:36 -05003964 lpfc_els_rcv_rnid(vport, elsiocb, ndlp);
James Smartde0c5b32007-04-25 09:52:27 -04003965 if (newnode)
James Smart2e0fef82007-06-17 19:56:36 -05003966 lpfc_drop_node(vport, ndlp);
dea31012005-04-17 16:05:31 -05003967 break;
3968 default:
James Smart858c9f62007-06-17 19:56:39 -05003969 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3970 "RCV ELS cmd: cmd:x%x did:x%x/ste:x%x",
3971 cmd, did, vport->port_state);
3972
dea31012005-04-17 16:05:31 -05003973 /* Unsupported ELS command, reject */
James Smart858c9f62007-06-17 19:56:39 -05003974 rjt_err = LSRJT_INVALID_CMD;
dea31012005-04-17 16:05:31 -05003975
3976 /* Unknown ELS command <elsCmd> received from NPORT <did> */
3977 lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
James Smart92d7f7b2007-06-17 19:56:38 -05003978 "%d (%d):0115 Unknown ELS command x%x "
James Smarted957682007-06-17 19:56:37 -05003979 "received from NPORT x%x\n",
James Smart92d7f7b2007-06-17 19:56:38 -05003980 phba->brd_no, vport->vpi, cmd, did);
James Smartde0c5b32007-04-25 09:52:27 -04003981 if (newnode)
James Smart2e0fef82007-06-17 19:56:36 -05003982 lpfc_drop_node(vport, ndlp);
dea31012005-04-17 16:05:31 -05003983 break;
3984 }
3985
3986 /* check if need to LS_RJT received ELS cmd */
3987 if (rjt_err) {
James Smart92d7f7b2007-06-17 19:56:38 -05003988 memset(&stat, 0, sizeof(stat));
James Smart858c9f62007-06-17 19:56:39 -05003989 stat.un.b.lsRjtRsnCode = rjt_err;
James.Smart@Emulex.Com1f679ca2005-06-25 10:34:27 -04003990 stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
James Smart858c9f62007-06-17 19:56:39 -05003991 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, elsiocb, ndlp,
3992 NULL);
James Smart92d7f7b2007-06-17 19:56:38 -05003993 if (newnode)
3994 lpfc_drop_node(vport, ndlp);
dea31012005-04-17 16:05:31 -05003995 }
3996
James Smarted957682007-06-17 19:56:37 -05003997 return;
3998
3999dropit:
4000 lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
James Smart92d7f7b2007-06-17 19:56:38 -05004001 "%d (%d):0111 Dropping received ELS cmd "
James Smarted957682007-06-17 19:56:37 -05004002 "Data: x%x x%x x%x\n",
James Smart92d7f7b2007-06-17 19:56:38 -05004003 phba->brd_no, vport ? vport->vpi : 0xffff,
James Smarted957682007-06-17 19:56:37 -05004004 icmd->ulpStatus, icmd->un.ulpWord[4],
4005 icmd->ulpTimeout);
4006 phba->fc_stat.elsRcvDrop++;
4007}
4008
James Smart92d7f7b2007-06-17 19:56:38 -05004009static struct lpfc_vport *
4010lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi)
4011{
4012 struct lpfc_vport *vport;
4013
4014 list_for_each_entry(vport, &phba->port_list, listentry) {
4015 if (vport->vpi == vpi)
4016 return vport;
4017 }
4018 return NULL;
4019}
James Smarted957682007-06-17 19:56:37 -05004020
4021void
4022lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
4023 struct lpfc_iocbq *elsiocb)
4024{
4025 struct lpfc_vport *vport = phba->pport;
James Smarted957682007-06-17 19:56:37 -05004026 IOCB_t *icmd = &elsiocb->iocb;
James Smarted957682007-06-17 19:56:37 -05004027 dma_addr_t paddr;
James Smart92d7f7b2007-06-17 19:56:38 -05004028 struct lpfc_dmabuf *bdeBuf1 = elsiocb->context2;
4029 struct lpfc_dmabuf *bdeBuf2 = elsiocb->context3;
James Smarted957682007-06-17 19:56:37 -05004030
James Smart92d7f7b2007-06-17 19:56:38 -05004031 elsiocb->context2 = NULL;
4032 elsiocb->context3 = NULL;
4033
4034 if (icmd->ulpStatus == IOSTAT_NEED_BUFFER) {
4035 lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
4036 } else if (icmd->ulpStatus == IOSTAT_LOCAL_REJECT &&
4037 (icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING) {
James Smarted957682007-06-17 19:56:37 -05004038 phba->fc_stat.NoRcvBuf++;
4039 /* Not enough posted buffers; Try posting more buffers */
James Smart92d7f7b2007-06-17 19:56:38 -05004040 if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED))
James Smarted957682007-06-17 19:56:37 -05004041 lpfc_post_buffer(phba, pring, 0, 1);
4042 return;
4043 }
4044
James Smart92d7f7b2007-06-17 19:56:38 -05004045 if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
4046 (icmd->ulpCommand == CMD_IOCB_RCV_ELS64_CX ||
4047 icmd->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) {
4048 if (icmd->unsli3.rcvsli3.vpi == 0xffff)
4049 vport = phba->pport;
4050 else {
4051 uint16_t vpi = icmd->unsli3.rcvsli3.vpi;
4052 vport = lpfc_find_vport_by_vpid(phba, vpi);
4053 }
4054 }
4055 /* If there are no BDEs associated
4056 * with this IOCB, there is nothing to do.
4057 */
James Smarted957682007-06-17 19:56:37 -05004058 if (icmd->ulpBdeCount == 0)
4059 return;
4060
James Smart92d7f7b2007-06-17 19:56:38 -05004061 /* type of ELS cmd is first 32bit word
4062 * in packet
4063 */
James Smarted957682007-06-17 19:56:37 -05004064 if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
James Smart92d7f7b2007-06-17 19:56:38 -05004065 elsiocb->context2 = bdeBuf1;
James Smarted957682007-06-17 19:56:37 -05004066 } else {
4067 paddr = getPaddr(icmd->un.cont64[0].addrHigh,
4068 icmd->un.cont64[0].addrLow);
James Smart92d7f7b2007-06-17 19:56:38 -05004069 elsiocb->context2 = lpfc_sli_ringpostbuf_get(phba, pring,
4070 paddr);
James Smarted957682007-06-17 19:56:37 -05004071 }
4072
James Smart92d7f7b2007-06-17 19:56:38 -05004073 lpfc_els_unsol_buffer(phba, pring, vport, elsiocb);
4074 /*
4075 * The different unsolicited event handlers would tell us
4076 * if they are done with "mp" by setting context2 to NULL.
4077 */
James Smart329f9bc2007-04-25 09:53:01 -04004078 lpfc_nlp_put(elsiocb->context1);
4079 elsiocb->context1 = NULL;
dea31012005-04-17 16:05:31 -05004080 if (elsiocb->context2) {
James Smart92d7f7b2007-06-17 19:56:38 -05004081 lpfc_in_buf_free(phba, (struct lpfc_dmabuf *)elsiocb->context2);
4082 elsiocb->context2 = NULL;
dea31012005-04-17 16:05:31 -05004083 }
James Smarted957682007-06-17 19:56:37 -05004084
4085 /* RCV_ELS64_CX provide for 2 BDEs - process 2nd if included */
James Smart92d7f7b2007-06-17 19:56:38 -05004086 if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) &&
James Smarted957682007-06-17 19:56:37 -05004087 icmd->ulpBdeCount == 2) {
James Smart92d7f7b2007-06-17 19:56:38 -05004088 elsiocb->context2 = bdeBuf2;
4089 lpfc_els_unsol_buffer(phba, pring, vport, elsiocb);
James Smarted957682007-06-17 19:56:37 -05004090 /* free mp if we are done with it */
4091 if (elsiocb->context2) {
James Smart92d7f7b2007-06-17 19:56:38 -05004092 lpfc_in_buf_free(phba, elsiocb->context2);
4093 elsiocb->context2 = NULL;
James Smarted957682007-06-17 19:56:37 -05004094 }
dea31012005-04-17 16:05:31 -05004095 }
dea31012005-04-17 16:05:31 -05004096}
James Smart92d7f7b2007-06-17 19:56:38 -05004097
4098void
4099lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport)
4100{
4101 struct lpfc_nodelist *ndlp, *ndlp_fdmi;
4102
4103 ndlp = lpfc_findnode_did(vport, NameServer_DID);
4104 if (!ndlp) {
4105 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
4106 if (!ndlp) {
4107 if (phba->fc_topology == TOPOLOGY_LOOP) {
4108 lpfc_disc_start(vport);
4109 return;
4110 }
4111 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
4112 lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
4113 "%d (%d):0251 NameServer login: no memory\n",
4114 phba->brd_no, vport->vpi);
4115 return;
4116 }
4117 lpfc_nlp_init(vport, ndlp, NameServer_DID);
4118 ndlp->nlp_type |= NLP_FABRIC;
4119 }
4120
4121 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
4122
4123 if (lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0)) {
4124 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
4125 lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
4126 "%d (%d):0252 Cannot issue NameServer login\n",
4127 phba->brd_no, vport->vpi);
4128 return;
4129 }
4130
4131 if (phba->cfg_fdmi_on) {
4132 ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
4133 GFP_KERNEL);
4134 if (ndlp_fdmi) {
4135 lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID);
4136 ndlp_fdmi->nlp_type |= NLP_FABRIC;
4137 ndlp_fdmi->nlp_state =
4138 NLP_STE_PLOGI_ISSUE;
4139 lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID,
4140 0);
4141 }
4142 }
4143 return;
4144}
4145
4146static void
4147lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
4148{
4149 struct lpfc_vport *vport = pmb->vport;
4150 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
4151 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
4152 MAILBOX_t *mb = &pmb->mb;
4153
4154 vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
4155 lpfc_nlp_put(ndlp);
4156
4157 if (mb->mbxStatus) {
4158 lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
4159 "%d (%d):0915 Register VPI failed: 0x%x\n",
4160 phba->brd_no, vport->vpi, mb->mbxStatus);
4161
4162 switch (mb->mbxStatus) {
4163 case 0x11: /* unsupported feature */
4164 case 0x9603: /* max_vpi exceeded */
4165 /* giving up on vport registration */
4166 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
4167 spin_lock_irq(shost->host_lock);
4168 vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
4169 spin_unlock_irq(shost->host_lock);
4170 lpfc_can_disctmo(vport);
4171 break;
4172 default:
4173 /* Try to recover from this error */
4174 lpfc_mbx_unreg_vpi(vport);
4175 vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
4176 lpfc_initial_fdisc(vport);
4177 break;
4178 }
4179
4180 } else {
4181 if (vport == phba->pport)
4182 lpfc_issue_fabric_reglogin(vport);
4183 else
4184 lpfc_do_scr_ns_plogi(phba, vport);
4185 }
4186 mempool_free(pmb, phba->mbox_mem_pool);
4187 return;
4188}
4189
4190void
4191lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport,
4192 struct lpfc_nodelist *ndlp)
4193{
4194 LPFC_MBOXQ_t *mbox;
4195
4196 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
4197 if (mbox) {
4198 lpfc_reg_vpi(phba, vport->vpi, vport->fc_myDID, mbox);
4199 mbox->vport = vport;
4200 mbox->context2 = lpfc_nlp_get(ndlp);
4201 mbox->mbox_cmpl = lpfc_cmpl_reg_new_vport;
4202 if (lpfc_sli_issue_mbox(phba, mbox,
4203 MBX_NOWAIT | MBX_STOP_IOCB)
4204 == MBX_NOT_FINISHED) {
4205 mempool_free(mbox, phba->mbox_mem_pool);
4206 vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
4207
4208 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
4209
4210 lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
4211 "%d (%d):0253 Register VPI: Cannot send mbox\n",
4212 phba->brd_no, vport->vpi);
4213 }
4214 } else {
4215 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
4216
4217 lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
4218 "%d (%d):0254 Register VPI: no memory\n",
4219 phba->brd_no, vport->vpi);
4220
4221 vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
4222 lpfc_nlp_put(ndlp);
4223 }
4224}
4225
4226static void
4227lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
4228 struct lpfc_iocbq *rspiocb)
4229{
4230 struct lpfc_vport *vport = cmdiocb->vport;
4231 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
4232 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
4233 struct lpfc_nodelist *np;
4234 struct lpfc_nodelist *next_np;
4235 IOCB_t *irsp = &rspiocb->iocb;
4236 struct lpfc_iocbq *piocb;
4237
4238 lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
4239 "%d (%d):0123 FDISC completes. x%x/x%x prevDID: x%x\n",
4240 phba->brd_no, vport->vpi,
4241 irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_prevDID);
4242
4243 /* Since all FDISCs are being single threaded, we
4244 * must reset the discovery timer for ALL vports
4245 * waiting to send FDISC when one completes.
4246 */
4247 list_for_each_entry(piocb, &phba->fabric_iocb_list, list) {
4248 lpfc_set_disctmo(piocb->vport);
4249 }
4250
James Smart858c9f62007-06-17 19:56:39 -05004251 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
4252 "FDISC cmpl: status:x%x/x%x prevdid:x%x",
4253 irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_prevDID);
4254
James Smart92d7f7b2007-06-17 19:56:38 -05004255 if (irsp->ulpStatus) {
4256 /* Check for retry */
4257 if (lpfc_els_retry(phba, cmdiocb, rspiocb))
4258 goto out;
4259
4260 /* FDISC failed */
4261 lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
4262 "%d (%d):0124 FDISC failed. (%d/%d)\n",
4263 phba->brd_no, vport->vpi,
4264 irsp->ulpStatus, irsp->un.ulpWord[4]);
James Smart858c9f62007-06-17 19:56:39 -05004265
James Smart92d7f7b2007-06-17 19:56:38 -05004266 if (vport->fc_vport->vport_state == FC_VPORT_INITIALIZING)
4267 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
4268
4269 lpfc_nlp_put(ndlp);
4270 /* giving up on FDISC. Cancel discovery timer */
4271 lpfc_can_disctmo(vport);
4272 } else {
4273 spin_lock_irq(shost->host_lock);
4274 vport->fc_flag |= FC_FABRIC;
4275 if (vport->phba->fc_topology == TOPOLOGY_LOOP)
4276 vport->fc_flag |= FC_PUBLIC_LOOP;
4277 spin_unlock_irq(shost->host_lock);
4278
4279 vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID;
4280 lpfc_vport_set_state(vport, FC_VPORT_ACTIVE);
4281 if ((vport->fc_prevDID != vport->fc_myDID) &&
4282 !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) {
4283 /* If our NportID changed, we need to ensure all
4284 * remaining NPORTs get unreg_login'ed so we can
4285 * issue unreg_vpi.
4286 */
4287 list_for_each_entry_safe(np, next_np,
4288 &vport->fc_nodes, nlp_listp) {
4289 if (np->nlp_state != NLP_STE_NPR_NODE
4290 || !(np->nlp_flag & NLP_NPR_ADISC))
4291 continue;
4292 spin_lock_irq(shost->host_lock);
4293 np->nlp_flag &= ~NLP_NPR_ADISC;
4294 spin_unlock_irq(shost->host_lock);
4295 lpfc_unreg_rpi(vport, np);
4296 }
4297 lpfc_mbx_unreg_vpi(vport);
4298 vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
4299 }
4300
4301 if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)
4302 lpfc_register_new_vport(phba, vport, ndlp);
4303 else
4304 lpfc_do_scr_ns_plogi(phba, vport);
4305
4306 lpfc_nlp_put(ndlp); /* Free Fabric ndlp for vports */
4307 }
4308
4309out:
4310 lpfc_els_free_iocb(phba, cmdiocb);
4311}
4312
4313int
4314lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
4315 uint8_t retry)
4316{
4317 struct lpfc_hba *phba = vport->phba;
4318 IOCB_t *icmd;
4319 struct lpfc_iocbq *elsiocb;
4320 struct serv_parm *sp;
4321 uint8_t *pcmd;
4322 uint16_t cmdsize;
4323 int did = ndlp->nlp_DID;
4324 int rc;
James Smart92d7f7b2007-06-17 19:56:38 -05004325
4326 cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
4327 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did,
4328 ELS_CMD_FDISC);
4329 if (!elsiocb) {
James Smart92d7f7b2007-06-17 19:56:38 -05004330 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
4331
4332 lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
4333 "%d (%d):0255 Issue FDISC: no IOCB\n",
4334 phba->brd_no, vport->vpi);
4335 return 1;
4336 }
4337
4338 icmd = &elsiocb->iocb;
4339 icmd->un.elsreq64.myID = 0;
4340 icmd->un.elsreq64.fl = 1;
4341
4342 /* For FDISC, Let FDISC rsp set the NPortID for this VPI */
4343 icmd->ulpCt_h = 1;
4344 icmd->ulpCt_l = 0;
4345
4346 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
4347 *((uint32_t *) (pcmd)) = ELS_CMD_FDISC;
4348 pcmd += sizeof(uint32_t); /* CSP Word 1 */
4349 memcpy(pcmd, &vport->phba->pport->fc_sparam, sizeof(struct serv_parm));
4350 sp = (struct serv_parm *) pcmd;
4351 /* Setup CSPs accordingly for Fabric */
4352 sp->cmn.e_d_tov = 0;
4353 sp->cmn.w2.r_a_tov = 0;
4354 sp->cls1.classValid = 0;
4355 sp->cls2.seqDelivery = 1;
4356 sp->cls3.seqDelivery = 1;
4357
4358 pcmd += sizeof(uint32_t); /* CSP Word 2 */
4359 pcmd += sizeof(uint32_t); /* CSP Word 3 */
4360 pcmd += sizeof(uint32_t); /* CSP Word 4 */
4361 pcmd += sizeof(uint32_t); /* Port Name */
4362 memcpy(pcmd, &vport->fc_portname, 8);
4363 pcmd += sizeof(uint32_t); /* Node Name */
4364 pcmd += sizeof(uint32_t); /* Node Name */
4365 memcpy(pcmd, &vport->fc_nodename, 8);
4366
4367 lpfc_set_disctmo(vport);
4368
4369 phba->fc_stat.elsXmitFDISC++;
4370 elsiocb->iocb_cmpl = lpfc_cmpl_els_fdisc;
4371
James Smart858c9f62007-06-17 19:56:39 -05004372 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
4373 "Issue FDISC: did:x%x",
4374 did, 0, 0);
4375
James Smart92d7f7b2007-06-17 19:56:38 -05004376 rc = lpfc_issue_fabric_iocb(phba, elsiocb);
4377 if (rc == IOCB_ERROR) {
4378 lpfc_els_free_iocb(phba, elsiocb);
James Smart92d7f7b2007-06-17 19:56:38 -05004379 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
4380
4381 lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
4382 "%d (%d):0256 Issue FDISC: Cannot send IOCB\n",
4383 phba->brd_no, vport->vpi);
4384
4385 return 1;
4386 }
4387 lpfc_vport_set_state(vport, FC_VPORT_INITIALIZING);
4388 vport->port_state = LPFC_FDISC;
4389 return 0;
4390}
4391
4392static void
4393lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
4394 struct lpfc_iocbq *rspiocb)
4395{
4396 struct lpfc_vport *vport = cmdiocb->vport;
James Smart858c9f62007-06-17 19:56:39 -05004397 IOCB_t *irsp;
4398
4399 irsp = &rspiocb->iocb;
4400 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
4401 "LOGO npiv cmpl: status:x%x/x%x did:x%x",
4402 irsp->ulpStatus, irsp->un.ulpWord[4], irsp->un.rcvels.remoteID);
James Smart92d7f7b2007-06-17 19:56:38 -05004403
4404 lpfc_els_free_iocb(phba, cmdiocb);
4405 vport->unreg_vpi_cmpl = VPORT_ERROR;
4406}
4407
4408int
4409lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
4410{
4411 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
4412 struct lpfc_hba *phba = vport->phba;
4413 struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
4414 IOCB_t *icmd;
4415 struct lpfc_iocbq *elsiocb;
4416 uint8_t *pcmd;
4417 uint16_t cmdsize;
4418
4419 cmdsize = 2 * sizeof(uint32_t) + sizeof(struct lpfc_name);
4420 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, ndlp->nlp_DID,
4421 ELS_CMD_LOGO);
4422 if (!elsiocb)
4423 return 1;
4424
4425 icmd = &elsiocb->iocb;
4426 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
4427 *((uint32_t *) (pcmd)) = ELS_CMD_LOGO;
4428 pcmd += sizeof(uint32_t);
4429
4430 /* Fill in LOGO payload */
4431 *((uint32_t *) (pcmd)) = be32_to_cpu(vport->fc_myDID);
4432 pcmd += sizeof(uint32_t);
4433 memcpy(pcmd, &vport->fc_portname, sizeof(struct lpfc_name));
4434
James Smart858c9f62007-06-17 19:56:39 -05004435 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
4436 "Issue LOGO npiv did:x%x flg:x%x",
4437 ndlp->nlp_DID, ndlp->nlp_flag, 0);
4438
James Smart92d7f7b2007-06-17 19:56:38 -05004439 elsiocb->iocb_cmpl = lpfc_cmpl_els_npiv_logo;
4440 spin_lock_irq(shost->host_lock);
4441 ndlp->nlp_flag |= NLP_LOGO_SND;
4442 spin_unlock_irq(shost->host_lock);
4443 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
4444 spin_lock_irq(shost->host_lock);
4445 ndlp->nlp_flag &= ~NLP_LOGO_SND;
4446 spin_unlock_irq(shost->host_lock);
4447 lpfc_els_free_iocb(phba, elsiocb);
4448 return 1;
4449 }
4450 return 0;
4451}
4452
4453void
4454lpfc_fabric_block_timeout(unsigned long ptr)
4455{
4456 struct lpfc_hba *phba = (struct lpfc_hba *) ptr;
4457 unsigned long iflags;
4458 uint32_t tmo_posted;
4459 spin_lock_irqsave(&phba->pport->work_port_lock, iflags);
4460 tmo_posted = phba->pport->work_port_events & WORKER_FABRIC_BLOCK_TMO;
4461 if (!tmo_posted)
4462 phba->pport->work_port_events |= WORKER_FABRIC_BLOCK_TMO;
4463 spin_unlock_irqrestore(&phba->pport->work_port_lock, iflags);
4464
4465 if (!tmo_posted) {
4466 spin_lock_irqsave(&phba->hbalock, iflags);
4467 if (phba->work_wait)
4468 lpfc_worker_wake_up(phba);
4469 spin_unlock_irqrestore(&phba->hbalock, iflags);
4470 }
4471}
4472
4473static void
4474lpfc_resume_fabric_iocbs(struct lpfc_hba *phba)
4475{
4476 struct lpfc_iocbq *iocb;
4477 unsigned long iflags;
4478 int ret;
4479 struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
4480 IOCB_t *cmd;
4481
4482repeat:
4483 iocb = NULL;
4484 spin_lock_irqsave(&phba->hbalock, iflags);
4485 /* Post any pending iocb to the SLI layer */
4486 if (atomic_read(&phba->fabric_iocb_count) == 0) {
4487 list_remove_head(&phba->fabric_iocb_list, iocb, typeof(*iocb),
4488 list);
4489 if (iocb)
4490 atomic_inc(&phba->fabric_iocb_count);
4491 }
4492 spin_unlock_irqrestore(&phba->hbalock, iflags);
4493 if (iocb) {
4494 iocb->fabric_iocb_cmpl = iocb->iocb_cmpl;
4495 iocb->iocb_cmpl = lpfc_cmpl_fabric_iocb;
4496 iocb->iocb_flag |= LPFC_IO_FABRIC;
4497
James Smart858c9f62007-06-17 19:56:39 -05004498 lpfc_debugfs_disc_trc(iocb->vport, LPFC_DISC_TRC_ELS_CMD,
4499 "Fabric sched1: ste:x%x",
4500 iocb->vport->port_state, 0, 0);
4501
James Smart92d7f7b2007-06-17 19:56:38 -05004502 ret = lpfc_sli_issue_iocb(phba, pring, iocb, 0);
4503
4504 if (ret == IOCB_ERROR) {
4505 iocb->iocb_cmpl = iocb->fabric_iocb_cmpl;
4506 iocb->fabric_iocb_cmpl = NULL;
4507 iocb->iocb_flag &= ~LPFC_IO_FABRIC;
4508 cmd = &iocb->iocb;
4509 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
4510 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
4511 iocb->iocb_cmpl(phba, iocb, iocb);
4512
4513 atomic_dec(&phba->fabric_iocb_count);
4514 goto repeat;
4515 }
4516 }
4517
4518 return;
4519}
4520
4521void
4522lpfc_unblock_fabric_iocbs(struct lpfc_hba *phba)
4523{
4524 clear_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags);
4525
4526 lpfc_resume_fabric_iocbs(phba);
4527 return;
4528}
4529
4530static void
4531lpfc_block_fabric_iocbs(struct lpfc_hba *phba)
4532{
4533 int blocked;
4534
4535 blocked = test_and_set_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags);
4536 /* Start a timer to unblock fabric
4537 * iocbs after 100ms
4538 */
4539 if (!blocked)
4540 mod_timer(&phba->fabric_block_timer, jiffies + HZ/10 );
4541
4542 return;
4543}
4544
4545static void
4546lpfc_cmpl_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
4547 struct lpfc_iocbq *rspiocb)
4548{
4549 struct ls_rjt stat;
4550
4551 if ((cmdiocb->iocb_flag & LPFC_IO_FABRIC) != LPFC_IO_FABRIC)
4552 BUG();
4553
4554 switch (rspiocb->iocb.ulpStatus) {
4555 case IOSTAT_NPORT_RJT:
4556 case IOSTAT_FABRIC_RJT:
4557 if (rspiocb->iocb.un.ulpWord[4] & RJT_UNAVAIL_TEMP) {
4558 lpfc_block_fabric_iocbs(phba);
4559 }
4560 break;
4561
4562 case IOSTAT_NPORT_BSY:
4563 case IOSTAT_FABRIC_BSY:
4564 lpfc_block_fabric_iocbs(phba);
4565 break;
4566
4567 case IOSTAT_LS_RJT:
4568 stat.un.lsRjtError =
4569 be32_to_cpu(rspiocb->iocb.un.ulpWord[4]);
4570 if ((stat.un.b.lsRjtRsnCode == LSRJT_UNABLE_TPC) ||
4571 (stat.un.b.lsRjtRsnCode == LSRJT_LOGICAL_BSY))
4572 lpfc_block_fabric_iocbs(phba);
4573 break;
4574 }
4575
4576 if (atomic_read(&phba->fabric_iocb_count) == 0)
4577 BUG();
4578
4579 cmdiocb->iocb_cmpl = cmdiocb->fabric_iocb_cmpl;
4580 cmdiocb->fabric_iocb_cmpl = NULL;
4581 cmdiocb->iocb_flag &= ~LPFC_IO_FABRIC;
4582 cmdiocb->iocb_cmpl(phba, cmdiocb, rspiocb);
4583
4584 atomic_dec(&phba->fabric_iocb_count);
4585 if (!test_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags)) {
4586 /* Post any pending iocbs to HBA */
4587 lpfc_resume_fabric_iocbs(phba);
4588 }
4589}
4590
4591int
4592lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb)
4593{
4594 unsigned long iflags;
4595 struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
4596 int ready;
4597 int ret;
4598
4599 if (atomic_read(&phba->fabric_iocb_count) > 1)
4600 BUG();
4601
4602 spin_lock_irqsave(&phba->hbalock, iflags);
4603 ready = atomic_read(&phba->fabric_iocb_count) == 0 &&
4604 !test_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags);
4605
4606 spin_unlock_irqrestore(&phba->hbalock, iflags);
4607 if (ready) {
4608 iocb->fabric_iocb_cmpl = iocb->iocb_cmpl;
4609 iocb->iocb_cmpl = lpfc_cmpl_fabric_iocb;
4610 iocb->iocb_flag |= LPFC_IO_FABRIC;
4611
James Smart858c9f62007-06-17 19:56:39 -05004612 lpfc_debugfs_disc_trc(iocb->vport, LPFC_DISC_TRC_ELS_CMD,
4613 "Fabric sched2: ste:x%x",
4614 iocb->vport->port_state, 0, 0);
4615
James Smart92d7f7b2007-06-17 19:56:38 -05004616 atomic_inc(&phba->fabric_iocb_count);
4617 ret = lpfc_sli_issue_iocb(phba, pring, iocb, 0);
4618
4619 if (ret == IOCB_ERROR) {
4620 iocb->iocb_cmpl = iocb->fabric_iocb_cmpl;
4621 iocb->fabric_iocb_cmpl = NULL;
4622 iocb->iocb_flag &= ~LPFC_IO_FABRIC;
4623 atomic_dec(&phba->fabric_iocb_count);
4624 }
4625 } else {
4626 spin_lock_irqsave(&phba->hbalock, iflags);
4627 list_add_tail(&iocb->list, &phba->fabric_iocb_list);
4628 spin_unlock_irqrestore(&phba->hbalock, iflags);
4629 ret = IOCB_SUCCESS;
4630 }
4631 return ret;
4632}
4633
4634
4635void lpfc_fabric_abort_vport(struct lpfc_vport *vport)
4636{
4637 LIST_HEAD(completions);
4638 struct lpfc_hba *phba = vport->phba;
4639 struct lpfc_iocbq *tmp_iocb, *piocb;
4640 IOCB_t *cmd;
4641
4642 spin_lock_irq(&phba->hbalock);
4643 list_for_each_entry_safe(piocb, tmp_iocb, &phba->fabric_iocb_list,
4644 list) {
4645
4646 if (piocb->vport != vport)
4647 continue;
4648
4649 list_move_tail(&piocb->list, &completions);
4650 }
4651 spin_unlock_irq(&phba->hbalock);
4652
4653 while (!list_empty(&completions)) {
4654 piocb = list_get_first(&completions, struct lpfc_iocbq, list);
4655 list_del_init(&piocb->list);
4656
4657 cmd = &piocb->iocb;
4658 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
4659 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
4660 (piocb->iocb_cmpl) (phba, piocb, piocb);
4661 }
4662}
4663
4664void lpfc_fabric_abort_nport(struct lpfc_nodelist *ndlp)
4665{
4666 LIST_HEAD(completions);
4667 struct lpfc_hba *phba = ndlp->vport->phba;
4668 struct lpfc_iocbq *tmp_iocb, *piocb;
4669 struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
4670 IOCB_t *cmd;
4671
4672 spin_lock_irq(&phba->hbalock);
4673 list_for_each_entry_safe(piocb, tmp_iocb, &phba->fabric_iocb_list,
4674 list) {
4675 if ((lpfc_check_sli_ndlp(phba, pring, piocb, ndlp))) {
4676
4677 list_move_tail(&piocb->list, &completions);
4678 }
4679 }
4680 spin_unlock_irq(&phba->hbalock);
4681
4682 while (!list_empty(&completions)) {
4683 piocb = list_get_first(&completions, struct lpfc_iocbq, list);
4684 list_del_init(&piocb->list);
4685
4686 cmd = &piocb->iocb;
4687 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
4688 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
4689 (piocb->iocb_cmpl) (phba, piocb, piocb);
4690 }
4691}
4692
4693void lpfc_fabric_abort_hba(struct lpfc_hba *phba)
4694{
4695 LIST_HEAD(completions);
4696 struct lpfc_iocbq *piocb;
4697 IOCB_t *cmd;
4698
4699 spin_lock_irq(&phba->hbalock);
4700 list_splice_init(&phba->fabric_iocb_list, &completions);
4701 spin_unlock_irq(&phba->hbalock);
4702
4703 while (!list_empty(&completions)) {
4704 piocb = list_get_first(&completions, struct lpfc_iocbq, list);
4705 list_del_init(&piocb->list);
4706
4707 cmd = &piocb->iocb;
4708 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
4709 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
4710 (piocb->iocb_cmpl) (phba, piocb, piocb);
4711 }
4712}
4713
4714
4715void lpfc_fabric_abort_flogi(struct lpfc_hba *phba)
4716{
4717 LIST_HEAD(completions);
4718 struct lpfc_iocbq *tmp_iocb, *piocb;
4719 IOCB_t *cmd;
4720 struct lpfc_nodelist *ndlp;
4721
4722 spin_lock_irq(&phba->hbalock);
4723 list_for_each_entry_safe(piocb, tmp_iocb, &phba->fabric_iocb_list,
4724 list) {
4725
4726 cmd = &piocb->iocb;
4727 ndlp = (struct lpfc_nodelist *) piocb->context1;
4728 if (cmd->ulpCommand == CMD_ELS_REQUEST64_CR &&
4729 ndlp != NULL &&
4730 ndlp->nlp_DID == Fabric_DID)
4731 list_move_tail(&piocb->list, &completions);
4732 }
4733 spin_unlock_irq(&phba->hbalock);
4734
4735 while (!list_empty(&completions)) {
4736 piocb = list_get_first(&completions, struct lpfc_iocbq, list);
4737 list_del_init(&piocb->list);
4738
4739 cmd = &piocb->iocb;
4740 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
4741 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
4742 (piocb->iocb_cmpl) (phba, piocb, piocb);
4743 }
4744}
4745
4746