blob: 9315c3c2e6f68bfbc2d3cf527f6572b757e4786b [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 Smarte8b62012007-08-02 11:10:09 -040066 lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
67 "0237 Pending Link Event during "
68 "Discovery: State x%x\n",
69 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 Smart98c9ea52007-10-27 13:37:33 -0400112 pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
113 if (pcmd)
114 pcmd->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &pcmd->phys);
115 if (!pcmd || !pcmd->virt) {
Jesper Juhlc9475cb2005-11-07 01:01:26 -0800116 kfree(pcmd);
dea31012005-04-17 16:05:31 -0500117
James Bottomley604a3e32005-10-29 10:28:33 -0500118 lpfc_sli_release_iocbq(phba, elsiocb);
dea31012005-04-17 16:05:31 -0500119 return NULL;
120 }
121
122 INIT_LIST_HEAD(&pcmd->list);
123
124 /* Allocate buffer for response payload */
125 if (expectRsp) {
James Smart92d7f7b2007-06-17 19:56:38 -0500126 prsp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
dea31012005-04-17 16:05:31 -0500127 if (prsp)
128 prsp->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
129 &prsp->phys);
James Smart98c9ea52007-10-27 13:37:33 -0400130 if (!prsp || !prsp->virt) {
Jesper Juhlc9475cb2005-11-07 01:01:26 -0800131 kfree(prsp);
dea31012005-04-17 16:05:31 -0500132 lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
133 kfree(pcmd);
James Bottomley604a3e32005-10-29 10:28:33 -0500134 lpfc_sli_release_iocbq(phba, elsiocb);
dea31012005-04-17 16:05:31 -0500135 return NULL;
136 }
137 INIT_LIST_HEAD(&prsp->list);
138 } else {
139 prsp = NULL;
140 }
141
142 /* Allocate buffer for Buffer ptr list */
James Smart92d7f7b2007-06-17 19:56:38 -0500143 pbuflist = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
dea31012005-04-17 16:05:31 -0500144 if (pbuflist)
James Smarted957682007-06-17 19:56:37 -0500145 pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
146 &pbuflist->phys);
James Smart98c9ea52007-10-27 13:37:33 -0400147 if (!pbuflist || !pbuflist->virt) {
James Bottomley604a3e32005-10-29 10:28:33 -0500148 lpfc_sli_release_iocbq(phba, elsiocb);
dea31012005-04-17 16:05:31 -0500149 lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
150 lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
151 kfree(pcmd);
152 kfree(prsp);
Jesper Juhlc9475cb2005-11-07 01:01:26 -0800153 kfree(pbuflist);
dea31012005-04-17 16:05:31 -0500154 return NULL;
155 }
156
157 INIT_LIST_HEAD(&pbuflist->list);
158
159 icmd->un.elsreq64.bdl.addrHigh = putPaddrHigh(pbuflist->phys);
160 icmd->un.elsreq64.bdl.addrLow = putPaddrLow(pbuflist->phys);
161 icmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BDL;
James Smart2e0fef82007-06-17 19:56:36 -0500162 icmd->un.elsreq64.remoteID = did; /* DID */
dea31012005-04-17 16:05:31 -0500163 if (expectRsp) {
James Smart92d7f7b2007-06-17 19:56:38 -0500164 icmd->un.elsreq64.bdl.bdeSize = (2 * sizeof(struct ulp_bde64));
dea31012005-04-17 16:05:31 -0500165 icmd->ulpCommand = CMD_ELS_REQUEST64_CR;
James Smart2680eea2007-04-25 09:52:55 -0400166 icmd->ulpTimeout = phba->fc_ratov * 2;
dea31012005-04-17 16:05:31 -0500167 } else {
James Smart92d7f7b2007-06-17 19:56:38 -0500168 icmd->un.elsreq64.bdl.bdeSize = sizeof(struct ulp_bde64);
dea31012005-04-17 16:05:31 -0500169 icmd->ulpCommand = CMD_XMIT_ELS_RSP64_CX;
170 }
dea31012005-04-17 16:05:31 -0500171 icmd->ulpBdeCount = 1;
172 icmd->ulpLe = 1;
173 icmd->ulpClass = CLASS3;
174
James Smart92d7f7b2007-06-17 19:56:38 -0500175 if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
176 icmd->un.elsreq64.myID = vport->fc_myDID;
177
178 /* For ELS_REQUEST64_CR, use the VPI by default */
179 icmd->ulpContext = vport->vpi;
180 icmd->ulpCt_h = 0;
181 icmd->ulpCt_l = 1;
182 }
183
dea31012005-04-17 16:05:31 -0500184 bpl = (struct ulp_bde64 *) pbuflist->virt;
185 bpl->addrLow = le32_to_cpu(putPaddrLow(pcmd->phys));
186 bpl->addrHigh = le32_to_cpu(putPaddrHigh(pcmd->phys));
187 bpl->tus.f.bdeSize = cmdSize;
188 bpl->tus.f.bdeFlags = 0;
189 bpl->tus.w = le32_to_cpu(bpl->tus.w);
190
191 if (expectRsp) {
192 bpl++;
193 bpl->addrLow = le32_to_cpu(putPaddrLow(prsp->phys));
194 bpl->addrHigh = le32_to_cpu(putPaddrHigh(prsp->phys));
195 bpl->tus.f.bdeSize = FCELSSIZE;
196 bpl->tus.f.bdeFlags = BUFF_USE_RCV;
197 bpl->tus.w = le32_to_cpu(bpl->tus.w);
198 }
199
James Smart51ef4c22007-08-02 11:10:31 -0400200 elsiocb->context1 = lpfc_nlp_get(ndlp);
James Smart329f9bc2007-04-25 09:53:01 -0400201 elsiocb->context2 = pcmd;
202 elsiocb->context3 = pbuflist;
dea31012005-04-17 16:05:31 -0500203 elsiocb->retry = retry;
James Smart2e0fef82007-06-17 19:56:36 -0500204 elsiocb->vport = vport;
dea31012005-04-17 16:05:31 -0500205 elsiocb->drvrTimeout = (phba->fc_ratov << 1) + LPFC_DRVR_TIMEOUT;
206
207 if (prsp) {
208 list_add(&prsp->list, &pcmd->list);
209 }
dea31012005-04-17 16:05:31 -0500210 if (expectRsp) {
211 /* Xmit ELS command <elsCmd> to remote NPORT <did> */
James Smarte8b62012007-08-02 11:10:09 -0400212 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
213 "0116 Xmit ELS command x%x to remote "
214 "NPORT x%x I/O tag: x%x, port state: x%x\n",
215 elscmd, did, elsiocb->iotag,
216 vport->port_state);
dea31012005-04-17 16:05:31 -0500217 } else {
218 /* Xmit ELS response <elsCmd> to remote NPORT <did> */
James Smarte8b62012007-08-02 11:10:09 -0400219 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
220 "0117 Xmit ELS response x%x to remote "
221 "NPORT x%x I/O tag: x%x, size: x%x\n",
222 elscmd, ndlp->nlp_DID, elsiocb->iotag,
223 cmdSize);
dea31012005-04-17 16:05:31 -0500224 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500225 return elsiocb;
dea31012005-04-17 16:05:31 -0500226}
227
228
229static int
James Smart92d7f7b2007-06-17 19:56:38 -0500230lpfc_issue_fabric_reglogin(struct lpfc_vport *vport)
231{
232 struct lpfc_hba *phba = vport->phba;
233 LPFC_MBOXQ_t *mbox;
234 struct lpfc_dmabuf *mp;
235 struct lpfc_nodelist *ndlp;
236 struct serv_parm *sp;
237 int rc;
James Smart98c9ea52007-10-27 13:37:33 -0400238 int err = 0;
James Smart92d7f7b2007-06-17 19:56:38 -0500239
240 sp = &phba->fc_fabparam;
241 ndlp = lpfc_findnode_did(vport, Fabric_DID);
James Smart98c9ea52007-10-27 13:37:33 -0400242 if (!ndlp) {
243 err = 1;
James Smart92d7f7b2007-06-17 19:56:38 -0500244 goto fail;
James Smart98c9ea52007-10-27 13:37:33 -0400245 }
James Smart92d7f7b2007-06-17 19:56:38 -0500246
247 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
James Smart98c9ea52007-10-27 13:37:33 -0400248 if (!mbox) {
249 err = 2;
James Smart92d7f7b2007-06-17 19:56:38 -0500250 goto fail;
James Smart98c9ea52007-10-27 13:37:33 -0400251 }
James Smart92d7f7b2007-06-17 19:56:38 -0500252
253 vport->port_state = LPFC_FABRIC_CFG_LINK;
254 lpfc_config_link(phba, mbox);
255 mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
256 mbox->vport = vport;
257
James Smart0b727fe2007-10-27 13:37:25 -0400258 rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
James Smart98c9ea52007-10-27 13:37:33 -0400259 if (rc == MBX_NOT_FINISHED) {
260 err = 3;
James Smart92d7f7b2007-06-17 19:56:38 -0500261 goto fail_free_mbox;
James Smart98c9ea52007-10-27 13:37:33 -0400262 }
James Smart92d7f7b2007-06-17 19:56:38 -0500263
264 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
James Smart98c9ea52007-10-27 13:37:33 -0400265 if (!mbox) {
266 err = 4;
James Smart92d7f7b2007-06-17 19:56:38 -0500267 goto fail;
James Smart98c9ea52007-10-27 13:37:33 -0400268 }
James Smart92d7f7b2007-06-17 19:56:38 -0500269 rc = lpfc_reg_login(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox,
270 0);
James Smart98c9ea52007-10-27 13:37:33 -0400271 if (rc) {
272 err = 5;
James Smart92d7f7b2007-06-17 19:56:38 -0500273 goto fail_free_mbox;
James Smart98c9ea52007-10-27 13:37:33 -0400274 }
James Smart92d7f7b2007-06-17 19:56:38 -0500275
276 mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login;
277 mbox->vport = vport;
278 mbox->context2 = lpfc_nlp_get(ndlp);
279
James Smart0b727fe2007-10-27 13:37:25 -0400280 rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
James Smart98c9ea52007-10-27 13:37:33 -0400281 if (rc == MBX_NOT_FINISHED) {
282 err = 6;
James Smart92d7f7b2007-06-17 19:56:38 -0500283 goto fail_issue_reg_login;
James Smart98c9ea52007-10-27 13:37:33 -0400284 }
James Smart92d7f7b2007-06-17 19:56:38 -0500285
286 return 0;
287
288fail_issue_reg_login:
289 lpfc_nlp_put(ndlp);
290 mp = (struct lpfc_dmabuf *) mbox->context1;
291 lpfc_mbuf_free(phba, mp->virt, mp->phys);
292 kfree(mp);
293fail_free_mbox:
294 mempool_free(mbox, phba->mbox_mem_pool);
295
296fail:
297 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
James Smarte8b62012007-08-02 11:10:09 -0400298 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
James Smart98c9ea52007-10-27 13:37:33 -0400299 "0249 Cannot issue Register Fabric login: Err %d\n", err);
James Smart92d7f7b2007-06-17 19:56:38 -0500300 return -ENXIO;
301}
302
303static int
James Smart2e0fef82007-06-17 19:56:36 -0500304lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
305 struct serv_parm *sp, IOCB_t *irsp)
dea31012005-04-17 16:05:31 -0500306{
James Smart2e0fef82007-06-17 19:56:36 -0500307 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
308 struct lpfc_hba *phba = vport->phba;
James Smart92d7f7b2007-06-17 19:56:38 -0500309 struct lpfc_nodelist *np;
310 struct lpfc_nodelist *next_np;
dea31012005-04-17 16:05:31 -0500311
James Smart2e0fef82007-06-17 19:56:36 -0500312 spin_lock_irq(shost->host_lock);
313 vport->fc_flag |= FC_FABRIC;
314 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500315
316 phba->fc_edtov = be32_to_cpu(sp->cmn.e_d_tov);
317 if (sp->cmn.edtovResolution) /* E_D_TOV ticks are in nanoseconds */
318 phba->fc_edtov = (phba->fc_edtov + 999999) / 1000000;
319
320 phba->fc_ratov = (be32_to_cpu(sp->cmn.w2.r_a_tov) + 999) / 1000;
321
322 if (phba->fc_topology == TOPOLOGY_LOOP) {
James Smart2e0fef82007-06-17 19:56:36 -0500323 spin_lock_irq(shost->host_lock);
324 vport->fc_flag |= FC_PUBLIC_LOOP;
325 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500326 } else {
327 /*
328 * If we are a N-port connected to a Fabric, fixup sparam's so
329 * logins to devices on remote loops work.
330 */
James Smart2e0fef82007-06-17 19:56:36 -0500331 vport->fc_sparam.cmn.altBbCredit = 1;
dea31012005-04-17 16:05:31 -0500332 }
333
James Smart2e0fef82007-06-17 19:56:36 -0500334 vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID;
dea31012005-04-17 16:05:31 -0500335 memcpy(&ndlp->nlp_portname, &sp->portName, sizeof(struct lpfc_name));
James Smart92d7f7b2007-06-17 19:56:38 -0500336 memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -0500337 ndlp->nlp_class_sup = 0;
338 if (sp->cls1.classValid)
339 ndlp->nlp_class_sup |= FC_COS_CLASS1;
340 if (sp->cls2.classValid)
341 ndlp->nlp_class_sup |= FC_COS_CLASS2;
342 if (sp->cls3.classValid)
343 ndlp->nlp_class_sup |= FC_COS_CLASS3;
344 if (sp->cls4.classValid)
345 ndlp->nlp_class_sup |= FC_COS_CLASS4;
346 ndlp->nlp_maxframe = ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) |
347 sp->cmn.bbRcvSizeLsb;
348 memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
349
James Smart92d7f7b2007-06-17 19:56:38 -0500350 if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
351 if (sp->cmn.response_multiple_NPort) {
James Smarte8b62012007-08-02 11:10:09 -0400352 lpfc_printf_vlog(vport, KERN_WARNING,
353 LOG_ELS | LOG_VPORT,
354 "1816 FLOGI NPIV supported, "
355 "response data 0x%x\n",
356 sp->cmn.response_multiple_NPort);
James Smart92d7f7b2007-06-17 19:56:38 -0500357 phba->link_flag |= LS_NPIV_FAB_SUPPORTED;
James Smart92d7f7b2007-06-17 19:56:38 -0500358 } else {
359 /* Because we asked f/w for NPIV it still expects us
James Smarte8b62012007-08-02 11:10:09 -0400360 to call reg_vnpid atleast for the physcial host */
361 lpfc_printf_vlog(vport, KERN_WARNING,
362 LOG_ELS | LOG_VPORT,
363 "1817 Fabric does not support NPIV "
364 "- configuring single port mode.\n");
James Smart92d7f7b2007-06-17 19:56:38 -0500365 phba->link_flag &= ~LS_NPIV_FAB_SUPPORTED;
366 }
367 }
368
369 if ((vport->fc_prevDID != vport->fc_myDID) &&
370 !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) {
371
372 /* If our NportID changed, we need to ensure all
373 * remaining NPORTs get unreg_login'ed.
374 */
375 list_for_each_entry_safe(np, next_np,
376 &vport->fc_nodes, nlp_listp) {
377 if ((np->nlp_state != NLP_STE_NPR_NODE) ||
378 !(np->nlp_flag & NLP_NPR_ADISC))
379 continue;
380 spin_lock_irq(shost->host_lock);
381 np->nlp_flag &= ~NLP_NPR_ADISC;
382 spin_unlock_irq(shost->host_lock);
383 lpfc_unreg_rpi(vport, np);
384 }
385 if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
386 lpfc_mbx_unreg_vpi(vport);
387 vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
388 }
389 }
390
James Smart2e0fef82007-06-17 19:56:36 -0500391 ndlp->nlp_sid = irsp->un.ulpWord[4] & Mask_DID;
James Smart92d7f7b2007-06-17 19:56:38 -0500392 lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE);
James Smart2e0fef82007-06-17 19:56:36 -0500393
James Smart92d7f7b2007-06-17 19:56:38 -0500394 if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED &&
395 vport->fc_flag & FC_VPORT_NEEDS_REG_VPI) {
396 lpfc_register_new_vport(phba, vport, ndlp);
397 return 0;
398 }
399 lpfc_issue_fabric_reglogin(vport);
dea31012005-04-17 16:05:31 -0500400 return 0;
dea31012005-04-17 16:05:31 -0500401}
402
403/*
404 * We FLOGIed into an NPort, initiate pt2pt protocol
405 */
406static int
James Smart2e0fef82007-06-17 19:56:36 -0500407lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
408 struct serv_parm *sp)
dea31012005-04-17 16:05:31 -0500409{
James Smart2e0fef82007-06-17 19:56:36 -0500410 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
411 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500412 LPFC_MBOXQ_t *mbox;
413 int rc;
414
James Smart2e0fef82007-06-17 19:56:36 -0500415 spin_lock_irq(shost->host_lock);
416 vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
417 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500418
419 phba->fc_edtov = FF_DEF_EDTOV;
420 phba->fc_ratov = FF_DEF_RATOV;
James Smart2e0fef82007-06-17 19:56:36 -0500421 rc = memcmp(&vport->fc_portname, &sp->portName,
James Smart92d7f7b2007-06-17 19:56:38 -0500422 sizeof(vport->fc_portname));
dea31012005-04-17 16:05:31 -0500423 if (rc >= 0) {
424 /* This side will initiate the PLOGI */
James Smart2e0fef82007-06-17 19:56:36 -0500425 spin_lock_irq(shost->host_lock);
426 vport->fc_flag |= FC_PT2PT_PLOGI;
427 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500428
429 /*
430 * N_Port ID cannot be 0, set our to LocalID the other
431 * side will be RemoteID.
432 */
433
434 /* not equal */
435 if (rc)
James Smart2e0fef82007-06-17 19:56:36 -0500436 vport->fc_myDID = PT2PT_LocalID;
dea31012005-04-17 16:05:31 -0500437
438 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
439 if (!mbox)
440 goto fail;
441
442 lpfc_config_link(phba, mbox);
443
444 mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
James Smarted957682007-06-17 19:56:37 -0500445 mbox->vport = vport;
James Smart0b727fe2007-10-27 13:37:25 -0400446 rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
dea31012005-04-17 16:05:31 -0500447 if (rc == MBX_NOT_FINISHED) {
448 mempool_free(mbox, phba->mbox_mem_pool);
449 goto fail;
450 }
James Smart329f9bc2007-04-25 09:53:01 -0400451 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -0500452
James Smart2e0fef82007-06-17 19:56:36 -0500453 ndlp = lpfc_findnode_did(vport, PT2PT_RemoteID);
dea31012005-04-17 16:05:31 -0500454 if (!ndlp) {
455 /*
456 * Cannot find existing Fabric ndlp, so allocate a
457 * new one
458 */
459 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
460 if (!ndlp)
461 goto fail;
462
James Smart2e0fef82007-06-17 19:56:36 -0500463 lpfc_nlp_init(vport, ndlp, PT2PT_RemoteID);
dea31012005-04-17 16:05:31 -0500464 }
465
466 memcpy(&ndlp->nlp_portname, &sp->portName,
James Smart2e0fef82007-06-17 19:56:36 -0500467 sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -0500468 memcpy(&ndlp->nlp_nodename, &sp->nodeName,
James Smart2e0fef82007-06-17 19:56:36 -0500469 sizeof(struct lpfc_name));
470 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
471 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500472 ndlp->nlp_flag |= NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -0500473 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500474 } else {
475 /* This side will wait for the PLOGI */
James Smart329f9bc2007-04-25 09:53:01 -0400476 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -0500477 }
478
James Smart2e0fef82007-06-17 19:56:36 -0500479 spin_lock_irq(shost->host_lock);
480 vport->fc_flag |= FC_PT2PT;
481 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500482
483 /* Start discovery - this should just do CLEAR_LA */
James Smart2e0fef82007-06-17 19:56:36 -0500484 lpfc_disc_start(vport);
dea31012005-04-17 16:05:31 -0500485 return 0;
James Smart92d7f7b2007-06-17 19:56:38 -0500486fail:
dea31012005-04-17 16:05:31 -0500487 return -ENXIO;
488}
489
490static void
James Smart329f9bc2007-04-25 09:53:01 -0400491lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
492 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -0500493{
James Smart2e0fef82007-06-17 19:56:36 -0500494 struct lpfc_vport *vport = cmdiocb->vport;
495 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -0500496 IOCB_t *irsp = &rspiocb->iocb;
497 struct lpfc_nodelist *ndlp = cmdiocb->context1;
498 struct lpfc_dmabuf *pcmd = cmdiocb->context2, *prsp;
499 struct serv_parm *sp;
500 int rc;
501
502 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -0500503 if (lpfc_els_chk_latt(vport)) {
James Smart329f9bc2007-04-25 09:53:01 -0400504 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -0500505 goto out;
506 }
507
James Smart858c9f62007-06-17 19:56:39 -0500508 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
509 "FLOGI cmpl: status:x%x/x%x state:x%x",
510 irsp->ulpStatus, irsp->un.ulpWord[4],
511 vport->port_state);
512
dea31012005-04-17 16:05:31 -0500513 if (irsp->ulpStatus) {
514 /* Check for retry */
James Smart2e0fef82007-06-17 19:56:36 -0500515 if (lpfc_els_retry(phba, cmdiocb, rspiocb))
dea31012005-04-17 16:05:31 -0500516 goto out;
James Smart2e0fef82007-06-17 19:56:36 -0500517
dea31012005-04-17 16:05:31 -0500518 /* FLOGI failed, so there is no fabric */
James Smart2e0fef82007-06-17 19:56:36 -0500519 spin_lock_irq(shost->host_lock);
520 vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
521 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500522
James Smart329f9bc2007-04-25 09:53:01 -0400523 /* If private loop, then allow max outstanding els to be
dea31012005-04-17 16:05:31 -0500524 * LPFC_MAX_DISC_THREADS (32). Scanning in the case of no
525 * alpa map would take too long otherwise.
526 */
527 if (phba->alpa_map[0] == 0) {
James Smart3de2a652007-08-02 11:09:59 -0400528 vport->cfg_discovery_threads = LPFC_MAX_DISC_THREADS;
dea31012005-04-17 16:05:31 -0500529 }
530
531 /* FLOGI failure */
James Smarte8b62012007-08-02 11:10:09 -0400532 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
533 "0100 FLOGI failure Data: x%x x%x "
534 "x%x\n",
535 irsp->ulpStatus, irsp->un.ulpWord[4],
536 irsp->ulpTimeout);
dea31012005-04-17 16:05:31 -0500537 goto flogifail;
538 }
539
540 /*
541 * The FLogI succeeded. Sync the data for the CPU before
542 * accessing it.
543 */
544 prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list);
545
546 sp = prsp->virt + sizeof(uint32_t);
547
548 /* FLOGI completes successfully */
James Smarte8b62012007-08-02 11:10:09 -0400549 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
550 "0101 FLOGI completes sucessfully "
551 "Data: x%x x%x x%x x%x\n",
552 irsp->un.ulpWord[4], sp->cmn.e_d_tov,
553 sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution);
dea31012005-04-17 16:05:31 -0500554
James Smart2e0fef82007-06-17 19:56:36 -0500555 if (vport->port_state == LPFC_FLOGI) {
dea31012005-04-17 16:05:31 -0500556 /*
557 * If Common Service Parameters indicate Nport
558 * we are point to point, if Fport we are Fabric.
559 */
560 if (sp->cmn.fPort)
James Smart2e0fef82007-06-17 19:56:36 -0500561 rc = lpfc_cmpl_els_flogi_fabric(vport, ndlp, sp, irsp);
dea31012005-04-17 16:05:31 -0500562 else
James Smart2e0fef82007-06-17 19:56:36 -0500563 rc = lpfc_cmpl_els_flogi_nport(vport, ndlp, sp);
dea31012005-04-17 16:05:31 -0500564
565 if (!rc)
566 goto out;
567 }
568
569flogifail:
James Smart329f9bc2007-04-25 09:53:01 -0400570 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -0500571
James Smart858c9f62007-06-17 19:56:39 -0500572 if (!lpfc_error_lost_link(irsp)) {
dea31012005-04-17 16:05:31 -0500573 /* FLOGI failed, so just use loop map to make discovery list */
James Smart2e0fef82007-06-17 19:56:36 -0500574 lpfc_disc_list_loopmap(vport);
dea31012005-04-17 16:05:31 -0500575
576 /* Start discovery */
James Smart2e0fef82007-06-17 19:56:36 -0500577 lpfc_disc_start(vport);
James Smart87af33f2007-10-27 13:37:43 -0400578 } else if (((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
579 ((irsp->un.ulpWord[4] != IOERR_SLI_ABORTED) &&
580 (irsp->un.ulpWord[4] != IOERR_SLI_DOWN))) &&
581 (phba->link_state != LPFC_CLEAR_LA)) {
582 /* If FLOGI failed enable link interrupt. */
583 lpfc_issue_clear_la(phba, vport);
dea31012005-04-17 16:05:31 -0500584 }
dea31012005-04-17 16:05:31 -0500585out:
586 lpfc_els_free_iocb(phba, cmdiocb);
587}
588
589static int
James Smart2e0fef82007-06-17 19:56:36 -0500590lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
dea31012005-04-17 16:05:31 -0500591 uint8_t retry)
592{
James Smart2e0fef82007-06-17 19:56:36 -0500593 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500594 struct serv_parm *sp;
595 IOCB_t *icmd;
596 struct lpfc_iocbq *elsiocb;
597 struct lpfc_sli_ring *pring;
598 uint8_t *pcmd;
599 uint16_t cmdsize;
600 uint32_t tmo;
601 int rc;
602
603 pring = &phba->sli.ring[LPFC_ELS_RING];
604
James Smart92d7f7b2007-06-17 19:56:38 -0500605 cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
James Smart2e0fef82007-06-17 19:56:36 -0500606 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
607 ndlp->nlp_DID, ELS_CMD_FLOGI);
James Smart92d7f7b2007-06-17 19:56:38 -0500608
James Smart488d1462006-03-07 15:02:37 -0500609 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500610 return 1;
dea31012005-04-17 16:05:31 -0500611
612 icmd = &elsiocb->iocb;
613 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
614
615 /* For FLOGI request, remainder of payload is service parameters */
616 *((uint32_t *) (pcmd)) = ELS_CMD_FLOGI;
James Smart92d7f7b2007-06-17 19:56:38 -0500617 pcmd += sizeof(uint32_t);
618 memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
dea31012005-04-17 16:05:31 -0500619 sp = (struct serv_parm *) pcmd;
620
621 /* Setup CSPs accordingly for Fabric */
622 sp->cmn.e_d_tov = 0;
623 sp->cmn.w2.r_a_tov = 0;
624 sp->cls1.classValid = 0;
625 sp->cls2.seqDelivery = 1;
626 sp->cls3.seqDelivery = 1;
627 if (sp->cmn.fcphLow < FC_PH3)
628 sp->cmn.fcphLow = FC_PH3;
629 if (sp->cmn.fcphHigh < FC_PH3)
630 sp->cmn.fcphHigh = FC_PH3;
631
James Smart92d7f7b2007-06-17 19:56:38 -0500632 if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
633 sp->cmn.request_multiple_Nport = 1;
634
635 /* For FLOGI, Let FLOGI rsp set the NPortID for VPI 0 */
636 icmd->ulpCt_h = 1;
637 icmd->ulpCt_l = 0;
638 }
639
James Smart858c9f62007-06-17 19:56:39 -0500640 if (phba->fc_topology != TOPOLOGY_LOOP) {
641 icmd->un.elsreq64.myID = 0;
642 icmd->un.elsreq64.fl = 1;
643 }
644
dea31012005-04-17 16:05:31 -0500645 tmo = phba->fc_ratov;
646 phba->fc_ratov = LPFC_DISC_FLOGI_TMO;
James Smart2e0fef82007-06-17 19:56:36 -0500647 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -0500648 phba->fc_ratov = tmo;
649
650 phba->fc_stat.elsXmitFLOGI++;
651 elsiocb->iocb_cmpl = lpfc_cmpl_els_flogi;
James Smart858c9f62007-06-17 19:56:39 -0500652
653 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
654 "Issue FLOGI: opt:x%x",
655 phba->sli3_options, 0, 0);
656
James Smart92d7f7b2007-06-17 19:56:38 -0500657 rc = lpfc_issue_fabric_iocb(phba, elsiocb);
dea31012005-04-17 16:05:31 -0500658 if (rc == IOCB_ERROR) {
659 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500660 return 1;
dea31012005-04-17 16:05:31 -0500661 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500662 return 0;
dea31012005-04-17 16:05:31 -0500663}
664
665int
James Smart2e0fef82007-06-17 19:56:36 -0500666lpfc_els_abort_flogi(struct lpfc_hba *phba)
dea31012005-04-17 16:05:31 -0500667{
668 struct lpfc_sli_ring *pring;
669 struct lpfc_iocbq *iocb, *next_iocb;
670 struct lpfc_nodelist *ndlp;
671 IOCB_t *icmd;
672
673 /* Abort outstanding I/O on NPort <nlp_DID> */
674 lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
James Smarte8b62012007-08-02 11:10:09 -0400675 "0201 Abort outstanding I/O on NPort x%x\n",
676 Fabric_DID);
dea31012005-04-17 16:05:31 -0500677
678 pring = &phba->sli.ring[LPFC_ELS_RING];
679
680 /*
681 * Check the txcmplq for an iocb that matches the nport the driver is
682 * searching for.
683 */
James Smart2e0fef82007-06-17 19:56:36 -0500684 spin_lock_irq(&phba->hbalock);
dea31012005-04-17 16:05:31 -0500685 list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
686 icmd = &iocb->iocb;
James Smart2e0fef82007-06-17 19:56:36 -0500687 if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR &&
688 icmd->un.elsreq64.bdl.ulpIoTag32) {
dea31012005-04-17 16:05:31 -0500689 ndlp = (struct lpfc_nodelist *)(iocb->context1);
James Smart92d7f7b2007-06-17 19:56:38 -0500690 if (ndlp && (ndlp->nlp_DID == Fabric_DID)) {
James Smart07951072007-04-25 09:51:38 -0400691 lpfc_sli_issue_abort_iotag(phba, pring, iocb);
James Smart92d7f7b2007-06-17 19:56:38 -0500692 }
dea31012005-04-17 16:05:31 -0500693 }
694 }
James Smart2e0fef82007-06-17 19:56:36 -0500695 spin_unlock_irq(&phba->hbalock);
dea31012005-04-17 16:05:31 -0500696
697 return 0;
698}
699
700int
James Smart2e0fef82007-06-17 19:56:36 -0500701lpfc_initial_flogi(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -0500702{
James Smart2e0fef82007-06-17 19:56:36 -0500703 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500704 struct lpfc_nodelist *ndlp;
705
James Smart98c9ea52007-10-27 13:37:33 -0400706 vport->port_state = LPFC_FLOGI;
707 lpfc_set_disctmo(vport);
708
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500709 /* First look for the Fabric ndlp */
James Smart2e0fef82007-06-17 19:56:36 -0500710 ndlp = lpfc_findnode_did(vport, Fabric_DID);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500711 if (!ndlp) {
dea31012005-04-17 16:05:31 -0500712 /* Cannot find existing Fabric ndlp, so allocate a new one */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500713 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
714 if (!ndlp)
715 return 0;
James Smart2e0fef82007-06-17 19:56:36 -0500716 lpfc_nlp_init(vport, ndlp, Fabric_DID);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500717 } else {
James Smart2e0fef82007-06-17 19:56:36 -0500718 lpfc_dequeue_node(vport, ndlp);
dea31012005-04-17 16:05:31 -0500719 }
James Smart87af33f2007-10-27 13:37:43 -0400720
James Smart2e0fef82007-06-17 19:56:36 -0500721 if (lpfc_issue_els_flogi(vport, ndlp, 0)) {
James Smart329f9bc2007-04-25 09:53:01 -0400722 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -0500723 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500724 return 1;
dea31012005-04-17 16:05:31 -0500725}
726
James Smart92d7f7b2007-06-17 19:56:38 -0500727int
728lpfc_initial_fdisc(struct lpfc_vport *vport)
729{
730 struct lpfc_hba *phba = vport->phba;
731 struct lpfc_nodelist *ndlp;
732
733 /* First look for the Fabric ndlp */
734 ndlp = lpfc_findnode_did(vport, Fabric_DID);
735 if (!ndlp) {
736 /* Cannot find existing Fabric ndlp, so allocate a new one */
737 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
738 if (!ndlp)
739 return 0;
740 lpfc_nlp_init(vport, ndlp, Fabric_DID);
741 } else {
742 lpfc_dequeue_node(vport, ndlp);
743 }
744 if (lpfc_issue_els_fdisc(vport, ndlp, 0)) {
745 lpfc_nlp_put(ndlp);
746 }
747 return 1;
748}
James Smart87af33f2007-10-27 13:37:43 -0400749
750void
James Smart2e0fef82007-06-17 19:56:36 -0500751lpfc_more_plogi(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -0500752{
753 int sentplogi;
754
James Smart2e0fef82007-06-17 19:56:36 -0500755 if (vport->num_disc_nodes)
756 vport->num_disc_nodes--;
dea31012005-04-17 16:05:31 -0500757
758 /* Continue discovery with <num_disc_nodes> PLOGIs to go */
James Smarte8b62012007-08-02 11:10:09 -0400759 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
760 "0232 Continue discovery with %d PLOGIs to go "
761 "Data: x%x x%x x%x\n",
762 vport->num_disc_nodes, vport->fc_plogi_cnt,
763 vport->fc_flag, vport->port_state);
dea31012005-04-17 16:05:31 -0500764 /* Check to see if there are more PLOGIs to be sent */
James Smart2e0fef82007-06-17 19:56:36 -0500765 if (vport->fc_flag & FC_NLP_MORE)
766 /* go thru NPR nodes and issue any remaining ELS PLOGIs */
767 sentplogi = lpfc_els_disc_plogi(vport);
768
dea31012005-04-17 16:05:31 -0500769 return;
770}
771
James Smart488d1462006-03-07 15:02:37 -0500772static struct lpfc_nodelist *
James Smart92d7f7b2007-06-17 19:56:38 -0500773lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
James Smart488d1462006-03-07 15:02:37 -0500774 struct lpfc_nodelist *ndlp)
775{
James Smart2e0fef82007-06-17 19:56:36 -0500776 struct lpfc_vport *vport = ndlp->vport;
James Smart488d1462006-03-07 15:02:37 -0500777 struct lpfc_nodelist *new_ndlp;
James Smart488d1462006-03-07 15:02:37 -0500778 struct serv_parm *sp;
James Smart92d7f7b2007-06-17 19:56:38 -0500779 uint8_t name[sizeof(struct lpfc_name)];
James Smart488d1462006-03-07 15:02:37 -0500780 uint32_t rc;
781
James Smart2fb9bd82006-12-02 13:33:57 -0500782 /* Fabric nodes can have the same WWPN so we don't bother searching
783 * by WWPN. Just return the ndlp that was given to us.
784 */
785 if (ndlp->nlp_type & NLP_FABRIC)
786 return ndlp;
787
James Smart92d7f7b2007-06-17 19:56:38 -0500788 sp = (struct serv_parm *) ((uint8_t *) prsp + sizeof(uint32_t));
James Smart685f0bf2007-04-25 09:53:08 -0400789 memset(name, 0, sizeof(struct lpfc_name));
James Smart488d1462006-03-07 15:02:37 -0500790
James Smart685f0bf2007-04-25 09:53:08 -0400791 /* Now we find out if the NPort we are logging into, matches the WWPN
James Smart488d1462006-03-07 15:02:37 -0500792 * we have for that ndlp. If not, we have some work to do.
793 */
James Smart2e0fef82007-06-17 19:56:36 -0500794 new_ndlp = lpfc_findnode_wwpn(vport, &sp->portName);
James Smart488d1462006-03-07 15:02:37 -0500795
James Smart92795652006-07-06 15:50:02 -0400796 if (new_ndlp == ndlp)
James Smart488d1462006-03-07 15:02:37 -0500797 return ndlp;
James Smart488d1462006-03-07 15:02:37 -0500798
799 if (!new_ndlp) {
James Smart2e0fef82007-06-17 19:56:36 -0500800 rc = memcmp(&ndlp->nlp_portname, name,
801 sizeof(struct lpfc_name));
James Smart92795652006-07-06 15:50:02 -0400802 if (!rc)
803 return ndlp;
James Smart488d1462006-03-07 15:02:37 -0500804 new_ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC);
805 if (!new_ndlp)
806 return ndlp;
807
James Smart2e0fef82007-06-17 19:56:36 -0500808 lpfc_nlp_init(vport, new_ndlp, ndlp->nlp_DID);
James Smart488d1462006-03-07 15:02:37 -0500809 }
810
James Smart2e0fef82007-06-17 19:56:36 -0500811 lpfc_unreg_rpi(vport, new_ndlp);
James Smart488d1462006-03-07 15:02:37 -0500812 new_ndlp->nlp_DID = ndlp->nlp_DID;
James Smart92795652006-07-06 15:50:02 -0400813 new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
James Smart2e0fef82007-06-17 19:56:36 -0500814 lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state);
James Smart488d1462006-03-07 15:02:37 -0500815
James Smart2e0fef82007-06-17 19:56:36 -0500816 /* Move this back to NPR state */
James Smart87af33f2007-10-27 13:37:43 -0400817 if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) {
818 /* The new_ndlp is replacing ndlp totally, so we need
819 * to put ndlp on UNUSED list and try to free it.
820 */
James Smart2e0fef82007-06-17 19:56:36 -0500821 lpfc_drop_node(vport, ndlp);
James Smart87af33f2007-10-27 13:37:43 -0400822 }
James Smart92795652006-07-06 15:50:02 -0400823 else {
James Smart2e0fef82007-06-17 19:56:36 -0500824 lpfc_unreg_rpi(vport, ndlp);
James Smart92795652006-07-06 15:50:02 -0400825 ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
James Smart2e0fef82007-06-17 19:56:36 -0500826 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
James Smart92795652006-07-06 15:50:02 -0400827 }
James Smart488d1462006-03-07 15:02:37 -0500828 return new_ndlp;
829}
830
James Smart87af33f2007-10-27 13:37:43 -0400831void
832lpfc_end_rscn(struct lpfc_vport *vport)
833{
834 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
835
836 if (vport->fc_flag & FC_RSCN_MODE) {
837 /*
838 * Check to see if more RSCNs came in while we were
839 * processing this one.
840 */
841 if (vport->fc_rscn_id_cnt ||
842 (vport->fc_flag & FC_RSCN_DISCOVERY) != 0)
843 lpfc_els_handle_rscn(vport);
844 else {
845 spin_lock_irq(shost->host_lock);
846 vport->fc_flag &= ~FC_RSCN_MODE;
847 spin_unlock_irq(shost->host_lock);
848 }
849 }
850}
851
dea31012005-04-17 16:05:31 -0500852static void
James Smart2e0fef82007-06-17 19:56:36 -0500853lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
854 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -0500855{
James Smart2e0fef82007-06-17 19:56:36 -0500856 struct lpfc_vport *vport = cmdiocb->vport;
857 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -0500858 IOCB_t *irsp;
dea31012005-04-17 16:05:31 -0500859 struct lpfc_nodelist *ndlp;
James Smart92795652006-07-06 15:50:02 -0400860 struct lpfc_dmabuf *prsp;
dea31012005-04-17 16:05:31 -0500861 int disc, rc, did, type;
862
dea31012005-04-17 16:05:31 -0500863 /* we pass cmdiocb to state machine which needs rspiocb as well */
864 cmdiocb->context_un.rsp_iocb = rspiocb;
865
866 irsp = &rspiocb->iocb;
James Smart858c9f62007-06-17 19:56:39 -0500867 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
868 "PLOGI cmpl: status:x%x/x%x did:x%x",
869 irsp->ulpStatus, irsp->un.ulpWord[4],
870 irsp->un.elsreq64.remoteID);
871
James Smart2e0fef82007-06-17 19:56:36 -0500872 ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID);
James Smarted957682007-06-17 19:56:37 -0500873 if (!ndlp) {
James Smarte8b62012007-08-02 11:10:09 -0400874 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
875 "0136 PLOGI completes to NPort x%x "
876 "with no ndlp. Data: x%x x%x x%x\n",
877 irsp->un.elsreq64.remoteID,
878 irsp->ulpStatus, irsp->un.ulpWord[4],
879 irsp->ulpIoTag);
James Smart488d1462006-03-07 15:02:37 -0500880 goto out;
James Smarted957682007-06-17 19:56:37 -0500881 }
dea31012005-04-17 16:05:31 -0500882
883 /* Since ndlp can be freed in the disc state machine, note if this node
884 * is being used during discovery.
885 */
James Smart2e0fef82007-06-17 19:56:36 -0500886 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500887 disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
James Smart488d1462006-03-07 15:02:37 -0500888 ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -0500889 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500890 rc = 0;
891
892 /* PLOGI completes to NPort <nlp_DID> */
James Smarte8b62012007-08-02 11:10:09 -0400893 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
894 "0102 PLOGI completes to NPort x%x "
895 "Data: x%x x%x x%x x%x x%x\n",
896 ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4],
897 irsp->ulpTimeout, disc, vport->num_disc_nodes);
dea31012005-04-17 16:05:31 -0500898 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -0500899 if (lpfc_els_chk_latt(vport)) {
900 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500901 ndlp->nlp_flag |= NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -0500902 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500903 goto out;
904 }
905
906 /* ndlp could be freed in DSM, save these values now */
907 type = ndlp->nlp_type;
908 did = ndlp->nlp_DID;
909
910 if (irsp->ulpStatus) {
911 /* Check for retry */
912 if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
913 /* ELS command is being retried */
914 if (disc) {
James Smart2e0fef82007-06-17 19:56:36 -0500915 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500916 ndlp->nlp_flag |= NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -0500917 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500918 }
919 goto out;
920 }
dea31012005-04-17 16:05:31 -0500921 /* PLOGI failed */
922 /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
James Smart858c9f62007-06-17 19:56:39 -0500923 if (lpfc_error_lost_link(irsp)) {
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500924 rc = NLP_STE_FREED_NODE;
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -0500925 } else {
James Smart2e0fef82007-06-17 19:56:36 -0500926 rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart92d7f7b2007-06-17 19:56:38 -0500927 NLP_EVT_CMPL_PLOGI);
dea31012005-04-17 16:05:31 -0500928 }
929 } else {
930 /* Good status, call state machine */
James Smart92795652006-07-06 15:50:02 -0400931 prsp = list_entry(((struct lpfc_dmabuf *)
James Smart92d7f7b2007-06-17 19:56:38 -0500932 cmdiocb->context2)->list.next,
933 struct lpfc_dmabuf, list);
934 ndlp = lpfc_plogi_confirm_nport(phba, prsp->virt, ndlp);
James Smart2e0fef82007-06-17 19:56:36 -0500935 rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart92d7f7b2007-06-17 19:56:38 -0500936 NLP_EVT_CMPL_PLOGI);
dea31012005-04-17 16:05:31 -0500937 }
938
James Smart2e0fef82007-06-17 19:56:36 -0500939 if (disc && vport->num_disc_nodes) {
dea31012005-04-17 16:05:31 -0500940 /* Check to see if there are more PLOGIs to be sent */
James Smart2e0fef82007-06-17 19:56:36 -0500941 lpfc_more_plogi(vport);
dea31012005-04-17 16:05:31 -0500942
James Smart2e0fef82007-06-17 19:56:36 -0500943 if (vport->num_disc_nodes == 0) {
944 spin_lock_irq(shost->host_lock);
945 vport->fc_flag &= ~FC_NDISC_ACTIVE;
946 spin_unlock_irq(shost->host_lock);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500947
James Smart2e0fef82007-06-17 19:56:36 -0500948 lpfc_can_disctmo(vport);
James Smart87af33f2007-10-27 13:37:43 -0400949 lpfc_end_rscn(vport);
dea31012005-04-17 16:05:31 -0500950 }
951 }
952
953out:
954 lpfc_els_free_iocb(phba, cmdiocb);
955 return;
956}
957
958int
James Smart2e0fef82007-06-17 19:56:36 -0500959lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
dea31012005-04-17 16:05:31 -0500960{
James Smart2e0fef82007-06-17 19:56:36 -0500961 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500962 struct serv_parm *sp;
963 IOCB_t *icmd;
James Smart98c9ea52007-10-27 13:37:33 -0400964 struct lpfc_nodelist *ndlp;
dea31012005-04-17 16:05:31 -0500965 struct lpfc_iocbq *elsiocb;
966 struct lpfc_sli_ring *pring;
967 struct lpfc_sli *psli;
968 uint8_t *pcmd;
969 uint16_t cmdsize;
James Smart92d7f7b2007-06-17 19:56:38 -0500970 int ret;
dea31012005-04-17 16:05:31 -0500971
972 psli = &phba->sli;
973 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
974
James Smart98c9ea52007-10-27 13:37:33 -0400975 ndlp = lpfc_findnode_did(vport, did);
976 /* If ndlp if not NULL, we will bump the reference count on it */
977
James Smart92d7f7b2007-06-17 19:56:38 -0500978 cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
James Smart98c9ea52007-10-27 13:37:33 -0400979 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did,
James Smart2e0fef82007-06-17 19:56:36 -0500980 ELS_CMD_PLOGI);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500981 if (!elsiocb)
982 return 1;
dea31012005-04-17 16:05:31 -0500983
984 icmd = &elsiocb->iocb;
985 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
986
987 /* For PLOGI request, remainder of payload is service parameters */
988 *((uint32_t *) (pcmd)) = ELS_CMD_PLOGI;
James Smart92d7f7b2007-06-17 19:56:38 -0500989 pcmd += sizeof(uint32_t);
990 memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
dea31012005-04-17 16:05:31 -0500991 sp = (struct serv_parm *) pcmd;
992
993 if (sp->cmn.fcphLow < FC_PH_4_3)
994 sp->cmn.fcphLow = FC_PH_4_3;
995
996 if (sp->cmn.fcphHigh < FC_PH3)
997 sp->cmn.fcphHigh = FC_PH3;
998
James Smart858c9f62007-06-17 19:56:39 -0500999 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1000 "Issue PLOGI: did:x%x",
1001 did, 0, 0);
1002
dea31012005-04-17 16:05:31 -05001003 phba->fc_stat.elsXmitPLOGI++;
1004 elsiocb->iocb_cmpl = lpfc_cmpl_els_plogi;
James Smart92d7f7b2007-06-17 19:56:38 -05001005 ret = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
1006
1007 if (ret == IOCB_ERROR) {
dea31012005-04-17 16:05:31 -05001008 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001009 return 1;
dea31012005-04-17 16:05:31 -05001010 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001011 return 0;
dea31012005-04-17 16:05:31 -05001012}
1013
1014static void
James Smart2e0fef82007-06-17 19:56:36 -05001015lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1016 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05001017{
James Smart2e0fef82007-06-17 19:56:36 -05001018 struct lpfc_vport *vport = cmdiocb->vport;
1019 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05001020 IOCB_t *irsp;
1021 struct lpfc_sli *psli;
1022 struct lpfc_nodelist *ndlp;
1023
1024 psli = &phba->sli;
1025 /* we pass cmdiocb to state machine which needs rspiocb as well */
1026 cmdiocb->context_un.rsp_iocb = rspiocb;
1027
1028 irsp = &(rspiocb->iocb);
1029 ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
James Smart2e0fef82007-06-17 19:56:36 -05001030 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001031 ndlp->nlp_flag &= ~NLP_PRLI_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001032 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001033
James Smart858c9f62007-06-17 19:56:39 -05001034 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1035 "PRLI cmpl: status:x%x/x%x did:x%x",
1036 irsp->ulpStatus, irsp->un.ulpWord[4],
1037 ndlp->nlp_DID);
dea31012005-04-17 16:05:31 -05001038 /* PRLI completes to NPort <nlp_DID> */
James Smarte8b62012007-08-02 11:10:09 -04001039 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
1040 "0103 PRLI completes to NPort x%x "
1041 "Data: x%x x%x x%x x%x\n",
1042 ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4],
1043 irsp->ulpTimeout, vport->num_disc_nodes);
dea31012005-04-17 16:05:31 -05001044
James Smart2e0fef82007-06-17 19:56:36 -05001045 vport->fc_prli_sent--;
dea31012005-04-17 16:05:31 -05001046 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -05001047 if (lpfc_els_chk_latt(vport))
dea31012005-04-17 16:05:31 -05001048 goto out;
1049
1050 if (irsp->ulpStatus) {
1051 /* Check for retry */
1052 if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
1053 /* ELS command is being retried */
1054 goto out;
1055 }
1056 /* PRLI failed */
1057 /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
James Smart858c9f62007-06-17 19:56:39 -05001058 if (lpfc_error_lost_link(irsp)) {
dea31012005-04-17 16:05:31 -05001059 goto out;
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05001060 } else {
James Smart2e0fef82007-06-17 19:56:36 -05001061 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart92d7f7b2007-06-17 19:56:38 -05001062 NLP_EVT_CMPL_PRLI);
dea31012005-04-17 16:05:31 -05001063 }
1064 } else {
1065 /* Good status, call state machine */
James Smart2e0fef82007-06-17 19:56:36 -05001066 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart92d7f7b2007-06-17 19:56:38 -05001067 NLP_EVT_CMPL_PRLI);
dea31012005-04-17 16:05:31 -05001068 }
1069
1070out:
1071 lpfc_els_free_iocb(phba, cmdiocb);
1072 return;
1073}
1074
1075int
James Smart2e0fef82007-06-17 19:56:36 -05001076lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
dea31012005-04-17 16:05:31 -05001077 uint8_t retry)
1078{
James Smart2e0fef82007-06-17 19:56:36 -05001079 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1080 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001081 PRLI *npr;
1082 IOCB_t *icmd;
1083 struct lpfc_iocbq *elsiocb;
1084 struct lpfc_sli_ring *pring;
1085 struct lpfc_sli *psli;
1086 uint8_t *pcmd;
1087 uint16_t cmdsize;
1088
1089 psli = &phba->sli;
1090 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
1091
James Smart92d7f7b2007-06-17 19:56:38 -05001092 cmdsize = (sizeof(uint32_t) + sizeof(PRLI));
James Smart2e0fef82007-06-17 19:56:36 -05001093 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
1094 ndlp->nlp_DID, ELS_CMD_PRLI);
James Smart488d1462006-03-07 15:02:37 -05001095 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001096 return 1;
dea31012005-04-17 16:05:31 -05001097
1098 icmd = &elsiocb->iocb;
1099 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1100
1101 /* For PRLI request, remainder of payload is service parameters */
James Smart92d7f7b2007-06-17 19:56:38 -05001102 memset(pcmd, 0, (sizeof(PRLI) + sizeof(uint32_t)));
dea31012005-04-17 16:05:31 -05001103 *((uint32_t *) (pcmd)) = ELS_CMD_PRLI;
James Smart92d7f7b2007-06-17 19:56:38 -05001104 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05001105
1106 /* For PRLI, remainder of payload is PRLI parameter page */
1107 npr = (PRLI *) pcmd;
1108 /*
1109 * If our firmware version is 3.20 or later,
1110 * set the following bits for FC-TAPE support.
1111 */
1112 if (phba->vpd.rev.feaLevelHigh >= 0x02) {
1113 npr->ConfmComplAllowed = 1;
1114 npr->Retry = 1;
1115 npr->TaskRetryIdReq = 1;
1116 }
1117 npr->estabImagePair = 1;
1118 npr->readXferRdyDis = 1;
1119
1120 /* For FCP support */
1121 npr->prliType = PRLI_FCP_TYPE;
1122 npr->initiatorFunc = 1;
1123
James Smart858c9f62007-06-17 19:56:39 -05001124 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1125 "Issue PRLI: did:x%x",
1126 ndlp->nlp_DID, 0, 0);
1127
dea31012005-04-17 16:05:31 -05001128 phba->fc_stat.elsXmitPRLI++;
1129 elsiocb->iocb_cmpl = lpfc_cmpl_els_prli;
James Smart2e0fef82007-06-17 19:56:36 -05001130 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001131 ndlp->nlp_flag |= NLP_PRLI_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001132 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001133 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
James Smart2e0fef82007-06-17 19:56:36 -05001134 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001135 ndlp->nlp_flag &= ~NLP_PRLI_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001136 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001137 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001138 return 1;
dea31012005-04-17 16:05:31 -05001139 }
James Smart2e0fef82007-06-17 19:56:36 -05001140 vport->fc_prli_sent++;
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001141 return 0;
dea31012005-04-17 16:05:31 -05001142}
1143
1144static void
James Smart2e0fef82007-06-17 19:56:36 -05001145lpfc_more_adisc(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05001146{
1147 int sentadisc;
1148
James Smart2e0fef82007-06-17 19:56:36 -05001149 if (vport->num_disc_nodes)
1150 vport->num_disc_nodes--;
dea31012005-04-17 16:05:31 -05001151 /* Continue discovery with <num_disc_nodes> ADISCs to go */
James Smarte8b62012007-08-02 11:10:09 -04001152 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
1153 "0210 Continue discovery with %d ADISCs to go "
1154 "Data: x%x x%x x%x\n",
1155 vport->num_disc_nodes, vport->fc_adisc_cnt,
1156 vport->fc_flag, vport->port_state);
dea31012005-04-17 16:05:31 -05001157 /* Check to see if there are more ADISCs to be sent */
James Smart2e0fef82007-06-17 19:56:36 -05001158 if (vport->fc_flag & FC_NLP_MORE) {
1159 lpfc_set_disctmo(vport);
1160 /* go thru NPR nodes and issue any remaining ELS ADISCs */
1161 sentadisc = lpfc_els_disc_adisc(vport);
dea31012005-04-17 16:05:31 -05001162 }
1163 return;
1164}
1165
1166static void
James Smart2e0fef82007-06-17 19:56:36 -05001167lpfc_rscn_disc(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05001168{
James Smart858c9f62007-06-17 19:56:39 -05001169 lpfc_can_disctmo(vport);
1170
dea31012005-04-17 16:05:31 -05001171 /* RSCN discovery */
James Smart2e0fef82007-06-17 19:56:36 -05001172 /* go thru NPR nodes and issue ELS PLOGIs */
1173 if (vport->fc_npr_cnt)
1174 if (lpfc_els_disc_plogi(vport))
dea31012005-04-17 16:05:31 -05001175 return;
James Smart2e0fef82007-06-17 19:56:36 -05001176
James Smart87af33f2007-10-27 13:37:43 -04001177 lpfc_end_rscn(vport);
dea31012005-04-17 16:05:31 -05001178}
1179
1180static void
James Smart2e0fef82007-06-17 19:56:36 -05001181lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1182 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05001183{
James Smart2e0fef82007-06-17 19:56:36 -05001184 struct lpfc_vport *vport = cmdiocb->vport;
1185 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05001186 IOCB_t *irsp;
dea31012005-04-17 16:05:31 -05001187 struct lpfc_nodelist *ndlp;
James Smart2e0fef82007-06-17 19:56:36 -05001188 int disc;
dea31012005-04-17 16:05:31 -05001189
1190 /* we pass cmdiocb to state machine which needs rspiocb as well */
1191 cmdiocb->context_un.rsp_iocb = rspiocb;
1192
1193 irsp = &(rspiocb->iocb);
1194 ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
dea31012005-04-17 16:05:31 -05001195
James Smart858c9f62007-06-17 19:56:39 -05001196 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1197 "ADISC cmpl: status:x%x/x%x did:x%x",
1198 irsp->ulpStatus, irsp->un.ulpWord[4],
1199 ndlp->nlp_DID);
1200
dea31012005-04-17 16:05:31 -05001201 /* Since ndlp can be freed in the disc state machine, note if this node
1202 * is being used during discovery.
1203 */
James Smart2e0fef82007-06-17 19:56:36 -05001204 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001205 disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001206 ndlp->nlp_flag &= ~(NLP_ADISC_SND | NLP_NPR_2B_DISC);
James Smart2e0fef82007-06-17 19:56:36 -05001207 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001208 /* ADISC completes to NPort <nlp_DID> */
James Smarte8b62012007-08-02 11:10:09 -04001209 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
1210 "0104 ADISC completes to NPort x%x "
1211 "Data: x%x x%x x%x x%x x%x\n",
1212 ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4],
1213 irsp->ulpTimeout, disc, vport->num_disc_nodes);
dea31012005-04-17 16:05:31 -05001214 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -05001215 if (lpfc_els_chk_latt(vport)) {
1216 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001217 ndlp->nlp_flag |= NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -05001218 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001219 goto out;
1220 }
1221
1222 if (irsp->ulpStatus) {
1223 /* Check for retry */
1224 if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
1225 /* ELS command is being retried */
1226 if (disc) {
James Smart2e0fef82007-06-17 19:56:36 -05001227 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001228 ndlp->nlp_flag |= NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -05001229 spin_unlock_irq(shost->host_lock);
1230 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -05001231 }
1232 goto out;
1233 }
1234 /* ADISC failed */
1235 /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
James Smart858c9f62007-06-17 19:56:39 -05001236 if (!lpfc_error_lost_link(irsp)) {
James Smart2e0fef82007-06-17 19:56:36 -05001237 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart858c9f62007-06-17 19:56:39 -05001238 NLP_EVT_CMPL_ADISC);
dea31012005-04-17 16:05:31 -05001239 }
1240 } else {
1241 /* Good status, call state machine */
James Smart2e0fef82007-06-17 19:56:36 -05001242 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
dea31012005-04-17 16:05:31 -05001243 NLP_EVT_CMPL_ADISC);
1244 }
1245
James Smart2e0fef82007-06-17 19:56:36 -05001246 if (disc && vport->num_disc_nodes) {
dea31012005-04-17 16:05:31 -05001247 /* Check to see if there are more ADISCs to be sent */
James Smart2e0fef82007-06-17 19:56:36 -05001248 lpfc_more_adisc(vport);
dea31012005-04-17 16:05:31 -05001249
1250 /* Check to see if we are done with ADISC authentication */
James Smart2e0fef82007-06-17 19:56:36 -05001251 if (vport->num_disc_nodes == 0) {
James Smart92d7f7b2007-06-17 19:56:38 -05001252 /* If we get here, there is nothing left to ADISC */
1253 /*
1254 * For NPIV, cmpl_reg_vpi will set port_state to READY,
1255 * and continue discovery.
1256 */
1257 if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
1258 !(vport->fc_flag & FC_RSCN_MODE)) {
1259 lpfc_issue_reg_vpi(phba, vport);
1260 goto out;
1261 }
1262 /*
1263 * For SLI2, we need to set port_state to READY
1264 * and continue discovery.
1265 */
1266 if (vport->port_state < LPFC_VPORT_READY) {
1267 /* If we get here, there is nothing to ADISC */
James Smarted957682007-06-17 19:56:37 -05001268 if (vport->port_type == LPFC_PHYSICAL_PORT)
James Smart2e0fef82007-06-17 19:56:36 -05001269 lpfc_issue_clear_la(phba, vport);
James Smart92d7f7b2007-06-17 19:56:38 -05001270
1271 if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) {
1272 vport->num_disc_nodes = 0;
1273 /* go thru NPR list, issue ELS PLOGIs */
1274 if (vport->fc_npr_cnt)
1275 lpfc_els_disc_plogi(vport);
1276
1277 if (!vport->num_disc_nodes) {
1278 spin_lock_irq(shost->host_lock);
1279 vport->fc_flag &=
1280 ~FC_NDISC_ACTIVE;
1281 spin_unlock_irq(
1282 shost->host_lock);
1283 lpfc_can_disctmo(vport);
1284 }
1285 }
1286 vport->port_state = LPFC_VPORT_READY;
dea31012005-04-17 16:05:31 -05001287 } else {
James Smart2e0fef82007-06-17 19:56:36 -05001288 lpfc_rscn_disc(vport);
dea31012005-04-17 16:05:31 -05001289 }
1290 }
1291 }
dea31012005-04-17 16:05:31 -05001292out:
1293 lpfc_els_free_iocb(phba, cmdiocb);
1294 return;
1295}
1296
1297int
James Smart2e0fef82007-06-17 19:56:36 -05001298lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
dea31012005-04-17 16:05:31 -05001299 uint8_t retry)
1300{
James Smart2e0fef82007-06-17 19:56:36 -05001301 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1302 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001303 ADISC *ap;
1304 IOCB_t *icmd;
1305 struct lpfc_iocbq *elsiocb;
James Smart2e0fef82007-06-17 19:56:36 -05001306 struct lpfc_sli *psli = &phba->sli;
1307 struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
dea31012005-04-17 16:05:31 -05001308 uint8_t *pcmd;
1309 uint16_t cmdsize;
1310
James Smart92d7f7b2007-06-17 19:56:38 -05001311 cmdsize = (sizeof(uint32_t) + sizeof(ADISC));
James Smart2e0fef82007-06-17 19:56:36 -05001312 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
1313 ndlp->nlp_DID, ELS_CMD_ADISC);
James Smart488d1462006-03-07 15:02:37 -05001314 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001315 return 1;
dea31012005-04-17 16:05:31 -05001316
1317 icmd = &elsiocb->iocb;
1318 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1319
1320 /* For ADISC request, remainder of payload is service parameters */
1321 *((uint32_t *) (pcmd)) = ELS_CMD_ADISC;
James Smart92d7f7b2007-06-17 19:56:38 -05001322 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05001323
1324 /* Fill in ADISC payload */
1325 ap = (ADISC *) pcmd;
1326 ap->hardAL_PA = phba->fc_pref_ALPA;
James Smart92d7f7b2007-06-17 19:56:38 -05001327 memcpy(&ap->portName, &vport->fc_portname, sizeof(struct lpfc_name));
1328 memcpy(&ap->nodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
James Smart2e0fef82007-06-17 19:56:36 -05001329 ap->DID = be32_to_cpu(vport->fc_myDID);
dea31012005-04-17 16:05:31 -05001330
James Smart858c9f62007-06-17 19:56:39 -05001331 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1332 "Issue ADISC: did:x%x",
1333 ndlp->nlp_DID, 0, 0);
1334
dea31012005-04-17 16:05:31 -05001335 phba->fc_stat.elsXmitADISC++;
1336 elsiocb->iocb_cmpl = lpfc_cmpl_els_adisc;
James Smart2e0fef82007-06-17 19:56:36 -05001337 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001338 ndlp->nlp_flag |= NLP_ADISC_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001339 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001340 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
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 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001345 return 1;
dea31012005-04-17 16:05:31 -05001346 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001347 return 0;
dea31012005-04-17 16:05:31 -05001348}
1349
1350static void
James Smart2e0fef82007-06-17 19:56:36 -05001351lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1352 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05001353{
James Smart2e0fef82007-06-17 19:56:36 -05001354 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
1355 struct lpfc_vport *vport = ndlp->vport;
1356 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05001357 IOCB_t *irsp;
1358 struct lpfc_sli *psli;
dea31012005-04-17 16:05:31 -05001359
1360 psli = &phba->sli;
1361 /* we pass cmdiocb to state machine which needs rspiocb as well */
1362 cmdiocb->context_un.rsp_iocb = rspiocb;
1363
1364 irsp = &(rspiocb->iocb);
James Smart2e0fef82007-06-17 19:56:36 -05001365 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001366 ndlp->nlp_flag &= ~NLP_LOGO_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001367 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001368
James Smart858c9f62007-06-17 19:56:39 -05001369 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1370 "LOGO cmpl: status:x%x/x%x did:x%x",
1371 irsp->ulpStatus, irsp->un.ulpWord[4],
1372 ndlp->nlp_DID);
dea31012005-04-17 16:05:31 -05001373 /* LOGO completes to NPort <nlp_DID> */
James Smarte8b62012007-08-02 11:10:09 -04001374 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
1375 "0105 LOGO completes to NPort x%x "
1376 "Data: x%x x%x x%x x%x\n",
1377 ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4],
1378 irsp->ulpTimeout, vport->num_disc_nodes);
dea31012005-04-17 16:05:31 -05001379 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -05001380 if (lpfc_els_chk_latt(vport))
dea31012005-04-17 16:05:31 -05001381 goto out;
1382
James Smart92d7f7b2007-06-17 19:56:38 -05001383 if (ndlp->nlp_flag & NLP_TARGET_REMOVE) {
1384 /* NLP_EVT_DEVICE_RM should unregister the RPI
1385 * which should abort all outstanding IOs.
1386 */
1387 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
1388 NLP_EVT_DEVICE_RM);
1389 goto out;
1390 }
1391
dea31012005-04-17 16:05:31 -05001392 if (irsp->ulpStatus) {
1393 /* Check for retry */
James Smart2e0fef82007-06-17 19:56:36 -05001394 if (lpfc_els_retry(phba, cmdiocb, rspiocb))
dea31012005-04-17 16:05:31 -05001395 /* ELS command is being retried */
1396 goto out;
dea31012005-04-17 16:05:31 -05001397 /* LOGO failed */
1398 /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
James Smart858c9f62007-06-17 19:56:39 -05001399 if (lpfc_error_lost_link(irsp))
dea31012005-04-17 16:05:31 -05001400 goto out;
James Smart858c9f62007-06-17 19:56:39 -05001401 else
James Smart2e0fef82007-06-17 19:56:36 -05001402 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart92d7f7b2007-06-17 19:56:38 -05001403 NLP_EVT_CMPL_LOGO);
dea31012005-04-17 16:05:31 -05001404 } else {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001405 /* Good status, call state machine.
1406 * This will unregister the rpi if needed.
1407 */
James Smart2e0fef82007-06-17 19:56:36 -05001408 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart92d7f7b2007-06-17 19:56:38 -05001409 NLP_EVT_CMPL_LOGO);
dea31012005-04-17 16:05:31 -05001410 }
1411
1412out:
1413 lpfc_els_free_iocb(phba, cmdiocb);
1414 return;
1415}
1416
1417int
James Smart2e0fef82007-06-17 19:56:36 -05001418lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
dea31012005-04-17 16:05:31 -05001419 uint8_t retry)
1420{
James Smart2e0fef82007-06-17 19:56:36 -05001421 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1422 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001423 IOCB_t *icmd;
1424 struct lpfc_iocbq *elsiocb;
1425 struct lpfc_sli_ring *pring;
1426 struct lpfc_sli *psli;
1427 uint8_t *pcmd;
1428 uint16_t cmdsize;
James Smart92d7f7b2007-06-17 19:56:38 -05001429 int rc;
dea31012005-04-17 16:05:31 -05001430
1431 psli = &phba->sli;
1432 pring = &psli->ring[LPFC_ELS_RING];
1433
James Smart98c9ea52007-10-27 13:37:33 -04001434 spin_lock_irq(shost->host_lock);
1435 if (ndlp->nlp_flag & NLP_LOGO_SND) {
1436 spin_unlock_irq(shost->host_lock);
1437 return 0;
1438 }
1439 spin_unlock_irq(shost->host_lock);
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);
dea31012005-04-17 16:05:31 -05001491 /* ELS cmd tag <ulpIoTag> completes */
James Smarte8b62012007-08-02 11:10:09 -04001492 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
1493 "0106 ELS cmd tag x%x completes Data: x%x x%x x%x\n",
1494 irsp->ulpIoTag, irsp->ulpStatus,
1495 irsp->un.ulpWord[4], irsp->ulpTimeout);
dea31012005-04-17 16:05:31 -05001496 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -05001497 lpfc_els_chk_latt(vport);
dea31012005-04-17 16:05:31 -05001498 lpfc_els_free_iocb(phba, cmdiocb);
1499 return;
1500}
1501
1502int
James Smart2e0fef82007-06-17 19:56:36 -05001503lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
dea31012005-04-17 16:05:31 -05001504{
James Smart2e0fef82007-06-17 19:56:36 -05001505 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001506 IOCB_t *icmd;
1507 struct lpfc_iocbq *elsiocb;
1508 struct lpfc_sli_ring *pring;
1509 struct lpfc_sli *psli;
1510 uint8_t *pcmd;
1511 uint16_t cmdsize;
1512 struct lpfc_nodelist *ndlp;
1513
1514 psli = &phba->sli;
1515 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
James Smart92d7f7b2007-06-17 19:56:38 -05001516 cmdsize = (sizeof(uint32_t) + sizeof(SCR));
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001517 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
1518 if (!ndlp)
1519 return 1;
dea31012005-04-17 16:05:31 -05001520
James Smart2e0fef82007-06-17 19:56:36 -05001521 lpfc_nlp_init(vport, ndlp, nportid);
dea31012005-04-17 16:05:31 -05001522
James Smart2e0fef82007-06-17 19:56:36 -05001523 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
1524 ndlp->nlp_DID, ELS_CMD_SCR);
1525
James Smart488d1462006-03-07 15:02:37 -05001526 if (!elsiocb) {
James Smart329f9bc2007-04-25 09:53:01 -04001527 lpfc_nlp_put(ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001528 return 1;
dea31012005-04-17 16:05:31 -05001529 }
1530
1531 icmd = &elsiocb->iocb;
1532 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1533
1534 *((uint32_t *) (pcmd)) = ELS_CMD_SCR;
James Smart92d7f7b2007-06-17 19:56:38 -05001535 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05001536
1537 /* For SCR, remainder of payload is SCR parameter page */
James Smart92d7f7b2007-06-17 19:56:38 -05001538 memset(pcmd, 0, sizeof(SCR));
dea31012005-04-17 16:05:31 -05001539 ((SCR *) pcmd)->Function = SCR_FUNC_FULL;
1540
James Smart858c9f62007-06-17 19:56:39 -05001541 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1542 "Issue SCR: did:x%x",
1543 ndlp->nlp_DID, 0, 0);
1544
dea31012005-04-17 16:05:31 -05001545 phba->fc_stat.elsXmitSCR++;
1546 elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
dea31012005-04-17 16:05:31 -05001547 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
James Smart329f9bc2007-04-25 09:53:01 -04001548 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05001549 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001550 return 1;
dea31012005-04-17 16:05:31 -05001551 }
James Smart329f9bc2007-04-25 09:53:01 -04001552 lpfc_nlp_put(ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001553 return 0;
dea31012005-04-17 16:05:31 -05001554}
1555
1556static int
James Smart2e0fef82007-06-17 19:56:36 -05001557lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
dea31012005-04-17 16:05:31 -05001558{
James Smart2e0fef82007-06-17 19:56:36 -05001559 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001560 IOCB_t *icmd;
1561 struct lpfc_iocbq *elsiocb;
1562 struct lpfc_sli_ring *pring;
1563 struct lpfc_sli *psli;
1564 FARP *fp;
1565 uint8_t *pcmd;
1566 uint32_t *lp;
1567 uint16_t cmdsize;
1568 struct lpfc_nodelist *ondlp;
1569 struct lpfc_nodelist *ndlp;
1570
1571 psli = &phba->sli;
1572 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
James Smart92d7f7b2007-06-17 19:56:38 -05001573 cmdsize = (sizeof(uint32_t) + sizeof(FARP));
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001574 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
1575 if (!ndlp)
1576 return 1;
dea31012005-04-17 16:05:31 -05001577
James Smart2e0fef82007-06-17 19:56:36 -05001578 lpfc_nlp_init(vport, ndlp, nportid);
1579
1580 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
1581 ndlp->nlp_DID, ELS_CMD_RNID);
James Smart488d1462006-03-07 15:02:37 -05001582 if (!elsiocb) {
James Smart329f9bc2007-04-25 09:53:01 -04001583 lpfc_nlp_put(ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001584 return 1;
dea31012005-04-17 16:05:31 -05001585 }
1586
1587 icmd = &elsiocb->iocb;
1588 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1589
1590 *((uint32_t *) (pcmd)) = ELS_CMD_FARPR;
James Smart92d7f7b2007-06-17 19:56:38 -05001591 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05001592
1593 /* Fill in FARPR payload */
1594 fp = (FARP *) (pcmd);
James Smart92d7f7b2007-06-17 19:56:38 -05001595 memset(fp, 0, sizeof(FARP));
dea31012005-04-17 16:05:31 -05001596 lp = (uint32_t *) pcmd;
1597 *lp++ = be32_to_cpu(nportid);
James Smart2e0fef82007-06-17 19:56:36 -05001598 *lp++ = be32_to_cpu(vport->fc_myDID);
dea31012005-04-17 16:05:31 -05001599 fp->Rflags = 0;
1600 fp->Mflags = (FARP_MATCH_PORT | FARP_MATCH_NODE);
1601
James Smart92d7f7b2007-06-17 19:56:38 -05001602 memcpy(&fp->RportName, &vport->fc_portname, sizeof(struct lpfc_name));
1603 memcpy(&fp->RnodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
James Smart2e0fef82007-06-17 19:56:36 -05001604 ondlp = lpfc_findnode_did(vport, nportid);
1605 if (ondlp) {
dea31012005-04-17 16:05:31 -05001606 memcpy(&fp->OportName, &ondlp->nlp_portname,
James Smart92d7f7b2007-06-17 19:56:38 -05001607 sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05001608 memcpy(&fp->OnodeName, &ondlp->nlp_nodename,
James Smart92d7f7b2007-06-17 19:56:38 -05001609 sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05001610 }
1611
James Smart858c9f62007-06-17 19:56:39 -05001612 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1613 "Issue FARPR: did:x%x",
1614 ndlp->nlp_DID, 0, 0);
1615
dea31012005-04-17 16:05:31 -05001616 phba->fc_stat.elsXmitFARPR++;
1617 elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
dea31012005-04-17 16:05:31 -05001618 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
James Smart329f9bc2007-04-25 09:53:01 -04001619 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05001620 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001621 return 1;
dea31012005-04-17 16:05:31 -05001622 }
James Smart329f9bc2007-04-25 09:53:01 -04001623 lpfc_nlp_put(ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001624 return 0;
dea31012005-04-17 16:05:31 -05001625}
1626
1627void
James Smart2e0fef82007-06-17 19:56:36 -05001628lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp)
James Smartfdcebe22006-03-07 15:04:01 -05001629{
James Smart2e0fef82007-06-17 19:56:36 -05001630 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1631
1632 spin_lock_irq(shost->host_lock);
James Smartfdcebe22006-03-07 15:04:01 -05001633 nlp->nlp_flag &= ~NLP_DELAY_TMO;
James Smart2e0fef82007-06-17 19:56:36 -05001634 spin_unlock_irq(shost->host_lock);
James Smartfdcebe22006-03-07 15:04:01 -05001635 del_timer_sync(&nlp->nlp_delayfunc);
1636 nlp->nlp_last_elscmd = 0;
1637
1638 if (!list_empty(&nlp->els_retry_evt.evt_listp))
1639 list_del_init(&nlp->els_retry_evt.evt_listp);
1640
1641 if (nlp->nlp_flag & NLP_NPR_2B_DISC) {
James Smart2e0fef82007-06-17 19:56:36 -05001642 spin_lock_irq(shost->host_lock);
James Smartfdcebe22006-03-07 15:04:01 -05001643 nlp->nlp_flag &= ~NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -05001644 spin_unlock_irq(shost->host_lock);
1645 if (vport->num_disc_nodes) {
James Smartfdcebe22006-03-07 15:04:01 -05001646 /* Check to see if there are more
1647 * PLOGIs to be sent
1648 */
James Smart2e0fef82007-06-17 19:56:36 -05001649 lpfc_more_plogi(vport);
James Smartfdcebe22006-03-07 15:04:01 -05001650
James Smart2e0fef82007-06-17 19:56:36 -05001651 if (vport->num_disc_nodes == 0) {
1652 spin_lock_irq(shost->host_lock);
1653 vport->fc_flag &= ~FC_NDISC_ACTIVE;
1654 spin_unlock_irq(shost->host_lock);
1655 lpfc_can_disctmo(vport);
James Smarted957682007-06-17 19:56:37 -05001656 lpfc_end_rscn(vport);
James Smartfdcebe22006-03-07 15:04:01 -05001657 }
1658 }
1659 }
1660 return;
1661}
1662
1663void
dea31012005-04-17 16:05:31 -05001664lpfc_els_retry_delay(unsigned long ptr)
1665{
James Smart2e0fef82007-06-17 19:56:36 -05001666 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) ptr;
1667 struct lpfc_vport *vport = ndlp->vport;
James Smart2e0fef82007-06-17 19:56:36 -05001668 struct lpfc_hba *phba = vport->phba;
James Smart92d7f7b2007-06-17 19:56:38 -05001669 unsigned long flags;
James Smart2e0fef82007-06-17 19:56:36 -05001670 struct lpfc_work_evt *evtp = &ndlp->els_retry_evt;
dea31012005-04-17 16:05:31 -05001671
James Smart2e0fef82007-06-17 19:56:36 -05001672 ndlp = (struct lpfc_nodelist *) ptr;
1673 phba = ndlp->vport->phba;
dea31012005-04-17 16:05:31 -05001674 evtp = &ndlp->els_retry_evt;
1675
James Smart92d7f7b2007-06-17 19:56:38 -05001676 spin_lock_irqsave(&phba->hbalock, flags);
dea31012005-04-17 16:05:31 -05001677 if (!list_empty(&evtp->evt_listp)) {
James Smart92d7f7b2007-06-17 19:56:38 -05001678 spin_unlock_irqrestore(&phba->hbalock, flags);
dea31012005-04-17 16:05:31 -05001679 return;
1680 }
1681
1682 evtp->evt_arg1 = ndlp;
1683 evtp->evt = LPFC_EVT_ELS_RETRY;
1684 list_add_tail(&evtp->evt_listp, &phba->work_list);
1685 if (phba->work_wait)
James Smart92d7f7b2007-06-17 19:56:38 -05001686 lpfc_worker_wake_up(phba);
dea31012005-04-17 16:05:31 -05001687
James Smart92d7f7b2007-06-17 19:56:38 -05001688 spin_unlock_irqrestore(&phba->hbalock, flags);
dea31012005-04-17 16:05:31 -05001689 return;
1690}
1691
1692void
1693lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp)
1694{
James Smart2e0fef82007-06-17 19:56:36 -05001695 struct lpfc_vport *vport = ndlp->vport;
1696 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1697 uint32_t cmd, did, retry;
dea31012005-04-17 16:05:31 -05001698
James Smart2e0fef82007-06-17 19:56:36 -05001699 spin_lock_irq(shost->host_lock);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001700 did = ndlp->nlp_DID;
1701 cmd = ndlp->nlp_last_elscmd;
1702 ndlp->nlp_last_elscmd = 0;
dea31012005-04-17 16:05:31 -05001703
1704 if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
James Smart2e0fef82007-06-17 19:56:36 -05001705 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001706 return;
1707 }
1708
1709 ndlp->nlp_flag &= ~NLP_DELAY_TMO;
James Smart2e0fef82007-06-17 19:56:36 -05001710 spin_unlock_irq(shost->host_lock);
James Smart1a169682006-03-07 15:04:06 -05001711 /*
1712 * If a discovery event readded nlp_delayfunc after timer
1713 * firing and before processing the timer, cancel the
1714 * nlp_delayfunc.
1715 */
1716 del_timer_sync(&ndlp->nlp_delayfunc);
dea31012005-04-17 16:05:31 -05001717 retry = ndlp->nlp_retry;
1718
1719 switch (cmd) {
1720 case ELS_CMD_FLOGI:
James Smart2e0fef82007-06-17 19:56:36 -05001721 lpfc_issue_els_flogi(vport, ndlp, retry);
dea31012005-04-17 16:05:31 -05001722 break;
1723 case ELS_CMD_PLOGI:
James Smart2e0fef82007-06-17 19:56:36 -05001724 if (!lpfc_issue_els_plogi(vport, ndlp->nlp_DID, retry)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001725 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001726 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
Jamie Wellnitz6ad42532006-02-28 19:25:16 -05001727 }
dea31012005-04-17 16:05:31 -05001728 break;
1729 case ELS_CMD_ADISC:
James Smart2e0fef82007-06-17 19:56:36 -05001730 if (!lpfc_issue_els_adisc(vport, ndlp, retry)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001731 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001732 lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
Jamie Wellnitz6ad42532006-02-28 19:25:16 -05001733 }
dea31012005-04-17 16:05:31 -05001734 break;
1735 case ELS_CMD_PRLI:
James Smart2e0fef82007-06-17 19:56:36 -05001736 if (!lpfc_issue_els_prli(vport, ndlp, retry)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001737 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001738 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
Jamie Wellnitz6ad42532006-02-28 19:25:16 -05001739 }
dea31012005-04-17 16:05:31 -05001740 break;
1741 case ELS_CMD_LOGO:
James Smart2e0fef82007-06-17 19:56:36 -05001742 if (!lpfc_issue_els_logo(vport, ndlp, retry)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001743 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001744 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
Jamie Wellnitz6ad42532006-02-28 19:25:16 -05001745 }
dea31012005-04-17 16:05:31 -05001746 break;
James Smart92d7f7b2007-06-17 19:56:38 -05001747 case ELS_CMD_FDISC:
1748 lpfc_issue_els_fdisc(vport, ndlp, retry);
1749 break;
dea31012005-04-17 16:05:31 -05001750 }
1751 return;
1752}
1753
1754static int
James Smart2e0fef82007-06-17 19:56:36 -05001755lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1756 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05001757{
James Smart2e0fef82007-06-17 19:56:36 -05001758 struct lpfc_vport *vport = cmdiocb->vport;
1759 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1760 IOCB_t *irsp = &rspiocb->iocb;
1761 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
1762 struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
dea31012005-04-17 16:05:31 -05001763 uint32_t *elscmd;
1764 struct ls_rjt stat;
James Smart2e0fef82007-06-17 19:56:36 -05001765 int retry = 0, maxretry = lpfc_max_els_tries, delay = 0;
James Smart98c9ea52007-10-27 13:37:33 -04001766 int logerr = 0;
James Smart2e0fef82007-06-17 19:56:36 -05001767 uint32_t cmd = 0;
James Smart488d1462006-03-07 15:02:37 -05001768 uint32_t did;
dea31012005-04-17 16:05:31 -05001769
James Smart488d1462006-03-07 15:02:37 -05001770
dea31012005-04-17 16:05:31 -05001771 /* Note: context2 may be 0 for internal driver abort
1772 * of delays ELS command.
1773 */
1774
1775 if (pcmd && pcmd->virt) {
1776 elscmd = (uint32_t *) (pcmd->virt);
1777 cmd = *elscmd++;
1778 }
1779
James Smart329f9bc2007-04-25 09:53:01 -04001780 if (ndlp)
James Smart488d1462006-03-07 15:02:37 -05001781 did = ndlp->nlp_DID;
1782 else {
1783 /* We should only hit this case for retrying PLOGI */
1784 did = irsp->un.elsreq64.remoteID;
James Smart2e0fef82007-06-17 19:56:36 -05001785 ndlp = lpfc_findnode_did(vport, did);
James Smart488d1462006-03-07 15:02:37 -05001786 if (!ndlp && (cmd != ELS_CMD_PLOGI))
1787 return 1;
1788 }
1789
James Smart858c9f62007-06-17 19:56:39 -05001790 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1791 "Retry ELS: wd7:x%x wd4:x%x did:x%x",
1792 *(((uint32_t *) irsp) + 7), irsp->un.ulpWord[4], ndlp->nlp_DID);
1793
dea31012005-04-17 16:05:31 -05001794 switch (irsp->ulpStatus) {
1795 case IOSTAT_FCP_RSP_ERROR:
1796 case IOSTAT_REMOTE_STOP:
1797 break;
1798
1799 case IOSTAT_LOCAL_REJECT:
1800 switch ((irsp->un.ulpWord[4] & 0xff)) {
1801 case IOERR_LOOP_OPEN_FAILURE:
James Smart2e0fef82007-06-17 19:56:36 -05001802 if (cmd == ELS_CMD_PLOGI && cmdiocb->retry == 0)
James Smart92d7f7b2007-06-17 19:56:38 -05001803 delay = 1000;
dea31012005-04-17 16:05:31 -05001804 retry = 1;
1805 break;
1806
James Smart92d7f7b2007-06-17 19:56:38 -05001807 case IOERR_ILLEGAL_COMMAND:
1808 if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) &&
1809 (cmd == ELS_CMD_FDISC)) {
James Smarte8b62012007-08-02 11:10:09 -04001810 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
1811 "0124 FDISC failed (3/6) "
1812 "retrying...\n");
James Smart92d7f7b2007-06-17 19:56:38 -05001813 lpfc_mbx_unreg_vpi(vport);
1814 retry = 1;
James Smart51ef4c22007-08-02 11:10:31 -04001815 /* FDISC retry policy */
1816 maxretry = 48;
1817 if (cmdiocb->retry >= 32)
1818 delay = 1000;
James Smart92d7f7b2007-06-17 19:56:38 -05001819 }
1820 break;
1821
dea31012005-04-17 16:05:31 -05001822 case IOERR_NO_RESOURCES:
James Smart98c9ea52007-10-27 13:37:33 -04001823 logerr = 1; /* HBA out of resources */
James Smart858c9f62007-06-17 19:56:39 -05001824 retry = 1;
1825 if (cmdiocb->retry > 100)
1826 delay = 100;
1827 maxretry = 250;
1828 break;
1829
1830 case IOERR_ILLEGAL_FRAME:
James Smart92d7f7b2007-06-17 19:56:38 -05001831 delay = 100;
dea31012005-04-17 16:05:31 -05001832 retry = 1;
1833 break;
1834
James Smart858c9f62007-06-17 19:56:39 -05001835 case IOERR_SEQUENCE_TIMEOUT:
dea31012005-04-17 16:05:31 -05001836 case IOERR_INVALID_RPI:
1837 retry = 1;
1838 break;
1839 }
1840 break;
1841
1842 case IOSTAT_NPORT_RJT:
1843 case IOSTAT_FABRIC_RJT:
1844 if (irsp->un.ulpWord[4] & RJT_UNAVAIL_TEMP) {
1845 retry = 1;
1846 break;
1847 }
1848 break;
1849
1850 case IOSTAT_NPORT_BSY:
1851 case IOSTAT_FABRIC_BSY:
James Smart98c9ea52007-10-27 13:37:33 -04001852 logerr = 1; /* Fabric / Remote NPort out of resources */
dea31012005-04-17 16:05:31 -05001853 retry = 1;
1854 break;
1855
1856 case IOSTAT_LS_RJT:
1857 stat.un.lsRjtError = be32_to_cpu(irsp->un.ulpWord[4]);
1858 /* Added for Vendor specifc support
1859 * Just keep retrying for these Rsn / Exp codes
1860 */
1861 switch (stat.un.b.lsRjtRsnCode) {
1862 case LSRJT_UNABLE_TPC:
1863 if (stat.un.b.lsRjtRsnCodeExp ==
1864 LSEXP_CMD_IN_PROGRESS) {
1865 if (cmd == ELS_CMD_PLOGI) {
James Smart92d7f7b2007-06-17 19:56:38 -05001866 delay = 1000;
dea31012005-04-17 16:05:31 -05001867 maxretry = 48;
1868 }
1869 retry = 1;
1870 break;
1871 }
1872 if (cmd == ELS_CMD_PLOGI) {
James Smart92d7f7b2007-06-17 19:56:38 -05001873 delay = 1000;
dea31012005-04-17 16:05:31 -05001874 maxretry = lpfc_max_els_tries + 1;
1875 retry = 1;
1876 break;
1877 }
James Smart92d7f7b2007-06-17 19:56:38 -05001878 if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
1879 (cmd == ELS_CMD_FDISC) &&
1880 (stat.un.b.lsRjtRsnCodeExp == LSEXP_OUT_OF_RESOURCE)){
James Smarte8b62012007-08-02 11:10:09 -04001881 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
1882 "0125 FDISC Failed (x%x). "
1883 "Fabric out of resources\n",
1884 stat.un.lsRjtError);
James Smart92d7f7b2007-06-17 19:56:38 -05001885 lpfc_vport_set_state(vport,
1886 FC_VPORT_NO_FABRIC_RSCS);
1887 }
dea31012005-04-17 16:05:31 -05001888 break;
1889
1890 case LSRJT_LOGICAL_BSY:
James Smart858c9f62007-06-17 19:56:39 -05001891 if ((cmd == ELS_CMD_PLOGI) ||
1892 (cmd == ELS_CMD_PRLI)) {
James Smart92d7f7b2007-06-17 19:56:38 -05001893 delay = 1000;
dea31012005-04-17 16:05:31 -05001894 maxretry = 48;
James Smart92d7f7b2007-06-17 19:56:38 -05001895 } else if (cmd == ELS_CMD_FDISC) {
James Smart51ef4c22007-08-02 11:10:31 -04001896 /* FDISC retry policy */
1897 maxretry = 48;
1898 if (cmdiocb->retry >= 32)
1899 delay = 1000;
dea31012005-04-17 16:05:31 -05001900 }
1901 retry = 1;
1902 break;
James Smart92d7f7b2007-06-17 19:56:38 -05001903
1904 case LSRJT_LOGICAL_ERR:
1905 case LSRJT_PROTOCOL_ERR:
1906 if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
1907 (cmd == ELS_CMD_FDISC) &&
1908 ((stat.un.b.lsRjtRsnCodeExp == LSEXP_INVALID_PNAME) ||
1909 (stat.un.b.lsRjtRsnCodeExp == LSEXP_INVALID_NPORT_ID))
1910 ) {
James Smarte8b62012007-08-02 11:10:09 -04001911 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
1912 "0123 FDISC Failed (x%x). "
1913 "Fabric Detected Bad WWN\n",
1914 stat.un.lsRjtError);
James Smart92d7f7b2007-06-17 19:56:38 -05001915 lpfc_vport_set_state(vport,
1916 FC_VPORT_FABRIC_REJ_WWN);
1917 }
1918 break;
dea31012005-04-17 16:05:31 -05001919 }
1920 break;
1921
1922 case IOSTAT_INTERMED_RSP:
1923 case IOSTAT_BA_RJT:
1924 break;
1925
1926 default:
1927 break;
1928 }
1929
James Smart488d1462006-03-07 15:02:37 -05001930 if (did == FDMI_DID)
dea31012005-04-17 16:05:31 -05001931 retry = 1;
dea31012005-04-17 16:05:31 -05001932
James Smart98c9ea52007-10-27 13:37:33 -04001933 if ((cmd == ELS_CMD_FLOGI) &&
1934 (phba->fc_topology != TOPOLOGY_LOOP)) {
1935 /* FLOGI retry policy */
1936 retry = 1;
1937 maxretry = 48;
1938 if (cmdiocb->retry >= 32)
1939 delay = 1000;
1940 }
1941
dea31012005-04-17 16:05:31 -05001942 if ((++cmdiocb->retry) >= maxretry) {
1943 phba->fc_stat.elsRetryExceeded++;
1944 retry = 0;
1945 }
1946
James Smarted957682007-06-17 19:56:37 -05001947 if ((vport->load_flag & FC_UNLOADING) != 0)
1948 retry = 0;
1949
dea31012005-04-17 16:05:31 -05001950 if (retry) {
1951
1952 /* Retry ELS command <elsCmd> to remote NPORT <did> */
James Smarte8b62012007-08-02 11:10:09 -04001953 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
1954 "0107 Retry ELS command x%x to remote "
1955 "NPORT x%x Data: x%x x%x\n",
1956 cmd, did, cmdiocb->retry, delay);
dea31012005-04-17 16:05:31 -05001957
James Smart858c9f62007-06-17 19:56:39 -05001958 if (((cmd == ELS_CMD_PLOGI) || (cmd == ELS_CMD_ADISC)) &&
1959 ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
1960 ((irsp->un.ulpWord[4] & 0xff) != IOERR_NO_RESOURCES))) {
1961 /* Don't reset timer for no resources */
1962
dea31012005-04-17 16:05:31 -05001963 /* If discovery / RSCN timer is running, reset it */
James Smart2e0fef82007-06-17 19:56:36 -05001964 if (timer_pending(&vport->fc_disctmo) ||
James Smart92d7f7b2007-06-17 19:56:38 -05001965 (vport->fc_flag & FC_RSCN_MODE))
James Smart2e0fef82007-06-17 19:56:36 -05001966 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -05001967 }
1968
1969 phba->fc_stat.elsXmitRetry++;
James Smart488d1462006-03-07 15:02:37 -05001970 if (ndlp && delay) {
dea31012005-04-17 16:05:31 -05001971 phba->fc_stat.elsDelayRetry++;
1972 ndlp->nlp_retry = cmdiocb->retry;
1973
James Smart92d7f7b2007-06-17 19:56:38 -05001974 /* delay is specified in milliseconds */
1975 mod_timer(&ndlp->nlp_delayfunc,
1976 jiffies + msecs_to_jiffies(delay));
James Smart2e0fef82007-06-17 19:56:36 -05001977 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001978 ndlp->nlp_flag |= NLP_DELAY_TMO;
James Smart2e0fef82007-06-17 19:56:36 -05001979 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001980
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001981 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart858c9f62007-06-17 19:56:39 -05001982 if (cmd == ELS_CMD_PRLI)
1983 lpfc_nlp_set_state(vport, ndlp,
1984 NLP_STE_REG_LOGIN_ISSUE);
1985 else
1986 lpfc_nlp_set_state(vport, ndlp,
1987 NLP_STE_NPR_NODE);
dea31012005-04-17 16:05:31 -05001988 ndlp->nlp_last_elscmd = cmd;
1989
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001990 return 1;
dea31012005-04-17 16:05:31 -05001991 }
1992 switch (cmd) {
1993 case ELS_CMD_FLOGI:
James Smart2e0fef82007-06-17 19:56:36 -05001994 lpfc_issue_els_flogi(vport, ndlp, cmdiocb->retry);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001995 return 1;
James Smart92d7f7b2007-06-17 19:56:38 -05001996 case ELS_CMD_FDISC:
1997 lpfc_issue_els_fdisc(vport, ndlp, cmdiocb->retry);
1998 return 1;
dea31012005-04-17 16:05:31 -05001999 case ELS_CMD_PLOGI:
James Smart488d1462006-03-07 15:02:37 -05002000 if (ndlp) {
2001 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002002 lpfc_nlp_set_state(vport, ndlp,
James Smartde0c5b32007-04-25 09:52:27 -04002003 NLP_STE_PLOGI_ISSUE);
James Smart488d1462006-03-07 15:02:37 -05002004 }
James Smart2e0fef82007-06-17 19:56:36 -05002005 lpfc_issue_els_plogi(vport, did, cmdiocb->retry);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002006 return 1;
dea31012005-04-17 16:05:31 -05002007 case ELS_CMD_ADISC:
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05002008 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002009 lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
2010 lpfc_issue_els_adisc(vport, ndlp, cmdiocb->retry);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002011 return 1;
dea31012005-04-17 16:05:31 -05002012 case ELS_CMD_PRLI:
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05002013 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002014 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
2015 lpfc_issue_els_prli(vport, ndlp, cmdiocb->retry);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002016 return 1;
dea31012005-04-17 16:05:31 -05002017 case ELS_CMD_LOGO:
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_NPR_NODE);
2020 lpfc_issue_els_logo(vport, ndlp, cmdiocb->retry);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002021 return 1;
dea31012005-04-17 16:05:31 -05002022 }
2023 }
dea31012005-04-17 16:05:31 -05002024 /* No retry ELS command <elsCmd> to remote NPORT <did> */
James Smart98c9ea52007-10-27 13:37:33 -04002025 if (logerr) {
2026 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
2027 "0137 No retry ELS command x%x to remote "
2028 "NPORT x%x: Out of Resources: Error:x%x/%x\n",
2029 cmd, did, irsp->ulpStatus,
2030 irsp->un.ulpWord[4]);
2031 }
2032 else {
2033 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
James Smarta58cbd52007-08-02 11:09:43 -04002034 "0108 No retry ELS command x%x to remote "
2035 "NPORT x%x Retried:%d Error:x%x/%x\n",
2036 cmd, did, cmdiocb->retry, irsp->ulpStatus,
2037 irsp->un.ulpWord[4]);
James Smart98c9ea52007-10-27 13:37:33 -04002038 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002039 return 0;
dea31012005-04-17 16:05:31 -05002040}
2041
2042int
James Smart87af33f2007-10-27 13:37:43 -04002043lpfc_els_free_data(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr1)
2044{
2045 struct lpfc_dmabuf *buf_ptr;
2046
2047 /* Free the response before processing the command. */
2048 if (!list_empty(&buf_ptr1->list)) {
2049 list_remove_head(&buf_ptr1->list, buf_ptr,
2050 struct lpfc_dmabuf,
2051 list);
2052 lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
2053 kfree(buf_ptr);
2054 }
2055 lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys);
2056 kfree(buf_ptr1);
2057 return 0;
2058}
2059
2060int
2061lpfc_els_free_bpl(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr)
2062{
2063 lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
2064 kfree(buf_ptr);
2065 return 0;
2066}
2067
2068int
James Smart329f9bc2007-04-25 09:53:01 -04002069lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
dea31012005-04-17 16:05:31 -05002070{
2071 struct lpfc_dmabuf *buf_ptr, *buf_ptr1;
James Smarta8adb832007-10-27 13:37:53 -04002072 struct lpfc_nodelist *ndlp;
dea31012005-04-17 16:05:31 -05002073
James Smarta8adb832007-10-27 13:37:53 -04002074 ndlp = (struct lpfc_nodelist *)elsiocb->context1;
2075 if (ndlp) {
2076 if (ndlp->nlp_flag & NLP_DEFER_RM) {
2077 lpfc_nlp_put(ndlp);
2078
2079 /* If the ndlp is not being used by another discovery
2080 * thread, free it.
2081 */
2082 if (!lpfc_nlp_not_used(ndlp)) {
2083 /* If ndlp is being used by another discovery
2084 * thread, just clear NLP_DEFER_RM
2085 */
2086 ndlp->nlp_flag &= ~NLP_DEFER_RM;
2087 }
2088 }
2089 else
2090 lpfc_nlp_put(ndlp);
James Smart329f9bc2007-04-25 09:53:01 -04002091 elsiocb->context1 = NULL;
2092 }
dea31012005-04-17 16:05:31 -05002093 /* context2 = cmd, context2->next = rsp, context3 = bpl */
2094 if (elsiocb->context2) {
2095 buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
James Smart87af33f2007-10-27 13:37:43 -04002096 lpfc_els_free_data(phba, buf_ptr1);
dea31012005-04-17 16:05:31 -05002097 }
2098
2099 if (elsiocb->context3) {
2100 buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3;
James Smart87af33f2007-10-27 13:37:43 -04002101 lpfc_els_free_bpl(phba, buf_ptr);
dea31012005-04-17 16:05:31 -05002102 }
James Bottomley604a3e32005-10-29 10:28:33 -05002103 lpfc_sli_release_iocbq(phba, elsiocb);
dea31012005-04-17 16:05:31 -05002104 return 0;
2105}
2106
2107static void
James Smart2e0fef82007-06-17 19:56:36 -05002108lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
2109 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05002110{
James Smart2e0fef82007-06-17 19:56:36 -05002111 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
2112 struct lpfc_vport *vport = cmdiocb->vport;
James Smart858c9f62007-06-17 19:56:39 -05002113 IOCB_t *irsp;
2114
2115 irsp = &rspiocb->iocb;
2116 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2117 "ACC LOGO cmpl: status:x%x/x%x did:x%x",
2118 irsp->ulpStatus, irsp->un.ulpWord[4], ndlp->nlp_DID);
dea31012005-04-17 16:05:31 -05002119 /* ACC to LOGO completes to NPort <nlp_DID> */
James Smarte8b62012007-08-02 11:10:09 -04002120 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
2121 "0109 ACC to LOGO completes to NPort x%x "
2122 "Data: x%x x%x x%x\n",
2123 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
2124 ndlp->nlp_rpi);
James Smart87af33f2007-10-27 13:37:43 -04002125
2126 if (ndlp->nlp_state == NLP_STE_NPR_NODE) {
2127 /* NPort Recovery mode or node is just allocated */
2128 if (!lpfc_nlp_not_used(ndlp)) {
2129 /* If the ndlp is being used by another discovery
2130 * thread, just unregister the RPI.
2131 */
2132 lpfc_unreg_rpi(vport, ndlp);
2133 }
dea31012005-04-17 16:05:31 -05002134 }
2135 lpfc_els_free_iocb(phba, cmdiocb);
2136 return;
2137}
2138
James Smart858c9f62007-06-17 19:56:39 -05002139void
2140lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
2141{
2142 struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
2143 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
2144
2145 pmb->context1 = NULL;
2146 lpfc_mbuf_free(phba, mp->virt, mp->phys);
2147 kfree(mp);
2148 mempool_free(pmb, phba->mbox_mem_pool);
James Smarta8adb832007-10-27 13:37:53 -04002149 if (ndlp) {
2150 lpfc_nlp_put(ndlp);
James Smart98c9ea52007-10-27 13:37:33 -04002151
James Smarta8adb832007-10-27 13:37:53 -04002152 /* This is the end of the default RPI cleanup logic for this
2153 * ndlp. If no other discovery threads are using this ndlp.
2154 * we should free all resources associated with it.
2155 */
2156 lpfc_nlp_not_used(ndlp);
2157 }
James Smart858c9f62007-06-17 19:56:39 -05002158 return;
2159}
2160
dea31012005-04-17 16:05:31 -05002161static void
James Smart858c9f62007-06-17 19:56:39 -05002162lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
James Smart329f9bc2007-04-25 09:53:01 -04002163 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05002164{
James Smart2e0fef82007-06-17 19:56:36 -05002165 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
2166 struct lpfc_vport *vport = ndlp ? ndlp->vport : NULL;
2167 struct Scsi_Host *shost = vport ? lpfc_shost_from_vport(vport) : NULL;
James Smart87af33f2007-10-27 13:37:43 -04002168 IOCB_t *irsp;
2169 uint8_t *pcmd;
dea31012005-04-17 16:05:31 -05002170 LPFC_MBOXQ_t *mbox = NULL;
James Smart2e0fef82007-06-17 19:56:36 -05002171 struct lpfc_dmabuf *mp = NULL;
James Smart87af33f2007-10-27 13:37:43 -04002172 uint32_t ls_rjt = 0;
dea31012005-04-17 16:05:31 -05002173
James Smart33ccf8d2006-08-17 11:57:58 -04002174 irsp = &rspiocb->iocb;
2175
dea31012005-04-17 16:05:31 -05002176 if (cmdiocb->context_un.mbox)
2177 mbox = cmdiocb->context_un.mbox;
2178
James Smart87af33f2007-10-27 13:37:43 -04002179 /* First determine if this is a LS_RJT cmpl */
2180 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) cmdiocb->context2)->virt);
2181 if (*((uint32_t *) (pcmd)) == ELS_CMD_LS_RJT) {
2182 /* A LS_RJT associated with Default RPI cleanup
2183 * has its own seperate code path.
2184 */
2185 if (!(ndlp->nlp_flag & NLP_RM_DFLT_RPI))
2186 ls_rjt = 1;
2187 }
2188
dea31012005-04-17 16:05:31 -05002189 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -05002190 if (!ndlp || lpfc_els_chk_latt(vport)) {
dea31012005-04-17 16:05:31 -05002191 if (mbox) {
James Smart14691152006-12-02 13:34:28 -05002192 mp = (struct lpfc_dmabuf *) mbox->context1;
2193 if (mp) {
2194 lpfc_mbuf_free(phba, mp->virt, mp->phys);
2195 kfree(mp);
2196 }
James Smart329f9bc2007-04-25 09:53:01 -04002197 mempool_free(mbox, phba->mbox_mem_pool);
dea31012005-04-17 16:05:31 -05002198 }
James Smart98c9ea52007-10-27 13:37:33 -04002199 if (ndlp && (ndlp->nlp_flag & NLP_RM_DFLT_RPI))
2200 if (lpfc_nlp_not_used(ndlp))
2201 ndlp = NULL;
dea31012005-04-17 16:05:31 -05002202 goto out;
2203 }
2204
James Smart858c9f62007-06-17 19:56:39 -05002205 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
James Smart51ef4c22007-08-02 11:10:31 -04002206 "ELS rsp cmpl: status:x%x/x%x did:x%x",
James Smart858c9f62007-06-17 19:56:39 -05002207 irsp->ulpStatus, irsp->un.ulpWord[4],
James Smart51ef4c22007-08-02 11:10:31 -04002208 cmdiocb->iocb.un.elsreq64.remoteID);
dea31012005-04-17 16:05:31 -05002209 /* ELS response tag <ulpIoTag> completes */
James Smarte8b62012007-08-02 11:10:09 -04002210 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
2211 "0110 ELS response tag x%x completes "
2212 "Data: x%x x%x x%x x%x x%x x%x x%x\n",
2213 cmdiocb->iocb.ulpIoTag, rspiocb->iocb.ulpStatus,
2214 rspiocb->iocb.un.ulpWord[4], rspiocb->iocb.ulpTimeout,
2215 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
2216 ndlp->nlp_rpi);
dea31012005-04-17 16:05:31 -05002217 if (mbox) {
2218 if ((rspiocb->iocb.ulpStatus == 0)
2219 && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) {
James Smart2e0fef82007-06-17 19:56:36 -05002220 lpfc_unreg_rpi(vport, ndlp);
James Smart329f9bc2007-04-25 09:53:01 -04002221 mbox->context2 = lpfc_nlp_get(ndlp);
James Smart2e0fef82007-06-17 19:56:36 -05002222 mbox->vport = vport;
James Smart858c9f62007-06-17 19:56:39 -05002223 if (ndlp->nlp_flag & NLP_RM_DFLT_RPI) {
2224 mbox->mbox_flag |= LPFC_MBX_IMED_UNREG;
2225 mbox->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;
2226 }
2227 else {
2228 mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
2229 ndlp->nlp_prev_state = ndlp->nlp_state;
2230 lpfc_nlp_set_state(vport, ndlp,
James Smart2e0fef82007-06-17 19:56:36 -05002231 NLP_STE_REG_LOGIN_ISSUE);
James Smart858c9f62007-06-17 19:56:39 -05002232 }
James Smart0b727fe2007-10-27 13:37:25 -04002233 if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
dea31012005-04-17 16:05:31 -05002234 != MBX_NOT_FINISHED) {
2235 goto out;
2236 }
James Smart98c9ea52007-10-27 13:37:33 -04002237
2238 /* ELS rsp: Cannot issue reg_login for <NPortid> */
2239 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
2240 "0138 ELS rsp: Cannot issue reg_login for x%x "
2241 "Data: x%x x%x x%x\n",
2242 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
2243 ndlp->nlp_rpi);
2244
2245 if (lpfc_nlp_not_used(ndlp))
2246 ndlp = NULL;
dea31012005-04-17 16:05:31 -05002247 } else {
James Smart858c9f62007-06-17 19:56:39 -05002248 /* Do not drop node for lpfc_els_abort'ed ELS cmds */
2249 if (!lpfc_error_lost_link(irsp) &&
2250 ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
James Smart98c9ea52007-10-27 13:37:33 -04002251 if (lpfc_nlp_not_used(ndlp))
2252 ndlp = NULL;
dea31012005-04-17 16:05:31 -05002253 }
2254 }
James Smart14691152006-12-02 13:34:28 -05002255 mp = (struct lpfc_dmabuf *) mbox->context1;
2256 if (mp) {
2257 lpfc_mbuf_free(phba, mp->virt, mp->phys);
2258 kfree(mp);
2259 }
2260 mempool_free(mbox, phba->mbox_mem_pool);
dea31012005-04-17 16:05:31 -05002261 }
2262out:
2263 if (ndlp) {
James Smart2e0fef82007-06-17 19:56:36 -05002264 spin_lock_irq(shost->host_lock);
James Smart858c9f62007-06-17 19:56:39 -05002265 ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI);
James Smart2e0fef82007-06-17 19:56:36 -05002266 spin_unlock_irq(shost->host_lock);
James Smart87af33f2007-10-27 13:37:43 -04002267
2268 /* If the node is not being used by another discovery thread,
2269 * and we are sending a reject, we are done with it.
2270 * Release driver reference count here and free associated
2271 * resources.
2272 */
2273 if (ls_rjt)
2274 lpfc_nlp_not_used(ndlp);
dea31012005-04-17 16:05:31 -05002275 }
James Smart87af33f2007-10-27 13:37:43 -04002276
dea31012005-04-17 16:05:31 -05002277 lpfc_els_free_iocb(phba, cmdiocb);
2278 return;
2279}
2280
2281int
James Smart2e0fef82007-06-17 19:56:36 -05002282lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
2283 struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp,
James Smart51ef4c22007-08-02 11:10:31 -04002284 LPFC_MBOXQ_t *mbox)
dea31012005-04-17 16:05:31 -05002285{
James Smart2e0fef82007-06-17 19:56:36 -05002286 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
2287 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002288 IOCB_t *icmd;
2289 IOCB_t *oldcmd;
2290 struct lpfc_iocbq *elsiocb;
2291 struct lpfc_sli_ring *pring;
2292 struct lpfc_sli *psli;
2293 uint8_t *pcmd;
2294 uint16_t cmdsize;
2295 int rc;
James Smart82d9a2a2006-04-15 11:53:05 -04002296 ELS_PKT *els_pkt_ptr;
dea31012005-04-17 16:05:31 -05002297
2298 psli = &phba->sli;
2299 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
2300 oldcmd = &oldiocb->iocb;
2301
2302 switch (flag) {
2303 case ELS_CMD_ACC:
James Smart92d7f7b2007-06-17 19:56:38 -05002304 cmdsize = sizeof(uint32_t);
James Smart2e0fef82007-06-17 19:56:36 -05002305 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
2306 ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
James Smart488d1462006-03-07 15:02:37 -05002307 if (!elsiocb) {
James Smart2e0fef82007-06-17 19:56:36 -05002308 spin_lock_irq(shost->host_lock);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05002309 ndlp->nlp_flag &= ~NLP_LOGO_ACC;
James Smart2e0fef82007-06-17 19:56:36 -05002310 spin_unlock_irq(shost->host_lock);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002311 return 1;
dea31012005-04-17 16:05:31 -05002312 }
James Smart2e0fef82007-06-17 19:56:36 -05002313
dea31012005-04-17 16:05:31 -05002314 icmd = &elsiocb->iocb;
2315 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
2316 pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2317 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
James Smart92d7f7b2007-06-17 19:56:38 -05002318 pcmd += sizeof(uint32_t);
James Smart858c9f62007-06-17 19:56:39 -05002319
2320 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2321 "Issue ACC: did:x%x flg:x%x",
2322 ndlp->nlp_DID, ndlp->nlp_flag, 0);
dea31012005-04-17 16:05:31 -05002323 break;
2324 case ELS_CMD_PLOGI:
James Smart92d7f7b2007-06-17 19:56:38 -05002325 cmdsize = (sizeof(struct serv_parm) + sizeof(uint32_t));
James Smart2e0fef82007-06-17 19:56:36 -05002326 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
2327 ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
James Smart488d1462006-03-07 15:02:37 -05002328 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002329 return 1;
James Smart488d1462006-03-07 15:02:37 -05002330
dea31012005-04-17 16:05:31 -05002331 icmd = &elsiocb->iocb;
2332 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
2333 pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2334
2335 if (mbox)
2336 elsiocb->context_un.mbox = mbox;
2337
2338 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
James Smart92d7f7b2007-06-17 19:56:38 -05002339 pcmd += sizeof(uint32_t);
2340 memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
James Smart858c9f62007-06-17 19:56:39 -05002341
2342 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2343 "Issue ACC PLOGI: did:x%x flg:x%x",
2344 ndlp->nlp_DID, ndlp->nlp_flag, 0);
dea31012005-04-17 16:05:31 -05002345 break;
James Smart82d9a2a2006-04-15 11:53:05 -04002346 case ELS_CMD_PRLO:
James Smart92d7f7b2007-06-17 19:56:38 -05002347 cmdsize = sizeof(uint32_t) + sizeof(PRLO);
James Smart2e0fef82007-06-17 19:56:36 -05002348 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
James Smart82d9a2a2006-04-15 11:53:05 -04002349 ndlp, ndlp->nlp_DID, ELS_CMD_PRLO);
2350 if (!elsiocb)
2351 return 1;
2352
2353 icmd = &elsiocb->iocb;
2354 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
2355 pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2356
2357 memcpy(pcmd, ((struct lpfc_dmabuf *) oldiocb->context2)->virt,
James Smart92d7f7b2007-06-17 19:56:38 -05002358 sizeof(uint32_t) + sizeof(PRLO));
James Smart82d9a2a2006-04-15 11:53:05 -04002359 *((uint32_t *) (pcmd)) = ELS_CMD_PRLO_ACC;
2360 els_pkt_ptr = (ELS_PKT *) pcmd;
2361 els_pkt_ptr->un.prlo.acceptRspCode = PRLO_REQ_EXECUTED;
James Smart858c9f62007-06-17 19:56:39 -05002362
2363 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2364 "Issue ACC PRLO: did:x%x flg:x%x",
2365 ndlp->nlp_DID, ndlp->nlp_flag, 0);
James Smart82d9a2a2006-04-15 11:53:05 -04002366 break;
dea31012005-04-17 16:05:31 -05002367 default:
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002368 return 1;
dea31012005-04-17 16:05:31 -05002369 }
dea31012005-04-17 16:05:31 -05002370 /* Xmit ELS ACC response tag <ulpIoTag> */
James Smarte8b62012007-08-02 11:10:09 -04002371 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
2372 "0128 Xmit ELS ACC response tag x%x, XRI: x%x, "
2373 "DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x\n",
2374 elsiocb->iotag, elsiocb->iocb.ulpContext,
2375 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
2376 ndlp->nlp_rpi);
dea31012005-04-17 16:05:31 -05002377 if (ndlp->nlp_flag & NLP_LOGO_ACC) {
James Smart2e0fef82007-06-17 19:56:36 -05002378 spin_lock_irq(shost->host_lock);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002379 ndlp->nlp_flag &= ~NLP_LOGO_ACC;
James Smart2e0fef82007-06-17 19:56:36 -05002380 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05002381 elsiocb->iocb_cmpl = lpfc_cmpl_els_logo_acc;
2382 } else {
James Smart858c9f62007-06-17 19:56:39 -05002383 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
dea31012005-04-17 16:05:31 -05002384 }
2385
2386 phba->fc_stat.elsXmitACC++;
dea31012005-04-17 16:05:31 -05002387 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
dea31012005-04-17 16:05:31 -05002388 if (rc == IOCB_ERROR) {
2389 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002390 return 1;
dea31012005-04-17 16:05:31 -05002391 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002392 return 0;
dea31012005-04-17 16:05:31 -05002393}
2394
2395int
James Smart2e0fef82007-06-17 19:56:36 -05002396lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
James Smart858c9f62007-06-17 19:56:39 -05002397 struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp,
2398 LPFC_MBOXQ_t *mbox)
dea31012005-04-17 16:05:31 -05002399{
James Smart2e0fef82007-06-17 19:56:36 -05002400 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002401 IOCB_t *icmd;
2402 IOCB_t *oldcmd;
2403 struct lpfc_iocbq *elsiocb;
2404 struct lpfc_sli_ring *pring;
2405 struct lpfc_sli *psli;
2406 uint8_t *pcmd;
2407 uint16_t cmdsize;
2408 int rc;
2409
2410 psli = &phba->sli;
2411 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
2412
James Smart92d7f7b2007-06-17 19:56:38 -05002413 cmdsize = 2 * sizeof(uint32_t);
James Smart2e0fef82007-06-17 19:56:36 -05002414 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
2415 ndlp->nlp_DID, ELS_CMD_LS_RJT);
James Smart488d1462006-03-07 15:02:37 -05002416 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002417 return 1;
dea31012005-04-17 16:05:31 -05002418
2419 icmd = &elsiocb->iocb;
2420 oldcmd = &oldiocb->iocb;
2421 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
2422 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2423
2424 *((uint32_t *) (pcmd)) = ELS_CMD_LS_RJT;
James Smart92d7f7b2007-06-17 19:56:38 -05002425 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05002426 *((uint32_t *) (pcmd)) = rejectError;
2427
James Smart51ef4c22007-08-02 11:10:31 -04002428 if (mbox)
James Smart858c9f62007-06-17 19:56:39 -05002429 elsiocb->context_un.mbox = mbox;
James Smart858c9f62007-06-17 19:56:39 -05002430
dea31012005-04-17 16:05:31 -05002431 /* Xmit ELS RJT <err> response tag <ulpIoTag> */
James Smarte8b62012007-08-02 11:10:09 -04002432 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
2433 "0129 Xmit ELS RJT x%x response tag x%x "
2434 "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, "
2435 "rpi x%x\n",
2436 rejectError, elsiocb->iotag,
2437 elsiocb->iocb.ulpContext, ndlp->nlp_DID,
2438 ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
James Smart858c9f62007-06-17 19:56:39 -05002439 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2440 "Issue LS_RJT: did:x%x flg:x%x err:x%x",
2441 ndlp->nlp_DID, ndlp->nlp_flag, rejectError);
2442
dea31012005-04-17 16:05:31 -05002443 phba->fc_stat.elsXmitLSRJT++;
James Smart858c9f62007-06-17 19:56:39 -05002444 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
dea31012005-04-17 16:05:31 -05002445 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
James Smart51ef4c22007-08-02 11:10:31 -04002446
dea31012005-04-17 16:05:31 -05002447 if (rc == IOCB_ERROR) {
2448 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002449 return 1;
dea31012005-04-17 16:05:31 -05002450 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002451 return 0;
dea31012005-04-17 16:05:31 -05002452}
2453
2454int
James Smart2e0fef82007-06-17 19:56:36 -05002455lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
2456 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05002457{
James Smart2e0fef82007-06-17 19:56:36 -05002458 struct lpfc_hba *phba = vport->phba;
2459 struct lpfc_sli *psli = &phba->sli;
2460 struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
dea31012005-04-17 16:05:31 -05002461 ADISC *ap;
James Smart2e0fef82007-06-17 19:56:36 -05002462 IOCB_t *icmd, *oldcmd;
dea31012005-04-17 16:05:31 -05002463 struct lpfc_iocbq *elsiocb;
dea31012005-04-17 16:05:31 -05002464 uint8_t *pcmd;
2465 uint16_t cmdsize;
2466 int rc;
2467
James Smart92d7f7b2007-06-17 19:56:38 -05002468 cmdsize = sizeof(uint32_t) + sizeof(ADISC);
James Smart2e0fef82007-06-17 19:56:36 -05002469 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
2470 ndlp->nlp_DID, ELS_CMD_ACC);
James Smart488d1462006-03-07 15:02:37 -05002471 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002472 return 1;
dea31012005-04-17 16:05:31 -05002473
dea31012005-04-17 16:05:31 -05002474 icmd = &elsiocb->iocb;
2475 oldcmd = &oldiocb->iocb;
2476 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
James Smart5b8bd0c2007-04-25 09:52:49 -04002477
2478 /* Xmit ADISC ACC response tag <ulpIoTag> */
James Smarte8b62012007-08-02 11:10:09 -04002479 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
2480 "0130 Xmit ADISC ACC response iotag x%x xri: "
2481 "x%x, did x%x, nlp_flag x%x, nlp_state x%x rpi x%x\n",
2482 elsiocb->iotag, elsiocb->iocb.ulpContext,
2483 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
2484 ndlp->nlp_rpi);
dea31012005-04-17 16:05:31 -05002485 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2486
2487 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
James Smart92d7f7b2007-06-17 19:56:38 -05002488 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05002489
2490 ap = (ADISC *) (pcmd);
2491 ap->hardAL_PA = phba->fc_pref_ALPA;
James Smart92d7f7b2007-06-17 19:56:38 -05002492 memcpy(&ap->portName, &vport->fc_portname, sizeof(struct lpfc_name));
2493 memcpy(&ap->nodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
James Smart2e0fef82007-06-17 19:56:36 -05002494 ap->DID = be32_to_cpu(vport->fc_myDID);
dea31012005-04-17 16:05:31 -05002495
James Smart858c9f62007-06-17 19:56:39 -05002496 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2497 "Issue ACC ADISC: did:x%x flg:x%x",
2498 ndlp->nlp_DID, ndlp->nlp_flag, 0);
2499
dea31012005-04-17 16:05:31 -05002500 phba->fc_stat.elsXmitACC++;
James Smart858c9f62007-06-17 19:56:39 -05002501 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
dea31012005-04-17 16:05:31 -05002502 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
dea31012005-04-17 16:05:31 -05002503 if (rc == IOCB_ERROR) {
2504 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002505 return 1;
dea31012005-04-17 16:05:31 -05002506 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002507 return 0;
dea31012005-04-17 16:05:31 -05002508}
2509
2510int
James Smart2e0fef82007-06-17 19:56:36 -05002511lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
James Smart5b8bd0c2007-04-25 09:52:49 -04002512 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05002513{
James Smart2e0fef82007-06-17 19:56:36 -05002514 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002515 PRLI *npr;
2516 lpfc_vpd_t *vpd;
2517 IOCB_t *icmd;
2518 IOCB_t *oldcmd;
2519 struct lpfc_iocbq *elsiocb;
2520 struct lpfc_sli_ring *pring;
2521 struct lpfc_sli *psli;
2522 uint8_t *pcmd;
2523 uint16_t cmdsize;
2524 int rc;
2525
2526 psli = &phba->sli;
2527 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
2528
James Smart92d7f7b2007-06-17 19:56:38 -05002529 cmdsize = sizeof(uint32_t) + sizeof(PRLI);
James Smart2e0fef82007-06-17 19:56:36 -05002530 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
James Smart92d7f7b2007-06-17 19:56:38 -05002531 ndlp->nlp_DID, (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK)));
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002532 if (!elsiocb)
2533 return 1;
dea31012005-04-17 16:05:31 -05002534
dea31012005-04-17 16:05:31 -05002535 icmd = &elsiocb->iocb;
2536 oldcmd = &oldiocb->iocb;
2537 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
James Smart5b8bd0c2007-04-25 09:52:49 -04002538 /* Xmit PRLI ACC response tag <ulpIoTag> */
James Smarte8b62012007-08-02 11:10:09 -04002539 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
2540 "0131 Xmit PRLI ACC response tag x%x xri x%x, "
2541 "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
2542 elsiocb->iotag, elsiocb->iocb.ulpContext,
2543 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
2544 ndlp->nlp_rpi);
dea31012005-04-17 16:05:31 -05002545 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2546
2547 *((uint32_t *) (pcmd)) = (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK));
James Smart92d7f7b2007-06-17 19:56:38 -05002548 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05002549
2550 /* For PRLI, remainder of payload is PRLI parameter page */
James Smart92d7f7b2007-06-17 19:56:38 -05002551 memset(pcmd, 0, sizeof(PRLI));
dea31012005-04-17 16:05:31 -05002552
2553 npr = (PRLI *) pcmd;
2554 vpd = &phba->vpd;
2555 /*
2556 * If our firmware version is 3.20 or later,
2557 * set the following bits for FC-TAPE support.
2558 */
2559 if (vpd->rev.feaLevelHigh >= 0x02) {
2560 npr->ConfmComplAllowed = 1;
2561 npr->Retry = 1;
2562 npr->TaskRetryIdReq = 1;
2563 }
2564
2565 npr->acceptRspCode = PRLI_REQ_EXECUTED;
2566 npr->estabImagePair = 1;
2567 npr->readXferRdyDis = 1;
2568 npr->ConfmComplAllowed = 1;
2569
2570 npr->prliType = PRLI_FCP_TYPE;
2571 npr->initiatorFunc = 1;
2572
James Smart858c9f62007-06-17 19:56:39 -05002573 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2574 "Issue ACC PRLI: did:x%x flg:x%x",
2575 ndlp->nlp_DID, ndlp->nlp_flag, 0);
2576
dea31012005-04-17 16:05:31 -05002577 phba->fc_stat.elsXmitACC++;
James Smart858c9f62007-06-17 19:56:39 -05002578 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
dea31012005-04-17 16:05:31 -05002579
dea31012005-04-17 16:05:31 -05002580 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
dea31012005-04-17 16:05:31 -05002581 if (rc == IOCB_ERROR) {
2582 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002583 return 1;
dea31012005-04-17 16:05:31 -05002584 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002585 return 0;
dea31012005-04-17 16:05:31 -05002586}
2587
2588static int
James Smart2e0fef82007-06-17 19:56:36 -05002589lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format,
James Smart329f9bc2007-04-25 09:53:01 -04002590 struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05002591{
James Smart2e0fef82007-06-17 19:56:36 -05002592 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002593 RNID *rn;
James Smart2e0fef82007-06-17 19:56:36 -05002594 IOCB_t *icmd, *oldcmd;
dea31012005-04-17 16:05:31 -05002595 struct lpfc_iocbq *elsiocb;
2596 struct lpfc_sli_ring *pring;
2597 struct lpfc_sli *psli;
2598 uint8_t *pcmd;
2599 uint16_t cmdsize;
2600 int rc;
2601
2602 psli = &phba->sli;
2603 pring = &psli->ring[LPFC_ELS_RING];
2604
James Smart92d7f7b2007-06-17 19:56:38 -05002605 cmdsize = sizeof(uint32_t) + sizeof(uint32_t)
2606 + (2 * sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05002607 if (format)
James Smart92d7f7b2007-06-17 19:56:38 -05002608 cmdsize += sizeof(RNID_TOP_DISC);
dea31012005-04-17 16:05:31 -05002609
James Smart2e0fef82007-06-17 19:56:36 -05002610 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
2611 ndlp->nlp_DID, ELS_CMD_ACC);
James Smart488d1462006-03-07 15:02:37 -05002612 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002613 return 1;
dea31012005-04-17 16:05:31 -05002614
dea31012005-04-17 16:05:31 -05002615 icmd = &elsiocb->iocb;
2616 oldcmd = &oldiocb->iocb;
2617 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
James Smart5b8bd0c2007-04-25 09:52:49 -04002618 /* Xmit RNID ACC response tag <ulpIoTag> */
James Smarte8b62012007-08-02 11:10:09 -04002619 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
2620 "0132 Xmit RNID ACC response tag x%x xri x%x\n",
2621 elsiocb->iotag, elsiocb->iocb.ulpContext);
dea31012005-04-17 16:05:31 -05002622 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
dea31012005-04-17 16:05:31 -05002623 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
James Smart92d7f7b2007-06-17 19:56:38 -05002624 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05002625
James Smart92d7f7b2007-06-17 19:56:38 -05002626 memset(pcmd, 0, sizeof(RNID));
dea31012005-04-17 16:05:31 -05002627 rn = (RNID *) (pcmd);
2628 rn->Format = format;
James Smart92d7f7b2007-06-17 19:56:38 -05002629 rn->CommonLen = (2 * sizeof(struct lpfc_name));
2630 memcpy(&rn->portName, &vport->fc_portname, sizeof(struct lpfc_name));
2631 memcpy(&rn->nodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05002632 switch (format) {
2633 case 0:
2634 rn->SpecificLen = 0;
2635 break;
2636 case RNID_TOPOLOGY_DISC:
James Smart92d7f7b2007-06-17 19:56:38 -05002637 rn->SpecificLen = sizeof(RNID_TOP_DISC);
dea31012005-04-17 16:05:31 -05002638 memcpy(&rn->un.topologyDisc.portName,
James Smart92d7f7b2007-06-17 19:56:38 -05002639 &vport->fc_portname, sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05002640 rn->un.topologyDisc.unitType = RNID_HBA;
2641 rn->un.topologyDisc.physPort = 0;
2642 rn->un.topologyDisc.attachedNodes = 0;
2643 break;
2644 default:
2645 rn->CommonLen = 0;
2646 rn->SpecificLen = 0;
2647 break;
2648 }
2649
James Smart858c9f62007-06-17 19:56:39 -05002650 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2651 "Issue ACC RNID: did:x%x flg:x%x",
2652 ndlp->nlp_DID, ndlp->nlp_flag, 0);
2653
dea31012005-04-17 16:05:31 -05002654 phba->fc_stat.elsXmitACC++;
James Smart858c9f62007-06-17 19:56:39 -05002655 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
James Smart329f9bc2007-04-25 09:53:01 -04002656 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05002657 elsiocb->context1 = NULL; /* Don't need ndlp for cmpl,
2658 * it could be freed */
2659
dea31012005-04-17 16:05:31 -05002660 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
dea31012005-04-17 16:05:31 -05002661 if (rc == IOCB_ERROR) {
2662 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002663 return 1;
dea31012005-04-17 16:05:31 -05002664 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002665 return 0;
dea31012005-04-17 16:05:31 -05002666}
2667
2668int
James Smart2e0fef82007-06-17 19:56:36 -05002669lpfc_els_disc_adisc(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05002670{
James Smart2e0fef82007-06-17 19:56:36 -05002671 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05002672 struct lpfc_nodelist *ndlp, *next_ndlp;
James Smart2e0fef82007-06-17 19:56:36 -05002673 int sentadisc = 0;
dea31012005-04-17 16:05:31 -05002674
James Smart685f0bf2007-04-25 09:53:08 -04002675 /* go thru NPR nodes and issue any remaining ELS ADISCs */
James Smart2e0fef82007-06-17 19:56:36 -05002676 list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
James Smart685f0bf2007-04-25 09:53:08 -04002677 if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
2678 (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
2679 (ndlp->nlp_flag & NLP_NPR_ADISC) != 0) {
James Smart2e0fef82007-06-17 19:56:36 -05002680 spin_lock_irq(shost->host_lock);
James Smart685f0bf2007-04-25 09:53:08 -04002681 ndlp->nlp_flag &= ~NLP_NPR_ADISC;
James Smart2e0fef82007-06-17 19:56:36 -05002682 spin_unlock_irq(shost->host_lock);
James Smart685f0bf2007-04-25 09:53:08 -04002683 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002684 lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
2685 lpfc_issue_els_adisc(vport, ndlp, 0);
James Smart685f0bf2007-04-25 09:53:08 -04002686 sentadisc++;
James Smart2e0fef82007-06-17 19:56:36 -05002687 vport->num_disc_nodes++;
2688 if (vport->num_disc_nodes >=
James Smart3de2a652007-08-02 11:09:59 -04002689 vport->cfg_discovery_threads) {
James Smart2e0fef82007-06-17 19:56:36 -05002690 spin_lock_irq(shost->host_lock);
2691 vport->fc_flag |= FC_NLP_MORE;
2692 spin_unlock_irq(shost->host_lock);
James Smart685f0bf2007-04-25 09:53:08 -04002693 break;
dea31012005-04-17 16:05:31 -05002694 }
2695 }
2696 }
2697 if (sentadisc == 0) {
James Smart2e0fef82007-06-17 19:56:36 -05002698 spin_lock_irq(shost->host_lock);
2699 vport->fc_flag &= ~FC_NLP_MORE;
2700 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05002701 }
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05002702 return sentadisc;
dea31012005-04-17 16:05:31 -05002703}
2704
2705int
James Smart2e0fef82007-06-17 19:56:36 -05002706lpfc_els_disc_plogi(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05002707{
James Smart2e0fef82007-06-17 19:56:36 -05002708 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05002709 struct lpfc_nodelist *ndlp, *next_ndlp;
James Smart2e0fef82007-06-17 19:56:36 -05002710 int sentplogi = 0;
dea31012005-04-17 16:05:31 -05002711
James Smart2e0fef82007-06-17 19:56:36 -05002712 /* go thru NPR nodes and issue any remaining ELS PLOGIs */
2713 list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
James Smart685f0bf2007-04-25 09:53:08 -04002714 if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
2715 (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
2716 (ndlp->nlp_flag & NLP_DELAY_TMO) == 0 &&
2717 (ndlp->nlp_flag & NLP_NPR_ADISC) == 0) {
2718 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002719 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
2720 lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
James Smart685f0bf2007-04-25 09:53:08 -04002721 sentplogi++;
James Smart2e0fef82007-06-17 19:56:36 -05002722 vport->num_disc_nodes++;
2723 if (vport->num_disc_nodes >=
James Smart3de2a652007-08-02 11:09:59 -04002724 vport->cfg_discovery_threads) {
James Smart2e0fef82007-06-17 19:56:36 -05002725 spin_lock_irq(shost->host_lock);
2726 vport->fc_flag |= FC_NLP_MORE;
2727 spin_unlock_irq(shost->host_lock);
James Smart685f0bf2007-04-25 09:53:08 -04002728 break;
dea31012005-04-17 16:05:31 -05002729 }
2730 }
2731 }
James Smart87af33f2007-10-27 13:37:43 -04002732 if (sentplogi) {
2733 lpfc_set_disctmo(vport);
2734 }
2735 else {
James Smart2e0fef82007-06-17 19:56:36 -05002736 spin_lock_irq(shost->host_lock);
2737 vport->fc_flag &= ~FC_NLP_MORE;
2738 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05002739 }
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05002740 return sentplogi;
dea31012005-04-17 16:05:31 -05002741}
2742
James Smart92d7f7b2007-06-17 19:56:38 -05002743void
James Smart2e0fef82007-06-17 19:56:36 -05002744lpfc_els_flush_rscn(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05002745{
James Smart2e0fef82007-06-17 19:56:36 -05002746 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
2747 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002748 int i;
2749
James Smart2e0fef82007-06-17 19:56:36 -05002750 for (i = 0; i < vport->fc_rscn_id_cnt; i++) {
James Smart92d7f7b2007-06-17 19:56:38 -05002751 lpfc_in_buf_free(phba, vport->fc_rscn_id_list[i]);
James Smart2e0fef82007-06-17 19:56:36 -05002752 vport->fc_rscn_id_list[i] = NULL;
dea31012005-04-17 16:05:31 -05002753 }
James Smart2e0fef82007-06-17 19:56:36 -05002754 spin_lock_irq(shost->host_lock);
2755 vport->fc_rscn_id_cnt = 0;
2756 vport->fc_flag &= ~(FC_RSCN_MODE | FC_RSCN_DISCOVERY);
2757 spin_unlock_irq(shost->host_lock);
2758 lpfc_can_disctmo(vport);
dea31012005-04-17 16:05:31 -05002759}
2760
2761int
James Smart2e0fef82007-06-17 19:56:36 -05002762lpfc_rscn_payload_check(struct lpfc_vport *vport, uint32_t did)
dea31012005-04-17 16:05:31 -05002763{
2764 D_ID ns_did;
2765 D_ID rscn_did;
dea31012005-04-17 16:05:31 -05002766 uint32_t *lp;
James Smart92d7f7b2007-06-17 19:56:38 -05002767 uint32_t payload_len, i;
dea31012005-04-17 16:05:31 -05002768
2769 ns_did.un.word = did;
dea31012005-04-17 16:05:31 -05002770
2771 /* Never match fabric nodes for RSCNs */
2772 if ((did & Fabric_DID_MASK) == Fabric_DID_MASK)
James Smart2e0fef82007-06-17 19:56:36 -05002773 return 0;
dea31012005-04-17 16:05:31 -05002774
2775 /* If we are doing a FULL RSCN rediscovery, match everything */
James Smart2e0fef82007-06-17 19:56:36 -05002776 if (vport->fc_flag & FC_RSCN_DISCOVERY)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002777 return did;
dea31012005-04-17 16:05:31 -05002778
James Smart2e0fef82007-06-17 19:56:36 -05002779 for (i = 0; i < vport->fc_rscn_id_cnt; i++) {
James Smart92d7f7b2007-06-17 19:56:38 -05002780 lp = vport->fc_rscn_id_list[i]->virt;
2781 payload_len = be32_to_cpu(*lp++ & ~ELS_CMD_MASK);
2782 payload_len -= sizeof(uint32_t); /* take off word 0 */
dea31012005-04-17 16:05:31 -05002783 while (payload_len) {
James Smart92d7f7b2007-06-17 19:56:38 -05002784 rscn_did.un.word = be32_to_cpu(*lp++);
2785 payload_len -= sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05002786 switch (rscn_did.un.b.resv) {
2787 case 0: /* Single N_Port ID effected */
James Smart2e0fef82007-06-17 19:56:36 -05002788 if (ns_did.un.word == rscn_did.un.word)
James Smart92d7f7b2007-06-17 19:56:38 -05002789 return did;
dea31012005-04-17 16:05:31 -05002790 break;
2791 case 1: /* Whole N_Port Area effected */
2792 if ((ns_did.un.b.domain == rscn_did.un.b.domain)
2793 && (ns_did.un.b.area == rscn_did.un.b.area))
James Smart92d7f7b2007-06-17 19:56:38 -05002794 return did;
dea31012005-04-17 16:05:31 -05002795 break;
2796 case 2: /* Whole N_Port Domain effected */
2797 if (ns_did.un.b.domain == rscn_did.un.b.domain)
James Smart92d7f7b2007-06-17 19:56:38 -05002798 return did;
dea31012005-04-17 16:05:31 -05002799 break;
2800 default:
James Smart2e0fef82007-06-17 19:56:36 -05002801 /* Unknown Identifier in RSCN node */
James Smarte8b62012007-08-02 11:10:09 -04002802 lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
2803 "0217 Unknown Identifier in "
2804 "RSCN payload Data: x%x\n",
2805 rscn_did.un.word);
James Smart92d7f7b2007-06-17 19:56:38 -05002806 case 3: /* Whole Fabric effected */
2807 return did;
dea31012005-04-17 16:05:31 -05002808 }
2809 }
James Smart92d7f7b2007-06-17 19:56:38 -05002810 }
2811 return 0;
dea31012005-04-17 16:05:31 -05002812}
2813
2814static int
James Smart2e0fef82007-06-17 19:56:36 -05002815lpfc_rscn_recovery_check(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05002816{
James Smart685f0bf2007-04-25 09:53:08 -04002817 struct lpfc_nodelist *ndlp = NULL;
dea31012005-04-17 16:05:31 -05002818
2819 /* Look at all nodes effected by pending RSCNs and move
James Smart685f0bf2007-04-25 09:53:08 -04002820 * them to NPR state.
dea31012005-04-17 16:05:31 -05002821 */
James Smart685f0bf2007-04-25 09:53:08 -04002822
James Smart2e0fef82007-06-17 19:56:36 -05002823 list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
James Smart685f0bf2007-04-25 09:53:08 -04002824 if (ndlp->nlp_state == NLP_STE_UNUSED_NODE ||
James Smart2e0fef82007-06-17 19:56:36 -05002825 lpfc_rscn_payload_check(vport, ndlp->nlp_DID) == 0)
dea31012005-04-17 16:05:31 -05002826 continue;
2827
James Smart2e0fef82007-06-17 19:56:36 -05002828 lpfc_disc_state_machine(vport, ndlp, NULL,
James Smart92d7f7b2007-06-17 19:56:38 -05002829 NLP_EVT_DEVICE_RECOVERY);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05002830
James Smart685f0bf2007-04-25 09:53:08 -04002831 /*
2832 * Make sure NLP_DELAY_TMO is NOT running after a device
2833 * recovery event.
2834 */
2835 if (ndlp->nlp_flag & NLP_DELAY_TMO)
James Smart2e0fef82007-06-17 19:56:36 -05002836 lpfc_cancel_retry_delay_tmo(vport, ndlp);
dea31012005-04-17 16:05:31 -05002837 }
James Smart685f0bf2007-04-25 09:53:08 -04002838
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002839 return 0;
dea31012005-04-17 16:05:31 -05002840}
2841
2842static int
James Smart2e0fef82007-06-17 19:56:36 -05002843lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
James Smart51ef4c22007-08-02 11:10:31 -04002844 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05002845{
James Smart2e0fef82007-06-17 19:56:36 -05002846 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
2847 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002848 struct lpfc_dmabuf *pcmd;
James Smart92d7f7b2007-06-17 19:56:38 -05002849 uint32_t *lp, *datap;
dea31012005-04-17 16:05:31 -05002850 IOCB_t *icmd;
James Smart92d7f7b2007-06-17 19:56:38 -05002851 uint32_t payload_len, length, nportid, *cmd;
2852 int rscn_cnt = vport->fc_rscn_id_cnt;
2853 int rscn_id = 0, hba_id = 0;
James Smartd2873e42006-08-18 17:46:43 -04002854 int i;
dea31012005-04-17 16:05:31 -05002855
2856 icmd = &cmdiocb->iocb;
2857 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
2858 lp = (uint32_t *) pcmd->virt;
2859
James Smart92d7f7b2007-06-17 19:56:38 -05002860 payload_len = be32_to_cpu(*lp++ & ~ELS_CMD_MASK);
2861 payload_len -= sizeof(uint32_t); /* take off word 0 */
dea31012005-04-17 16:05:31 -05002862 /* RSCN received */
James Smarte8b62012007-08-02 11:10:09 -04002863 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
2864 "0214 RSCN received Data: x%x x%x x%x x%x\n",
2865 vport->fc_flag, payload_len, *lp, rscn_cnt);
James Smartd2873e42006-08-18 17:46:43 -04002866 for (i = 0; i < payload_len/sizeof(uint32_t); i++)
James Smart2e0fef82007-06-17 19:56:36 -05002867 fc_host_post_event(shost, fc_get_event_number(),
James Smartd2873e42006-08-18 17:46:43 -04002868 FCH_EVT_RSCN, lp[i]);
2869
dea31012005-04-17 16:05:31 -05002870 /* If we are about to begin discovery, just ACC the RSCN.
2871 * Discovery processing will satisfy it.
2872 */
James Smart2e0fef82007-06-17 19:56:36 -05002873 if (vport->port_state <= LPFC_NS_QRY) {
James Smart858c9f62007-06-17 19:56:39 -05002874 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
2875 "RCV RSCN ignore: did:x%x/ste:x%x flg:x%x",
2876 ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
2877
James Smart51ef4c22007-08-02 11:10:31 -04002878 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002879 return 0;
dea31012005-04-17 16:05:31 -05002880 }
2881
James Smart92d7f7b2007-06-17 19:56:38 -05002882 /* If this RSCN just contains NPortIDs for other vports on this HBA,
2883 * just ACC and ignore it.
2884 */
2885 if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
James Smart3de2a652007-08-02 11:09:59 -04002886 !(vport->cfg_peer_port_login)) {
James Smart92d7f7b2007-06-17 19:56:38 -05002887 i = payload_len;
2888 datap = lp;
2889 while (i > 0) {
2890 nportid = *datap++;
2891 nportid = ((be32_to_cpu(nportid)) & Mask_DID);
2892 i -= sizeof(uint32_t);
2893 rscn_id++;
James Smart549e55c2007-08-02 11:09:51 -04002894 if (lpfc_find_vport_by_did(phba, nportid))
2895 hba_id++;
James Smart92d7f7b2007-06-17 19:56:38 -05002896 }
2897 if (rscn_id == hba_id) {
2898 /* ALL NPortIDs in RSCN are on HBA */
James Smarte8b62012007-08-02 11:10:09 -04002899 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
2900 "0214 Ignore RSCN "
2901 "Data: x%x x%x x%x x%x\n",
2902 vport->fc_flag, payload_len,
2903 *lp, rscn_cnt);
James Smart858c9f62007-06-17 19:56:39 -05002904 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
2905 "RCV RSCN vport: did:x%x/ste:x%x flg:x%x",
2906 ndlp->nlp_DID, vport->port_state,
2907 ndlp->nlp_flag);
2908
James Smart92d7f7b2007-06-17 19:56:38 -05002909 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb,
James Smart51ef4c22007-08-02 11:10:31 -04002910 ndlp, NULL);
James Smart92d7f7b2007-06-17 19:56:38 -05002911 return 0;
2912 }
2913 }
2914
dea31012005-04-17 16:05:31 -05002915 /* If we are already processing an RSCN, save the received
2916 * RSCN payload buffer, cmdiocb->context2 to process later.
2917 */
James Smart2e0fef82007-06-17 19:56:36 -05002918 if (vport->fc_flag & (FC_RSCN_MODE | FC_NDISC_ACTIVE)) {
James Smart858c9f62007-06-17 19:56:39 -05002919 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
2920 "RCV RSCN defer: did:x%x/ste:x%x flg:x%x",
2921 ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
2922
James Smart92d7f7b2007-06-17 19:56:38 -05002923 vport->fc_flag |= FC_RSCN_DEFERRED;
2924 if ((rscn_cnt < FC_MAX_HOLD_RSCN) &&
James Smart2e0fef82007-06-17 19:56:36 -05002925 !(vport->fc_flag & FC_RSCN_DISCOVERY)) {
2926 spin_lock_irq(shost->host_lock);
2927 vport->fc_flag |= FC_RSCN_MODE;
2928 spin_unlock_irq(shost->host_lock);
James Smart92d7f7b2007-06-17 19:56:38 -05002929 if (rscn_cnt) {
2930 cmd = vport->fc_rscn_id_list[rscn_cnt-1]->virt;
2931 length = be32_to_cpu(*cmd & ~ELS_CMD_MASK);
2932 }
2933 if ((rscn_cnt) &&
2934 (payload_len + length <= LPFC_BPL_SIZE)) {
2935 *cmd &= ELS_CMD_MASK;
2936 *cmd |= be32_to_cpu(payload_len + length);
2937 memcpy(((uint8_t *)cmd) + length, lp,
2938 payload_len);
2939 } else {
2940 vport->fc_rscn_id_list[rscn_cnt] = pcmd;
2941 vport->fc_rscn_id_cnt++;
2942 /* If we zero, cmdiocb->context2, the calling
2943 * routine will not try to free it.
2944 */
2945 cmdiocb->context2 = NULL;
2946 }
dea31012005-04-17 16:05:31 -05002947
2948 /* Deferred RSCN */
James Smarte8b62012007-08-02 11:10:09 -04002949 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
2950 "0235 Deferred RSCN "
2951 "Data: x%x x%x x%x\n",
2952 vport->fc_rscn_id_cnt, vport->fc_flag,
2953 vport->port_state);
dea31012005-04-17 16:05:31 -05002954 } else {
James Smart2e0fef82007-06-17 19:56:36 -05002955 spin_lock_irq(shost->host_lock);
2956 vport->fc_flag |= FC_RSCN_DISCOVERY;
2957 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05002958 /* ReDiscovery RSCN */
James Smarte8b62012007-08-02 11:10:09 -04002959 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
2960 "0234 ReDiscovery RSCN "
2961 "Data: x%x x%x x%x\n",
2962 vport->fc_rscn_id_cnt, vport->fc_flag,
2963 vport->port_state);
dea31012005-04-17 16:05:31 -05002964 }
2965 /* Send back ACC */
James Smart51ef4c22007-08-02 11:10:31 -04002966 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
dea31012005-04-17 16:05:31 -05002967
2968 /* send RECOVERY event for ALL nodes that match RSCN payload */
James Smart2e0fef82007-06-17 19:56:36 -05002969 lpfc_rscn_recovery_check(vport);
James Smart92d7f7b2007-06-17 19:56:38 -05002970 vport->fc_flag &= ~FC_RSCN_DEFERRED;
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002971 return 0;
dea31012005-04-17 16:05:31 -05002972 }
2973
James Smart858c9f62007-06-17 19:56:39 -05002974 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
2975 "RCV RSCN: did:x%x/ste:x%x flg:x%x",
2976 ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
2977
James Smart2e0fef82007-06-17 19:56:36 -05002978 spin_lock_irq(shost->host_lock);
2979 vport->fc_flag |= FC_RSCN_MODE;
2980 spin_unlock_irq(shost->host_lock);
2981 vport->fc_rscn_id_list[vport->fc_rscn_id_cnt++] = pcmd;
dea31012005-04-17 16:05:31 -05002982 /*
2983 * If we zero, cmdiocb->context2, the calling routine will
2984 * not try to free it.
2985 */
2986 cmdiocb->context2 = NULL;
2987
James Smart2e0fef82007-06-17 19:56:36 -05002988 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -05002989
2990 /* Send back ACC */
James Smart51ef4c22007-08-02 11:10:31 -04002991 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
dea31012005-04-17 16:05:31 -05002992
2993 /* send RECOVERY event for ALL nodes that match RSCN payload */
James Smart2e0fef82007-06-17 19:56:36 -05002994 lpfc_rscn_recovery_check(vport);
dea31012005-04-17 16:05:31 -05002995
James Smart2e0fef82007-06-17 19:56:36 -05002996 return lpfc_els_handle_rscn(vport);
dea31012005-04-17 16:05:31 -05002997}
2998
2999int
James Smart2e0fef82007-06-17 19:56:36 -05003000lpfc_els_handle_rscn(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05003001{
3002 struct lpfc_nodelist *ndlp;
James Smart2e0fef82007-06-17 19:56:36 -05003003 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05003004
James Smart92d7f7b2007-06-17 19:56:38 -05003005 /* Ignore RSCN if the port is being torn down. */
3006 if (vport->load_flag & FC_UNLOADING) {
3007 lpfc_els_flush_rscn(vport);
3008 return 0;
3009 }
3010
dea31012005-04-17 16:05:31 -05003011 /* Start timer for RSCN processing */
James Smart2e0fef82007-06-17 19:56:36 -05003012 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -05003013
3014 /* RSCN processed */
James Smarte8b62012007-08-02 11:10:09 -04003015 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
3016 "0215 RSCN processed Data: x%x x%x x%x x%x\n",
3017 vport->fc_flag, 0, vport->fc_rscn_id_cnt,
3018 vport->port_state);
dea31012005-04-17 16:05:31 -05003019
3020 /* To process RSCN, first compare RSCN data with NameServer */
James Smart2e0fef82007-06-17 19:56:36 -05003021 vport->fc_ns_retry = 0;
3022 ndlp = lpfc_findnode_did(vport, NameServer_DID);
James Smart685f0bf2007-04-25 09:53:08 -04003023 if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
dea31012005-04-17 16:05:31 -05003024 /* Good ndlp, issue CT Request to NameServer */
James Smart92d7f7b2007-06-17 19:56:38 -05003025 if (lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, 0, 0) == 0)
dea31012005-04-17 16:05:31 -05003026 /* Wait for NameServer query cmpl before we can
3027 continue */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003028 return 1;
dea31012005-04-17 16:05:31 -05003029 } else {
3030 /* If login to NameServer does not exist, issue one */
3031 /* Good status, issue PLOGI to NameServer */
James Smart2e0fef82007-06-17 19:56:36 -05003032 ndlp = lpfc_findnode_did(vport, NameServer_DID);
3033 if (ndlp)
dea31012005-04-17 16:05:31 -05003034 /* Wait for NameServer login cmpl before we can
3035 continue */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003036 return 1;
James Smart2e0fef82007-06-17 19:56:36 -05003037
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003038 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
3039 if (!ndlp) {
James Smart2e0fef82007-06-17 19:56:36 -05003040 lpfc_els_flush_rscn(vport);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003041 return 0;
dea31012005-04-17 16:05:31 -05003042 } else {
James Smart2e0fef82007-06-17 19:56:36 -05003043 lpfc_nlp_init(vport, ndlp, NameServer_DID);
dea31012005-04-17 16:05:31 -05003044 ndlp->nlp_type |= NLP_FABRIC;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003045 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05003046 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
3047 lpfc_issue_els_plogi(vport, NameServer_DID, 0);
dea31012005-04-17 16:05:31 -05003048 /* Wait for NameServer login cmpl before we can
3049 continue */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003050 return 1;
dea31012005-04-17 16:05:31 -05003051 }
3052 }
3053
James Smart2e0fef82007-06-17 19:56:36 -05003054 lpfc_els_flush_rscn(vport);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003055 return 0;
dea31012005-04-17 16:05:31 -05003056}
3057
3058static int
James Smart2e0fef82007-06-17 19:56:36 -05003059lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
James Smart51ef4c22007-08-02 11:10:31 -04003060 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05003061{
James Smart2e0fef82007-06-17 19:56:36 -05003062 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
3063 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05003064 struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3065 uint32_t *lp = (uint32_t *) pcmd->virt;
3066 IOCB_t *icmd = &cmdiocb->iocb;
3067 struct serv_parm *sp;
3068 LPFC_MBOXQ_t *mbox;
3069 struct ls_rjt stat;
3070 uint32_t cmd, did;
3071 int rc;
3072
3073 cmd = *lp++;
3074 sp = (struct serv_parm *) lp;
3075
3076 /* FLOGI received */
3077
James Smart2e0fef82007-06-17 19:56:36 -05003078 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -05003079
3080 if (phba->fc_topology == TOPOLOGY_LOOP) {
3081 /* We should never receive a FLOGI in loop mode, ignore it */
3082 did = icmd->un.elsreq64.remoteID;
3083
3084 /* An FLOGI ELS command <elsCmd> was received from DID <did> in
3085 Loop Mode */
James Smarte8b62012007-08-02 11:10:09 -04003086 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
3087 "0113 An FLOGI ELS command x%x was "
3088 "received from DID x%x in Loop Mode\n",
3089 cmd, did);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003090 return 1;
dea31012005-04-17 16:05:31 -05003091 }
3092
3093 did = Fabric_DID;
3094
James Smart2e0fef82007-06-17 19:56:36 -05003095 if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3))) {
dea31012005-04-17 16:05:31 -05003096 /* For a FLOGI we accept, then if our portname is greater
3097 * then the remote portname we initiate Nport login.
3098 */
3099
James Smart2e0fef82007-06-17 19:56:36 -05003100 rc = memcmp(&vport->fc_portname, &sp->portName,
James Smart92d7f7b2007-06-17 19:56:38 -05003101 sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05003102
3103 if (!rc) {
James Smart2e0fef82007-06-17 19:56:36 -05003104 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
3105 if (!mbox)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003106 return 1;
James Smart2e0fef82007-06-17 19:56:36 -05003107
dea31012005-04-17 16:05:31 -05003108 lpfc_linkdown(phba);
3109 lpfc_init_link(phba, mbox,
3110 phba->cfg_topology,
3111 phba->cfg_link_speed);
3112 mbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
3113 mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
James Smarted957682007-06-17 19:56:37 -05003114 mbox->vport = vport;
James Smart0b727fe2007-10-27 13:37:25 -04003115 rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
James Smart5b8bd0c2007-04-25 09:52:49 -04003116 lpfc_set_loopback_flag(phba);
dea31012005-04-17 16:05:31 -05003117 if (rc == MBX_NOT_FINISHED) {
James Smart329f9bc2007-04-25 09:53:01 -04003118 mempool_free(mbox, phba->mbox_mem_pool);
dea31012005-04-17 16:05:31 -05003119 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003120 return 1;
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05003121 } else if (rc > 0) { /* greater than */
James Smart2e0fef82007-06-17 19:56:36 -05003122 spin_lock_irq(shost->host_lock);
3123 vport->fc_flag |= FC_PT2PT_PLOGI;
3124 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05003125 }
James Smart2e0fef82007-06-17 19:56:36 -05003126 spin_lock_irq(shost->host_lock);
3127 vport->fc_flag |= FC_PT2PT;
3128 vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
3129 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05003130 } else {
3131 /* Reject this request because invalid parameters */
3132 stat.un.b.lsRjtRsvd0 = 0;
3133 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
3134 stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
3135 stat.un.b.vendorUnique = 0;
James Smart858c9f62007-06-17 19:56:39 -05003136 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
3137 NULL);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003138 return 1;
dea31012005-04-17 16:05:31 -05003139 }
3140
3141 /* Send back ACC */
James Smart51ef4c22007-08-02 11:10:31 -04003142 lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL);
dea31012005-04-17 16:05:31 -05003143
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003144 return 0;
dea31012005-04-17 16:05:31 -05003145}
3146
3147static int
James Smart2e0fef82007-06-17 19:56:36 -05003148lpfc_els_rcv_rnid(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3149 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05003150{
3151 struct lpfc_dmabuf *pcmd;
3152 uint32_t *lp;
3153 IOCB_t *icmd;
3154 RNID *rn;
3155 struct ls_rjt stat;
3156 uint32_t cmd, did;
3157
3158 icmd = &cmdiocb->iocb;
3159 did = icmd->un.elsreq64.remoteID;
3160 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3161 lp = (uint32_t *) pcmd->virt;
3162
3163 cmd = *lp++;
3164 rn = (RNID *) lp;
3165
3166 /* RNID received */
3167
3168 switch (rn->Format) {
3169 case 0:
3170 case RNID_TOPOLOGY_DISC:
3171 /* Send back ACC */
James Smart2e0fef82007-06-17 19:56:36 -05003172 lpfc_els_rsp_rnid_acc(vport, rn->Format, cmdiocb, ndlp);
dea31012005-04-17 16:05:31 -05003173 break;
3174 default:
3175 /* Reject this request because format not supported */
3176 stat.un.b.lsRjtRsvd0 = 0;
3177 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
3178 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
3179 stat.un.b.vendorUnique = 0;
James Smart858c9f62007-06-17 19:56:39 -05003180 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
3181 NULL);
dea31012005-04-17 16:05:31 -05003182 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003183 return 0;
dea31012005-04-17 16:05:31 -05003184}
3185
3186static int
James Smart2e0fef82007-06-17 19:56:36 -05003187lpfc_els_rcv_lirr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3188 struct lpfc_nodelist *ndlp)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003189{
3190 struct ls_rjt stat;
3191
3192 /* For now, unconditionally reject this command */
3193 stat.un.b.lsRjtRsvd0 = 0;
3194 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
3195 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
3196 stat.un.b.vendorUnique = 0;
James Smart858c9f62007-06-17 19:56:39 -05003197 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003198 return 0;
3199}
3200
Jamie Wellnitz082c0262006-02-28 19:25:30 -05003201static void
James Smart329f9bc2007-04-25 09:53:01 -04003202lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003203{
James Smart2e0fef82007-06-17 19:56:36 -05003204 struct lpfc_sli *psli = &phba->sli;
3205 struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003206 MAILBOX_t *mb;
3207 IOCB_t *icmd;
3208 RPS_RSP *rps_rsp;
3209 uint8_t *pcmd;
3210 struct lpfc_iocbq *elsiocb;
3211 struct lpfc_nodelist *ndlp;
3212 uint16_t xri, status;
3213 uint32_t cmdsize;
3214
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003215 mb = &pmb->mb;
3216
3217 ndlp = (struct lpfc_nodelist *) pmb->context2;
3218 xri = (uint16_t) ((unsigned long)(pmb->context1));
Randy Dunlap041976f2006-06-25 01:58:51 -07003219 pmb->context1 = NULL;
3220 pmb->context2 = NULL;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003221
3222 if (mb->mbxStatus) {
James Smart329f9bc2007-04-25 09:53:01 -04003223 mempool_free(pmb, phba->mbox_mem_pool);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003224 return;
3225 }
3226
3227 cmdsize = sizeof(RPS_RSP) + sizeof(uint32_t);
James Smart329f9bc2007-04-25 09:53:01 -04003228 mempool_free(pmb, phba->mbox_mem_pool);
James Smart2e0fef82007-06-17 19:56:36 -05003229 elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize,
3230 lpfc_max_els_tries, ndlp,
3231 ndlp->nlp_DID, ELS_CMD_ACC);
James Smart329f9bc2007-04-25 09:53:01 -04003232 lpfc_nlp_put(ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003233 if (!elsiocb)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003234 return;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003235
3236 icmd = &elsiocb->iocb;
3237 icmd->ulpContext = xri;
3238
3239 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
3240 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
James Smart92d7f7b2007-06-17 19:56:38 -05003241 pcmd += sizeof(uint32_t); /* Skip past command */
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003242 rps_rsp = (RPS_RSP *)pcmd;
3243
3244 if (phba->fc_topology != TOPOLOGY_LOOP)
3245 status = 0x10;
3246 else
3247 status = 0x8;
James Smart2e0fef82007-06-17 19:56:36 -05003248 if (phba->pport->fc_flag & FC_FABRIC)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003249 status |= 0x4;
3250
3251 rps_rsp->rsvd1 = 0;
3252 rps_rsp->portStatus = be16_to_cpu(status);
3253 rps_rsp->linkFailureCnt = be32_to_cpu(mb->un.varRdLnk.linkFailureCnt);
3254 rps_rsp->lossSyncCnt = be32_to_cpu(mb->un.varRdLnk.lossSyncCnt);
3255 rps_rsp->lossSignalCnt = be32_to_cpu(mb->un.varRdLnk.lossSignalCnt);
3256 rps_rsp->primSeqErrCnt = be32_to_cpu(mb->un.varRdLnk.primSeqErrCnt);
3257 rps_rsp->invalidXmitWord = be32_to_cpu(mb->un.varRdLnk.invalidXmitWord);
3258 rps_rsp->crcCnt = be32_to_cpu(mb->un.varRdLnk.crcCnt);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003259 /* Xmit ELS RPS ACC response tag <ulpIoTag> */
James Smarte8b62012007-08-02 11:10:09 -04003260 lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS,
3261 "0118 Xmit ELS RPS ACC response tag x%x xri x%x, "
3262 "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
3263 elsiocb->iotag, elsiocb->iocb.ulpContext,
3264 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
3265 ndlp->nlp_rpi);
James Smart858c9f62007-06-17 19:56:39 -05003266 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003267 phba->fc_stat.elsXmitACC++;
James Smarted957682007-06-17 19:56:37 -05003268 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003269 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003270 return;
3271}
3272
3273static int
James Smart2e0fef82007-06-17 19:56:36 -05003274lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3275 struct lpfc_nodelist *ndlp)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003276{
James Smart2e0fef82007-06-17 19:56:36 -05003277 struct lpfc_hba *phba = vport->phba;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003278 uint32_t *lp;
3279 uint8_t flag;
3280 LPFC_MBOXQ_t *mbox;
3281 struct lpfc_dmabuf *pcmd;
3282 RPS *rps;
3283 struct ls_rjt stat;
3284
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05003285 if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
3286 (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) {
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003287 stat.un.b.lsRjtRsvd0 = 0;
3288 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
3289 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
3290 stat.un.b.vendorUnique = 0;
James Smart858c9f62007-06-17 19:56:39 -05003291 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
3292 NULL);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003293 }
3294
3295 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3296 lp = (uint32_t *) pcmd->virt;
3297 flag = (be32_to_cpu(*lp++) & 0xf);
3298 rps = (RPS *) lp;
3299
3300 if ((flag == 0) ||
3301 ((flag == 1) && (be32_to_cpu(rps->un.portNum) == 0)) ||
James Smart2e0fef82007-06-17 19:56:36 -05003302 ((flag == 2) && (memcmp(&rps->un.portName, &vport->fc_portname,
James Smart92d7f7b2007-06-17 19:56:38 -05003303 sizeof(struct lpfc_name)) == 0))) {
James Smart2e0fef82007-06-17 19:56:36 -05003304
James Smart92d7f7b2007-06-17 19:56:38 -05003305 printk("Fix me....\n");
3306 dump_stack();
James Smart2e0fef82007-06-17 19:56:36 -05003307 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC);
3308 if (mbox) {
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003309 lpfc_read_lnk_stat(phba, mbox);
3310 mbox->context1 =
James Smart92d7f7b2007-06-17 19:56:38 -05003311 (void *)((unsigned long) cmdiocb->iocb.ulpContext);
James Smart329f9bc2007-04-25 09:53:01 -04003312 mbox->context2 = lpfc_nlp_get(ndlp);
James Smart92d7f7b2007-06-17 19:56:38 -05003313 mbox->vport = vport;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003314 mbox->mbox_cmpl = lpfc_els_rsp_rps_acc;
James Smart0b727fe2007-10-27 13:37:25 -04003315 if (lpfc_sli_issue_mbox (phba, mbox, MBX_NOWAIT)
3316 != MBX_NOT_FINISHED)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003317 /* Mbox completion will send ELS Response */
3318 return 0;
James Smart2e0fef82007-06-17 19:56:36 -05003319
James Smart329f9bc2007-04-25 09:53:01 -04003320 lpfc_nlp_put(ndlp);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003321 mempool_free(mbox, phba->mbox_mem_pool);
3322 }
3323 }
3324 stat.un.b.lsRjtRsvd0 = 0;
3325 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
3326 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
3327 stat.un.b.vendorUnique = 0;
James Smart858c9f62007-06-17 19:56:39 -05003328 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003329 return 0;
3330}
3331
Jamie Wellnitz082c0262006-02-28 19:25:30 -05003332static int
James Smart2e0fef82007-06-17 19:56:36 -05003333lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize,
3334 struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003335{
James Smart2e0fef82007-06-17 19:56:36 -05003336 struct lpfc_hba *phba = vport->phba;
3337 IOCB_t *icmd, *oldcmd;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003338 RPL_RSP rpl_rsp;
3339 struct lpfc_iocbq *elsiocb;
James Smart2e0fef82007-06-17 19:56:36 -05003340 struct lpfc_sli *psli = &phba->sli;
3341 struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003342 uint8_t *pcmd;
3343
James Smart2e0fef82007-06-17 19:56:36 -05003344 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
3345 ndlp->nlp_DID, ELS_CMD_ACC);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003346
James Smart488d1462006-03-07 15:02:37 -05003347 if (!elsiocb)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003348 return 1;
James Smart488d1462006-03-07 15:02:37 -05003349
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003350 icmd = &elsiocb->iocb;
3351 oldcmd = &oldiocb->iocb;
3352 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
3353
3354 pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
3355 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
James Smart92d7f7b2007-06-17 19:56:38 -05003356 pcmd += sizeof(uint16_t);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003357 *((uint16_t *)(pcmd)) = be16_to_cpu(cmdsize);
3358 pcmd += sizeof(uint16_t);
3359
3360 /* Setup the RPL ACC payload */
3361 rpl_rsp.listLen = be32_to_cpu(1);
3362 rpl_rsp.index = 0;
3363 rpl_rsp.port_num_blk.portNum = 0;
James Smart2e0fef82007-06-17 19:56:36 -05003364 rpl_rsp.port_num_blk.portID = be32_to_cpu(vport->fc_myDID);
3365 memcpy(&rpl_rsp.port_num_blk.portName, &vport->fc_portname,
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003366 sizeof(struct lpfc_name));
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003367 memcpy(pcmd, &rpl_rsp, cmdsize - sizeof(uint32_t));
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003368 /* Xmit ELS RPL ACC response tag <ulpIoTag> */
James Smarte8b62012007-08-02 11:10:09 -04003369 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
3370 "0120 Xmit ELS RPL ACC response tag x%x "
3371 "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, "
3372 "rpi x%x\n",
3373 elsiocb->iotag, elsiocb->iocb.ulpContext,
3374 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
3375 ndlp->nlp_rpi);
James Smart858c9f62007-06-17 19:56:39 -05003376 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003377 phba->fc_stat.elsXmitACC++;
3378 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
3379 lpfc_els_free_iocb(phba, elsiocb);
3380 return 1;
3381 }
3382 return 0;
3383}
3384
3385static int
James Smart2e0fef82007-06-17 19:56:36 -05003386lpfc_els_rcv_rpl(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3387 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05003388{
3389 struct lpfc_dmabuf *pcmd;
3390 uint32_t *lp;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003391 uint32_t maxsize;
3392 uint16_t cmdsize;
3393 RPL *rpl;
3394 struct ls_rjt stat;
dea31012005-04-17 16:05:31 -05003395
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05003396 if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
3397 (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) {
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003398 stat.un.b.lsRjtRsvd0 = 0;
3399 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
3400 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
3401 stat.un.b.vendorUnique = 0;
James Smart858c9f62007-06-17 19:56:39 -05003402 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
3403 NULL);
dea31012005-04-17 16:05:31 -05003404 }
3405
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003406 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3407 lp = (uint32_t *) pcmd->virt;
3408 rpl = (RPL *) (lp + 1);
3409
3410 maxsize = be32_to_cpu(rpl->maxsize);
3411
3412 /* We support only one port */
3413 if ((rpl->index == 0) &&
3414 ((maxsize == 0) ||
3415 ((maxsize * sizeof(uint32_t)) >= sizeof(RPL_RSP)))) {
3416 cmdsize = sizeof(uint32_t) + sizeof(RPL_RSP);
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05003417 } else {
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003418 cmdsize = sizeof(uint32_t) + maxsize * sizeof(uint32_t);
3419 }
James Smart2e0fef82007-06-17 19:56:36 -05003420 lpfc_els_rsp_rpl_acc(vport, cmdsize, cmdiocb, ndlp);
dea31012005-04-17 16:05:31 -05003421
3422 return 0;
3423}
3424
3425static int
James Smart2e0fef82007-06-17 19:56:36 -05003426lpfc_els_rcv_farp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3427 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05003428{
3429 struct lpfc_dmabuf *pcmd;
3430 uint32_t *lp;
3431 IOCB_t *icmd;
3432 FARP *fp;
3433 uint32_t cmd, cnt, did;
3434
3435 icmd = &cmdiocb->iocb;
3436 did = icmd->un.elsreq64.remoteID;
3437 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3438 lp = (uint32_t *) pcmd->virt;
3439
3440 cmd = *lp++;
3441 fp = (FARP *) lp;
dea31012005-04-17 16:05:31 -05003442 /* FARP-REQ received from DID <did> */
James Smarte8b62012007-08-02 11:10:09 -04003443 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
3444 "0601 FARP-REQ received from DID x%x\n", did);
dea31012005-04-17 16:05:31 -05003445 /* We will only support match on WWPN or WWNN */
3446 if (fp->Mflags & ~(FARP_MATCH_NODE | FARP_MATCH_PORT)) {
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003447 return 0;
dea31012005-04-17 16:05:31 -05003448 }
3449
3450 cnt = 0;
3451 /* If this FARP command is searching for my portname */
3452 if (fp->Mflags & FARP_MATCH_PORT) {
James Smart2e0fef82007-06-17 19:56:36 -05003453 if (memcmp(&fp->RportName, &vport->fc_portname,
James Smart92d7f7b2007-06-17 19:56:38 -05003454 sizeof(struct lpfc_name)) == 0)
dea31012005-04-17 16:05:31 -05003455 cnt = 1;
3456 }
3457
3458 /* If this FARP command is searching for my nodename */
3459 if (fp->Mflags & FARP_MATCH_NODE) {
James Smart2e0fef82007-06-17 19:56:36 -05003460 if (memcmp(&fp->RnodeName, &vport->fc_nodename,
James Smart92d7f7b2007-06-17 19:56:38 -05003461 sizeof(struct lpfc_name)) == 0)
dea31012005-04-17 16:05:31 -05003462 cnt = 1;
3463 }
3464
3465 if (cnt) {
3466 if ((ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) ||
3467 (ndlp->nlp_state == NLP_STE_MAPPED_NODE)) {
3468 /* Log back into the node before sending the FARP. */
3469 if (fp->Rflags & FARP_REQUEST_PLOGI) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003470 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05003471 lpfc_nlp_set_state(vport, ndlp,
James Smartde0c5b32007-04-25 09:52:27 -04003472 NLP_STE_PLOGI_ISSUE);
James Smart2e0fef82007-06-17 19:56:36 -05003473 lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
dea31012005-04-17 16:05:31 -05003474 }
3475
3476 /* Send a FARP response to that node */
James Smart2e0fef82007-06-17 19:56:36 -05003477 if (fp->Rflags & FARP_REQUEST_FARPR)
3478 lpfc_issue_els_farpr(vport, did, 0);
dea31012005-04-17 16:05:31 -05003479 }
3480 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003481 return 0;
dea31012005-04-17 16:05:31 -05003482}
3483
3484static int
James Smart2e0fef82007-06-17 19:56:36 -05003485lpfc_els_rcv_farpr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3486 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05003487{
3488 struct lpfc_dmabuf *pcmd;
3489 uint32_t *lp;
3490 IOCB_t *icmd;
3491 uint32_t cmd, did;
3492
3493 icmd = &cmdiocb->iocb;
3494 did = icmd->un.elsreq64.remoteID;
3495 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3496 lp = (uint32_t *) pcmd->virt;
3497
3498 cmd = *lp++;
3499 /* FARP-RSP received from DID <did> */
James Smarte8b62012007-08-02 11:10:09 -04003500 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
3501 "0600 FARP-RSP received from DID x%x\n", did);
dea31012005-04-17 16:05:31 -05003502 /* ACCEPT the Farp resp request */
James Smart51ef4c22007-08-02 11:10:31 -04003503 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
dea31012005-04-17 16:05:31 -05003504
3505 return 0;
3506}
3507
3508static int
James Smart2e0fef82007-06-17 19:56:36 -05003509lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3510 struct lpfc_nodelist *fan_ndlp)
dea31012005-04-17 16:05:31 -05003511{
3512 struct lpfc_dmabuf *pcmd;
3513 uint32_t *lp;
3514 IOCB_t *icmd;
dea31012005-04-17 16:05:31 -05003515 uint32_t cmd, did;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003516 FAN *fp;
3517 struct lpfc_nodelist *ndlp, *next_ndlp;
James Smart2e0fef82007-06-17 19:56:36 -05003518 struct lpfc_hba *phba = vport->phba;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003519
3520 /* FAN received */
James Smarte8b62012007-08-02 11:10:09 -04003521 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
3522 "0265 FAN received\n");
dea31012005-04-17 16:05:31 -05003523 icmd = &cmdiocb->iocb;
3524 did = icmd->un.elsreq64.remoteID;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003525 pcmd = (struct lpfc_dmabuf *)cmdiocb->context2;
3526 lp = (uint32_t *)pcmd->virt;
dea31012005-04-17 16:05:31 -05003527
3528 cmd = *lp++;
James Smart92d7f7b2007-06-17 19:56:38 -05003529 fp = (FAN *) lp;
dea31012005-04-17 16:05:31 -05003530
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003531 /* FAN received; Fan does not have a reply sequence */
dea31012005-04-17 16:05:31 -05003532
James Smart2e0fef82007-06-17 19:56:36 -05003533 if (phba->pport->port_state == LPFC_LOCAL_CFG_LINK) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003534 if ((memcmp(&phba->fc_fabparam.nodeName, &fp->FnodeName,
3535 sizeof(struct lpfc_name)) != 0) ||
3536 (memcmp(&phba->fc_fabparam.portName, &fp->FportName,
3537 sizeof(struct lpfc_name)) != 0)) {
3538 /*
3539 * This node has switched fabrics. FLOGI is required
3540 * Clean up the old rpi's
dea31012005-04-17 16:05:31 -05003541 */
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003542
3543 list_for_each_entry_safe(ndlp, next_ndlp,
James Smart2e0fef82007-06-17 19:56:36 -05003544 &vport->fc_nodes, nlp_listp) {
James Smart685f0bf2007-04-25 09:53:08 -04003545 if (ndlp->nlp_state != NLP_STE_NPR_NODE)
3546 continue;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003547 if (ndlp->nlp_type & NLP_FABRIC) {
3548 /*
3549 * Clean up old Fabric, Nameserver and
3550 * other NLP_FABRIC logins
3551 */
James Smart2e0fef82007-06-17 19:56:36 -05003552 lpfc_drop_node(vport, ndlp);
James Smart87af33f2007-10-27 13:37:43 -04003553
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05003554 } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003555 /* Fail outstanding I/O now since this
3556 * device is marked for PLOGI
3557 */
James Smart2e0fef82007-06-17 19:56:36 -05003558 lpfc_unreg_rpi(vport, ndlp);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003559 }
3560 }
3561
James Smart2e0fef82007-06-17 19:56:36 -05003562 lpfc_initial_flogi(vport);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003563 return 0;
dea31012005-04-17 16:05:31 -05003564 }
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003565 /* Discovery not needed,
3566 * move the nodes to their original state.
3567 */
James Smart2e0fef82007-06-17 19:56:36 -05003568 list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
James Smart685f0bf2007-04-25 09:53:08 -04003569 nlp_listp) {
3570 if (ndlp->nlp_state != NLP_STE_NPR_NODE)
3571 continue;
dea31012005-04-17 16:05:31 -05003572
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003573 switch (ndlp->nlp_prev_state) {
3574 case NLP_STE_UNMAPPED_NODE:
3575 ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
James Smart2e0fef82007-06-17 19:56:36 -05003576 lpfc_nlp_set_state(vport, ndlp,
James Smartde0c5b32007-04-25 09:52:27 -04003577 NLP_STE_UNMAPPED_NODE);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003578 break;
3579
3580 case NLP_STE_MAPPED_NODE:
3581 ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
James Smart2e0fef82007-06-17 19:56:36 -05003582 lpfc_nlp_set_state(vport, ndlp,
James Smartde0c5b32007-04-25 09:52:27 -04003583 NLP_STE_MAPPED_NODE);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003584 break;
3585
3586 default:
3587 break;
3588 }
3589 }
3590
3591 /* Start discovery - this should just do CLEAR_LA */
James Smart2e0fef82007-06-17 19:56:36 -05003592 lpfc_disc_start(vport);
dea31012005-04-17 16:05:31 -05003593 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003594 return 0;
dea31012005-04-17 16:05:31 -05003595}
3596
3597void
3598lpfc_els_timeout(unsigned long ptr)
3599{
James Smart2e0fef82007-06-17 19:56:36 -05003600 struct lpfc_vport *vport = (struct lpfc_vport *) ptr;
3601 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05003602 unsigned long iflag;
3603
James Smart2e0fef82007-06-17 19:56:36 -05003604 spin_lock_irqsave(&vport->work_port_lock, iflag);
3605 if ((vport->work_port_events & WORKER_ELS_TMO) == 0) {
3606 vport->work_port_events |= WORKER_ELS_TMO;
James Smart92d7f7b2007-06-17 19:56:38 -05003607 spin_unlock_irqrestore(&vport->work_port_lock, iflag);
3608
3609 spin_lock_irqsave(&phba->hbalock, iflag);
dea31012005-04-17 16:05:31 -05003610 if (phba->work_wait)
James Smart92d7f7b2007-06-17 19:56:38 -05003611 lpfc_worker_wake_up(phba);
3612 spin_unlock_irqrestore(&phba->hbalock, iflag);
dea31012005-04-17 16:05:31 -05003613 }
James Smart92d7f7b2007-06-17 19:56:38 -05003614 else
3615 spin_unlock_irqrestore(&vport->work_port_lock, iflag);
dea31012005-04-17 16:05:31 -05003616 return;
3617}
3618
3619void
James Smart2e0fef82007-06-17 19:56:36 -05003620lpfc_els_timeout_handler(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05003621{
James Smart2e0fef82007-06-17 19:56:36 -05003622 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05003623 struct lpfc_sli_ring *pring;
3624 struct lpfc_iocbq *tmp_iocb, *piocb;
3625 IOCB_t *cmd = NULL;
3626 struct lpfc_dmabuf *pcmd;
James Smart2e0fef82007-06-17 19:56:36 -05003627 uint32_t els_command = 0;
dea31012005-04-17 16:05:31 -05003628 uint32_t timeout;
James Smart2e0fef82007-06-17 19:56:36 -05003629 uint32_t remote_ID = 0xffffffff;
dea31012005-04-17 16:05:31 -05003630
dea31012005-04-17 16:05:31 -05003631 /* If the timer is already canceled do nothing */
James Smart2e0fef82007-06-17 19:56:36 -05003632 if ((vport->work_port_events & WORKER_ELS_TMO) == 0) {
dea31012005-04-17 16:05:31 -05003633 return;
3634 }
James Smart2e0fef82007-06-17 19:56:36 -05003635 spin_lock_irq(&phba->hbalock);
dea31012005-04-17 16:05:31 -05003636 timeout = (uint32_t)(phba->fc_ratov << 1);
3637
3638 pring = &phba->sli.ring[LPFC_ELS_RING];
dea31012005-04-17 16:05:31 -05003639
3640 list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
3641 cmd = &piocb->iocb;
3642
James Smart2e0fef82007-06-17 19:56:36 -05003643 if ((piocb->iocb_flag & LPFC_IO_LIBDFC) != 0 ||
3644 piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN ||
3645 piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)
dea31012005-04-17 16:05:31 -05003646 continue;
James Smart2e0fef82007-06-17 19:56:36 -05003647
3648 if (piocb->vport != vport)
3649 continue;
3650
dea31012005-04-17 16:05:31 -05003651 pcmd = (struct lpfc_dmabuf *) piocb->context2;
James Smart2e0fef82007-06-17 19:56:36 -05003652 if (pcmd)
3653 els_command = *(uint32_t *) (pcmd->virt);
dea31012005-04-17 16:05:31 -05003654
James Smart92d7f7b2007-06-17 19:56:38 -05003655 if (els_command == ELS_CMD_FARP ||
3656 els_command == ELS_CMD_FARPR ||
3657 els_command == ELS_CMD_FDISC)
dea31012005-04-17 16:05:31 -05003658 continue;
James Smart92d7f7b2007-06-17 19:56:38 -05003659
3660 if (vport != piocb->vport)
3661 continue;
dea31012005-04-17 16:05:31 -05003662
3663 if (piocb->drvrTimeout > 0) {
James Smart92d7f7b2007-06-17 19:56:38 -05003664 if (piocb->drvrTimeout >= timeout)
dea31012005-04-17 16:05:31 -05003665 piocb->drvrTimeout -= timeout;
James Smart92d7f7b2007-06-17 19:56:38 -05003666 else
dea31012005-04-17 16:05:31 -05003667 piocb->drvrTimeout = 0;
dea31012005-04-17 16:05:31 -05003668 continue;
3669 }
3670
James Smart2e0fef82007-06-17 19:56:36 -05003671 remote_ID = 0xffffffff;
3672 if (cmd->ulpCommand != CMD_GEN_REQUEST64_CR)
dea31012005-04-17 16:05:31 -05003673 remote_ID = cmd->un.elsreq64.remoteID;
James Smart2e0fef82007-06-17 19:56:36 -05003674 else {
3675 struct lpfc_nodelist *ndlp;
3676 ndlp = __lpfc_findnode_rpi(vport, cmd->ulpContext);
3677 if (ndlp)
3678 remote_ID = ndlp->nlp_DID;
dea31012005-04-17 16:05:31 -05003679 }
James Smarte8b62012007-08-02 11:10:09 -04003680 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
3681 "0127 ELS timeout Data: x%x x%x x%x "
3682 "x%x\n", els_command,
3683 remote_ID, cmd->ulpCommand, cmd->ulpIoTag);
James Smart07951072007-04-25 09:51:38 -04003684 lpfc_sli_issue_abort_iotag(phba, pring, piocb);
dea31012005-04-17 16:05:31 -05003685 }
James Smart2e0fef82007-06-17 19:56:36 -05003686 spin_unlock_irq(&phba->hbalock);
James Smart5a0e3262006-07-06 15:49:16 -04003687
James Smart2e0fef82007-06-17 19:56:36 -05003688 if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt)
3689 mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout);
dea31012005-04-17 16:05:31 -05003690}
3691
3692void
James Smart2e0fef82007-06-17 19:56:36 -05003693lpfc_els_flush_cmd(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05003694{
James Smart2534ba72007-04-25 09:52:20 -04003695 LIST_HEAD(completions);
James Smart2e0fef82007-06-17 19:56:36 -05003696 struct lpfc_hba *phba = vport->phba;
James Smart329f9bc2007-04-25 09:53:01 -04003697 struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
dea31012005-04-17 16:05:31 -05003698 struct lpfc_iocbq *tmp_iocb, *piocb;
3699 IOCB_t *cmd = NULL;
James Smart92d7f7b2007-06-17 19:56:38 -05003700
3701 lpfc_fabric_abort_vport(vport);
dea31012005-04-17 16:05:31 -05003702
James Smart2e0fef82007-06-17 19:56:36 -05003703 spin_lock_irq(&phba->hbalock);
dea31012005-04-17 16:05:31 -05003704 list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
3705 cmd = &piocb->iocb;
3706
3707 if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
3708 continue;
3709 }
3710
3711 /* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */
James Smart329f9bc2007-04-25 09:53:01 -04003712 if (cmd->ulpCommand == CMD_QUE_RING_BUF_CN ||
3713 cmd->ulpCommand == CMD_QUE_RING_BUF64_CN ||
3714 cmd->ulpCommand == CMD_CLOSE_XRI_CN ||
3715 cmd->ulpCommand == CMD_ABORT_XRI_CN)
dea31012005-04-17 16:05:31 -05003716 continue;
dea31012005-04-17 16:05:31 -05003717
James Smart2e0fef82007-06-17 19:56:36 -05003718 if (piocb->vport != vport)
3719 continue;
3720
James Smart2534ba72007-04-25 09:52:20 -04003721 list_move_tail(&piocb->list, &completions);
James Smart1dcb58e2007-04-25 09:51:30 -04003722 pring->txq_cnt--;
dea31012005-04-17 16:05:31 -05003723 }
3724
3725 list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
dea31012005-04-17 16:05:31 -05003726 if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
3727 continue;
3728 }
dea31012005-04-17 16:05:31 -05003729
James Smart2e0fef82007-06-17 19:56:36 -05003730 if (piocb->vport != vport)
3731 continue;
3732
James Smart07951072007-04-25 09:51:38 -04003733 lpfc_sli_issue_abort_iotag(phba, pring, piocb);
dea31012005-04-17 16:05:31 -05003734 }
James Smart2e0fef82007-06-17 19:56:36 -05003735 spin_unlock_irq(&phba->hbalock);
James Smart2534ba72007-04-25 09:52:20 -04003736
James Smart2e0fef82007-06-17 19:56:36 -05003737 while (!list_empty(&completions)) {
James Smart2534ba72007-04-25 09:52:20 -04003738 piocb = list_get_first(&completions, struct lpfc_iocbq, list);
3739 cmd = &piocb->iocb;
James Smart92d7f7b2007-06-17 19:56:38 -05003740 list_del_init(&piocb->list);
James Smart2534ba72007-04-25 09:52:20 -04003741
James Smart2e0fef82007-06-17 19:56:36 -05003742 if (!piocb->iocb_cmpl)
3743 lpfc_sli_release_iocbq(phba, piocb);
3744 else {
James Smart2534ba72007-04-25 09:52:20 -04003745 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
3746 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
3747 (piocb->iocb_cmpl) (phba, piocb, piocb);
James Smart2e0fef82007-06-17 19:56:36 -05003748 }
James Smart2534ba72007-04-25 09:52:20 -04003749 }
3750
dea31012005-04-17 16:05:31 -05003751 return;
3752}
3753
James Smart549e55c2007-08-02 11:09:51 -04003754void
3755lpfc_els_flush_all_cmd(struct lpfc_hba *phba)
3756{
3757 LIST_HEAD(completions);
3758 struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
3759 struct lpfc_iocbq *tmp_iocb, *piocb;
3760 IOCB_t *cmd = NULL;
3761
3762 lpfc_fabric_abort_hba(phba);
3763 spin_lock_irq(&phba->hbalock);
3764 list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
3765 cmd = &piocb->iocb;
3766 if (piocb->iocb_flag & LPFC_IO_LIBDFC)
3767 continue;
3768 /* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */
3769 if (cmd->ulpCommand == CMD_QUE_RING_BUF_CN ||
3770 cmd->ulpCommand == CMD_QUE_RING_BUF64_CN ||
3771 cmd->ulpCommand == CMD_CLOSE_XRI_CN ||
3772 cmd->ulpCommand == CMD_ABORT_XRI_CN)
3773 continue;
3774 list_move_tail(&piocb->list, &completions);
3775 pring->txq_cnt--;
3776 }
3777 list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
3778 if (piocb->iocb_flag & LPFC_IO_LIBDFC)
3779 continue;
3780 lpfc_sli_issue_abort_iotag(phba, pring, piocb);
3781 }
3782 spin_unlock_irq(&phba->hbalock);
3783 while (!list_empty(&completions)) {
3784 piocb = list_get_first(&completions, struct lpfc_iocbq, list);
3785 cmd = &piocb->iocb;
3786 list_del_init(&piocb->list);
3787 if (!piocb->iocb_cmpl)
3788 lpfc_sli_release_iocbq(phba, piocb);
3789 else {
3790 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
3791 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
3792 (piocb->iocb_cmpl) (phba, piocb, piocb);
3793 }
3794 }
3795 return;
3796}
3797
James Smarted957682007-06-17 19:56:37 -05003798static void
3799lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
James Smart92d7f7b2007-06-17 19:56:38 -05003800 struct lpfc_vport *vport, struct lpfc_iocbq *elsiocb)
dea31012005-04-17 16:05:31 -05003801{
James Smart87af33f2007-10-27 13:37:43 -04003802 struct Scsi_Host *shost;
dea31012005-04-17 16:05:31 -05003803 struct lpfc_nodelist *ndlp;
dea31012005-04-17 16:05:31 -05003804 struct ls_rjt stat;
James Smart92d7f7b2007-06-17 19:56:38 -05003805 uint32_t *payload;
James Smart2e0fef82007-06-17 19:56:36 -05003806 uint32_t cmd, did, newnode, rjt_err = 0;
James Smarted957682007-06-17 19:56:37 -05003807 IOCB_t *icmd = &elsiocb->iocb;
dea31012005-04-17 16:05:31 -05003808
James Smart92d7f7b2007-06-17 19:56:38 -05003809 if (vport == NULL || elsiocb->context2 == NULL)
dea31012005-04-17 16:05:31 -05003810 goto dropit;
James Smart2e0fef82007-06-17 19:56:36 -05003811
dea31012005-04-17 16:05:31 -05003812 newnode = 0;
James Smart92d7f7b2007-06-17 19:56:38 -05003813 payload = ((struct lpfc_dmabuf *)elsiocb->context2)->virt;
3814 cmd = *payload;
James Smarted957682007-06-17 19:56:37 -05003815 if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) == 0)
3816 lpfc_post_buffer(phba, pring, 1, 1);
dea31012005-04-17 16:05:31 -05003817
James Smart858c9f62007-06-17 19:56:39 -05003818 did = icmd->un.rcvels.remoteID;
3819 if (icmd->ulpStatus) {
3820 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3821 "RCV Unsol ELS: status:x%x/x%x did:x%x",
3822 icmd->ulpStatus, icmd->un.ulpWord[4], did);
dea31012005-04-17 16:05:31 -05003823 goto dropit;
James Smart858c9f62007-06-17 19:56:39 -05003824 }
dea31012005-04-17 16:05:31 -05003825
3826 /* Check to see if link went down during discovery */
James Smarted957682007-06-17 19:56:37 -05003827 if (lpfc_els_chk_latt(vport))
dea31012005-04-17 16:05:31 -05003828 goto dropit;
dea31012005-04-17 16:05:31 -05003829
James Smart92d7f7b2007-06-17 19:56:38 -05003830 /* Ignore traffic recevied during vport shutdown. */
3831 if (vport->load_flag & FC_UNLOADING)
3832 goto dropit;
3833
James Smart2e0fef82007-06-17 19:56:36 -05003834 ndlp = lpfc_findnode_did(vport, did);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003835 if (!ndlp) {
dea31012005-04-17 16:05:31 -05003836 /* Cannot find existing Fabric ndlp, so allocate a new one */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003837 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
James Smarted957682007-06-17 19:56:37 -05003838 if (!ndlp)
dea31012005-04-17 16:05:31 -05003839 goto dropit;
dea31012005-04-17 16:05:31 -05003840
James Smart2e0fef82007-06-17 19:56:36 -05003841 lpfc_nlp_init(vport, ndlp, did);
James Smart98c9ea52007-10-27 13:37:33 -04003842 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
dea31012005-04-17 16:05:31 -05003843 newnode = 1;
3844 if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) {
3845 ndlp->nlp_type |= NLP_FABRIC;
3846 }
3847 }
James Smart87af33f2007-10-27 13:37:43 -04003848 else {
3849 if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) {
3850 /* This is simular to the new node path */
3851 lpfc_nlp_get(ndlp);
3852 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
3853 newnode = 1;
3854 }
3855 }
dea31012005-04-17 16:05:31 -05003856
3857 phba->fc_stat.elsRcvFrame++;
James Smart329f9bc2007-04-25 09:53:01 -04003858 if (elsiocb->context1)
3859 lpfc_nlp_put(elsiocb->context1);
3860 elsiocb->context1 = lpfc_nlp_get(ndlp);
James Smart2e0fef82007-06-17 19:56:36 -05003861 elsiocb->vport = vport;
dea31012005-04-17 16:05:31 -05003862
3863 if ((cmd & ELS_CMD_MASK) == ELS_CMD_RSCN) {
3864 cmd &= ELS_CMD_MASK;
3865 }
3866 /* ELS command <elsCmd> received from NPORT <did> */
James Smarte8b62012007-08-02 11:10:09 -04003867 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
3868 "0112 ELS command x%x received from NPORT x%x "
3869 "Data: x%x\n", cmd, did, vport->port_state);
dea31012005-04-17 16:05:31 -05003870 switch (cmd) {
3871 case ELS_CMD_PLOGI:
James Smart858c9f62007-06-17 19:56:39 -05003872 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3873 "RCV PLOGI: did:x%x/ste:x%x flg:x%x",
3874 did, vport->port_state, ndlp->nlp_flag);
3875
dea31012005-04-17 16:05:31 -05003876 phba->fc_stat.elsRcvPLOGI++;
James Smart858c9f62007-06-17 19:56:39 -05003877 ndlp = lpfc_plogi_confirm_nport(phba, payload, ndlp);
3878
3879 if (vport->port_state < LPFC_DISC_AUTH) {
3880 rjt_err = LSRJT_UNABLE_TPC;
dea31012005-04-17 16:05:31 -05003881 break;
3882 }
James Smart87af33f2007-10-27 13:37:43 -04003883
3884 shost = lpfc_shost_from_vport(vport);
3885 spin_lock_irq(shost->host_lock);
3886 ndlp->nlp_flag &= ~NLP_TARGET_REMOVE;
3887 spin_unlock_irq(shost->host_lock);
3888
James Smart2e0fef82007-06-17 19:56:36 -05003889 lpfc_disc_state_machine(vport, ndlp, elsiocb,
3890 NLP_EVT_RCV_PLOGI);
James Smart858c9f62007-06-17 19:56:39 -05003891
dea31012005-04-17 16:05:31 -05003892 break;
3893 case ELS_CMD_FLOGI:
James Smart858c9f62007-06-17 19:56:39 -05003894 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3895 "RCV FLOGI: did:x%x/ste:x%x flg:x%x",
3896 did, vport->port_state, ndlp->nlp_flag);
3897
dea31012005-04-17 16:05:31 -05003898 phba->fc_stat.elsRcvFLOGI++;
James Smart51ef4c22007-08-02 11:10:31 -04003899 lpfc_els_rcv_flogi(vport, elsiocb, ndlp);
James Smart87af33f2007-10-27 13:37:43 -04003900 if (newnode)
James Smart98c9ea52007-10-27 13:37:33 -04003901 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05003902 break;
3903 case ELS_CMD_LOGO:
James Smart858c9f62007-06-17 19:56:39 -05003904 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3905 "RCV LOGO: did:x%x/ste:x%x flg:x%x",
3906 did, vport->port_state, ndlp->nlp_flag);
3907
dea31012005-04-17 16:05:31 -05003908 phba->fc_stat.elsRcvLOGO++;
James Smart2e0fef82007-06-17 19:56:36 -05003909 if (vport->port_state < LPFC_DISC_AUTH) {
James Smart858c9f62007-06-17 19:56:39 -05003910 rjt_err = LSRJT_UNABLE_TPC;
dea31012005-04-17 16:05:31 -05003911 break;
3912 }
James Smart2e0fef82007-06-17 19:56:36 -05003913 lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_LOGO);
dea31012005-04-17 16:05:31 -05003914 break;
3915 case ELS_CMD_PRLO:
James Smart858c9f62007-06-17 19:56:39 -05003916 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3917 "RCV PRLO: did:x%x/ste:x%x flg:x%x",
3918 did, vport->port_state, ndlp->nlp_flag);
3919
dea31012005-04-17 16:05:31 -05003920 phba->fc_stat.elsRcvPRLO++;
James Smart2e0fef82007-06-17 19:56:36 -05003921 if (vport->port_state < LPFC_DISC_AUTH) {
James Smart858c9f62007-06-17 19:56:39 -05003922 rjt_err = LSRJT_UNABLE_TPC;
dea31012005-04-17 16:05:31 -05003923 break;
3924 }
James Smart2e0fef82007-06-17 19:56:36 -05003925 lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PRLO);
dea31012005-04-17 16:05:31 -05003926 break;
3927 case ELS_CMD_RSCN:
3928 phba->fc_stat.elsRcvRSCN++;
James Smart51ef4c22007-08-02 11:10:31 -04003929 lpfc_els_rcv_rscn(vport, elsiocb, ndlp);
James Smart87af33f2007-10-27 13:37:43 -04003930 if (newnode)
James Smart98c9ea52007-10-27 13:37:33 -04003931 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05003932 break;
3933 case ELS_CMD_ADISC:
James Smart858c9f62007-06-17 19:56:39 -05003934 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3935 "RCV ADISC: did:x%x/ste:x%x flg:x%x",
3936 did, vport->port_state, ndlp->nlp_flag);
3937
dea31012005-04-17 16:05:31 -05003938 phba->fc_stat.elsRcvADISC++;
James Smart2e0fef82007-06-17 19:56:36 -05003939 if (vport->port_state < LPFC_DISC_AUTH) {
James Smart858c9f62007-06-17 19:56:39 -05003940 rjt_err = LSRJT_UNABLE_TPC;
dea31012005-04-17 16:05:31 -05003941 break;
3942 }
James Smart2e0fef82007-06-17 19:56:36 -05003943 lpfc_disc_state_machine(vport, ndlp, elsiocb,
3944 NLP_EVT_RCV_ADISC);
dea31012005-04-17 16:05:31 -05003945 break;
3946 case ELS_CMD_PDISC:
James Smart858c9f62007-06-17 19:56:39 -05003947 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3948 "RCV PDISC: did:x%x/ste:x%x flg:x%x",
3949 did, vport->port_state, ndlp->nlp_flag);
3950
dea31012005-04-17 16:05:31 -05003951 phba->fc_stat.elsRcvPDISC++;
James Smart2e0fef82007-06-17 19:56:36 -05003952 if (vport->port_state < LPFC_DISC_AUTH) {
James Smart858c9f62007-06-17 19:56:39 -05003953 rjt_err = LSRJT_UNABLE_TPC;
dea31012005-04-17 16:05:31 -05003954 break;
3955 }
James Smart2e0fef82007-06-17 19:56:36 -05003956 lpfc_disc_state_machine(vport, ndlp, elsiocb,
3957 NLP_EVT_RCV_PDISC);
dea31012005-04-17 16:05:31 -05003958 break;
3959 case ELS_CMD_FARPR:
James Smart858c9f62007-06-17 19:56:39 -05003960 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3961 "RCV FARPR: did:x%x/ste:x%x flg:x%x",
3962 did, vport->port_state, ndlp->nlp_flag);
3963
dea31012005-04-17 16:05:31 -05003964 phba->fc_stat.elsRcvFARPR++;
James Smart2e0fef82007-06-17 19:56:36 -05003965 lpfc_els_rcv_farpr(vport, elsiocb, ndlp);
dea31012005-04-17 16:05:31 -05003966 break;
3967 case ELS_CMD_FARP:
James Smart858c9f62007-06-17 19:56:39 -05003968 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3969 "RCV FARP: did:x%x/ste:x%x flg:x%x",
3970 did, vport->port_state, ndlp->nlp_flag);
3971
dea31012005-04-17 16:05:31 -05003972 phba->fc_stat.elsRcvFARP++;
James Smart2e0fef82007-06-17 19:56:36 -05003973 lpfc_els_rcv_farp(vport, elsiocb, ndlp);
dea31012005-04-17 16:05:31 -05003974 break;
3975 case ELS_CMD_FAN:
James Smart858c9f62007-06-17 19:56:39 -05003976 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3977 "RCV FAN: did:x%x/ste:x%x flg:x%x",
3978 did, vport->port_state, ndlp->nlp_flag);
3979
dea31012005-04-17 16:05:31 -05003980 phba->fc_stat.elsRcvFAN++;
James Smart2e0fef82007-06-17 19:56:36 -05003981 lpfc_els_rcv_fan(vport, elsiocb, ndlp);
dea31012005-04-17 16:05:31 -05003982 break;
dea31012005-04-17 16:05:31 -05003983 case ELS_CMD_PRLI:
James Smart858c9f62007-06-17 19:56:39 -05003984 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3985 "RCV PRLI: did:x%x/ste:x%x flg:x%x",
3986 did, vport->port_state, ndlp->nlp_flag);
3987
dea31012005-04-17 16:05:31 -05003988 phba->fc_stat.elsRcvPRLI++;
James Smart2e0fef82007-06-17 19:56:36 -05003989 if (vport->port_state < LPFC_DISC_AUTH) {
James Smart858c9f62007-06-17 19:56:39 -05003990 rjt_err = LSRJT_UNABLE_TPC;
dea31012005-04-17 16:05:31 -05003991 break;
3992 }
James Smart2e0fef82007-06-17 19:56:36 -05003993 lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PRLI);
dea31012005-04-17 16:05:31 -05003994 break;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003995 case ELS_CMD_LIRR:
James Smart858c9f62007-06-17 19:56:39 -05003996 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3997 "RCV LIRR: did:x%x/ste:x%x flg:x%x",
3998 did, vport->port_state, ndlp->nlp_flag);
3999
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05004000 phba->fc_stat.elsRcvLIRR++;
James Smart2e0fef82007-06-17 19:56:36 -05004001 lpfc_els_rcv_lirr(vport, elsiocb, ndlp);
James Smart87af33f2007-10-27 13:37:43 -04004002 if (newnode)
James Smart98c9ea52007-10-27 13:37:33 -04004003 lpfc_nlp_put(ndlp);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05004004 break;
4005 case ELS_CMD_RPS:
James Smart858c9f62007-06-17 19:56:39 -05004006 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
4007 "RCV RPS: did:x%x/ste:x%x flg:x%x",
4008 did, vport->port_state, ndlp->nlp_flag);
4009
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05004010 phba->fc_stat.elsRcvRPS++;
James Smart2e0fef82007-06-17 19:56:36 -05004011 lpfc_els_rcv_rps(vport, elsiocb, ndlp);
James Smart87af33f2007-10-27 13:37:43 -04004012 if (newnode)
James Smart98c9ea52007-10-27 13:37:33 -04004013 lpfc_nlp_put(ndlp);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05004014 break;
4015 case ELS_CMD_RPL:
James Smart858c9f62007-06-17 19:56:39 -05004016 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
4017 "RCV RPL: did:x%x/ste:x%x flg:x%x",
4018 did, vport->port_state, ndlp->nlp_flag);
4019
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05004020 phba->fc_stat.elsRcvRPL++;
James Smart2e0fef82007-06-17 19:56:36 -05004021 lpfc_els_rcv_rpl(vport, elsiocb, ndlp);
James Smart87af33f2007-10-27 13:37:43 -04004022 if (newnode)
James Smart98c9ea52007-10-27 13:37:33 -04004023 lpfc_nlp_put(ndlp);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05004024 break;
dea31012005-04-17 16:05:31 -05004025 case ELS_CMD_RNID:
James Smart858c9f62007-06-17 19:56:39 -05004026 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
4027 "RCV RNID: did:x%x/ste:x%x flg:x%x",
4028 did, vport->port_state, ndlp->nlp_flag);
4029
dea31012005-04-17 16:05:31 -05004030 phba->fc_stat.elsRcvRNID++;
James Smart2e0fef82007-06-17 19:56:36 -05004031 lpfc_els_rcv_rnid(vport, elsiocb, ndlp);
James Smart87af33f2007-10-27 13:37:43 -04004032 if (newnode)
James Smart98c9ea52007-10-27 13:37:33 -04004033 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05004034 break;
4035 default:
James Smart858c9f62007-06-17 19:56:39 -05004036 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
4037 "RCV ELS cmd: cmd:x%x did:x%x/ste:x%x",
4038 cmd, did, vport->port_state);
4039
dea31012005-04-17 16:05:31 -05004040 /* Unsupported ELS command, reject */
James Smart858c9f62007-06-17 19:56:39 -05004041 rjt_err = LSRJT_INVALID_CMD;
dea31012005-04-17 16:05:31 -05004042
4043 /* Unknown ELS command <elsCmd> received from NPORT <did> */
James Smarte8b62012007-08-02 11:10:09 -04004044 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
4045 "0115 Unknown ELS command x%x "
4046 "received from NPORT x%x\n", cmd, did);
James Smart87af33f2007-10-27 13:37:43 -04004047 if (newnode)
James Smart98c9ea52007-10-27 13:37:33 -04004048 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05004049 break;
4050 }
4051
4052 /* check if need to LS_RJT received ELS cmd */
4053 if (rjt_err) {
James Smart92d7f7b2007-06-17 19:56:38 -05004054 memset(&stat, 0, sizeof(stat));
James Smart858c9f62007-06-17 19:56:39 -05004055 stat.un.b.lsRjtRsnCode = rjt_err;
James.Smart@Emulex.Com1f679ca2005-06-25 10:34:27 -04004056 stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
James Smart858c9f62007-06-17 19:56:39 -05004057 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, elsiocb, ndlp,
4058 NULL);
dea31012005-04-17 16:05:31 -05004059 }
4060
James Smarted957682007-06-17 19:56:37 -05004061 return;
4062
4063dropit:
James Smart98c9ea52007-10-27 13:37:33 -04004064 if (vport && !(vport->load_flag & FC_UNLOADING))
4065 lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
James Smarte8b62012007-08-02 11:10:09 -04004066 "(%d):0111 Dropping received ELS cmd "
James Smarted957682007-06-17 19:56:37 -05004067 "Data: x%x x%x x%x\n",
James Smart98c9ea52007-10-27 13:37:33 -04004068 vport->vpi, icmd->ulpStatus,
James Smarte8b62012007-08-02 11:10:09 -04004069 icmd->un.ulpWord[4], icmd->ulpTimeout);
James Smarted957682007-06-17 19:56:37 -05004070 phba->fc_stat.elsRcvDrop++;
4071}
4072
James Smart92d7f7b2007-06-17 19:56:38 -05004073static struct lpfc_vport *
4074lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi)
4075{
4076 struct lpfc_vport *vport;
James Smart549e55c2007-08-02 11:09:51 -04004077 unsigned long flags;
James Smart92d7f7b2007-06-17 19:56:38 -05004078
James Smart549e55c2007-08-02 11:09:51 -04004079 spin_lock_irqsave(&phba->hbalock, flags);
James Smart92d7f7b2007-06-17 19:56:38 -05004080 list_for_each_entry(vport, &phba->port_list, listentry) {
James Smart549e55c2007-08-02 11:09:51 -04004081 if (vport->vpi == vpi) {
4082 spin_unlock_irqrestore(&phba->hbalock, flags);
James Smart92d7f7b2007-06-17 19:56:38 -05004083 return vport;
James Smart549e55c2007-08-02 11:09:51 -04004084 }
James Smart92d7f7b2007-06-17 19:56:38 -05004085 }
James Smart549e55c2007-08-02 11:09:51 -04004086 spin_unlock_irqrestore(&phba->hbalock, flags);
James Smart92d7f7b2007-06-17 19:56:38 -05004087 return NULL;
4088}
James Smarted957682007-06-17 19:56:37 -05004089
4090void
4091lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
4092 struct lpfc_iocbq *elsiocb)
4093{
4094 struct lpfc_vport *vport = phba->pport;
James Smarted957682007-06-17 19:56:37 -05004095 IOCB_t *icmd = &elsiocb->iocb;
James Smarted957682007-06-17 19:56:37 -05004096 dma_addr_t paddr;
James Smart92d7f7b2007-06-17 19:56:38 -05004097 struct lpfc_dmabuf *bdeBuf1 = elsiocb->context2;
4098 struct lpfc_dmabuf *bdeBuf2 = elsiocb->context3;
James Smarted957682007-06-17 19:56:37 -05004099
James Smart92d7f7b2007-06-17 19:56:38 -05004100 elsiocb->context2 = NULL;
4101 elsiocb->context3 = NULL;
4102
4103 if (icmd->ulpStatus == IOSTAT_NEED_BUFFER) {
4104 lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
4105 } else if (icmd->ulpStatus == IOSTAT_LOCAL_REJECT &&
4106 (icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING) {
James Smarted957682007-06-17 19:56:37 -05004107 phba->fc_stat.NoRcvBuf++;
4108 /* Not enough posted buffers; Try posting more buffers */
James Smart92d7f7b2007-06-17 19:56:38 -05004109 if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED))
James Smarted957682007-06-17 19:56:37 -05004110 lpfc_post_buffer(phba, pring, 0, 1);
4111 return;
4112 }
4113
James Smart92d7f7b2007-06-17 19:56:38 -05004114 if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
4115 (icmd->ulpCommand == CMD_IOCB_RCV_ELS64_CX ||
4116 icmd->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) {
4117 if (icmd->unsli3.rcvsli3.vpi == 0xffff)
4118 vport = phba->pport;
4119 else {
4120 uint16_t vpi = icmd->unsli3.rcvsli3.vpi;
4121 vport = lpfc_find_vport_by_vpid(phba, vpi);
4122 }
4123 }
4124 /* If there are no BDEs associated
4125 * with this IOCB, there is nothing to do.
4126 */
James Smarted957682007-06-17 19:56:37 -05004127 if (icmd->ulpBdeCount == 0)
4128 return;
4129
James Smart92d7f7b2007-06-17 19:56:38 -05004130 /* type of ELS cmd is first 32bit word
4131 * in packet
4132 */
James Smarted957682007-06-17 19:56:37 -05004133 if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
James Smart92d7f7b2007-06-17 19:56:38 -05004134 elsiocb->context2 = bdeBuf1;
James Smarted957682007-06-17 19:56:37 -05004135 } else {
4136 paddr = getPaddr(icmd->un.cont64[0].addrHigh,
4137 icmd->un.cont64[0].addrLow);
James Smart92d7f7b2007-06-17 19:56:38 -05004138 elsiocb->context2 = lpfc_sli_ringpostbuf_get(phba, pring,
4139 paddr);
James Smarted957682007-06-17 19:56:37 -05004140 }
4141
James Smart92d7f7b2007-06-17 19:56:38 -05004142 lpfc_els_unsol_buffer(phba, pring, vport, elsiocb);
4143 /*
4144 * The different unsolicited event handlers would tell us
4145 * if they are done with "mp" by setting context2 to NULL.
4146 */
James Smart329f9bc2007-04-25 09:53:01 -04004147 lpfc_nlp_put(elsiocb->context1);
4148 elsiocb->context1 = NULL;
dea31012005-04-17 16:05:31 -05004149 if (elsiocb->context2) {
James Smart92d7f7b2007-06-17 19:56:38 -05004150 lpfc_in_buf_free(phba, (struct lpfc_dmabuf *)elsiocb->context2);
4151 elsiocb->context2 = NULL;
dea31012005-04-17 16:05:31 -05004152 }
James Smarted957682007-06-17 19:56:37 -05004153
4154 /* RCV_ELS64_CX provide for 2 BDEs - process 2nd if included */
James Smart92d7f7b2007-06-17 19:56:38 -05004155 if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) &&
James Smarted957682007-06-17 19:56:37 -05004156 icmd->ulpBdeCount == 2) {
James Smart92d7f7b2007-06-17 19:56:38 -05004157 elsiocb->context2 = bdeBuf2;
4158 lpfc_els_unsol_buffer(phba, pring, vport, elsiocb);
James Smarted957682007-06-17 19:56:37 -05004159 /* free mp if we are done with it */
4160 if (elsiocb->context2) {
James Smart92d7f7b2007-06-17 19:56:38 -05004161 lpfc_in_buf_free(phba, elsiocb->context2);
4162 elsiocb->context2 = NULL;
James Smarted957682007-06-17 19:56:37 -05004163 }
dea31012005-04-17 16:05:31 -05004164 }
dea31012005-04-17 16:05:31 -05004165}
James Smart92d7f7b2007-06-17 19:56:38 -05004166
4167void
4168lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport)
4169{
4170 struct lpfc_nodelist *ndlp, *ndlp_fdmi;
4171
4172 ndlp = lpfc_findnode_did(vport, NameServer_DID);
4173 if (!ndlp) {
4174 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
4175 if (!ndlp) {
4176 if (phba->fc_topology == TOPOLOGY_LOOP) {
4177 lpfc_disc_start(vport);
4178 return;
4179 }
4180 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
James Smarte8b62012007-08-02 11:10:09 -04004181 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
4182 "0251 NameServer login: no memory\n");
James Smart92d7f7b2007-06-17 19:56:38 -05004183 return;
4184 }
4185 lpfc_nlp_init(vport, ndlp, NameServer_DID);
4186 ndlp->nlp_type |= NLP_FABRIC;
4187 }
4188
4189 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
4190
4191 if (lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0)) {
4192 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
James Smarte8b62012007-08-02 11:10:09 -04004193 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
4194 "0252 Cannot issue NameServer login\n");
James Smart92d7f7b2007-06-17 19:56:38 -05004195 return;
4196 }
4197
James Smart3de2a652007-08-02 11:09:59 -04004198 if (vport->cfg_fdmi_on) {
James Smart92d7f7b2007-06-17 19:56:38 -05004199 ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
4200 GFP_KERNEL);
4201 if (ndlp_fdmi) {
4202 lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID);
4203 ndlp_fdmi->nlp_type |= NLP_FABRIC;
4204 ndlp_fdmi->nlp_state =
4205 NLP_STE_PLOGI_ISSUE;
4206 lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID,
4207 0);
4208 }
4209 }
4210 return;
4211}
4212
4213static void
4214lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
4215{
4216 struct lpfc_vport *vport = pmb->vport;
4217 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
4218 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
4219 MAILBOX_t *mb = &pmb->mb;
4220
4221 vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
4222 lpfc_nlp_put(ndlp);
4223
4224 if (mb->mbxStatus) {
James Smarte8b62012007-08-02 11:10:09 -04004225 lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
4226 "0915 Register VPI failed: 0x%x\n",
4227 mb->mbxStatus);
James Smart92d7f7b2007-06-17 19:56:38 -05004228
4229 switch (mb->mbxStatus) {
4230 case 0x11: /* unsupported feature */
4231 case 0x9603: /* max_vpi exceeded */
4232 /* giving up on vport registration */
4233 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
4234 spin_lock_irq(shost->host_lock);
4235 vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
4236 spin_unlock_irq(shost->host_lock);
4237 lpfc_can_disctmo(vport);
4238 break;
4239 default:
4240 /* Try to recover from this error */
4241 lpfc_mbx_unreg_vpi(vport);
4242 vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
4243 lpfc_initial_fdisc(vport);
4244 break;
4245 }
4246
4247 } else {
4248 if (vport == phba->pport)
4249 lpfc_issue_fabric_reglogin(vport);
4250 else
4251 lpfc_do_scr_ns_plogi(phba, vport);
4252 }
4253 mempool_free(pmb, phba->mbox_mem_pool);
4254 return;
4255}
4256
4257void
4258lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport,
4259 struct lpfc_nodelist *ndlp)
4260{
4261 LPFC_MBOXQ_t *mbox;
4262
4263 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
4264 if (mbox) {
4265 lpfc_reg_vpi(phba, vport->vpi, vport->fc_myDID, mbox);
4266 mbox->vport = vport;
4267 mbox->context2 = lpfc_nlp_get(ndlp);
4268 mbox->mbox_cmpl = lpfc_cmpl_reg_new_vport;
James Smart0b727fe2007-10-27 13:37:25 -04004269 if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
James Smart92d7f7b2007-06-17 19:56:38 -05004270 == MBX_NOT_FINISHED) {
4271 mempool_free(mbox, phba->mbox_mem_pool);
4272 vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
4273
4274 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
James Smarte8b62012007-08-02 11:10:09 -04004275 lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
4276 "0253 Register VPI: Can't send mbox\n");
James Smart92d7f7b2007-06-17 19:56:38 -05004277 }
4278 } else {
4279 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
4280
James Smarte8b62012007-08-02 11:10:09 -04004281 lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
4282 "0254 Register VPI: no memory\n");
James Smart92d7f7b2007-06-17 19:56:38 -05004283
4284 vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
4285 lpfc_nlp_put(ndlp);
4286 }
4287}
4288
4289static void
4290lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
4291 struct lpfc_iocbq *rspiocb)
4292{
4293 struct lpfc_vport *vport = cmdiocb->vport;
4294 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
4295 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
4296 struct lpfc_nodelist *np;
4297 struct lpfc_nodelist *next_np;
4298 IOCB_t *irsp = &rspiocb->iocb;
4299 struct lpfc_iocbq *piocb;
4300
James Smarte8b62012007-08-02 11:10:09 -04004301 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
4302 "0123 FDISC completes. x%x/x%x prevDID: x%x\n",
4303 irsp->ulpStatus, irsp->un.ulpWord[4],
4304 vport->fc_prevDID);
James Smart92d7f7b2007-06-17 19:56:38 -05004305 /* Since all FDISCs are being single threaded, we
4306 * must reset the discovery timer for ALL vports
4307 * waiting to send FDISC when one completes.
4308 */
4309 list_for_each_entry(piocb, &phba->fabric_iocb_list, list) {
4310 lpfc_set_disctmo(piocb->vport);
4311 }
4312
James Smart858c9f62007-06-17 19:56:39 -05004313 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
4314 "FDISC cmpl: status:x%x/x%x prevdid:x%x",
4315 irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_prevDID);
4316
James Smart92d7f7b2007-06-17 19:56:38 -05004317 if (irsp->ulpStatus) {
4318 /* Check for retry */
4319 if (lpfc_els_retry(phba, cmdiocb, rspiocb))
4320 goto out;
James Smart92d7f7b2007-06-17 19:56:38 -05004321 /* FDISC failed */
James Smarte8b62012007-08-02 11:10:09 -04004322 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
4323 "0124 FDISC failed. (%d/%d)\n",
4324 irsp->ulpStatus, irsp->un.ulpWord[4]);
James Smart92d7f7b2007-06-17 19:56:38 -05004325 if (vport->fc_vport->vport_state == FC_VPORT_INITIALIZING)
4326 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
4327
4328 lpfc_nlp_put(ndlp);
4329 /* giving up on FDISC. Cancel discovery timer */
4330 lpfc_can_disctmo(vport);
4331 } else {
4332 spin_lock_irq(shost->host_lock);
4333 vport->fc_flag |= FC_FABRIC;
4334 if (vport->phba->fc_topology == TOPOLOGY_LOOP)
4335 vport->fc_flag |= FC_PUBLIC_LOOP;
4336 spin_unlock_irq(shost->host_lock);
4337
4338 vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID;
4339 lpfc_vport_set_state(vport, FC_VPORT_ACTIVE);
4340 if ((vport->fc_prevDID != vport->fc_myDID) &&
4341 !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) {
4342 /* If our NportID changed, we need to ensure all
4343 * remaining NPORTs get unreg_login'ed so we can
4344 * issue unreg_vpi.
4345 */
4346 list_for_each_entry_safe(np, next_np,
4347 &vport->fc_nodes, nlp_listp) {
4348 if (np->nlp_state != NLP_STE_NPR_NODE
4349 || !(np->nlp_flag & NLP_NPR_ADISC))
4350 continue;
4351 spin_lock_irq(shost->host_lock);
4352 np->nlp_flag &= ~NLP_NPR_ADISC;
4353 spin_unlock_irq(shost->host_lock);
4354 lpfc_unreg_rpi(vport, np);
4355 }
4356 lpfc_mbx_unreg_vpi(vport);
4357 vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
4358 }
4359
4360 if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)
4361 lpfc_register_new_vport(phba, vport, ndlp);
4362 else
4363 lpfc_do_scr_ns_plogi(phba, vport);
4364
4365 lpfc_nlp_put(ndlp); /* Free Fabric ndlp for vports */
4366 }
4367
4368out:
4369 lpfc_els_free_iocb(phba, cmdiocb);
4370}
4371
4372int
4373lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
4374 uint8_t retry)
4375{
4376 struct lpfc_hba *phba = vport->phba;
4377 IOCB_t *icmd;
4378 struct lpfc_iocbq *elsiocb;
4379 struct serv_parm *sp;
4380 uint8_t *pcmd;
4381 uint16_t cmdsize;
4382 int did = ndlp->nlp_DID;
4383 int rc;
James Smart92d7f7b2007-06-17 19:56:38 -05004384
4385 cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
4386 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did,
4387 ELS_CMD_FDISC);
4388 if (!elsiocb) {
James Smart92d7f7b2007-06-17 19:56:38 -05004389 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
James Smarte8b62012007-08-02 11:10:09 -04004390 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
4391 "0255 Issue FDISC: no IOCB\n");
James Smart92d7f7b2007-06-17 19:56:38 -05004392 return 1;
4393 }
4394
4395 icmd = &elsiocb->iocb;
4396 icmd->un.elsreq64.myID = 0;
4397 icmd->un.elsreq64.fl = 1;
4398
4399 /* For FDISC, Let FDISC rsp set the NPortID for this VPI */
4400 icmd->ulpCt_h = 1;
4401 icmd->ulpCt_l = 0;
4402
4403 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
4404 *((uint32_t *) (pcmd)) = ELS_CMD_FDISC;
4405 pcmd += sizeof(uint32_t); /* CSP Word 1 */
4406 memcpy(pcmd, &vport->phba->pport->fc_sparam, sizeof(struct serv_parm));
4407 sp = (struct serv_parm *) pcmd;
4408 /* Setup CSPs accordingly for Fabric */
4409 sp->cmn.e_d_tov = 0;
4410 sp->cmn.w2.r_a_tov = 0;
4411 sp->cls1.classValid = 0;
4412 sp->cls2.seqDelivery = 1;
4413 sp->cls3.seqDelivery = 1;
4414
4415 pcmd += sizeof(uint32_t); /* CSP Word 2 */
4416 pcmd += sizeof(uint32_t); /* CSP Word 3 */
4417 pcmd += sizeof(uint32_t); /* CSP Word 4 */
4418 pcmd += sizeof(uint32_t); /* Port Name */
4419 memcpy(pcmd, &vport->fc_portname, 8);
4420 pcmd += sizeof(uint32_t); /* Node Name */
4421 pcmd += sizeof(uint32_t); /* Node Name */
4422 memcpy(pcmd, &vport->fc_nodename, 8);
4423
4424 lpfc_set_disctmo(vport);
4425
4426 phba->fc_stat.elsXmitFDISC++;
4427 elsiocb->iocb_cmpl = lpfc_cmpl_els_fdisc;
4428
James Smart858c9f62007-06-17 19:56:39 -05004429 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
4430 "Issue FDISC: did:x%x",
4431 did, 0, 0);
4432
James Smart92d7f7b2007-06-17 19:56:38 -05004433 rc = lpfc_issue_fabric_iocb(phba, elsiocb);
4434 if (rc == IOCB_ERROR) {
4435 lpfc_els_free_iocb(phba, elsiocb);
James Smart92d7f7b2007-06-17 19:56:38 -05004436 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
James Smarte8b62012007-08-02 11:10:09 -04004437 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
4438 "0256 Issue FDISC: Cannot send IOCB\n");
James Smart92d7f7b2007-06-17 19:56:38 -05004439 return 1;
4440 }
4441 lpfc_vport_set_state(vport, FC_VPORT_INITIALIZING);
4442 vport->port_state = LPFC_FDISC;
4443 return 0;
4444}
4445
4446static void
4447lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
4448 struct lpfc_iocbq *rspiocb)
4449{
4450 struct lpfc_vport *vport = cmdiocb->vport;
James Smart858c9f62007-06-17 19:56:39 -05004451 IOCB_t *irsp;
4452
4453 irsp = &rspiocb->iocb;
4454 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
4455 "LOGO npiv cmpl: status:x%x/x%x did:x%x",
4456 irsp->ulpStatus, irsp->un.ulpWord[4], irsp->un.rcvels.remoteID);
James Smart92d7f7b2007-06-17 19:56:38 -05004457
4458 lpfc_els_free_iocb(phba, cmdiocb);
4459 vport->unreg_vpi_cmpl = VPORT_ERROR;
4460}
4461
4462int
4463lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
4464{
4465 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
4466 struct lpfc_hba *phba = vport->phba;
4467 struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
4468 IOCB_t *icmd;
4469 struct lpfc_iocbq *elsiocb;
4470 uint8_t *pcmd;
4471 uint16_t cmdsize;
4472
4473 cmdsize = 2 * sizeof(uint32_t) + sizeof(struct lpfc_name);
4474 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, ndlp->nlp_DID,
4475 ELS_CMD_LOGO);
4476 if (!elsiocb)
4477 return 1;
4478
4479 icmd = &elsiocb->iocb;
4480 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
4481 *((uint32_t *) (pcmd)) = ELS_CMD_LOGO;
4482 pcmd += sizeof(uint32_t);
4483
4484 /* Fill in LOGO payload */
4485 *((uint32_t *) (pcmd)) = be32_to_cpu(vport->fc_myDID);
4486 pcmd += sizeof(uint32_t);
4487 memcpy(pcmd, &vport->fc_portname, sizeof(struct lpfc_name));
4488
James Smart858c9f62007-06-17 19:56:39 -05004489 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
4490 "Issue LOGO npiv did:x%x flg:x%x",
4491 ndlp->nlp_DID, ndlp->nlp_flag, 0);
4492
James Smart92d7f7b2007-06-17 19:56:38 -05004493 elsiocb->iocb_cmpl = lpfc_cmpl_els_npiv_logo;
4494 spin_lock_irq(shost->host_lock);
4495 ndlp->nlp_flag |= NLP_LOGO_SND;
4496 spin_unlock_irq(shost->host_lock);
4497 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
4498 spin_lock_irq(shost->host_lock);
4499 ndlp->nlp_flag &= ~NLP_LOGO_SND;
4500 spin_unlock_irq(shost->host_lock);
4501 lpfc_els_free_iocb(phba, elsiocb);
4502 return 1;
4503 }
4504 return 0;
4505}
4506
4507void
4508lpfc_fabric_block_timeout(unsigned long ptr)
4509{
4510 struct lpfc_hba *phba = (struct lpfc_hba *) ptr;
4511 unsigned long iflags;
4512 uint32_t tmo_posted;
4513 spin_lock_irqsave(&phba->pport->work_port_lock, iflags);
4514 tmo_posted = phba->pport->work_port_events & WORKER_FABRIC_BLOCK_TMO;
4515 if (!tmo_posted)
4516 phba->pport->work_port_events |= WORKER_FABRIC_BLOCK_TMO;
4517 spin_unlock_irqrestore(&phba->pport->work_port_lock, iflags);
4518
4519 if (!tmo_posted) {
4520 spin_lock_irqsave(&phba->hbalock, iflags);
4521 if (phba->work_wait)
4522 lpfc_worker_wake_up(phba);
4523 spin_unlock_irqrestore(&phba->hbalock, iflags);
4524 }
4525}
4526
4527static void
4528lpfc_resume_fabric_iocbs(struct lpfc_hba *phba)
4529{
4530 struct lpfc_iocbq *iocb;
4531 unsigned long iflags;
4532 int ret;
4533 struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
4534 IOCB_t *cmd;
4535
4536repeat:
4537 iocb = NULL;
4538 spin_lock_irqsave(&phba->hbalock, iflags);
4539 /* Post any pending iocb to the SLI layer */
4540 if (atomic_read(&phba->fabric_iocb_count) == 0) {
4541 list_remove_head(&phba->fabric_iocb_list, iocb, typeof(*iocb),
4542 list);
4543 if (iocb)
4544 atomic_inc(&phba->fabric_iocb_count);
4545 }
4546 spin_unlock_irqrestore(&phba->hbalock, iflags);
4547 if (iocb) {
4548 iocb->fabric_iocb_cmpl = iocb->iocb_cmpl;
4549 iocb->iocb_cmpl = lpfc_cmpl_fabric_iocb;
4550 iocb->iocb_flag |= LPFC_IO_FABRIC;
4551
James Smart858c9f62007-06-17 19:56:39 -05004552 lpfc_debugfs_disc_trc(iocb->vport, LPFC_DISC_TRC_ELS_CMD,
4553 "Fabric sched1: ste:x%x",
4554 iocb->vport->port_state, 0, 0);
4555
James Smart92d7f7b2007-06-17 19:56:38 -05004556 ret = lpfc_sli_issue_iocb(phba, pring, iocb, 0);
4557
4558 if (ret == IOCB_ERROR) {
4559 iocb->iocb_cmpl = iocb->fabric_iocb_cmpl;
4560 iocb->fabric_iocb_cmpl = NULL;
4561 iocb->iocb_flag &= ~LPFC_IO_FABRIC;
4562 cmd = &iocb->iocb;
4563 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
4564 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
4565 iocb->iocb_cmpl(phba, iocb, iocb);
4566
4567 atomic_dec(&phba->fabric_iocb_count);
4568 goto repeat;
4569 }
4570 }
4571
4572 return;
4573}
4574
4575void
4576lpfc_unblock_fabric_iocbs(struct lpfc_hba *phba)
4577{
4578 clear_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags);
4579
4580 lpfc_resume_fabric_iocbs(phba);
4581 return;
4582}
4583
4584static void
4585lpfc_block_fabric_iocbs(struct lpfc_hba *phba)
4586{
4587 int blocked;
4588
4589 blocked = test_and_set_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags);
4590 /* Start a timer to unblock fabric
4591 * iocbs after 100ms
4592 */
4593 if (!blocked)
4594 mod_timer(&phba->fabric_block_timer, jiffies + HZ/10 );
4595
4596 return;
4597}
4598
4599static void
4600lpfc_cmpl_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
4601 struct lpfc_iocbq *rspiocb)
4602{
4603 struct ls_rjt stat;
4604
4605 if ((cmdiocb->iocb_flag & LPFC_IO_FABRIC) != LPFC_IO_FABRIC)
4606 BUG();
4607
4608 switch (rspiocb->iocb.ulpStatus) {
4609 case IOSTAT_NPORT_RJT:
4610 case IOSTAT_FABRIC_RJT:
4611 if (rspiocb->iocb.un.ulpWord[4] & RJT_UNAVAIL_TEMP) {
4612 lpfc_block_fabric_iocbs(phba);
4613 }
4614 break;
4615
4616 case IOSTAT_NPORT_BSY:
4617 case IOSTAT_FABRIC_BSY:
4618 lpfc_block_fabric_iocbs(phba);
4619 break;
4620
4621 case IOSTAT_LS_RJT:
4622 stat.un.lsRjtError =
4623 be32_to_cpu(rspiocb->iocb.un.ulpWord[4]);
4624 if ((stat.un.b.lsRjtRsnCode == LSRJT_UNABLE_TPC) ||
4625 (stat.un.b.lsRjtRsnCode == LSRJT_LOGICAL_BSY))
4626 lpfc_block_fabric_iocbs(phba);
4627 break;
4628 }
4629
4630 if (atomic_read(&phba->fabric_iocb_count) == 0)
4631 BUG();
4632
4633 cmdiocb->iocb_cmpl = cmdiocb->fabric_iocb_cmpl;
4634 cmdiocb->fabric_iocb_cmpl = NULL;
4635 cmdiocb->iocb_flag &= ~LPFC_IO_FABRIC;
4636 cmdiocb->iocb_cmpl(phba, cmdiocb, rspiocb);
4637
4638 atomic_dec(&phba->fabric_iocb_count);
4639 if (!test_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags)) {
4640 /* Post any pending iocbs to HBA */
4641 lpfc_resume_fabric_iocbs(phba);
4642 }
4643}
4644
4645int
4646lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb)
4647{
4648 unsigned long iflags;
4649 struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
4650 int ready;
4651 int ret;
4652
4653 if (atomic_read(&phba->fabric_iocb_count) > 1)
4654 BUG();
4655
4656 spin_lock_irqsave(&phba->hbalock, iflags);
4657 ready = atomic_read(&phba->fabric_iocb_count) == 0 &&
4658 !test_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags);
4659
4660 spin_unlock_irqrestore(&phba->hbalock, iflags);
4661 if (ready) {
4662 iocb->fabric_iocb_cmpl = iocb->iocb_cmpl;
4663 iocb->iocb_cmpl = lpfc_cmpl_fabric_iocb;
4664 iocb->iocb_flag |= LPFC_IO_FABRIC;
4665
James Smart858c9f62007-06-17 19:56:39 -05004666 lpfc_debugfs_disc_trc(iocb->vport, LPFC_DISC_TRC_ELS_CMD,
4667 "Fabric sched2: ste:x%x",
4668 iocb->vport->port_state, 0, 0);
4669
James Smart92d7f7b2007-06-17 19:56:38 -05004670 atomic_inc(&phba->fabric_iocb_count);
4671 ret = lpfc_sli_issue_iocb(phba, pring, iocb, 0);
4672
4673 if (ret == IOCB_ERROR) {
4674 iocb->iocb_cmpl = iocb->fabric_iocb_cmpl;
4675 iocb->fabric_iocb_cmpl = NULL;
4676 iocb->iocb_flag &= ~LPFC_IO_FABRIC;
4677 atomic_dec(&phba->fabric_iocb_count);
4678 }
4679 } else {
4680 spin_lock_irqsave(&phba->hbalock, iflags);
4681 list_add_tail(&iocb->list, &phba->fabric_iocb_list);
4682 spin_unlock_irqrestore(&phba->hbalock, iflags);
4683 ret = IOCB_SUCCESS;
4684 }
4685 return ret;
4686}
4687
4688
4689void lpfc_fabric_abort_vport(struct lpfc_vport *vport)
4690{
4691 LIST_HEAD(completions);
4692 struct lpfc_hba *phba = vport->phba;
4693 struct lpfc_iocbq *tmp_iocb, *piocb;
4694 IOCB_t *cmd;
4695
4696 spin_lock_irq(&phba->hbalock);
4697 list_for_each_entry_safe(piocb, tmp_iocb, &phba->fabric_iocb_list,
4698 list) {
4699
4700 if (piocb->vport != vport)
4701 continue;
4702
4703 list_move_tail(&piocb->list, &completions);
4704 }
4705 spin_unlock_irq(&phba->hbalock);
4706
4707 while (!list_empty(&completions)) {
4708 piocb = list_get_first(&completions, struct lpfc_iocbq, list);
4709 list_del_init(&piocb->list);
4710
4711 cmd = &piocb->iocb;
4712 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
4713 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
4714 (piocb->iocb_cmpl) (phba, piocb, piocb);
4715 }
4716}
4717
4718void lpfc_fabric_abort_nport(struct lpfc_nodelist *ndlp)
4719{
4720 LIST_HEAD(completions);
4721 struct lpfc_hba *phba = ndlp->vport->phba;
4722 struct lpfc_iocbq *tmp_iocb, *piocb;
4723 struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
4724 IOCB_t *cmd;
4725
4726 spin_lock_irq(&phba->hbalock);
4727 list_for_each_entry_safe(piocb, tmp_iocb, &phba->fabric_iocb_list,
4728 list) {
4729 if ((lpfc_check_sli_ndlp(phba, pring, piocb, ndlp))) {
4730
4731 list_move_tail(&piocb->list, &completions);
4732 }
4733 }
4734 spin_unlock_irq(&phba->hbalock);
4735
4736 while (!list_empty(&completions)) {
4737 piocb = list_get_first(&completions, struct lpfc_iocbq, list);
4738 list_del_init(&piocb->list);
4739
4740 cmd = &piocb->iocb;
4741 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
4742 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
4743 (piocb->iocb_cmpl) (phba, piocb, piocb);
4744 }
4745}
4746
4747void lpfc_fabric_abort_hba(struct lpfc_hba *phba)
4748{
4749 LIST_HEAD(completions);
4750 struct lpfc_iocbq *piocb;
4751 IOCB_t *cmd;
4752
4753 spin_lock_irq(&phba->hbalock);
4754 list_splice_init(&phba->fabric_iocb_list, &completions);
4755 spin_unlock_irq(&phba->hbalock);
4756
4757 while (!list_empty(&completions)) {
4758 piocb = list_get_first(&completions, struct lpfc_iocbq, list);
4759 list_del_init(&piocb->list);
4760
4761 cmd = &piocb->iocb;
4762 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
4763 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
4764 (piocb->iocb_cmpl) (phba, piocb, piocb);
4765 }
4766}
4767
4768
4769void lpfc_fabric_abort_flogi(struct lpfc_hba *phba)
4770{
4771 LIST_HEAD(completions);
4772 struct lpfc_iocbq *tmp_iocb, *piocb;
4773 IOCB_t *cmd;
4774 struct lpfc_nodelist *ndlp;
4775
4776 spin_lock_irq(&phba->hbalock);
4777 list_for_each_entry_safe(piocb, tmp_iocb, &phba->fabric_iocb_list,
4778 list) {
4779
4780 cmd = &piocb->iocb;
4781 ndlp = (struct lpfc_nodelist *) piocb->context1;
4782 if (cmd->ulpCommand == CMD_ELS_REQUEST64_CR &&
4783 ndlp != NULL &&
4784 ndlp->nlp_DID == Fabric_DID)
4785 list_move_tail(&piocb->list, &completions);
4786 }
4787 spin_unlock_irq(&phba->hbalock);
4788
4789 while (!list_empty(&completions)) {
4790 piocb = list_get_first(&completions, struct lpfc_iocbq, list);
4791 list_del_init(&piocb->list);
4792
4793 cmd = &piocb->iocb;
4794 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
4795 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
4796 (piocb->iocb_cmpl) (phba, piocb, piocb);
4797 }
4798}
4799
4800