blob: bf332cba2fc02f3df80e8f0360cb4d5c07660c01 [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 *);
Adrian Bunka6ababd2007-11-05 18:07:33 +010045static void lpfc_fabric_abort_vport(struct lpfc_vport *vport);
46static int lpfc_issue_els_fdisc(struct lpfc_vport *vport,
47 struct lpfc_nodelist *ndlp, uint8_t retry);
48static int lpfc_issue_fabric_iocb(struct lpfc_hba *phba,
49 struct lpfc_iocbq *iocb);
50static void lpfc_register_new_vport(struct lpfc_hba *phba,
51 struct lpfc_vport *vport,
52 struct lpfc_nodelist *ndlp);
James Smart92d7f7b2007-06-17 19:56:38 -050053
dea31012005-04-17 16:05:31 -050054static int lpfc_max_els_tries = 3;
55
James Smart858c9f62007-06-17 19:56:39 -050056int
James Smart2e0fef82007-06-17 19:56:36 -050057lpfc_els_chk_latt(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -050058{
James Smart2e0fef82007-06-17 19:56:36 -050059 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
60 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -050061 uint32_t ha_copy;
dea31012005-04-17 16:05:31 -050062
James Smart2e0fef82007-06-17 19:56:36 -050063 if (vport->port_state >= LPFC_VPORT_READY ||
64 phba->link_state == LPFC_LINK_DOWN)
dea31012005-04-17 16:05:31 -050065 return 0;
66
67 /* Read the HBA Host Attention Register */
dea31012005-04-17 16:05:31 -050068 ha_copy = readl(phba->HAregaddr);
dea31012005-04-17 16:05:31 -050069
70 if (!(ha_copy & HA_LATT))
71 return 0;
72
73 /* Pending Link Event during Discovery */
James Smarte8b62012007-08-02 11:10:09 -040074 lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
75 "0237 Pending Link Event during "
76 "Discovery: State x%x\n",
77 phba->pport->port_state);
dea31012005-04-17 16:05:31 -050078
79 /* CLEAR_LA should re-enable link attention events and
80 * we should then imediately take a LATT event. The
81 * LATT processing should call lpfc_linkdown() which
82 * will cleanup any left over in-progress discovery
83 * events.
84 */
James Smart2e0fef82007-06-17 19:56:36 -050085 spin_lock_irq(shost->host_lock);
86 vport->fc_flag |= FC_ABORT_DISCOVERY;
87 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -050088
James Smart92d7f7b2007-06-17 19:56:38 -050089 if (phba->link_state != LPFC_CLEAR_LA)
James Smarted957682007-06-17 19:56:37 -050090 lpfc_issue_clear_la(phba, vport);
dea31012005-04-17 16:05:31 -050091
Jamie Wellnitzc9f87352006-02-28 19:25:23 -050092 return 1;
dea31012005-04-17 16:05:31 -050093}
94
95static struct lpfc_iocbq *
James Smart2e0fef82007-06-17 19:56:36 -050096lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
97 uint16_t cmdSize, uint8_t retry,
98 struct lpfc_nodelist *ndlp, uint32_t did,
99 uint32_t elscmd)
dea31012005-04-17 16:05:31 -0500100{
James Smart2e0fef82007-06-17 19:56:36 -0500101 struct lpfc_hba *phba = vport->phba;
James.Smart@Emulex.Com0bd4ca22005-10-28 20:30:02 -0400102 struct lpfc_iocbq *elsiocb;
dea31012005-04-17 16:05:31 -0500103 struct lpfc_dmabuf *pcmd, *prsp, *pbuflist;
104 struct ulp_bde64 *bpl;
105 IOCB_t *icmd;
106
dea31012005-04-17 16:05:31 -0500107
James Smart2e0fef82007-06-17 19:56:36 -0500108 if (!lpfc_is_link_up(phba))
109 return NULL;
dea31012005-04-17 16:05:31 -0500110
dea31012005-04-17 16:05:31 -0500111 /* Allocate buffer for command iocb */
James.Smart@Emulex.Com0bd4ca22005-10-28 20:30:02 -0400112 elsiocb = lpfc_sli_get_iocbq(phba);
dea31012005-04-17 16:05:31 -0500113
114 if (elsiocb == NULL)
115 return NULL;
dea31012005-04-17 16:05:31 -0500116 icmd = &elsiocb->iocb;
117
118 /* fill in BDEs for command */
119 /* Allocate buffer for command payload */
James Smart98c9ea52007-10-27 13:37:33 -0400120 pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
121 if (pcmd)
122 pcmd->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &pcmd->phys);
123 if (!pcmd || !pcmd->virt) {
Jesper Juhlc9475cb2005-11-07 01:01:26 -0800124 kfree(pcmd);
dea31012005-04-17 16:05:31 -0500125
James Bottomley604a3e32005-10-29 10:28:33 -0500126 lpfc_sli_release_iocbq(phba, elsiocb);
dea31012005-04-17 16:05:31 -0500127 return NULL;
128 }
129
130 INIT_LIST_HEAD(&pcmd->list);
131
132 /* Allocate buffer for response payload */
133 if (expectRsp) {
James Smart92d7f7b2007-06-17 19:56:38 -0500134 prsp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
dea31012005-04-17 16:05:31 -0500135 if (prsp)
136 prsp->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
137 &prsp->phys);
James Smart98c9ea52007-10-27 13:37:33 -0400138 if (!prsp || !prsp->virt) {
Jesper Juhlc9475cb2005-11-07 01:01:26 -0800139 kfree(prsp);
dea31012005-04-17 16:05:31 -0500140 lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
141 kfree(pcmd);
James Bottomley604a3e32005-10-29 10:28:33 -0500142 lpfc_sli_release_iocbq(phba, elsiocb);
dea31012005-04-17 16:05:31 -0500143 return NULL;
144 }
145 INIT_LIST_HEAD(&prsp->list);
146 } else {
147 prsp = NULL;
148 }
149
150 /* Allocate buffer for Buffer ptr list */
James Smart92d7f7b2007-06-17 19:56:38 -0500151 pbuflist = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
dea31012005-04-17 16:05:31 -0500152 if (pbuflist)
James Smarted957682007-06-17 19:56:37 -0500153 pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
154 &pbuflist->phys);
James Smart98c9ea52007-10-27 13:37:33 -0400155 if (!pbuflist || !pbuflist->virt) {
James Bottomley604a3e32005-10-29 10:28:33 -0500156 lpfc_sli_release_iocbq(phba, elsiocb);
dea31012005-04-17 16:05:31 -0500157 lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
158 lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
159 kfree(pcmd);
160 kfree(prsp);
Jesper Juhlc9475cb2005-11-07 01:01:26 -0800161 kfree(pbuflist);
dea31012005-04-17 16:05:31 -0500162 return NULL;
163 }
164
165 INIT_LIST_HEAD(&pbuflist->list);
166
167 icmd->un.elsreq64.bdl.addrHigh = putPaddrHigh(pbuflist->phys);
168 icmd->un.elsreq64.bdl.addrLow = putPaddrLow(pbuflist->phys);
169 icmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BDL;
James Smart2e0fef82007-06-17 19:56:36 -0500170 icmd->un.elsreq64.remoteID = did; /* DID */
dea31012005-04-17 16:05:31 -0500171 if (expectRsp) {
James Smart92d7f7b2007-06-17 19:56:38 -0500172 icmd->un.elsreq64.bdl.bdeSize = (2 * sizeof(struct ulp_bde64));
dea31012005-04-17 16:05:31 -0500173 icmd->ulpCommand = CMD_ELS_REQUEST64_CR;
James Smart2680eea2007-04-25 09:52:55 -0400174 icmd->ulpTimeout = phba->fc_ratov * 2;
dea31012005-04-17 16:05:31 -0500175 } else {
James Smart92d7f7b2007-06-17 19:56:38 -0500176 icmd->un.elsreq64.bdl.bdeSize = sizeof(struct ulp_bde64);
dea31012005-04-17 16:05:31 -0500177 icmd->ulpCommand = CMD_XMIT_ELS_RSP64_CX;
178 }
dea31012005-04-17 16:05:31 -0500179 icmd->ulpBdeCount = 1;
180 icmd->ulpLe = 1;
181 icmd->ulpClass = CLASS3;
182
James Smart92d7f7b2007-06-17 19:56:38 -0500183 if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
184 icmd->un.elsreq64.myID = vport->fc_myDID;
185
186 /* For ELS_REQUEST64_CR, use the VPI by default */
187 icmd->ulpContext = vport->vpi;
188 icmd->ulpCt_h = 0;
189 icmd->ulpCt_l = 1;
190 }
191
dea31012005-04-17 16:05:31 -0500192 bpl = (struct ulp_bde64 *) pbuflist->virt;
193 bpl->addrLow = le32_to_cpu(putPaddrLow(pcmd->phys));
194 bpl->addrHigh = le32_to_cpu(putPaddrHigh(pcmd->phys));
195 bpl->tus.f.bdeSize = cmdSize;
196 bpl->tus.f.bdeFlags = 0;
197 bpl->tus.w = le32_to_cpu(bpl->tus.w);
198
199 if (expectRsp) {
200 bpl++;
201 bpl->addrLow = le32_to_cpu(putPaddrLow(prsp->phys));
202 bpl->addrHigh = le32_to_cpu(putPaddrHigh(prsp->phys));
203 bpl->tus.f.bdeSize = FCELSSIZE;
204 bpl->tus.f.bdeFlags = BUFF_USE_RCV;
205 bpl->tus.w = le32_to_cpu(bpl->tus.w);
206 }
207
James Smart51ef4c22007-08-02 11:10:31 -0400208 elsiocb->context1 = lpfc_nlp_get(ndlp);
James Smart329f9bc2007-04-25 09:53:01 -0400209 elsiocb->context2 = pcmd;
210 elsiocb->context3 = pbuflist;
dea31012005-04-17 16:05:31 -0500211 elsiocb->retry = retry;
James Smart2e0fef82007-06-17 19:56:36 -0500212 elsiocb->vport = vport;
dea31012005-04-17 16:05:31 -0500213 elsiocb->drvrTimeout = (phba->fc_ratov << 1) + LPFC_DRVR_TIMEOUT;
214
215 if (prsp) {
216 list_add(&prsp->list, &pcmd->list);
217 }
dea31012005-04-17 16:05:31 -0500218 if (expectRsp) {
219 /* Xmit ELS command <elsCmd> to remote NPORT <did> */
James Smarte8b62012007-08-02 11:10:09 -0400220 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
221 "0116 Xmit ELS command x%x to remote "
222 "NPORT x%x I/O tag: x%x, port state: x%x\n",
223 elscmd, did, elsiocb->iotag,
224 vport->port_state);
dea31012005-04-17 16:05:31 -0500225 } else {
226 /* Xmit ELS response <elsCmd> to remote NPORT <did> */
James Smarte8b62012007-08-02 11:10:09 -0400227 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
228 "0117 Xmit ELS response x%x to remote "
229 "NPORT x%x I/O tag: x%x, size: x%x\n",
230 elscmd, ndlp->nlp_DID, elsiocb->iotag,
231 cmdSize);
dea31012005-04-17 16:05:31 -0500232 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500233 return elsiocb;
dea31012005-04-17 16:05:31 -0500234}
235
236
237static int
James Smart92d7f7b2007-06-17 19:56:38 -0500238lpfc_issue_fabric_reglogin(struct lpfc_vport *vport)
239{
240 struct lpfc_hba *phba = vport->phba;
241 LPFC_MBOXQ_t *mbox;
242 struct lpfc_dmabuf *mp;
243 struct lpfc_nodelist *ndlp;
244 struct serv_parm *sp;
245 int rc;
James Smart98c9ea52007-10-27 13:37:33 -0400246 int err = 0;
James Smart92d7f7b2007-06-17 19:56:38 -0500247
248 sp = &phba->fc_fabparam;
249 ndlp = lpfc_findnode_did(vport, Fabric_DID);
James Smart98c9ea52007-10-27 13:37:33 -0400250 if (!ndlp) {
251 err = 1;
James Smart92d7f7b2007-06-17 19:56:38 -0500252 goto fail;
James Smart98c9ea52007-10-27 13:37:33 -0400253 }
James Smart92d7f7b2007-06-17 19:56:38 -0500254
255 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
James Smart98c9ea52007-10-27 13:37:33 -0400256 if (!mbox) {
257 err = 2;
James Smart92d7f7b2007-06-17 19:56:38 -0500258 goto fail;
James Smart98c9ea52007-10-27 13:37:33 -0400259 }
James Smart92d7f7b2007-06-17 19:56:38 -0500260
261 vport->port_state = LPFC_FABRIC_CFG_LINK;
262 lpfc_config_link(phba, mbox);
263 mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
264 mbox->vport = vport;
265
James Smart0b727fe2007-10-27 13:37:25 -0400266 rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
James Smart98c9ea52007-10-27 13:37:33 -0400267 if (rc == MBX_NOT_FINISHED) {
268 err = 3;
James Smart92d7f7b2007-06-17 19:56:38 -0500269 goto fail_free_mbox;
James Smart98c9ea52007-10-27 13:37:33 -0400270 }
James Smart92d7f7b2007-06-17 19:56:38 -0500271
272 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
James Smart98c9ea52007-10-27 13:37:33 -0400273 if (!mbox) {
274 err = 4;
James Smart92d7f7b2007-06-17 19:56:38 -0500275 goto fail;
James Smart98c9ea52007-10-27 13:37:33 -0400276 }
James Smart92d7f7b2007-06-17 19:56:38 -0500277 rc = lpfc_reg_login(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox,
278 0);
James Smart98c9ea52007-10-27 13:37:33 -0400279 if (rc) {
280 err = 5;
James Smart92d7f7b2007-06-17 19:56:38 -0500281 goto fail_free_mbox;
James Smart98c9ea52007-10-27 13:37:33 -0400282 }
James Smart92d7f7b2007-06-17 19:56:38 -0500283
284 mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login;
285 mbox->vport = vport;
286 mbox->context2 = lpfc_nlp_get(ndlp);
287
James Smart0b727fe2007-10-27 13:37:25 -0400288 rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
James Smart98c9ea52007-10-27 13:37:33 -0400289 if (rc == MBX_NOT_FINISHED) {
290 err = 6;
James Smart92d7f7b2007-06-17 19:56:38 -0500291 goto fail_issue_reg_login;
James Smart98c9ea52007-10-27 13:37:33 -0400292 }
James Smart92d7f7b2007-06-17 19:56:38 -0500293
294 return 0;
295
296fail_issue_reg_login:
297 lpfc_nlp_put(ndlp);
298 mp = (struct lpfc_dmabuf *) mbox->context1;
299 lpfc_mbuf_free(phba, mp->virt, mp->phys);
300 kfree(mp);
301fail_free_mbox:
302 mempool_free(mbox, phba->mbox_mem_pool);
303
304fail:
305 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
James Smarte8b62012007-08-02 11:10:09 -0400306 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
James Smart98c9ea52007-10-27 13:37:33 -0400307 "0249 Cannot issue Register Fabric login: Err %d\n", err);
James Smart92d7f7b2007-06-17 19:56:38 -0500308 return -ENXIO;
309}
310
311static int
James Smart2e0fef82007-06-17 19:56:36 -0500312lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
313 struct serv_parm *sp, IOCB_t *irsp)
dea31012005-04-17 16:05:31 -0500314{
James Smart2e0fef82007-06-17 19:56:36 -0500315 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
316 struct lpfc_hba *phba = vport->phba;
James Smart92d7f7b2007-06-17 19:56:38 -0500317 struct lpfc_nodelist *np;
318 struct lpfc_nodelist *next_np;
dea31012005-04-17 16:05:31 -0500319
James Smart2e0fef82007-06-17 19:56:36 -0500320 spin_lock_irq(shost->host_lock);
321 vport->fc_flag |= FC_FABRIC;
322 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500323
324 phba->fc_edtov = be32_to_cpu(sp->cmn.e_d_tov);
325 if (sp->cmn.edtovResolution) /* E_D_TOV ticks are in nanoseconds */
326 phba->fc_edtov = (phba->fc_edtov + 999999) / 1000000;
327
328 phba->fc_ratov = (be32_to_cpu(sp->cmn.w2.r_a_tov) + 999) / 1000;
329
330 if (phba->fc_topology == TOPOLOGY_LOOP) {
James Smart2e0fef82007-06-17 19:56:36 -0500331 spin_lock_irq(shost->host_lock);
332 vport->fc_flag |= FC_PUBLIC_LOOP;
333 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500334 } else {
335 /*
336 * If we are a N-port connected to a Fabric, fixup sparam's so
337 * logins to devices on remote loops work.
338 */
James Smart2e0fef82007-06-17 19:56:36 -0500339 vport->fc_sparam.cmn.altBbCredit = 1;
dea31012005-04-17 16:05:31 -0500340 }
341
James Smart2e0fef82007-06-17 19:56:36 -0500342 vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID;
dea31012005-04-17 16:05:31 -0500343 memcpy(&ndlp->nlp_portname, &sp->portName, sizeof(struct lpfc_name));
James Smart92d7f7b2007-06-17 19:56:38 -0500344 memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -0500345 ndlp->nlp_class_sup = 0;
346 if (sp->cls1.classValid)
347 ndlp->nlp_class_sup |= FC_COS_CLASS1;
348 if (sp->cls2.classValid)
349 ndlp->nlp_class_sup |= FC_COS_CLASS2;
350 if (sp->cls3.classValid)
351 ndlp->nlp_class_sup |= FC_COS_CLASS3;
352 if (sp->cls4.classValid)
353 ndlp->nlp_class_sup |= FC_COS_CLASS4;
354 ndlp->nlp_maxframe = ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) |
355 sp->cmn.bbRcvSizeLsb;
356 memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
357
James Smart92d7f7b2007-06-17 19:56:38 -0500358 if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
359 if (sp->cmn.response_multiple_NPort) {
James Smarte8b62012007-08-02 11:10:09 -0400360 lpfc_printf_vlog(vport, KERN_WARNING,
361 LOG_ELS | LOG_VPORT,
362 "1816 FLOGI NPIV supported, "
363 "response data 0x%x\n",
364 sp->cmn.response_multiple_NPort);
James Smart92d7f7b2007-06-17 19:56:38 -0500365 phba->link_flag |= LS_NPIV_FAB_SUPPORTED;
James Smart92d7f7b2007-06-17 19:56:38 -0500366 } else {
367 /* Because we asked f/w for NPIV it still expects us
James Smarte8b62012007-08-02 11:10:09 -0400368 to call reg_vnpid atleast for the physcial host */
369 lpfc_printf_vlog(vport, KERN_WARNING,
370 LOG_ELS | LOG_VPORT,
371 "1817 Fabric does not support NPIV "
372 "- configuring single port mode.\n");
James Smart92d7f7b2007-06-17 19:56:38 -0500373 phba->link_flag &= ~LS_NPIV_FAB_SUPPORTED;
374 }
375 }
376
377 if ((vport->fc_prevDID != vport->fc_myDID) &&
378 !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) {
379
380 /* If our NportID changed, we need to ensure all
381 * remaining NPORTs get unreg_login'ed.
382 */
383 list_for_each_entry_safe(np, next_np,
384 &vport->fc_nodes, nlp_listp) {
385 if ((np->nlp_state != NLP_STE_NPR_NODE) ||
386 !(np->nlp_flag & NLP_NPR_ADISC))
387 continue;
388 spin_lock_irq(shost->host_lock);
389 np->nlp_flag &= ~NLP_NPR_ADISC;
390 spin_unlock_irq(shost->host_lock);
391 lpfc_unreg_rpi(vport, np);
392 }
393 if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
394 lpfc_mbx_unreg_vpi(vport);
395 vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
396 }
397 }
398
James Smart2e0fef82007-06-17 19:56:36 -0500399 ndlp->nlp_sid = irsp->un.ulpWord[4] & Mask_DID;
James Smart92d7f7b2007-06-17 19:56:38 -0500400 lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE);
James Smart2e0fef82007-06-17 19:56:36 -0500401
James Smart92d7f7b2007-06-17 19:56:38 -0500402 if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED &&
403 vport->fc_flag & FC_VPORT_NEEDS_REG_VPI) {
404 lpfc_register_new_vport(phba, vport, ndlp);
405 return 0;
406 }
407 lpfc_issue_fabric_reglogin(vport);
dea31012005-04-17 16:05:31 -0500408 return 0;
dea31012005-04-17 16:05:31 -0500409}
410
411/*
412 * We FLOGIed into an NPort, initiate pt2pt protocol
413 */
414static int
James Smart2e0fef82007-06-17 19:56:36 -0500415lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
416 struct serv_parm *sp)
dea31012005-04-17 16:05:31 -0500417{
James Smart2e0fef82007-06-17 19:56:36 -0500418 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
419 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500420 LPFC_MBOXQ_t *mbox;
421 int rc;
422
James Smart2e0fef82007-06-17 19:56:36 -0500423 spin_lock_irq(shost->host_lock);
424 vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
425 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500426
427 phba->fc_edtov = FF_DEF_EDTOV;
428 phba->fc_ratov = FF_DEF_RATOV;
James Smart2e0fef82007-06-17 19:56:36 -0500429 rc = memcmp(&vport->fc_portname, &sp->portName,
James Smart92d7f7b2007-06-17 19:56:38 -0500430 sizeof(vport->fc_portname));
dea31012005-04-17 16:05:31 -0500431 if (rc >= 0) {
432 /* This side will initiate the PLOGI */
James Smart2e0fef82007-06-17 19:56:36 -0500433 spin_lock_irq(shost->host_lock);
434 vport->fc_flag |= FC_PT2PT_PLOGI;
435 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500436
437 /*
438 * N_Port ID cannot be 0, set our to LocalID the other
439 * side will be RemoteID.
440 */
441
442 /* not equal */
443 if (rc)
James Smart2e0fef82007-06-17 19:56:36 -0500444 vport->fc_myDID = PT2PT_LocalID;
dea31012005-04-17 16:05:31 -0500445
446 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
447 if (!mbox)
448 goto fail;
449
450 lpfc_config_link(phba, mbox);
451
452 mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
James Smarted957682007-06-17 19:56:37 -0500453 mbox->vport = vport;
James Smart0b727fe2007-10-27 13:37:25 -0400454 rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
dea31012005-04-17 16:05:31 -0500455 if (rc == MBX_NOT_FINISHED) {
456 mempool_free(mbox, phba->mbox_mem_pool);
457 goto fail;
458 }
James Smart329f9bc2007-04-25 09:53:01 -0400459 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -0500460
James Smart2e0fef82007-06-17 19:56:36 -0500461 ndlp = lpfc_findnode_did(vport, PT2PT_RemoteID);
dea31012005-04-17 16:05:31 -0500462 if (!ndlp) {
463 /*
464 * Cannot find existing Fabric ndlp, so allocate a
465 * new one
466 */
467 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
468 if (!ndlp)
469 goto fail;
470
James Smart2e0fef82007-06-17 19:56:36 -0500471 lpfc_nlp_init(vport, ndlp, PT2PT_RemoteID);
dea31012005-04-17 16:05:31 -0500472 }
473
474 memcpy(&ndlp->nlp_portname, &sp->portName,
James Smart2e0fef82007-06-17 19:56:36 -0500475 sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -0500476 memcpy(&ndlp->nlp_nodename, &sp->nodeName,
James Smart2e0fef82007-06-17 19:56:36 -0500477 sizeof(struct lpfc_name));
478 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
479 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500480 ndlp->nlp_flag |= NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -0500481 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500482 } else {
483 /* This side will wait for the PLOGI */
James Smart329f9bc2007-04-25 09:53:01 -0400484 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -0500485 }
486
James Smart2e0fef82007-06-17 19:56:36 -0500487 spin_lock_irq(shost->host_lock);
488 vport->fc_flag |= FC_PT2PT;
489 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500490
491 /* Start discovery - this should just do CLEAR_LA */
James Smart2e0fef82007-06-17 19:56:36 -0500492 lpfc_disc_start(vport);
dea31012005-04-17 16:05:31 -0500493 return 0;
James Smart92d7f7b2007-06-17 19:56:38 -0500494fail:
dea31012005-04-17 16:05:31 -0500495 return -ENXIO;
496}
497
498static void
James Smart329f9bc2007-04-25 09:53:01 -0400499lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
500 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -0500501{
James Smart2e0fef82007-06-17 19:56:36 -0500502 struct lpfc_vport *vport = cmdiocb->vport;
503 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -0500504 IOCB_t *irsp = &rspiocb->iocb;
505 struct lpfc_nodelist *ndlp = cmdiocb->context1;
506 struct lpfc_dmabuf *pcmd = cmdiocb->context2, *prsp;
507 struct serv_parm *sp;
508 int rc;
509
510 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -0500511 if (lpfc_els_chk_latt(vport)) {
James Smart329f9bc2007-04-25 09:53:01 -0400512 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -0500513 goto out;
514 }
515
James Smart858c9f62007-06-17 19:56:39 -0500516 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
517 "FLOGI cmpl: status:x%x/x%x state:x%x",
518 irsp->ulpStatus, irsp->un.ulpWord[4],
519 vport->port_state);
520
dea31012005-04-17 16:05:31 -0500521 if (irsp->ulpStatus) {
522 /* Check for retry */
James Smart2e0fef82007-06-17 19:56:36 -0500523 if (lpfc_els_retry(phba, cmdiocb, rspiocb))
dea31012005-04-17 16:05:31 -0500524 goto out;
James Smart2e0fef82007-06-17 19:56:36 -0500525
dea31012005-04-17 16:05:31 -0500526 /* FLOGI failed, so there is no fabric */
James Smart2e0fef82007-06-17 19:56:36 -0500527 spin_lock_irq(shost->host_lock);
528 vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
529 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500530
James Smart329f9bc2007-04-25 09:53:01 -0400531 /* If private loop, then allow max outstanding els to be
dea31012005-04-17 16:05:31 -0500532 * LPFC_MAX_DISC_THREADS (32). Scanning in the case of no
533 * alpa map would take too long otherwise.
534 */
535 if (phba->alpa_map[0] == 0) {
James Smart3de2a652007-08-02 11:09:59 -0400536 vport->cfg_discovery_threads = LPFC_MAX_DISC_THREADS;
dea31012005-04-17 16:05:31 -0500537 }
538
539 /* FLOGI failure */
James Smarte8b62012007-08-02 11:10:09 -0400540 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
541 "0100 FLOGI failure Data: x%x x%x "
542 "x%x\n",
543 irsp->ulpStatus, irsp->un.ulpWord[4],
544 irsp->ulpTimeout);
dea31012005-04-17 16:05:31 -0500545 goto flogifail;
546 }
547
548 /*
549 * The FLogI succeeded. Sync the data for the CPU before
550 * accessing it.
551 */
552 prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list);
553
554 sp = prsp->virt + sizeof(uint32_t);
555
556 /* FLOGI completes successfully */
James Smarte8b62012007-08-02 11:10:09 -0400557 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
558 "0101 FLOGI completes sucessfully "
559 "Data: x%x x%x x%x x%x\n",
560 irsp->un.ulpWord[4], sp->cmn.e_d_tov,
561 sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution);
dea31012005-04-17 16:05:31 -0500562
James Smart2e0fef82007-06-17 19:56:36 -0500563 if (vport->port_state == LPFC_FLOGI) {
dea31012005-04-17 16:05:31 -0500564 /*
565 * If Common Service Parameters indicate Nport
566 * we are point to point, if Fport we are Fabric.
567 */
568 if (sp->cmn.fPort)
James Smart2e0fef82007-06-17 19:56:36 -0500569 rc = lpfc_cmpl_els_flogi_fabric(vport, ndlp, sp, irsp);
dea31012005-04-17 16:05:31 -0500570 else
James Smart2e0fef82007-06-17 19:56:36 -0500571 rc = lpfc_cmpl_els_flogi_nport(vport, ndlp, sp);
dea31012005-04-17 16:05:31 -0500572
573 if (!rc)
574 goto out;
575 }
576
577flogifail:
James Smart329f9bc2007-04-25 09:53:01 -0400578 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -0500579
James Smart858c9f62007-06-17 19:56:39 -0500580 if (!lpfc_error_lost_link(irsp)) {
dea31012005-04-17 16:05:31 -0500581 /* FLOGI failed, so just use loop map to make discovery list */
James Smart2e0fef82007-06-17 19:56:36 -0500582 lpfc_disc_list_loopmap(vport);
dea31012005-04-17 16:05:31 -0500583
584 /* Start discovery */
James Smart2e0fef82007-06-17 19:56:36 -0500585 lpfc_disc_start(vport);
James Smart87af33f2007-10-27 13:37:43 -0400586 } else if (((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
587 ((irsp->un.ulpWord[4] != IOERR_SLI_ABORTED) &&
588 (irsp->un.ulpWord[4] != IOERR_SLI_DOWN))) &&
589 (phba->link_state != LPFC_CLEAR_LA)) {
590 /* If FLOGI failed enable link interrupt. */
591 lpfc_issue_clear_la(phba, vport);
dea31012005-04-17 16:05:31 -0500592 }
dea31012005-04-17 16:05:31 -0500593out:
594 lpfc_els_free_iocb(phba, cmdiocb);
595}
596
597static int
James Smart2e0fef82007-06-17 19:56:36 -0500598lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
dea31012005-04-17 16:05:31 -0500599 uint8_t retry)
600{
James Smart2e0fef82007-06-17 19:56:36 -0500601 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500602 struct serv_parm *sp;
603 IOCB_t *icmd;
604 struct lpfc_iocbq *elsiocb;
605 struct lpfc_sli_ring *pring;
606 uint8_t *pcmd;
607 uint16_t cmdsize;
608 uint32_t tmo;
609 int rc;
610
611 pring = &phba->sli.ring[LPFC_ELS_RING];
612
James Smart92d7f7b2007-06-17 19:56:38 -0500613 cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
James Smart2e0fef82007-06-17 19:56:36 -0500614 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
615 ndlp->nlp_DID, ELS_CMD_FLOGI);
James Smart92d7f7b2007-06-17 19:56:38 -0500616
James Smart488d1462006-03-07 15:02:37 -0500617 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500618 return 1;
dea31012005-04-17 16:05:31 -0500619
620 icmd = &elsiocb->iocb;
621 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
622
623 /* For FLOGI request, remainder of payload is service parameters */
624 *((uint32_t *) (pcmd)) = ELS_CMD_FLOGI;
James Smart92d7f7b2007-06-17 19:56:38 -0500625 pcmd += sizeof(uint32_t);
626 memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
dea31012005-04-17 16:05:31 -0500627 sp = (struct serv_parm *) pcmd;
628
629 /* Setup CSPs accordingly for Fabric */
630 sp->cmn.e_d_tov = 0;
631 sp->cmn.w2.r_a_tov = 0;
632 sp->cls1.classValid = 0;
633 sp->cls2.seqDelivery = 1;
634 sp->cls3.seqDelivery = 1;
635 if (sp->cmn.fcphLow < FC_PH3)
636 sp->cmn.fcphLow = FC_PH3;
637 if (sp->cmn.fcphHigh < FC_PH3)
638 sp->cmn.fcphHigh = FC_PH3;
639
James Smart92d7f7b2007-06-17 19:56:38 -0500640 if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
641 sp->cmn.request_multiple_Nport = 1;
642
643 /* For FLOGI, Let FLOGI rsp set the NPortID for VPI 0 */
644 icmd->ulpCt_h = 1;
645 icmd->ulpCt_l = 0;
646 }
647
James Smart858c9f62007-06-17 19:56:39 -0500648 if (phba->fc_topology != TOPOLOGY_LOOP) {
649 icmd->un.elsreq64.myID = 0;
650 icmd->un.elsreq64.fl = 1;
651 }
652
dea31012005-04-17 16:05:31 -0500653 tmo = phba->fc_ratov;
654 phba->fc_ratov = LPFC_DISC_FLOGI_TMO;
James Smart2e0fef82007-06-17 19:56:36 -0500655 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -0500656 phba->fc_ratov = tmo;
657
658 phba->fc_stat.elsXmitFLOGI++;
659 elsiocb->iocb_cmpl = lpfc_cmpl_els_flogi;
James Smart858c9f62007-06-17 19:56:39 -0500660
661 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
662 "Issue FLOGI: opt:x%x",
663 phba->sli3_options, 0, 0);
664
James Smart92d7f7b2007-06-17 19:56:38 -0500665 rc = lpfc_issue_fabric_iocb(phba, elsiocb);
dea31012005-04-17 16:05:31 -0500666 if (rc == IOCB_ERROR) {
667 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500668 return 1;
dea31012005-04-17 16:05:31 -0500669 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500670 return 0;
dea31012005-04-17 16:05:31 -0500671}
672
673int
James Smart2e0fef82007-06-17 19:56:36 -0500674lpfc_els_abort_flogi(struct lpfc_hba *phba)
dea31012005-04-17 16:05:31 -0500675{
676 struct lpfc_sli_ring *pring;
677 struct lpfc_iocbq *iocb, *next_iocb;
678 struct lpfc_nodelist *ndlp;
679 IOCB_t *icmd;
680
681 /* Abort outstanding I/O on NPort <nlp_DID> */
682 lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
James Smarte8b62012007-08-02 11:10:09 -0400683 "0201 Abort outstanding I/O on NPort x%x\n",
684 Fabric_DID);
dea31012005-04-17 16:05:31 -0500685
686 pring = &phba->sli.ring[LPFC_ELS_RING];
687
688 /*
689 * Check the txcmplq for an iocb that matches the nport the driver is
690 * searching for.
691 */
James Smart2e0fef82007-06-17 19:56:36 -0500692 spin_lock_irq(&phba->hbalock);
dea31012005-04-17 16:05:31 -0500693 list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
694 icmd = &iocb->iocb;
James Smart2e0fef82007-06-17 19:56:36 -0500695 if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR &&
696 icmd->un.elsreq64.bdl.ulpIoTag32) {
dea31012005-04-17 16:05:31 -0500697 ndlp = (struct lpfc_nodelist *)(iocb->context1);
James Smart92d7f7b2007-06-17 19:56:38 -0500698 if (ndlp && (ndlp->nlp_DID == Fabric_DID)) {
James Smart07951072007-04-25 09:51:38 -0400699 lpfc_sli_issue_abort_iotag(phba, pring, iocb);
James Smart92d7f7b2007-06-17 19:56:38 -0500700 }
dea31012005-04-17 16:05:31 -0500701 }
702 }
James Smart2e0fef82007-06-17 19:56:36 -0500703 spin_unlock_irq(&phba->hbalock);
dea31012005-04-17 16:05:31 -0500704
705 return 0;
706}
707
708int
James Smart2e0fef82007-06-17 19:56:36 -0500709lpfc_initial_flogi(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -0500710{
James Smart2e0fef82007-06-17 19:56:36 -0500711 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500712 struct lpfc_nodelist *ndlp;
713
James Smart98c9ea52007-10-27 13:37:33 -0400714 vport->port_state = LPFC_FLOGI;
715 lpfc_set_disctmo(vport);
716
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500717 /* First look for the Fabric ndlp */
James Smart2e0fef82007-06-17 19:56:36 -0500718 ndlp = lpfc_findnode_did(vport, Fabric_DID);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500719 if (!ndlp) {
dea31012005-04-17 16:05:31 -0500720 /* Cannot find existing Fabric ndlp, so allocate a new one */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500721 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
722 if (!ndlp)
723 return 0;
James Smart2e0fef82007-06-17 19:56:36 -0500724 lpfc_nlp_init(vport, ndlp, Fabric_DID);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500725 } else {
James Smart2e0fef82007-06-17 19:56:36 -0500726 lpfc_dequeue_node(vport, ndlp);
dea31012005-04-17 16:05:31 -0500727 }
James Smart87af33f2007-10-27 13:37:43 -0400728
James Smart2e0fef82007-06-17 19:56:36 -0500729 if (lpfc_issue_els_flogi(vport, ndlp, 0)) {
James Smart329f9bc2007-04-25 09:53:01 -0400730 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -0500731 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500732 return 1;
dea31012005-04-17 16:05:31 -0500733}
734
James Smart92d7f7b2007-06-17 19:56:38 -0500735int
736lpfc_initial_fdisc(struct lpfc_vport *vport)
737{
738 struct lpfc_hba *phba = vport->phba;
739 struct lpfc_nodelist *ndlp;
740
741 /* First look for the Fabric ndlp */
742 ndlp = lpfc_findnode_did(vport, Fabric_DID);
743 if (!ndlp) {
744 /* Cannot find existing Fabric ndlp, so allocate a new one */
745 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
746 if (!ndlp)
747 return 0;
748 lpfc_nlp_init(vport, ndlp, Fabric_DID);
749 } else {
750 lpfc_dequeue_node(vport, ndlp);
751 }
752 if (lpfc_issue_els_fdisc(vport, ndlp, 0)) {
753 lpfc_nlp_put(ndlp);
754 }
755 return 1;
756}
James Smart87af33f2007-10-27 13:37:43 -0400757
758void
James Smart2e0fef82007-06-17 19:56:36 -0500759lpfc_more_plogi(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -0500760{
761 int sentplogi;
762
James Smart2e0fef82007-06-17 19:56:36 -0500763 if (vport->num_disc_nodes)
764 vport->num_disc_nodes--;
dea31012005-04-17 16:05:31 -0500765
766 /* Continue discovery with <num_disc_nodes> PLOGIs to go */
James Smarte8b62012007-08-02 11:10:09 -0400767 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
768 "0232 Continue discovery with %d PLOGIs to go "
769 "Data: x%x x%x x%x\n",
770 vport->num_disc_nodes, vport->fc_plogi_cnt,
771 vport->fc_flag, vport->port_state);
dea31012005-04-17 16:05:31 -0500772 /* Check to see if there are more PLOGIs to be sent */
James Smart2e0fef82007-06-17 19:56:36 -0500773 if (vport->fc_flag & FC_NLP_MORE)
774 /* go thru NPR nodes and issue any remaining ELS PLOGIs */
775 sentplogi = lpfc_els_disc_plogi(vport);
776
dea31012005-04-17 16:05:31 -0500777 return;
778}
779
James Smart488d1462006-03-07 15:02:37 -0500780static struct lpfc_nodelist *
James Smart92d7f7b2007-06-17 19:56:38 -0500781lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
James Smart488d1462006-03-07 15:02:37 -0500782 struct lpfc_nodelist *ndlp)
783{
James Smart2e0fef82007-06-17 19:56:36 -0500784 struct lpfc_vport *vport = ndlp->vport;
James Smart488d1462006-03-07 15:02:37 -0500785 struct lpfc_nodelist *new_ndlp;
James Smart488d1462006-03-07 15:02:37 -0500786 struct serv_parm *sp;
James Smart92d7f7b2007-06-17 19:56:38 -0500787 uint8_t name[sizeof(struct lpfc_name)];
James Smart488d1462006-03-07 15:02:37 -0500788 uint32_t rc;
789
James Smart2fb9bd82006-12-02 13:33:57 -0500790 /* Fabric nodes can have the same WWPN so we don't bother searching
791 * by WWPN. Just return the ndlp that was given to us.
792 */
793 if (ndlp->nlp_type & NLP_FABRIC)
794 return ndlp;
795
James Smart92d7f7b2007-06-17 19:56:38 -0500796 sp = (struct serv_parm *) ((uint8_t *) prsp + sizeof(uint32_t));
James Smart685f0bf2007-04-25 09:53:08 -0400797 memset(name, 0, sizeof(struct lpfc_name));
James Smart488d1462006-03-07 15:02:37 -0500798
James Smart685f0bf2007-04-25 09:53:08 -0400799 /* Now we find out if the NPort we are logging into, matches the WWPN
James Smart488d1462006-03-07 15:02:37 -0500800 * we have for that ndlp. If not, we have some work to do.
801 */
James Smart2e0fef82007-06-17 19:56:36 -0500802 new_ndlp = lpfc_findnode_wwpn(vport, &sp->portName);
James Smart488d1462006-03-07 15:02:37 -0500803
James Smart92795652006-07-06 15:50:02 -0400804 if (new_ndlp == ndlp)
James Smart488d1462006-03-07 15:02:37 -0500805 return ndlp;
James Smart488d1462006-03-07 15:02:37 -0500806
807 if (!new_ndlp) {
James Smart2e0fef82007-06-17 19:56:36 -0500808 rc = memcmp(&ndlp->nlp_portname, name,
809 sizeof(struct lpfc_name));
James Smart92795652006-07-06 15:50:02 -0400810 if (!rc)
811 return ndlp;
James Smart488d1462006-03-07 15:02:37 -0500812 new_ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC);
813 if (!new_ndlp)
814 return ndlp;
815
James Smart2e0fef82007-06-17 19:56:36 -0500816 lpfc_nlp_init(vport, new_ndlp, ndlp->nlp_DID);
James Smart488d1462006-03-07 15:02:37 -0500817 }
818
James Smart2e0fef82007-06-17 19:56:36 -0500819 lpfc_unreg_rpi(vport, new_ndlp);
James Smart488d1462006-03-07 15:02:37 -0500820 new_ndlp->nlp_DID = ndlp->nlp_DID;
James Smart92795652006-07-06 15:50:02 -0400821 new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
James Smart2e0fef82007-06-17 19:56:36 -0500822 lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state);
James Smart488d1462006-03-07 15:02:37 -0500823
James Smart2e0fef82007-06-17 19:56:36 -0500824 /* Move this back to NPR state */
James Smart87af33f2007-10-27 13:37:43 -0400825 if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) {
826 /* The new_ndlp is replacing ndlp totally, so we need
827 * to put ndlp on UNUSED list and try to free it.
828 */
James Smart2e0fef82007-06-17 19:56:36 -0500829 lpfc_drop_node(vport, ndlp);
James Smart87af33f2007-10-27 13:37:43 -0400830 }
James Smart92795652006-07-06 15:50:02 -0400831 else {
James Smart2e0fef82007-06-17 19:56:36 -0500832 lpfc_unreg_rpi(vport, ndlp);
James Smart92795652006-07-06 15:50:02 -0400833 ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
James Smart2e0fef82007-06-17 19:56:36 -0500834 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
James Smart92795652006-07-06 15:50:02 -0400835 }
James Smart488d1462006-03-07 15:02:37 -0500836 return new_ndlp;
837}
838
James Smart87af33f2007-10-27 13:37:43 -0400839void
840lpfc_end_rscn(struct lpfc_vport *vport)
841{
842 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
843
844 if (vport->fc_flag & FC_RSCN_MODE) {
845 /*
846 * Check to see if more RSCNs came in while we were
847 * processing this one.
848 */
849 if (vport->fc_rscn_id_cnt ||
850 (vport->fc_flag & FC_RSCN_DISCOVERY) != 0)
851 lpfc_els_handle_rscn(vport);
852 else {
853 spin_lock_irq(shost->host_lock);
854 vport->fc_flag &= ~FC_RSCN_MODE;
855 spin_unlock_irq(shost->host_lock);
856 }
857 }
858}
859
dea31012005-04-17 16:05:31 -0500860static void
James Smart2e0fef82007-06-17 19:56:36 -0500861lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
862 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -0500863{
James Smart2e0fef82007-06-17 19:56:36 -0500864 struct lpfc_vport *vport = cmdiocb->vport;
865 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -0500866 IOCB_t *irsp;
dea31012005-04-17 16:05:31 -0500867 struct lpfc_nodelist *ndlp;
James Smart92795652006-07-06 15:50:02 -0400868 struct lpfc_dmabuf *prsp;
dea31012005-04-17 16:05:31 -0500869 int disc, rc, did, type;
870
dea31012005-04-17 16:05:31 -0500871 /* we pass cmdiocb to state machine which needs rspiocb as well */
872 cmdiocb->context_un.rsp_iocb = rspiocb;
873
874 irsp = &rspiocb->iocb;
James Smart858c9f62007-06-17 19:56:39 -0500875 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
876 "PLOGI cmpl: status:x%x/x%x did:x%x",
877 irsp->ulpStatus, irsp->un.ulpWord[4],
878 irsp->un.elsreq64.remoteID);
879
James Smart2e0fef82007-06-17 19:56:36 -0500880 ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID);
James Smarted957682007-06-17 19:56:37 -0500881 if (!ndlp) {
James Smarte8b62012007-08-02 11:10:09 -0400882 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
883 "0136 PLOGI completes to NPort x%x "
884 "with no ndlp. Data: x%x x%x x%x\n",
885 irsp->un.elsreq64.remoteID,
886 irsp->ulpStatus, irsp->un.ulpWord[4],
887 irsp->ulpIoTag);
James Smart488d1462006-03-07 15:02:37 -0500888 goto out;
James Smarted957682007-06-17 19:56:37 -0500889 }
dea31012005-04-17 16:05:31 -0500890
891 /* Since ndlp can be freed in the disc state machine, note if this node
892 * is being used during discovery.
893 */
James Smart2e0fef82007-06-17 19:56:36 -0500894 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500895 disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
James Smart488d1462006-03-07 15:02:37 -0500896 ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -0500897 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500898 rc = 0;
899
900 /* PLOGI completes to NPort <nlp_DID> */
James Smarte8b62012007-08-02 11:10:09 -0400901 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
902 "0102 PLOGI completes to NPort x%x "
903 "Data: x%x x%x x%x x%x x%x\n",
904 ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4],
905 irsp->ulpTimeout, disc, vport->num_disc_nodes);
dea31012005-04-17 16:05:31 -0500906 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -0500907 if (lpfc_els_chk_latt(vport)) {
908 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500909 ndlp->nlp_flag |= NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -0500910 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500911 goto out;
912 }
913
914 /* ndlp could be freed in DSM, save these values now */
915 type = ndlp->nlp_type;
916 did = ndlp->nlp_DID;
917
918 if (irsp->ulpStatus) {
919 /* Check for retry */
920 if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
921 /* ELS command is being retried */
922 if (disc) {
James Smart2e0fef82007-06-17 19:56:36 -0500923 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500924 ndlp->nlp_flag |= NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -0500925 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500926 }
927 goto out;
928 }
dea31012005-04-17 16:05:31 -0500929 /* PLOGI failed */
930 /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
James Smart858c9f62007-06-17 19:56:39 -0500931 if (lpfc_error_lost_link(irsp)) {
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500932 rc = NLP_STE_FREED_NODE;
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -0500933 } else {
James Smart2e0fef82007-06-17 19:56:36 -0500934 rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart92d7f7b2007-06-17 19:56:38 -0500935 NLP_EVT_CMPL_PLOGI);
dea31012005-04-17 16:05:31 -0500936 }
937 } else {
938 /* Good status, call state machine */
James Smart92795652006-07-06 15:50:02 -0400939 prsp = list_entry(((struct lpfc_dmabuf *)
James Smart92d7f7b2007-06-17 19:56:38 -0500940 cmdiocb->context2)->list.next,
941 struct lpfc_dmabuf, list);
942 ndlp = lpfc_plogi_confirm_nport(phba, prsp->virt, ndlp);
James Smart2e0fef82007-06-17 19:56:36 -0500943 rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart92d7f7b2007-06-17 19:56:38 -0500944 NLP_EVT_CMPL_PLOGI);
dea31012005-04-17 16:05:31 -0500945 }
946
James Smart2e0fef82007-06-17 19:56:36 -0500947 if (disc && vport->num_disc_nodes) {
dea31012005-04-17 16:05:31 -0500948 /* Check to see if there are more PLOGIs to be sent */
James Smart2e0fef82007-06-17 19:56:36 -0500949 lpfc_more_plogi(vport);
dea31012005-04-17 16:05:31 -0500950
James Smart2e0fef82007-06-17 19:56:36 -0500951 if (vport->num_disc_nodes == 0) {
952 spin_lock_irq(shost->host_lock);
953 vport->fc_flag &= ~FC_NDISC_ACTIVE;
954 spin_unlock_irq(shost->host_lock);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500955
James Smart2e0fef82007-06-17 19:56:36 -0500956 lpfc_can_disctmo(vport);
James Smart87af33f2007-10-27 13:37:43 -0400957 lpfc_end_rscn(vport);
dea31012005-04-17 16:05:31 -0500958 }
959 }
960
961out:
962 lpfc_els_free_iocb(phba, cmdiocb);
963 return;
964}
965
966int
James Smart2e0fef82007-06-17 19:56:36 -0500967lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
dea31012005-04-17 16:05:31 -0500968{
James Smart2e0fef82007-06-17 19:56:36 -0500969 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500970 struct serv_parm *sp;
971 IOCB_t *icmd;
James Smart98c9ea52007-10-27 13:37:33 -0400972 struct lpfc_nodelist *ndlp;
dea31012005-04-17 16:05:31 -0500973 struct lpfc_iocbq *elsiocb;
974 struct lpfc_sli_ring *pring;
975 struct lpfc_sli *psli;
976 uint8_t *pcmd;
977 uint16_t cmdsize;
James Smart92d7f7b2007-06-17 19:56:38 -0500978 int ret;
dea31012005-04-17 16:05:31 -0500979
980 psli = &phba->sli;
981 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
982
James Smart98c9ea52007-10-27 13:37:33 -0400983 ndlp = lpfc_findnode_did(vport, did);
984 /* If ndlp if not NULL, we will bump the reference count on it */
985
James Smart92d7f7b2007-06-17 19:56:38 -0500986 cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
James Smart98c9ea52007-10-27 13:37:33 -0400987 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did,
James Smart2e0fef82007-06-17 19:56:36 -0500988 ELS_CMD_PLOGI);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500989 if (!elsiocb)
990 return 1;
dea31012005-04-17 16:05:31 -0500991
992 icmd = &elsiocb->iocb;
993 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
994
995 /* For PLOGI request, remainder of payload is service parameters */
996 *((uint32_t *) (pcmd)) = ELS_CMD_PLOGI;
James Smart92d7f7b2007-06-17 19:56:38 -0500997 pcmd += sizeof(uint32_t);
998 memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
dea31012005-04-17 16:05:31 -0500999 sp = (struct serv_parm *) pcmd;
1000
1001 if (sp->cmn.fcphLow < FC_PH_4_3)
1002 sp->cmn.fcphLow = FC_PH_4_3;
1003
1004 if (sp->cmn.fcphHigh < FC_PH3)
1005 sp->cmn.fcphHigh = FC_PH3;
1006
James Smart858c9f62007-06-17 19:56:39 -05001007 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1008 "Issue PLOGI: did:x%x",
1009 did, 0, 0);
1010
dea31012005-04-17 16:05:31 -05001011 phba->fc_stat.elsXmitPLOGI++;
1012 elsiocb->iocb_cmpl = lpfc_cmpl_els_plogi;
James Smart92d7f7b2007-06-17 19:56:38 -05001013 ret = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
1014
1015 if (ret == IOCB_ERROR) {
dea31012005-04-17 16:05:31 -05001016 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001017 return 1;
dea31012005-04-17 16:05:31 -05001018 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001019 return 0;
dea31012005-04-17 16:05:31 -05001020}
1021
1022static void
James Smart2e0fef82007-06-17 19:56:36 -05001023lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1024 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05001025{
James Smart2e0fef82007-06-17 19:56:36 -05001026 struct lpfc_vport *vport = cmdiocb->vport;
1027 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05001028 IOCB_t *irsp;
1029 struct lpfc_sli *psli;
1030 struct lpfc_nodelist *ndlp;
1031
1032 psli = &phba->sli;
1033 /* we pass cmdiocb to state machine which needs rspiocb as well */
1034 cmdiocb->context_un.rsp_iocb = rspiocb;
1035
1036 irsp = &(rspiocb->iocb);
1037 ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
James Smart2e0fef82007-06-17 19:56:36 -05001038 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001039 ndlp->nlp_flag &= ~NLP_PRLI_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001040 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001041
James Smart858c9f62007-06-17 19:56:39 -05001042 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1043 "PRLI cmpl: status:x%x/x%x did:x%x",
1044 irsp->ulpStatus, irsp->un.ulpWord[4],
1045 ndlp->nlp_DID);
dea31012005-04-17 16:05:31 -05001046 /* PRLI completes to NPort <nlp_DID> */
James Smarte8b62012007-08-02 11:10:09 -04001047 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
1048 "0103 PRLI completes to NPort x%x "
1049 "Data: x%x x%x x%x x%x\n",
1050 ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4],
1051 irsp->ulpTimeout, vport->num_disc_nodes);
dea31012005-04-17 16:05:31 -05001052
James Smart2e0fef82007-06-17 19:56:36 -05001053 vport->fc_prli_sent--;
dea31012005-04-17 16:05:31 -05001054 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -05001055 if (lpfc_els_chk_latt(vport))
dea31012005-04-17 16:05:31 -05001056 goto out;
1057
1058 if (irsp->ulpStatus) {
1059 /* Check for retry */
1060 if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
1061 /* ELS command is being retried */
1062 goto out;
1063 }
1064 /* PRLI failed */
1065 /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
James Smart858c9f62007-06-17 19:56:39 -05001066 if (lpfc_error_lost_link(irsp)) {
dea31012005-04-17 16:05:31 -05001067 goto out;
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05001068 } else {
James Smart2e0fef82007-06-17 19:56:36 -05001069 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart92d7f7b2007-06-17 19:56:38 -05001070 NLP_EVT_CMPL_PRLI);
dea31012005-04-17 16:05:31 -05001071 }
1072 } else {
1073 /* Good status, call state machine */
James Smart2e0fef82007-06-17 19:56:36 -05001074 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart92d7f7b2007-06-17 19:56:38 -05001075 NLP_EVT_CMPL_PRLI);
dea31012005-04-17 16:05:31 -05001076 }
1077
1078out:
1079 lpfc_els_free_iocb(phba, cmdiocb);
1080 return;
1081}
1082
1083int
James Smart2e0fef82007-06-17 19:56:36 -05001084lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
dea31012005-04-17 16:05:31 -05001085 uint8_t retry)
1086{
James Smart2e0fef82007-06-17 19:56:36 -05001087 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1088 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001089 PRLI *npr;
1090 IOCB_t *icmd;
1091 struct lpfc_iocbq *elsiocb;
1092 struct lpfc_sli_ring *pring;
1093 struct lpfc_sli *psli;
1094 uint8_t *pcmd;
1095 uint16_t cmdsize;
1096
1097 psli = &phba->sli;
1098 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
1099
James Smart92d7f7b2007-06-17 19:56:38 -05001100 cmdsize = (sizeof(uint32_t) + sizeof(PRLI));
James Smart2e0fef82007-06-17 19:56:36 -05001101 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
1102 ndlp->nlp_DID, ELS_CMD_PRLI);
James Smart488d1462006-03-07 15:02:37 -05001103 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001104 return 1;
dea31012005-04-17 16:05:31 -05001105
1106 icmd = &elsiocb->iocb;
1107 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1108
1109 /* For PRLI request, remainder of payload is service parameters */
James Smart92d7f7b2007-06-17 19:56:38 -05001110 memset(pcmd, 0, (sizeof(PRLI) + sizeof(uint32_t)));
dea31012005-04-17 16:05:31 -05001111 *((uint32_t *) (pcmd)) = ELS_CMD_PRLI;
James Smart92d7f7b2007-06-17 19:56:38 -05001112 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05001113
1114 /* For PRLI, remainder of payload is PRLI parameter page */
1115 npr = (PRLI *) pcmd;
1116 /*
1117 * If our firmware version is 3.20 or later,
1118 * set the following bits for FC-TAPE support.
1119 */
1120 if (phba->vpd.rev.feaLevelHigh >= 0x02) {
1121 npr->ConfmComplAllowed = 1;
1122 npr->Retry = 1;
1123 npr->TaskRetryIdReq = 1;
1124 }
1125 npr->estabImagePair = 1;
1126 npr->readXferRdyDis = 1;
1127
1128 /* For FCP support */
1129 npr->prliType = PRLI_FCP_TYPE;
1130 npr->initiatorFunc = 1;
1131
James Smart858c9f62007-06-17 19:56:39 -05001132 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1133 "Issue PRLI: did:x%x",
1134 ndlp->nlp_DID, 0, 0);
1135
dea31012005-04-17 16:05:31 -05001136 phba->fc_stat.elsXmitPRLI++;
1137 elsiocb->iocb_cmpl = lpfc_cmpl_els_prli;
James Smart2e0fef82007-06-17 19:56:36 -05001138 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001139 ndlp->nlp_flag |= NLP_PRLI_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001140 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001141 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
James Smart2e0fef82007-06-17 19:56:36 -05001142 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001143 ndlp->nlp_flag &= ~NLP_PRLI_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001144 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001145 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001146 return 1;
dea31012005-04-17 16:05:31 -05001147 }
James Smart2e0fef82007-06-17 19:56:36 -05001148 vport->fc_prli_sent++;
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001149 return 0;
dea31012005-04-17 16:05:31 -05001150}
1151
1152static void
James Smart2e0fef82007-06-17 19:56:36 -05001153lpfc_more_adisc(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05001154{
1155 int sentadisc;
1156
James Smart2e0fef82007-06-17 19:56:36 -05001157 if (vport->num_disc_nodes)
1158 vport->num_disc_nodes--;
dea31012005-04-17 16:05:31 -05001159 /* Continue discovery with <num_disc_nodes> ADISCs to go */
James Smarte8b62012007-08-02 11:10:09 -04001160 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
1161 "0210 Continue discovery with %d ADISCs to go "
1162 "Data: x%x x%x x%x\n",
1163 vport->num_disc_nodes, vport->fc_adisc_cnt,
1164 vport->fc_flag, vport->port_state);
dea31012005-04-17 16:05:31 -05001165 /* Check to see if there are more ADISCs to be sent */
James Smart2e0fef82007-06-17 19:56:36 -05001166 if (vport->fc_flag & FC_NLP_MORE) {
1167 lpfc_set_disctmo(vport);
1168 /* go thru NPR nodes and issue any remaining ELS ADISCs */
1169 sentadisc = lpfc_els_disc_adisc(vport);
dea31012005-04-17 16:05:31 -05001170 }
1171 return;
1172}
1173
1174static void
James Smart2e0fef82007-06-17 19:56:36 -05001175lpfc_rscn_disc(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05001176{
James Smart858c9f62007-06-17 19:56:39 -05001177 lpfc_can_disctmo(vport);
1178
dea31012005-04-17 16:05:31 -05001179 /* RSCN discovery */
James Smart2e0fef82007-06-17 19:56:36 -05001180 /* go thru NPR nodes and issue ELS PLOGIs */
1181 if (vport->fc_npr_cnt)
1182 if (lpfc_els_disc_plogi(vport))
dea31012005-04-17 16:05:31 -05001183 return;
James Smart2e0fef82007-06-17 19:56:36 -05001184
James Smart87af33f2007-10-27 13:37:43 -04001185 lpfc_end_rscn(vport);
dea31012005-04-17 16:05:31 -05001186}
1187
1188static void
James Smart2e0fef82007-06-17 19:56:36 -05001189lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1190 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05001191{
James Smart2e0fef82007-06-17 19:56:36 -05001192 struct lpfc_vport *vport = cmdiocb->vport;
1193 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05001194 IOCB_t *irsp;
dea31012005-04-17 16:05:31 -05001195 struct lpfc_nodelist *ndlp;
James Smart2e0fef82007-06-17 19:56:36 -05001196 int disc;
dea31012005-04-17 16:05:31 -05001197
1198 /* we pass cmdiocb to state machine which needs rspiocb as well */
1199 cmdiocb->context_un.rsp_iocb = rspiocb;
1200
1201 irsp = &(rspiocb->iocb);
1202 ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
dea31012005-04-17 16:05:31 -05001203
James Smart858c9f62007-06-17 19:56:39 -05001204 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1205 "ADISC cmpl: status:x%x/x%x did:x%x",
1206 irsp->ulpStatus, irsp->un.ulpWord[4],
1207 ndlp->nlp_DID);
1208
dea31012005-04-17 16:05:31 -05001209 /* Since ndlp can be freed in the disc state machine, note if this node
1210 * is being used during discovery.
1211 */
James Smart2e0fef82007-06-17 19:56:36 -05001212 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001213 disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001214 ndlp->nlp_flag &= ~(NLP_ADISC_SND | NLP_NPR_2B_DISC);
James Smart2e0fef82007-06-17 19:56:36 -05001215 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001216 /* ADISC completes to NPort <nlp_DID> */
James Smarte8b62012007-08-02 11:10:09 -04001217 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
1218 "0104 ADISC completes to NPort x%x "
1219 "Data: x%x x%x x%x x%x x%x\n",
1220 ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4],
1221 irsp->ulpTimeout, disc, vport->num_disc_nodes);
dea31012005-04-17 16:05:31 -05001222 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -05001223 if (lpfc_els_chk_latt(vport)) {
1224 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001225 ndlp->nlp_flag |= NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -05001226 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001227 goto out;
1228 }
1229
1230 if (irsp->ulpStatus) {
1231 /* Check for retry */
1232 if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
1233 /* ELS command is being retried */
1234 if (disc) {
James Smart2e0fef82007-06-17 19:56:36 -05001235 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001236 ndlp->nlp_flag |= NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -05001237 spin_unlock_irq(shost->host_lock);
1238 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -05001239 }
1240 goto out;
1241 }
1242 /* ADISC failed */
1243 /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
James Smart858c9f62007-06-17 19:56:39 -05001244 if (!lpfc_error_lost_link(irsp)) {
James Smart2e0fef82007-06-17 19:56:36 -05001245 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart858c9f62007-06-17 19:56:39 -05001246 NLP_EVT_CMPL_ADISC);
dea31012005-04-17 16:05:31 -05001247 }
1248 } else {
1249 /* Good status, call state machine */
James Smart2e0fef82007-06-17 19:56:36 -05001250 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
dea31012005-04-17 16:05:31 -05001251 NLP_EVT_CMPL_ADISC);
1252 }
1253
James Smart2e0fef82007-06-17 19:56:36 -05001254 if (disc && vport->num_disc_nodes) {
dea31012005-04-17 16:05:31 -05001255 /* Check to see if there are more ADISCs to be sent */
James Smart2e0fef82007-06-17 19:56:36 -05001256 lpfc_more_adisc(vport);
dea31012005-04-17 16:05:31 -05001257
1258 /* Check to see if we are done with ADISC authentication */
James Smart2e0fef82007-06-17 19:56:36 -05001259 if (vport->num_disc_nodes == 0) {
James Smart92d7f7b2007-06-17 19:56:38 -05001260 /* If we get here, there is nothing left to ADISC */
1261 /*
1262 * For NPIV, cmpl_reg_vpi will set port_state to READY,
1263 * and continue discovery.
1264 */
1265 if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
1266 !(vport->fc_flag & FC_RSCN_MODE)) {
1267 lpfc_issue_reg_vpi(phba, vport);
1268 goto out;
1269 }
1270 /*
1271 * For SLI2, we need to set port_state to READY
1272 * and continue discovery.
1273 */
1274 if (vport->port_state < LPFC_VPORT_READY) {
1275 /* If we get here, there is nothing to ADISC */
James Smarted957682007-06-17 19:56:37 -05001276 if (vport->port_type == LPFC_PHYSICAL_PORT)
James Smart2e0fef82007-06-17 19:56:36 -05001277 lpfc_issue_clear_la(phba, vport);
James Smart92d7f7b2007-06-17 19:56:38 -05001278
1279 if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) {
1280 vport->num_disc_nodes = 0;
1281 /* go thru NPR list, issue ELS PLOGIs */
1282 if (vport->fc_npr_cnt)
1283 lpfc_els_disc_plogi(vport);
1284
1285 if (!vport->num_disc_nodes) {
1286 spin_lock_irq(shost->host_lock);
1287 vport->fc_flag &=
1288 ~FC_NDISC_ACTIVE;
1289 spin_unlock_irq(
1290 shost->host_lock);
1291 lpfc_can_disctmo(vport);
1292 }
1293 }
1294 vport->port_state = LPFC_VPORT_READY;
dea31012005-04-17 16:05:31 -05001295 } else {
James Smart2e0fef82007-06-17 19:56:36 -05001296 lpfc_rscn_disc(vport);
dea31012005-04-17 16:05:31 -05001297 }
1298 }
1299 }
dea31012005-04-17 16:05:31 -05001300out:
1301 lpfc_els_free_iocb(phba, cmdiocb);
1302 return;
1303}
1304
1305int
James Smart2e0fef82007-06-17 19:56:36 -05001306lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
dea31012005-04-17 16:05:31 -05001307 uint8_t retry)
1308{
James Smart2e0fef82007-06-17 19:56:36 -05001309 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1310 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001311 ADISC *ap;
1312 IOCB_t *icmd;
1313 struct lpfc_iocbq *elsiocb;
James Smart2e0fef82007-06-17 19:56:36 -05001314 struct lpfc_sli *psli = &phba->sli;
1315 struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
dea31012005-04-17 16:05:31 -05001316 uint8_t *pcmd;
1317 uint16_t cmdsize;
1318
James Smart92d7f7b2007-06-17 19:56:38 -05001319 cmdsize = (sizeof(uint32_t) + sizeof(ADISC));
James Smart2e0fef82007-06-17 19:56:36 -05001320 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
1321 ndlp->nlp_DID, ELS_CMD_ADISC);
James Smart488d1462006-03-07 15:02:37 -05001322 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001323 return 1;
dea31012005-04-17 16:05:31 -05001324
1325 icmd = &elsiocb->iocb;
1326 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1327
1328 /* For ADISC request, remainder of payload is service parameters */
1329 *((uint32_t *) (pcmd)) = ELS_CMD_ADISC;
James Smart92d7f7b2007-06-17 19:56:38 -05001330 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05001331
1332 /* Fill in ADISC payload */
1333 ap = (ADISC *) pcmd;
1334 ap->hardAL_PA = phba->fc_pref_ALPA;
James Smart92d7f7b2007-06-17 19:56:38 -05001335 memcpy(&ap->portName, &vport->fc_portname, sizeof(struct lpfc_name));
1336 memcpy(&ap->nodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
James Smart2e0fef82007-06-17 19:56:36 -05001337 ap->DID = be32_to_cpu(vport->fc_myDID);
dea31012005-04-17 16:05:31 -05001338
James Smart858c9f62007-06-17 19:56:39 -05001339 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1340 "Issue ADISC: did:x%x",
1341 ndlp->nlp_DID, 0, 0);
1342
dea31012005-04-17 16:05:31 -05001343 phba->fc_stat.elsXmitADISC++;
1344 elsiocb->iocb_cmpl = lpfc_cmpl_els_adisc;
James Smart2e0fef82007-06-17 19:56:36 -05001345 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001346 ndlp->nlp_flag |= NLP_ADISC_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001347 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001348 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
James Smart2e0fef82007-06-17 19:56:36 -05001349 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001350 ndlp->nlp_flag &= ~NLP_ADISC_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001351 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001352 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001353 return 1;
dea31012005-04-17 16:05:31 -05001354 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001355 return 0;
dea31012005-04-17 16:05:31 -05001356}
1357
1358static void
James Smart2e0fef82007-06-17 19:56:36 -05001359lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1360 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05001361{
James Smart2e0fef82007-06-17 19:56:36 -05001362 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
1363 struct lpfc_vport *vport = ndlp->vport;
1364 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05001365 IOCB_t *irsp;
1366 struct lpfc_sli *psli;
dea31012005-04-17 16:05:31 -05001367
1368 psli = &phba->sli;
1369 /* we pass cmdiocb to state machine which needs rspiocb as well */
1370 cmdiocb->context_un.rsp_iocb = rspiocb;
1371
1372 irsp = &(rspiocb->iocb);
James Smart2e0fef82007-06-17 19:56:36 -05001373 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001374 ndlp->nlp_flag &= ~NLP_LOGO_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001375 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001376
James Smart858c9f62007-06-17 19:56:39 -05001377 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1378 "LOGO cmpl: status:x%x/x%x did:x%x",
1379 irsp->ulpStatus, irsp->un.ulpWord[4],
1380 ndlp->nlp_DID);
dea31012005-04-17 16:05:31 -05001381 /* LOGO completes to NPort <nlp_DID> */
James Smarte8b62012007-08-02 11:10:09 -04001382 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
1383 "0105 LOGO completes to NPort x%x "
1384 "Data: x%x x%x x%x x%x\n",
1385 ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4],
1386 irsp->ulpTimeout, vport->num_disc_nodes);
dea31012005-04-17 16:05:31 -05001387 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -05001388 if (lpfc_els_chk_latt(vport))
dea31012005-04-17 16:05:31 -05001389 goto out;
1390
James Smart92d7f7b2007-06-17 19:56:38 -05001391 if (ndlp->nlp_flag & NLP_TARGET_REMOVE) {
1392 /* NLP_EVT_DEVICE_RM should unregister the RPI
1393 * which should abort all outstanding IOs.
1394 */
1395 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
1396 NLP_EVT_DEVICE_RM);
1397 goto out;
1398 }
1399
dea31012005-04-17 16:05:31 -05001400 if (irsp->ulpStatus) {
1401 /* Check for retry */
James Smart2e0fef82007-06-17 19:56:36 -05001402 if (lpfc_els_retry(phba, cmdiocb, rspiocb))
dea31012005-04-17 16:05:31 -05001403 /* ELS command is being retried */
1404 goto out;
dea31012005-04-17 16:05:31 -05001405 /* LOGO failed */
1406 /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
James Smart858c9f62007-06-17 19:56:39 -05001407 if (lpfc_error_lost_link(irsp))
dea31012005-04-17 16:05:31 -05001408 goto out;
James Smart858c9f62007-06-17 19:56:39 -05001409 else
James Smart2e0fef82007-06-17 19:56:36 -05001410 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart92d7f7b2007-06-17 19:56:38 -05001411 NLP_EVT_CMPL_LOGO);
dea31012005-04-17 16:05:31 -05001412 } else {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001413 /* Good status, call state machine.
1414 * This will unregister the rpi if needed.
1415 */
James Smart2e0fef82007-06-17 19:56:36 -05001416 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart92d7f7b2007-06-17 19:56:38 -05001417 NLP_EVT_CMPL_LOGO);
dea31012005-04-17 16:05:31 -05001418 }
1419
1420out:
1421 lpfc_els_free_iocb(phba, cmdiocb);
1422 return;
1423}
1424
1425int
James Smart2e0fef82007-06-17 19:56:36 -05001426lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
dea31012005-04-17 16:05:31 -05001427 uint8_t retry)
1428{
James Smart2e0fef82007-06-17 19:56:36 -05001429 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1430 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001431 IOCB_t *icmd;
1432 struct lpfc_iocbq *elsiocb;
1433 struct lpfc_sli_ring *pring;
1434 struct lpfc_sli *psli;
1435 uint8_t *pcmd;
1436 uint16_t cmdsize;
James Smart92d7f7b2007-06-17 19:56:38 -05001437 int rc;
dea31012005-04-17 16:05:31 -05001438
1439 psli = &phba->sli;
1440 pring = &psli->ring[LPFC_ELS_RING];
1441
James Smart98c9ea52007-10-27 13:37:33 -04001442 spin_lock_irq(shost->host_lock);
1443 if (ndlp->nlp_flag & NLP_LOGO_SND) {
1444 spin_unlock_irq(shost->host_lock);
1445 return 0;
1446 }
1447 spin_unlock_irq(shost->host_lock);
1448
James Smart92d7f7b2007-06-17 19:56:38 -05001449 cmdsize = (2 * sizeof(uint32_t)) + sizeof(struct lpfc_name);
James Smart2e0fef82007-06-17 19:56:36 -05001450 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
1451 ndlp->nlp_DID, ELS_CMD_LOGO);
James Smart488d1462006-03-07 15:02:37 -05001452 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001453 return 1;
dea31012005-04-17 16:05:31 -05001454
1455 icmd = &elsiocb->iocb;
1456 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1457 *((uint32_t *) (pcmd)) = ELS_CMD_LOGO;
James Smart92d7f7b2007-06-17 19:56:38 -05001458 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05001459
1460 /* Fill in LOGO payload */
James Smart2e0fef82007-06-17 19:56:36 -05001461 *((uint32_t *) (pcmd)) = be32_to_cpu(vport->fc_myDID);
James Smart92d7f7b2007-06-17 19:56:38 -05001462 pcmd += sizeof(uint32_t);
1463 memcpy(pcmd, &vport->fc_portname, sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05001464
James Smart858c9f62007-06-17 19:56:39 -05001465 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1466 "Issue LOGO: did:x%x",
1467 ndlp->nlp_DID, 0, 0);
1468
dea31012005-04-17 16:05:31 -05001469 phba->fc_stat.elsXmitLOGO++;
1470 elsiocb->iocb_cmpl = lpfc_cmpl_els_logo;
James Smart2e0fef82007-06-17 19:56:36 -05001471 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001472 ndlp->nlp_flag |= NLP_LOGO_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001473 spin_unlock_irq(shost->host_lock);
James Smart92d7f7b2007-06-17 19:56:38 -05001474 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
1475
1476 if (rc == IOCB_ERROR) {
James Smart2e0fef82007-06-17 19:56:36 -05001477 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001478 ndlp->nlp_flag &= ~NLP_LOGO_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001479 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001480 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001481 return 1;
dea31012005-04-17 16:05:31 -05001482 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001483 return 0;
dea31012005-04-17 16:05:31 -05001484}
1485
1486static void
James Smart2e0fef82007-06-17 19:56:36 -05001487lpfc_cmpl_els_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1488 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05001489{
James Smart2e0fef82007-06-17 19:56:36 -05001490 struct lpfc_vport *vport = cmdiocb->vport;
dea31012005-04-17 16:05:31 -05001491 IOCB_t *irsp;
1492
1493 irsp = &rspiocb->iocb;
1494
James Smart858c9f62007-06-17 19:56:39 -05001495 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1496 "ELS cmd cmpl: status:x%x/x%x did:x%x",
1497 irsp->ulpStatus, irsp->un.ulpWord[4],
1498 irsp->un.elsreq64.remoteID);
dea31012005-04-17 16:05:31 -05001499 /* ELS cmd tag <ulpIoTag> completes */
James Smarte8b62012007-08-02 11:10:09 -04001500 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
1501 "0106 ELS cmd tag x%x completes Data: x%x x%x x%x\n",
1502 irsp->ulpIoTag, irsp->ulpStatus,
1503 irsp->un.ulpWord[4], irsp->ulpTimeout);
dea31012005-04-17 16:05:31 -05001504 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -05001505 lpfc_els_chk_latt(vport);
dea31012005-04-17 16:05:31 -05001506 lpfc_els_free_iocb(phba, cmdiocb);
1507 return;
1508}
1509
1510int
James Smart2e0fef82007-06-17 19:56:36 -05001511lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
dea31012005-04-17 16:05:31 -05001512{
James Smart2e0fef82007-06-17 19:56:36 -05001513 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001514 IOCB_t *icmd;
1515 struct lpfc_iocbq *elsiocb;
1516 struct lpfc_sli_ring *pring;
1517 struct lpfc_sli *psli;
1518 uint8_t *pcmd;
1519 uint16_t cmdsize;
1520 struct lpfc_nodelist *ndlp;
1521
1522 psli = &phba->sli;
1523 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
James Smart92d7f7b2007-06-17 19:56:38 -05001524 cmdsize = (sizeof(uint32_t) + sizeof(SCR));
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001525 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
1526 if (!ndlp)
1527 return 1;
dea31012005-04-17 16:05:31 -05001528
James Smart2e0fef82007-06-17 19:56:36 -05001529 lpfc_nlp_init(vport, ndlp, nportid);
dea31012005-04-17 16:05:31 -05001530
James Smart2e0fef82007-06-17 19:56:36 -05001531 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
1532 ndlp->nlp_DID, ELS_CMD_SCR);
1533
James Smart488d1462006-03-07 15:02:37 -05001534 if (!elsiocb) {
James Smart329f9bc2007-04-25 09:53:01 -04001535 lpfc_nlp_put(ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001536 return 1;
dea31012005-04-17 16:05:31 -05001537 }
1538
1539 icmd = &elsiocb->iocb;
1540 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1541
1542 *((uint32_t *) (pcmd)) = ELS_CMD_SCR;
James Smart92d7f7b2007-06-17 19:56:38 -05001543 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05001544
1545 /* For SCR, remainder of payload is SCR parameter page */
James Smart92d7f7b2007-06-17 19:56:38 -05001546 memset(pcmd, 0, sizeof(SCR));
dea31012005-04-17 16:05:31 -05001547 ((SCR *) pcmd)->Function = SCR_FUNC_FULL;
1548
James Smart858c9f62007-06-17 19:56:39 -05001549 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1550 "Issue SCR: did:x%x",
1551 ndlp->nlp_DID, 0, 0);
1552
dea31012005-04-17 16:05:31 -05001553 phba->fc_stat.elsXmitSCR++;
1554 elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
dea31012005-04-17 16:05:31 -05001555 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
James Smart329f9bc2007-04-25 09:53:01 -04001556 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05001557 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001558 return 1;
dea31012005-04-17 16:05:31 -05001559 }
James Smart329f9bc2007-04-25 09:53:01 -04001560 lpfc_nlp_put(ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001561 return 0;
dea31012005-04-17 16:05:31 -05001562}
1563
1564static int
James Smart2e0fef82007-06-17 19:56:36 -05001565lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
dea31012005-04-17 16:05:31 -05001566{
James Smart2e0fef82007-06-17 19:56:36 -05001567 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001568 IOCB_t *icmd;
1569 struct lpfc_iocbq *elsiocb;
1570 struct lpfc_sli_ring *pring;
1571 struct lpfc_sli *psli;
1572 FARP *fp;
1573 uint8_t *pcmd;
1574 uint32_t *lp;
1575 uint16_t cmdsize;
1576 struct lpfc_nodelist *ondlp;
1577 struct lpfc_nodelist *ndlp;
1578
1579 psli = &phba->sli;
1580 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
James Smart92d7f7b2007-06-17 19:56:38 -05001581 cmdsize = (sizeof(uint32_t) + sizeof(FARP));
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001582 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
1583 if (!ndlp)
1584 return 1;
dea31012005-04-17 16:05:31 -05001585
James Smart2e0fef82007-06-17 19:56:36 -05001586 lpfc_nlp_init(vport, ndlp, nportid);
1587
1588 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
1589 ndlp->nlp_DID, ELS_CMD_RNID);
James Smart488d1462006-03-07 15:02:37 -05001590 if (!elsiocb) {
James Smart329f9bc2007-04-25 09:53:01 -04001591 lpfc_nlp_put(ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001592 return 1;
dea31012005-04-17 16:05:31 -05001593 }
1594
1595 icmd = &elsiocb->iocb;
1596 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1597
1598 *((uint32_t *) (pcmd)) = ELS_CMD_FARPR;
James Smart92d7f7b2007-06-17 19:56:38 -05001599 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05001600
1601 /* Fill in FARPR payload */
1602 fp = (FARP *) (pcmd);
James Smart92d7f7b2007-06-17 19:56:38 -05001603 memset(fp, 0, sizeof(FARP));
dea31012005-04-17 16:05:31 -05001604 lp = (uint32_t *) pcmd;
1605 *lp++ = be32_to_cpu(nportid);
James Smart2e0fef82007-06-17 19:56:36 -05001606 *lp++ = be32_to_cpu(vport->fc_myDID);
dea31012005-04-17 16:05:31 -05001607 fp->Rflags = 0;
1608 fp->Mflags = (FARP_MATCH_PORT | FARP_MATCH_NODE);
1609
James Smart92d7f7b2007-06-17 19:56:38 -05001610 memcpy(&fp->RportName, &vport->fc_portname, sizeof(struct lpfc_name));
1611 memcpy(&fp->RnodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
James Smart2e0fef82007-06-17 19:56:36 -05001612 ondlp = lpfc_findnode_did(vport, nportid);
1613 if (ondlp) {
dea31012005-04-17 16:05:31 -05001614 memcpy(&fp->OportName, &ondlp->nlp_portname,
James Smart92d7f7b2007-06-17 19:56:38 -05001615 sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05001616 memcpy(&fp->OnodeName, &ondlp->nlp_nodename,
James Smart92d7f7b2007-06-17 19:56:38 -05001617 sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05001618 }
1619
James Smart858c9f62007-06-17 19:56:39 -05001620 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1621 "Issue FARPR: did:x%x",
1622 ndlp->nlp_DID, 0, 0);
1623
dea31012005-04-17 16:05:31 -05001624 phba->fc_stat.elsXmitFARPR++;
1625 elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
dea31012005-04-17 16:05:31 -05001626 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
James Smart329f9bc2007-04-25 09:53:01 -04001627 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05001628 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001629 return 1;
dea31012005-04-17 16:05:31 -05001630 }
James Smart329f9bc2007-04-25 09:53:01 -04001631 lpfc_nlp_put(ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001632 return 0;
dea31012005-04-17 16:05:31 -05001633}
1634
1635void
James Smart2e0fef82007-06-17 19:56:36 -05001636lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp)
James Smartfdcebe22006-03-07 15:04:01 -05001637{
James Smart2e0fef82007-06-17 19:56:36 -05001638 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1639
1640 spin_lock_irq(shost->host_lock);
James Smartfdcebe22006-03-07 15:04:01 -05001641 nlp->nlp_flag &= ~NLP_DELAY_TMO;
James Smart2e0fef82007-06-17 19:56:36 -05001642 spin_unlock_irq(shost->host_lock);
James Smartfdcebe22006-03-07 15:04:01 -05001643 del_timer_sync(&nlp->nlp_delayfunc);
1644 nlp->nlp_last_elscmd = 0;
1645
1646 if (!list_empty(&nlp->els_retry_evt.evt_listp))
1647 list_del_init(&nlp->els_retry_evt.evt_listp);
1648
1649 if (nlp->nlp_flag & NLP_NPR_2B_DISC) {
James Smart2e0fef82007-06-17 19:56:36 -05001650 spin_lock_irq(shost->host_lock);
James Smartfdcebe22006-03-07 15:04:01 -05001651 nlp->nlp_flag &= ~NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -05001652 spin_unlock_irq(shost->host_lock);
1653 if (vport->num_disc_nodes) {
James Smartfdcebe22006-03-07 15:04:01 -05001654 /* Check to see if there are more
1655 * PLOGIs to be sent
1656 */
James Smart2e0fef82007-06-17 19:56:36 -05001657 lpfc_more_plogi(vport);
James Smartfdcebe22006-03-07 15:04:01 -05001658
James Smart2e0fef82007-06-17 19:56:36 -05001659 if (vport->num_disc_nodes == 0) {
1660 spin_lock_irq(shost->host_lock);
1661 vport->fc_flag &= ~FC_NDISC_ACTIVE;
1662 spin_unlock_irq(shost->host_lock);
1663 lpfc_can_disctmo(vport);
James Smarted957682007-06-17 19:56:37 -05001664 lpfc_end_rscn(vport);
James Smartfdcebe22006-03-07 15:04:01 -05001665 }
1666 }
1667 }
1668 return;
1669}
1670
1671void
dea31012005-04-17 16:05:31 -05001672lpfc_els_retry_delay(unsigned long ptr)
1673{
James Smart2e0fef82007-06-17 19:56:36 -05001674 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) ptr;
1675 struct lpfc_vport *vport = ndlp->vport;
James Smart2e0fef82007-06-17 19:56:36 -05001676 struct lpfc_hba *phba = vport->phba;
James Smart92d7f7b2007-06-17 19:56:38 -05001677 unsigned long flags;
James Smart2e0fef82007-06-17 19:56:36 -05001678 struct lpfc_work_evt *evtp = &ndlp->els_retry_evt;
dea31012005-04-17 16:05:31 -05001679
James Smart2e0fef82007-06-17 19:56:36 -05001680 ndlp = (struct lpfc_nodelist *) ptr;
1681 phba = ndlp->vport->phba;
dea31012005-04-17 16:05:31 -05001682 evtp = &ndlp->els_retry_evt;
1683
James Smart92d7f7b2007-06-17 19:56:38 -05001684 spin_lock_irqsave(&phba->hbalock, flags);
dea31012005-04-17 16:05:31 -05001685 if (!list_empty(&evtp->evt_listp)) {
James Smart92d7f7b2007-06-17 19:56:38 -05001686 spin_unlock_irqrestore(&phba->hbalock, flags);
dea31012005-04-17 16:05:31 -05001687 return;
1688 }
1689
1690 evtp->evt_arg1 = ndlp;
1691 evtp->evt = LPFC_EVT_ELS_RETRY;
1692 list_add_tail(&evtp->evt_listp, &phba->work_list);
1693 if (phba->work_wait)
James Smart92d7f7b2007-06-17 19:56:38 -05001694 lpfc_worker_wake_up(phba);
dea31012005-04-17 16:05:31 -05001695
James Smart92d7f7b2007-06-17 19:56:38 -05001696 spin_unlock_irqrestore(&phba->hbalock, flags);
dea31012005-04-17 16:05:31 -05001697 return;
1698}
1699
1700void
1701lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp)
1702{
James Smart2e0fef82007-06-17 19:56:36 -05001703 struct lpfc_vport *vport = ndlp->vport;
1704 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1705 uint32_t cmd, did, retry;
dea31012005-04-17 16:05:31 -05001706
James Smart2e0fef82007-06-17 19:56:36 -05001707 spin_lock_irq(shost->host_lock);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001708 did = ndlp->nlp_DID;
1709 cmd = ndlp->nlp_last_elscmd;
1710 ndlp->nlp_last_elscmd = 0;
dea31012005-04-17 16:05:31 -05001711
1712 if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
James Smart2e0fef82007-06-17 19:56:36 -05001713 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001714 return;
1715 }
1716
1717 ndlp->nlp_flag &= ~NLP_DELAY_TMO;
James Smart2e0fef82007-06-17 19:56:36 -05001718 spin_unlock_irq(shost->host_lock);
James Smart1a169682006-03-07 15:04:06 -05001719 /*
1720 * If a discovery event readded nlp_delayfunc after timer
1721 * firing and before processing the timer, cancel the
1722 * nlp_delayfunc.
1723 */
1724 del_timer_sync(&ndlp->nlp_delayfunc);
dea31012005-04-17 16:05:31 -05001725 retry = ndlp->nlp_retry;
1726
1727 switch (cmd) {
1728 case ELS_CMD_FLOGI:
James Smart2e0fef82007-06-17 19:56:36 -05001729 lpfc_issue_els_flogi(vport, ndlp, retry);
dea31012005-04-17 16:05:31 -05001730 break;
1731 case ELS_CMD_PLOGI:
James Smart2e0fef82007-06-17 19:56:36 -05001732 if (!lpfc_issue_els_plogi(vport, ndlp->nlp_DID, retry)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001733 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001734 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
Jamie Wellnitz6ad42532006-02-28 19:25:16 -05001735 }
dea31012005-04-17 16:05:31 -05001736 break;
1737 case ELS_CMD_ADISC:
James Smart2e0fef82007-06-17 19:56:36 -05001738 if (!lpfc_issue_els_adisc(vport, ndlp, retry)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001739 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001740 lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
Jamie Wellnitz6ad42532006-02-28 19:25:16 -05001741 }
dea31012005-04-17 16:05:31 -05001742 break;
1743 case ELS_CMD_PRLI:
James Smart2e0fef82007-06-17 19:56:36 -05001744 if (!lpfc_issue_els_prli(vport, ndlp, retry)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001745 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001746 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
Jamie Wellnitz6ad42532006-02-28 19:25:16 -05001747 }
dea31012005-04-17 16:05:31 -05001748 break;
1749 case ELS_CMD_LOGO:
James Smart2e0fef82007-06-17 19:56:36 -05001750 if (!lpfc_issue_els_logo(vport, ndlp, retry)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001751 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001752 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
Jamie Wellnitz6ad42532006-02-28 19:25:16 -05001753 }
dea31012005-04-17 16:05:31 -05001754 break;
James Smart92d7f7b2007-06-17 19:56:38 -05001755 case ELS_CMD_FDISC:
1756 lpfc_issue_els_fdisc(vport, ndlp, retry);
1757 break;
dea31012005-04-17 16:05:31 -05001758 }
1759 return;
1760}
1761
1762static int
James Smart2e0fef82007-06-17 19:56:36 -05001763lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1764 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05001765{
James Smart2e0fef82007-06-17 19:56:36 -05001766 struct lpfc_vport *vport = cmdiocb->vport;
1767 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1768 IOCB_t *irsp = &rspiocb->iocb;
1769 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
1770 struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
dea31012005-04-17 16:05:31 -05001771 uint32_t *elscmd;
1772 struct ls_rjt stat;
James Smart2e0fef82007-06-17 19:56:36 -05001773 int retry = 0, maxretry = lpfc_max_els_tries, delay = 0;
James Smart98c9ea52007-10-27 13:37:33 -04001774 int logerr = 0;
James Smart2e0fef82007-06-17 19:56:36 -05001775 uint32_t cmd = 0;
James Smart488d1462006-03-07 15:02:37 -05001776 uint32_t did;
dea31012005-04-17 16:05:31 -05001777
James Smart488d1462006-03-07 15:02:37 -05001778
dea31012005-04-17 16:05:31 -05001779 /* Note: context2 may be 0 for internal driver abort
1780 * of delays ELS command.
1781 */
1782
1783 if (pcmd && pcmd->virt) {
1784 elscmd = (uint32_t *) (pcmd->virt);
1785 cmd = *elscmd++;
1786 }
1787
James Smart329f9bc2007-04-25 09:53:01 -04001788 if (ndlp)
James Smart488d1462006-03-07 15:02:37 -05001789 did = ndlp->nlp_DID;
1790 else {
1791 /* We should only hit this case for retrying PLOGI */
1792 did = irsp->un.elsreq64.remoteID;
James Smart2e0fef82007-06-17 19:56:36 -05001793 ndlp = lpfc_findnode_did(vport, did);
James Smart488d1462006-03-07 15:02:37 -05001794 if (!ndlp && (cmd != ELS_CMD_PLOGI))
1795 return 1;
1796 }
1797
James Smart858c9f62007-06-17 19:56:39 -05001798 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1799 "Retry ELS: wd7:x%x wd4:x%x did:x%x",
1800 *(((uint32_t *) irsp) + 7), irsp->un.ulpWord[4], ndlp->nlp_DID);
1801
dea31012005-04-17 16:05:31 -05001802 switch (irsp->ulpStatus) {
1803 case IOSTAT_FCP_RSP_ERROR:
1804 case IOSTAT_REMOTE_STOP:
1805 break;
1806
1807 case IOSTAT_LOCAL_REJECT:
1808 switch ((irsp->un.ulpWord[4] & 0xff)) {
1809 case IOERR_LOOP_OPEN_FAILURE:
James Smart2e0fef82007-06-17 19:56:36 -05001810 if (cmd == ELS_CMD_PLOGI && cmdiocb->retry == 0)
James Smart92d7f7b2007-06-17 19:56:38 -05001811 delay = 1000;
dea31012005-04-17 16:05:31 -05001812 retry = 1;
1813 break;
1814
James Smart92d7f7b2007-06-17 19:56:38 -05001815 case IOERR_ILLEGAL_COMMAND:
1816 if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) &&
1817 (cmd == ELS_CMD_FDISC)) {
James Smarte8b62012007-08-02 11:10:09 -04001818 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
1819 "0124 FDISC failed (3/6) "
1820 "retrying...\n");
James Smart92d7f7b2007-06-17 19:56:38 -05001821 lpfc_mbx_unreg_vpi(vport);
1822 retry = 1;
James Smart51ef4c22007-08-02 11:10:31 -04001823 /* FDISC retry policy */
1824 maxretry = 48;
1825 if (cmdiocb->retry >= 32)
1826 delay = 1000;
James Smart92d7f7b2007-06-17 19:56:38 -05001827 }
1828 break;
1829
dea31012005-04-17 16:05:31 -05001830 case IOERR_NO_RESOURCES:
James Smart98c9ea52007-10-27 13:37:33 -04001831 logerr = 1; /* HBA out of resources */
James Smart858c9f62007-06-17 19:56:39 -05001832 retry = 1;
1833 if (cmdiocb->retry > 100)
1834 delay = 100;
1835 maxretry = 250;
1836 break;
1837
1838 case IOERR_ILLEGAL_FRAME:
James Smart92d7f7b2007-06-17 19:56:38 -05001839 delay = 100;
dea31012005-04-17 16:05:31 -05001840 retry = 1;
1841 break;
1842
James Smart858c9f62007-06-17 19:56:39 -05001843 case IOERR_SEQUENCE_TIMEOUT:
dea31012005-04-17 16:05:31 -05001844 case IOERR_INVALID_RPI:
1845 retry = 1;
1846 break;
1847 }
1848 break;
1849
1850 case IOSTAT_NPORT_RJT:
1851 case IOSTAT_FABRIC_RJT:
1852 if (irsp->un.ulpWord[4] & RJT_UNAVAIL_TEMP) {
1853 retry = 1;
1854 break;
1855 }
1856 break;
1857
1858 case IOSTAT_NPORT_BSY:
1859 case IOSTAT_FABRIC_BSY:
James Smart98c9ea52007-10-27 13:37:33 -04001860 logerr = 1; /* Fabric / Remote NPort out of resources */
dea31012005-04-17 16:05:31 -05001861 retry = 1;
1862 break;
1863
1864 case IOSTAT_LS_RJT:
1865 stat.un.lsRjtError = be32_to_cpu(irsp->un.ulpWord[4]);
1866 /* Added for Vendor specifc support
1867 * Just keep retrying for these Rsn / Exp codes
1868 */
1869 switch (stat.un.b.lsRjtRsnCode) {
1870 case LSRJT_UNABLE_TPC:
1871 if (stat.un.b.lsRjtRsnCodeExp ==
1872 LSEXP_CMD_IN_PROGRESS) {
1873 if (cmd == ELS_CMD_PLOGI) {
James Smart92d7f7b2007-06-17 19:56:38 -05001874 delay = 1000;
dea31012005-04-17 16:05:31 -05001875 maxretry = 48;
1876 }
1877 retry = 1;
1878 break;
1879 }
1880 if (cmd == ELS_CMD_PLOGI) {
James Smart92d7f7b2007-06-17 19:56:38 -05001881 delay = 1000;
dea31012005-04-17 16:05:31 -05001882 maxretry = lpfc_max_els_tries + 1;
1883 retry = 1;
1884 break;
1885 }
James Smart92d7f7b2007-06-17 19:56:38 -05001886 if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
1887 (cmd == ELS_CMD_FDISC) &&
1888 (stat.un.b.lsRjtRsnCodeExp == LSEXP_OUT_OF_RESOURCE)){
James Smarte8b62012007-08-02 11:10:09 -04001889 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
1890 "0125 FDISC Failed (x%x). "
1891 "Fabric out of resources\n",
1892 stat.un.lsRjtError);
James Smart92d7f7b2007-06-17 19:56:38 -05001893 lpfc_vport_set_state(vport,
1894 FC_VPORT_NO_FABRIC_RSCS);
1895 }
dea31012005-04-17 16:05:31 -05001896 break;
1897
1898 case LSRJT_LOGICAL_BSY:
James Smart858c9f62007-06-17 19:56:39 -05001899 if ((cmd == ELS_CMD_PLOGI) ||
1900 (cmd == ELS_CMD_PRLI)) {
James Smart92d7f7b2007-06-17 19:56:38 -05001901 delay = 1000;
dea31012005-04-17 16:05:31 -05001902 maxretry = 48;
James Smart92d7f7b2007-06-17 19:56:38 -05001903 } else if (cmd == ELS_CMD_FDISC) {
James Smart51ef4c22007-08-02 11:10:31 -04001904 /* FDISC retry policy */
1905 maxretry = 48;
1906 if (cmdiocb->retry >= 32)
1907 delay = 1000;
dea31012005-04-17 16:05:31 -05001908 }
1909 retry = 1;
1910 break;
James Smart92d7f7b2007-06-17 19:56:38 -05001911
1912 case LSRJT_LOGICAL_ERR:
1913 case LSRJT_PROTOCOL_ERR:
1914 if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
1915 (cmd == ELS_CMD_FDISC) &&
1916 ((stat.un.b.lsRjtRsnCodeExp == LSEXP_INVALID_PNAME) ||
1917 (stat.un.b.lsRjtRsnCodeExp == LSEXP_INVALID_NPORT_ID))
1918 ) {
James Smarte8b62012007-08-02 11:10:09 -04001919 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
1920 "0123 FDISC Failed (x%x). "
1921 "Fabric Detected Bad WWN\n",
1922 stat.un.lsRjtError);
James Smart92d7f7b2007-06-17 19:56:38 -05001923 lpfc_vport_set_state(vport,
1924 FC_VPORT_FABRIC_REJ_WWN);
1925 }
1926 break;
dea31012005-04-17 16:05:31 -05001927 }
1928 break;
1929
1930 case IOSTAT_INTERMED_RSP:
1931 case IOSTAT_BA_RJT:
1932 break;
1933
1934 default:
1935 break;
1936 }
1937
James Smart488d1462006-03-07 15:02:37 -05001938 if (did == FDMI_DID)
dea31012005-04-17 16:05:31 -05001939 retry = 1;
dea31012005-04-17 16:05:31 -05001940
James Smart98c9ea52007-10-27 13:37:33 -04001941 if ((cmd == ELS_CMD_FLOGI) &&
1942 (phba->fc_topology != TOPOLOGY_LOOP)) {
1943 /* FLOGI retry policy */
1944 retry = 1;
1945 maxretry = 48;
1946 if (cmdiocb->retry >= 32)
1947 delay = 1000;
1948 }
1949
dea31012005-04-17 16:05:31 -05001950 if ((++cmdiocb->retry) >= maxretry) {
1951 phba->fc_stat.elsRetryExceeded++;
1952 retry = 0;
1953 }
1954
James Smarted957682007-06-17 19:56:37 -05001955 if ((vport->load_flag & FC_UNLOADING) != 0)
1956 retry = 0;
1957
dea31012005-04-17 16:05:31 -05001958 if (retry) {
1959
1960 /* Retry ELS command <elsCmd> to remote NPORT <did> */
James Smarte8b62012007-08-02 11:10:09 -04001961 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
1962 "0107 Retry ELS command x%x to remote "
1963 "NPORT x%x Data: x%x x%x\n",
1964 cmd, did, cmdiocb->retry, delay);
dea31012005-04-17 16:05:31 -05001965
James Smart858c9f62007-06-17 19:56:39 -05001966 if (((cmd == ELS_CMD_PLOGI) || (cmd == ELS_CMD_ADISC)) &&
1967 ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
1968 ((irsp->un.ulpWord[4] & 0xff) != IOERR_NO_RESOURCES))) {
1969 /* Don't reset timer for no resources */
1970
dea31012005-04-17 16:05:31 -05001971 /* If discovery / RSCN timer is running, reset it */
James Smart2e0fef82007-06-17 19:56:36 -05001972 if (timer_pending(&vport->fc_disctmo) ||
James Smart92d7f7b2007-06-17 19:56:38 -05001973 (vport->fc_flag & FC_RSCN_MODE))
James Smart2e0fef82007-06-17 19:56:36 -05001974 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -05001975 }
1976
1977 phba->fc_stat.elsXmitRetry++;
James Smart488d1462006-03-07 15:02:37 -05001978 if (ndlp && delay) {
dea31012005-04-17 16:05:31 -05001979 phba->fc_stat.elsDelayRetry++;
1980 ndlp->nlp_retry = cmdiocb->retry;
1981
James Smart92d7f7b2007-06-17 19:56:38 -05001982 /* delay is specified in milliseconds */
1983 mod_timer(&ndlp->nlp_delayfunc,
1984 jiffies + msecs_to_jiffies(delay));
James Smart2e0fef82007-06-17 19:56:36 -05001985 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001986 ndlp->nlp_flag |= NLP_DELAY_TMO;
James Smart2e0fef82007-06-17 19:56:36 -05001987 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001988
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001989 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart858c9f62007-06-17 19:56:39 -05001990 if (cmd == ELS_CMD_PRLI)
1991 lpfc_nlp_set_state(vport, ndlp,
1992 NLP_STE_REG_LOGIN_ISSUE);
1993 else
1994 lpfc_nlp_set_state(vport, ndlp,
1995 NLP_STE_NPR_NODE);
dea31012005-04-17 16:05:31 -05001996 ndlp->nlp_last_elscmd = cmd;
1997
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001998 return 1;
dea31012005-04-17 16:05:31 -05001999 }
2000 switch (cmd) {
2001 case ELS_CMD_FLOGI:
James Smart2e0fef82007-06-17 19:56:36 -05002002 lpfc_issue_els_flogi(vport, ndlp, cmdiocb->retry);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002003 return 1;
James Smart92d7f7b2007-06-17 19:56:38 -05002004 case ELS_CMD_FDISC:
2005 lpfc_issue_els_fdisc(vport, ndlp, cmdiocb->retry);
2006 return 1;
dea31012005-04-17 16:05:31 -05002007 case ELS_CMD_PLOGI:
James Smart488d1462006-03-07 15:02:37 -05002008 if (ndlp) {
2009 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002010 lpfc_nlp_set_state(vport, ndlp,
James Smartde0c5b32007-04-25 09:52:27 -04002011 NLP_STE_PLOGI_ISSUE);
James Smart488d1462006-03-07 15:02:37 -05002012 }
James Smart2e0fef82007-06-17 19:56:36 -05002013 lpfc_issue_els_plogi(vport, did, cmdiocb->retry);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002014 return 1;
dea31012005-04-17 16:05:31 -05002015 case ELS_CMD_ADISC:
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05002016 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002017 lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
2018 lpfc_issue_els_adisc(vport, ndlp, cmdiocb->retry);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002019 return 1;
dea31012005-04-17 16:05:31 -05002020 case ELS_CMD_PRLI:
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05002021 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002022 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
2023 lpfc_issue_els_prli(vport, ndlp, cmdiocb->retry);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002024 return 1;
dea31012005-04-17 16:05:31 -05002025 case ELS_CMD_LOGO:
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05002026 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002027 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
2028 lpfc_issue_els_logo(vport, ndlp, cmdiocb->retry);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002029 return 1;
dea31012005-04-17 16:05:31 -05002030 }
2031 }
dea31012005-04-17 16:05:31 -05002032 /* No retry ELS command <elsCmd> to remote NPORT <did> */
James Smart98c9ea52007-10-27 13:37:33 -04002033 if (logerr) {
2034 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
2035 "0137 No retry ELS command x%x to remote "
2036 "NPORT x%x: Out of Resources: Error:x%x/%x\n",
2037 cmd, did, irsp->ulpStatus,
2038 irsp->un.ulpWord[4]);
2039 }
2040 else {
2041 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
James Smarta58cbd52007-08-02 11:09:43 -04002042 "0108 No retry ELS command x%x to remote "
2043 "NPORT x%x Retried:%d Error:x%x/%x\n",
2044 cmd, did, cmdiocb->retry, irsp->ulpStatus,
2045 irsp->un.ulpWord[4]);
James Smart98c9ea52007-10-27 13:37:33 -04002046 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002047 return 0;
dea31012005-04-17 16:05:31 -05002048}
2049
2050int
James Smart87af33f2007-10-27 13:37:43 -04002051lpfc_els_free_data(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr1)
2052{
2053 struct lpfc_dmabuf *buf_ptr;
2054
2055 /* Free the response before processing the command. */
2056 if (!list_empty(&buf_ptr1->list)) {
2057 list_remove_head(&buf_ptr1->list, buf_ptr,
2058 struct lpfc_dmabuf,
2059 list);
2060 lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
2061 kfree(buf_ptr);
2062 }
2063 lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys);
2064 kfree(buf_ptr1);
2065 return 0;
2066}
2067
2068int
2069lpfc_els_free_bpl(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr)
2070{
2071 lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
2072 kfree(buf_ptr);
2073 return 0;
2074}
2075
2076int
James Smart329f9bc2007-04-25 09:53:01 -04002077lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
dea31012005-04-17 16:05:31 -05002078{
2079 struct lpfc_dmabuf *buf_ptr, *buf_ptr1;
James Smarta8adb832007-10-27 13:37:53 -04002080 struct lpfc_nodelist *ndlp;
dea31012005-04-17 16:05:31 -05002081
James Smarta8adb832007-10-27 13:37:53 -04002082 ndlp = (struct lpfc_nodelist *)elsiocb->context1;
2083 if (ndlp) {
2084 if (ndlp->nlp_flag & NLP_DEFER_RM) {
2085 lpfc_nlp_put(ndlp);
2086
2087 /* If the ndlp is not being used by another discovery
2088 * thread, free it.
2089 */
2090 if (!lpfc_nlp_not_used(ndlp)) {
2091 /* If ndlp is being used by another discovery
2092 * thread, just clear NLP_DEFER_RM
2093 */
2094 ndlp->nlp_flag &= ~NLP_DEFER_RM;
2095 }
2096 }
2097 else
2098 lpfc_nlp_put(ndlp);
James Smart329f9bc2007-04-25 09:53:01 -04002099 elsiocb->context1 = NULL;
2100 }
dea31012005-04-17 16:05:31 -05002101 /* context2 = cmd, context2->next = rsp, context3 = bpl */
2102 if (elsiocb->context2) {
2103 buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
James Smart87af33f2007-10-27 13:37:43 -04002104 lpfc_els_free_data(phba, buf_ptr1);
dea31012005-04-17 16:05:31 -05002105 }
2106
2107 if (elsiocb->context3) {
2108 buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3;
James Smart87af33f2007-10-27 13:37:43 -04002109 lpfc_els_free_bpl(phba, buf_ptr);
dea31012005-04-17 16:05:31 -05002110 }
James Bottomley604a3e32005-10-29 10:28:33 -05002111 lpfc_sli_release_iocbq(phba, elsiocb);
dea31012005-04-17 16:05:31 -05002112 return 0;
2113}
2114
2115static void
James Smart2e0fef82007-06-17 19:56:36 -05002116lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
2117 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05002118{
James Smart2e0fef82007-06-17 19:56:36 -05002119 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
2120 struct lpfc_vport *vport = cmdiocb->vport;
James Smart858c9f62007-06-17 19:56:39 -05002121 IOCB_t *irsp;
2122
2123 irsp = &rspiocb->iocb;
2124 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2125 "ACC LOGO cmpl: status:x%x/x%x did:x%x",
2126 irsp->ulpStatus, irsp->un.ulpWord[4], ndlp->nlp_DID);
dea31012005-04-17 16:05:31 -05002127 /* ACC to LOGO completes to NPort <nlp_DID> */
James Smarte8b62012007-08-02 11:10:09 -04002128 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
2129 "0109 ACC to LOGO completes to NPort x%x "
2130 "Data: x%x x%x x%x\n",
2131 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
2132 ndlp->nlp_rpi);
James Smart87af33f2007-10-27 13:37:43 -04002133
2134 if (ndlp->nlp_state == NLP_STE_NPR_NODE) {
2135 /* NPort Recovery mode or node is just allocated */
2136 if (!lpfc_nlp_not_used(ndlp)) {
2137 /* If the ndlp is being used by another discovery
2138 * thread, just unregister the RPI.
2139 */
2140 lpfc_unreg_rpi(vport, ndlp);
2141 }
dea31012005-04-17 16:05:31 -05002142 }
2143 lpfc_els_free_iocb(phba, cmdiocb);
2144 return;
2145}
2146
James Smart858c9f62007-06-17 19:56:39 -05002147void
2148lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
2149{
2150 struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
2151 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
2152
2153 pmb->context1 = NULL;
2154 lpfc_mbuf_free(phba, mp->virt, mp->phys);
2155 kfree(mp);
2156 mempool_free(pmb, phba->mbox_mem_pool);
James Smarta8adb832007-10-27 13:37:53 -04002157 if (ndlp) {
2158 lpfc_nlp_put(ndlp);
James Smart98c9ea52007-10-27 13:37:33 -04002159
James Smarta8adb832007-10-27 13:37:53 -04002160 /* This is the end of the default RPI cleanup logic for this
2161 * ndlp. If no other discovery threads are using this ndlp.
2162 * we should free all resources associated with it.
2163 */
2164 lpfc_nlp_not_used(ndlp);
2165 }
James Smart858c9f62007-06-17 19:56:39 -05002166 return;
2167}
2168
dea31012005-04-17 16:05:31 -05002169static void
James Smart858c9f62007-06-17 19:56:39 -05002170lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
James Smart329f9bc2007-04-25 09:53:01 -04002171 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05002172{
James Smart2e0fef82007-06-17 19:56:36 -05002173 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
2174 struct lpfc_vport *vport = ndlp ? ndlp->vport : NULL;
2175 struct Scsi_Host *shost = vport ? lpfc_shost_from_vport(vport) : NULL;
James Smart87af33f2007-10-27 13:37:43 -04002176 IOCB_t *irsp;
2177 uint8_t *pcmd;
dea31012005-04-17 16:05:31 -05002178 LPFC_MBOXQ_t *mbox = NULL;
James Smart2e0fef82007-06-17 19:56:36 -05002179 struct lpfc_dmabuf *mp = NULL;
James Smart87af33f2007-10-27 13:37:43 -04002180 uint32_t ls_rjt = 0;
dea31012005-04-17 16:05:31 -05002181
James Smart33ccf8d2006-08-17 11:57:58 -04002182 irsp = &rspiocb->iocb;
2183
dea31012005-04-17 16:05:31 -05002184 if (cmdiocb->context_un.mbox)
2185 mbox = cmdiocb->context_un.mbox;
2186
James Smart87af33f2007-10-27 13:37:43 -04002187 /* First determine if this is a LS_RJT cmpl */
2188 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) cmdiocb->context2)->virt);
2189 if (*((uint32_t *) (pcmd)) == ELS_CMD_LS_RJT) {
2190 /* A LS_RJT associated with Default RPI cleanup
2191 * has its own seperate code path.
2192 */
2193 if (!(ndlp->nlp_flag & NLP_RM_DFLT_RPI))
2194 ls_rjt = 1;
2195 }
2196
dea31012005-04-17 16:05:31 -05002197 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -05002198 if (!ndlp || lpfc_els_chk_latt(vport)) {
dea31012005-04-17 16:05:31 -05002199 if (mbox) {
James Smart14691152006-12-02 13:34:28 -05002200 mp = (struct lpfc_dmabuf *) mbox->context1;
2201 if (mp) {
2202 lpfc_mbuf_free(phba, mp->virt, mp->phys);
2203 kfree(mp);
2204 }
James Smart329f9bc2007-04-25 09:53:01 -04002205 mempool_free(mbox, phba->mbox_mem_pool);
dea31012005-04-17 16:05:31 -05002206 }
James Smart98c9ea52007-10-27 13:37:33 -04002207 if (ndlp && (ndlp->nlp_flag & NLP_RM_DFLT_RPI))
2208 if (lpfc_nlp_not_used(ndlp))
2209 ndlp = NULL;
dea31012005-04-17 16:05:31 -05002210 goto out;
2211 }
2212
James Smart858c9f62007-06-17 19:56:39 -05002213 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
James Smart51ef4c22007-08-02 11:10:31 -04002214 "ELS rsp cmpl: status:x%x/x%x did:x%x",
James Smart858c9f62007-06-17 19:56:39 -05002215 irsp->ulpStatus, irsp->un.ulpWord[4],
James Smart51ef4c22007-08-02 11:10:31 -04002216 cmdiocb->iocb.un.elsreq64.remoteID);
dea31012005-04-17 16:05:31 -05002217 /* ELS response tag <ulpIoTag> completes */
James Smarte8b62012007-08-02 11:10:09 -04002218 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
2219 "0110 ELS response tag x%x completes "
2220 "Data: x%x x%x x%x x%x x%x x%x x%x\n",
2221 cmdiocb->iocb.ulpIoTag, rspiocb->iocb.ulpStatus,
2222 rspiocb->iocb.un.ulpWord[4], rspiocb->iocb.ulpTimeout,
2223 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
2224 ndlp->nlp_rpi);
dea31012005-04-17 16:05:31 -05002225 if (mbox) {
2226 if ((rspiocb->iocb.ulpStatus == 0)
2227 && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) {
James Smart2e0fef82007-06-17 19:56:36 -05002228 lpfc_unreg_rpi(vport, ndlp);
James Smart329f9bc2007-04-25 09:53:01 -04002229 mbox->context2 = lpfc_nlp_get(ndlp);
James Smart2e0fef82007-06-17 19:56:36 -05002230 mbox->vport = vport;
James Smart858c9f62007-06-17 19:56:39 -05002231 if (ndlp->nlp_flag & NLP_RM_DFLT_RPI) {
2232 mbox->mbox_flag |= LPFC_MBX_IMED_UNREG;
2233 mbox->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;
2234 }
2235 else {
2236 mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
2237 ndlp->nlp_prev_state = ndlp->nlp_state;
2238 lpfc_nlp_set_state(vport, ndlp,
James Smart2e0fef82007-06-17 19:56:36 -05002239 NLP_STE_REG_LOGIN_ISSUE);
James Smart858c9f62007-06-17 19:56:39 -05002240 }
James Smart0b727fe2007-10-27 13:37:25 -04002241 if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
dea31012005-04-17 16:05:31 -05002242 != MBX_NOT_FINISHED) {
2243 goto out;
2244 }
James Smart98c9ea52007-10-27 13:37:33 -04002245
2246 /* ELS rsp: Cannot issue reg_login for <NPortid> */
2247 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
2248 "0138 ELS rsp: Cannot issue reg_login for x%x "
2249 "Data: x%x x%x x%x\n",
2250 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
2251 ndlp->nlp_rpi);
2252
2253 if (lpfc_nlp_not_used(ndlp))
2254 ndlp = NULL;
dea31012005-04-17 16:05:31 -05002255 } else {
James Smart858c9f62007-06-17 19:56:39 -05002256 /* Do not drop node for lpfc_els_abort'ed ELS cmds */
2257 if (!lpfc_error_lost_link(irsp) &&
2258 ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
James Smart98c9ea52007-10-27 13:37:33 -04002259 if (lpfc_nlp_not_used(ndlp))
2260 ndlp = NULL;
dea31012005-04-17 16:05:31 -05002261 }
2262 }
James Smart14691152006-12-02 13:34:28 -05002263 mp = (struct lpfc_dmabuf *) mbox->context1;
2264 if (mp) {
2265 lpfc_mbuf_free(phba, mp->virt, mp->phys);
2266 kfree(mp);
2267 }
2268 mempool_free(mbox, phba->mbox_mem_pool);
dea31012005-04-17 16:05:31 -05002269 }
2270out:
2271 if (ndlp) {
James Smart2e0fef82007-06-17 19:56:36 -05002272 spin_lock_irq(shost->host_lock);
James Smart858c9f62007-06-17 19:56:39 -05002273 ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI);
James Smart2e0fef82007-06-17 19:56:36 -05002274 spin_unlock_irq(shost->host_lock);
James Smart87af33f2007-10-27 13:37:43 -04002275
2276 /* If the node is not being used by another discovery thread,
2277 * and we are sending a reject, we are done with it.
2278 * Release driver reference count here and free associated
2279 * resources.
2280 */
2281 if (ls_rjt)
2282 lpfc_nlp_not_used(ndlp);
dea31012005-04-17 16:05:31 -05002283 }
James Smart87af33f2007-10-27 13:37:43 -04002284
dea31012005-04-17 16:05:31 -05002285 lpfc_els_free_iocb(phba, cmdiocb);
2286 return;
2287}
2288
2289int
James Smart2e0fef82007-06-17 19:56:36 -05002290lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
2291 struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp,
James Smart51ef4c22007-08-02 11:10:31 -04002292 LPFC_MBOXQ_t *mbox)
dea31012005-04-17 16:05:31 -05002293{
James Smart2e0fef82007-06-17 19:56:36 -05002294 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
2295 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002296 IOCB_t *icmd;
2297 IOCB_t *oldcmd;
2298 struct lpfc_iocbq *elsiocb;
2299 struct lpfc_sli_ring *pring;
2300 struct lpfc_sli *psli;
2301 uint8_t *pcmd;
2302 uint16_t cmdsize;
2303 int rc;
James Smart82d9a2a2006-04-15 11:53:05 -04002304 ELS_PKT *els_pkt_ptr;
dea31012005-04-17 16:05:31 -05002305
2306 psli = &phba->sli;
2307 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
2308 oldcmd = &oldiocb->iocb;
2309
2310 switch (flag) {
2311 case ELS_CMD_ACC:
James Smart92d7f7b2007-06-17 19:56:38 -05002312 cmdsize = sizeof(uint32_t);
James Smart2e0fef82007-06-17 19:56:36 -05002313 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
2314 ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
James Smart488d1462006-03-07 15:02:37 -05002315 if (!elsiocb) {
James Smart2e0fef82007-06-17 19:56:36 -05002316 spin_lock_irq(shost->host_lock);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05002317 ndlp->nlp_flag &= ~NLP_LOGO_ACC;
James Smart2e0fef82007-06-17 19:56:36 -05002318 spin_unlock_irq(shost->host_lock);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002319 return 1;
dea31012005-04-17 16:05:31 -05002320 }
James Smart2e0fef82007-06-17 19:56:36 -05002321
dea31012005-04-17 16:05:31 -05002322 icmd = &elsiocb->iocb;
2323 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
2324 pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2325 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
James Smart92d7f7b2007-06-17 19:56:38 -05002326 pcmd += sizeof(uint32_t);
James Smart858c9f62007-06-17 19:56:39 -05002327
2328 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2329 "Issue ACC: did:x%x flg:x%x",
2330 ndlp->nlp_DID, ndlp->nlp_flag, 0);
dea31012005-04-17 16:05:31 -05002331 break;
2332 case ELS_CMD_PLOGI:
James Smart92d7f7b2007-06-17 19:56:38 -05002333 cmdsize = (sizeof(struct serv_parm) + sizeof(uint32_t));
James Smart2e0fef82007-06-17 19:56:36 -05002334 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
2335 ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
James Smart488d1462006-03-07 15:02:37 -05002336 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002337 return 1;
James Smart488d1462006-03-07 15:02:37 -05002338
dea31012005-04-17 16:05:31 -05002339 icmd = &elsiocb->iocb;
2340 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
2341 pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2342
2343 if (mbox)
2344 elsiocb->context_un.mbox = mbox;
2345
2346 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
James Smart92d7f7b2007-06-17 19:56:38 -05002347 pcmd += sizeof(uint32_t);
2348 memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
James Smart858c9f62007-06-17 19:56:39 -05002349
2350 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2351 "Issue ACC PLOGI: did:x%x flg:x%x",
2352 ndlp->nlp_DID, ndlp->nlp_flag, 0);
dea31012005-04-17 16:05:31 -05002353 break;
James Smart82d9a2a2006-04-15 11:53:05 -04002354 case ELS_CMD_PRLO:
James Smart92d7f7b2007-06-17 19:56:38 -05002355 cmdsize = sizeof(uint32_t) + sizeof(PRLO);
James Smart2e0fef82007-06-17 19:56:36 -05002356 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
James Smart82d9a2a2006-04-15 11:53:05 -04002357 ndlp, ndlp->nlp_DID, ELS_CMD_PRLO);
2358 if (!elsiocb)
2359 return 1;
2360
2361 icmd = &elsiocb->iocb;
2362 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
2363 pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2364
2365 memcpy(pcmd, ((struct lpfc_dmabuf *) oldiocb->context2)->virt,
James Smart92d7f7b2007-06-17 19:56:38 -05002366 sizeof(uint32_t) + sizeof(PRLO));
James Smart82d9a2a2006-04-15 11:53:05 -04002367 *((uint32_t *) (pcmd)) = ELS_CMD_PRLO_ACC;
2368 els_pkt_ptr = (ELS_PKT *) pcmd;
2369 els_pkt_ptr->un.prlo.acceptRspCode = PRLO_REQ_EXECUTED;
James Smart858c9f62007-06-17 19:56:39 -05002370
2371 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2372 "Issue ACC PRLO: did:x%x flg:x%x",
2373 ndlp->nlp_DID, ndlp->nlp_flag, 0);
James Smart82d9a2a2006-04-15 11:53:05 -04002374 break;
dea31012005-04-17 16:05:31 -05002375 default:
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002376 return 1;
dea31012005-04-17 16:05:31 -05002377 }
dea31012005-04-17 16:05:31 -05002378 /* Xmit ELS ACC response tag <ulpIoTag> */
James Smarte8b62012007-08-02 11:10:09 -04002379 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
2380 "0128 Xmit ELS ACC response tag x%x, XRI: x%x, "
2381 "DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x\n",
2382 elsiocb->iotag, elsiocb->iocb.ulpContext,
2383 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
2384 ndlp->nlp_rpi);
dea31012005-04-17 16:05:31 -05002385 if (ndlp->nlp_flag & NLP_LOGO_ACC) {
James Smart2e0fef82007-06-17 19:56:36 -05002386 spin_lock_irq(shost->host_lock);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002387 ndlp->nlp_flag &= ~NLP_LOGO_ACC;
James Smart2e0fef82007-06-17 19:56:36 -05002388 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05002389 elsiocb->iocb_cmpl = lpfc_cmpl_els_logo_acc;
2390 } else {
James Smart858c9f62007-06-17 19:56:39 -05002391 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
dea31012005-04-17 16:05:31 -05002392 }
2393
2394 phba->fc_stat.elsXmitACC++;
dea31012005-04-17 16:05:31 -05002395 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
dea31012005-04-17 16:05:31 -05002396 if (rc == IOCB_ERROR) {
2397 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002398 return 1;
dea31012005-04-17 16:05:31 -05002399 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002400 return 0;
dea31012005-04-17 16:05:31 -05002401}
2402
2403int
James Smart2e0fef82007-06-17 19:56:36 -05002404lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
James Smart858c9f62007-06-17 19:56:39 -05002405 struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp,
2406 LPFC_MBOXQ_t *mbox)
dea31012005-04-17 16:05:31 -05002407{
James Smart2e0fef82007-06-17 19:56:36 -05002408 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002409 IOCB_t *icmd;
2410 IOCB_t *oldcmd;
2411 struct lpfc_iocbq *elsiocb;
2412 struct lpfc_sli_ring *pring;
2413 struct lpfc_sli *psli;
2414 uint8_t *pcmd;
2415 uint16_t cmdsize;
2416 int rc;
2417
2418 psli = &phba->sli;
2419 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
2420
James Smart92d7f7b2007-06-17 19:56:38 -05002421 cmdsize = 2 * sizeof(uint32_t);
James Smart2e0fef82007-06-17 19:56:36 -05002422 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
2423 ndlp->nlp_DID, ELS_CMD_LS_RJT);
James Smart488d1462006-03-07 15:02:37 -05002424 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002425 return 1;
dea31012005-04-17 16:05:31 -05002426
2427 icmd = &elsiocb->iocb;
2428 oldcmd = &oldiocb->iocb;
2429 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
2430 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2431
2432 *((uint32_t *) (pcmd)) = ELS_CMD_LS_RJT;
James Smart92d7f7b2007-06-17 19:56:38 -05002433 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05002434 *((uint32_t *) (pcmd)) = rejectError;
2435
James Smart51ef4c22007-08-02 11:10:31 -04002436 if (mbox)
James Smart858c9f62007-06-17 19:56:39 -05002437 elsiocb->context_un.mbox = mbox;
James Smart858c9f62007-06-17 19:56:39 -05002438
dea31012005-04-17 16:05:31 -05002439 /* Xmit ELS RJT <err> response tag <ulpIoTag> */
James Smarte8b62012007-08-02 11:10:09 -04002440 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
2441 "0129 Xmit ELS RJT x%x response tag x%x "
2442 "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, "
2443 "rpi x%x\n",
2444 rejectError, elsiocb->iotag,
2445 elsiocb->iocb.ulpContext, ndlp->nlp_DID,
2446 ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
James Smart858c9f62007-06-17 19:56:39 -05002447 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2448 "Issue LS_RJT: did:x%x flg:x%x err:x%x",
2449 ndlp->nlp_DID, ndlp->nlp_flag, rejectError);
2450
dea31012005-04-17 16:05:31 -05002451 phba->fc_stat.elsXmitLSRJT++;
James Smart858c9f62007-06-17 19:56:39 -05002452 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
dea31012005-04-17 16:05:31 -05002453 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
James Smart51ef4c22007-08-02 11:10:31 -04002454
dea31012005-04-17 16:05:31 -05002455 if (rc == IOCB_ERROR) {
2456 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002457 return 1;
dea31012005-04-17 16:05:31 -05002458 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002459 return 0;
dea31012005-04-17 16:05:31 -05002460}
2461
2462int
James Smart2e0fef82007-06-17 19:56:36 -05002463lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
2464 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05002465{
James Smart2e0fef82007-06-17 19:56:36 -05002466 struct lpfc_hba *phba = vport->phba;
2467 struct lpfc_sli *psli = &phba->sli;
2468 struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
dea31012005-04-17 16:05:31 -05002469 ADISC *ap;
James Smart2e0fef82007-06-17 19:56:36 -05002470 IOCB_t *icmd, *oldcmd;
dea31012005-04-17 16:05:31 -05002471 struct lpfc_iocbq *elsiocb;
dea31012005-04-17 16:05:31 -05002472 uint8_t *pcmd;
2473 uint16_t cmdsize;
2474 int rc;
2475
James Smart92d7f7b2007-06-17 19:56:38 -05002476 cmdsize = sizeof(uint32_t) + sizeof(ADISC);
James Smart2e0fef82007-06-17 19:56:36 -05002477 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
2478 ndlp->nlp_DID, ELS_CMD_ACC);
James Smart488d1462006-03-07 15:02:37 -05002479 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002480 return 1;
dea31012005-04-17 16:05:31 -05002481
dea31012005-04-17 16:05:31 -05002482 icmd = &elsiocb->iocb;
2483 oldcmd = &oldiocb->iocb;
2484 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
James Smart5b8bd0c2007-04-25 09:52:49 -04002485
2486 /* Xmit ADISC ACC response tag <ulpIoTag> */
James Smarte8b62012007-08-02 11:10:09 -04002487 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
2488 "0130 Xmit ADISC ACC response iotag x%x xri: "
2489 "x%x, did x%x, nlp_flag x%x, nlp_state x%x rpi x%x\n",
2490 elsiocb->iotag, elsiocb->iocb.ulpContext,
2491 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
2492 ndlp->nlp_rpi);
dea31012005-04-17 16:05:31 -05002493 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2494
2495 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
James Smart92d7f7b2007-06-17 19:56:38 -05002496 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05002497
2498 ap = (ADISC *) (pcmd);
2499 ap->hardAL_PA = phba->fc_pref_ALPA;
James Smart92d7f7b2007-06-17 19:56:38 -05002500 memcpy(&ap->portName, &vport->fc_portname, sizeof(struct lpfc_name));
2501 memcpy(&ap->nodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
James Smart2e0fef82007-06-17 19:56:36 -05002502 ap->DID = be32_to_cpu(vport->fc_myDID);
dea31012005-04-17 16:05:31 -05002503
James Smart858c9f62007-06-17 19:56:39 -05002504 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2505 "Issue ACC ADISC: did:x%x flg:x%x",
2506 ndlp->nlp_DID, ndlp->nlp_flag, 0);
2507
dea31012005-04-17 16:05:31 -05002508 phba->fc_stat.elsXmitACC++;
James Smart858c9f62007-06-17 19:56:39 -05002509 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
dea31012005-04-17 16:05:31 -05002510 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
dea31012005-04-17 16:05:31 -05002511 if (rc == IOCB_ERROR) {
2512 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002513 return 1;
dea31012005-04-17 16:05:31 -05002514 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002515 return 0;
dea31012005-04-17 16:05:31 -05002516}
2517
2518int
James Smart2e0fef82007-06-17 19:56:36 -05002519lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
James Smart5b8bd0c2007-04-25 09:52:49 -04002520 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05002521{
James Smart2e0fef82007-06-17 19:56:36 -05002522 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002523 PRLI *npr;
2524 lpfc_vpd_t *vpd;
2525 IOCB_t *icmd;
2526 IOCB_t *oldcmd;
2527 struct lpfc_iocbq *elsiocb;
2528 struct lpfc_sli_ring *pring;
2529 struct lpfc_sli *psli;
2530 uint8_t *pcmd;
2531 uint16_t cmdsize;
2532 int rc;
2533
2534 psli = &phba->sli;
2535 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
2536
James Smart92d7f7b2007-06-17 19:56:38 -05002537 cmdsize = sizeof(uint32_t) + sizeof(PRLI);
James Smart2e0fef82007-06-17 19:56:36 -05002538 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
James Smart92d7f7b2007-06-17 19:56:38 -05002539 ndlp->nlp_DID, (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK)));
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002540 if (!elsiocb)
2541 return 1;
dea31012005-04-17 16:05:31 -05002542
dea31012005-04-17 16:05:31 -05002543 icmd = &elsiocb->iocb;
2544 oldcmd = &oldiocb->iocb;
2545 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
James Smart5b8bd0c2007-04-25 09:52:49 -04002546 /* Xmit PRLI ACC response tag <ulpIoTag> */
James Smarte8b62012007-08-02 11:10:09 -04002547 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
2548 "0131 Xmit PRLI ACC response tag x%x xri x%x, "
2549 "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
2550 elsiocb->iotag, elsiocb->iocb.ulpContext,
2551 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
2552 ndlp->nlp_rpi);
dea31012005-04-17 16:05:31 -05002553 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2554
2555 *((uint32_t *) (pcmd)) = (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK));
James Smart92d7f7b2007-06-17 19:56:38 -05002556 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05002557
2558 /* For PRLI, remainder of payload is PRLI parameter page */
James Smart92d7f7b2007-06-17 19:56:38 -05002559 memset(pcmd, 0, sizeof(PRLI));
dea31012005-04-17 16:05:31 -05002560
2561 npr = (PRLI *) pcmd;
2562 vpd = &phba->vpd;
2563 /*
2564 * If our firmware version is 3.20 or later,
2565 * set the following bits for FC-TAPE support.
2566 */
2567 if (vpd->rev.feaLevelHigh >= 0x02) {
2568 npr->ConfmComplAllowed = 1;
2569 npr->Retry = 1;
2570 npr->TaskRetryIdReq = 1;
2571 }
2572
2573 npr->acceptRspCode = PRLI_REQ_EXECUTED;
2574 npr->estabImagePair = 1;
2575 npr->readXferRdyDis = 1;
2576 npr->ConfmComplAllowed = 1;
2577
2578 npr->prliType = PRLI_FCP_TYPE;
2579 npr->initiatorFunc = 1;
2580
James Smart858c9f62007-06-17 19:56:39 -05002581 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2582 "Issue ACC PRLI: did:x%x flg:x%x",
2583 ndlp->nlp_DID, ndlp->nlp_flag, 0);
2584
dea31012005-04-17 16:05:31 -05002585 phba->fc_stat.elsXmitACC++;
James Smart858c9f62007-06-17 19:56:39 -05002586 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
dea31012005-04-17 16:05:31 -05002587
dea31012005-04-17 16:05:31 -05002588 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
dea31012005-04-17 16:05:31 -05002589 if (rc == IOCB_ERROR) {
2590 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002591 return 1;
dea31012005-04-17 16:05:31 -05002592 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002593 return 0;
dea31012005-04-17 16:05:31 -05002594}
2595
2596static int
James Smart2e0fef82007-06-17 19:56:36 -05002597lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format,
James Smart329f9bc2007-04-25 09:53:01 -04002598 struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05002599{
James Smart2e0fef82007-06-17 19:56:36 -05002600 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002601 RNID *rn;
James Smart2e0fef82007-06-17 19:56:36 -05002602 IOCB_t *icmd, *oldcmd;
dea31012005-04-17 16:05:31 -05002603 struct lpfc_iocbq *elsiocb;
2604 struct lpfc_sli_ring *pring;
2605 struct lpfc_sli *psli;
2606 uint8_t *pcmd;
2607 uint16_t cmdsize;
2608 int rc;
2609
2610 psli = &phba->sli;
2611 pring = &psli->ring[LPFC_ELS_RING];
2612
James Smart92d7f7b2007-06-17 19:56:38 -05002613 cmdsize = sizeof(uint32_t) + sizeof(uint32_t)
2614 + (2 * sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05002615 if (format)
James Smart92d7f7b2007-06-17 19:56:38 -05002616 cmdsize += sizeof(RNID_TOP_DISC);
dea31012005-04-17 16:05:31 -05002617
James Smart2e0fef82007-06-17 19:56:36 -05002618 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
2619 ndlp->nlp_DID, ELS_CMD_ACC);
James Smart488d1462006-03-07 15:02:37 -05002620 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002621 return 1;
dea31012005-04-17 16:05:31 -05002622
dea31012005-04-17 16:05:31 -05002623 icmd = &elsiocb->iocb;
2624 oldcmd = &oldiocb->iocb;
2625 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
James Smart5b8bd0c2007-04-25 09:52:49 -04002626 /* Xmit RNID ACC response tag <ulpIoTag> */
James Smarte8b62012007-08-02 11:10:09 -04002627 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
2628 "0132 Xmit RNID ACC response tag x%x xri x%x\n",
2629 elsiocb->iotag, elsiocb->iocb.ulpContext);
dea31012005-04-17 16:05:31 -05002630 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
dea31012005-04-17 16:05:31 -05002631 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
James Smart92d7f7b2007-06-17 19:56:38 -05002632 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05002633
James Smart92d7f7b2007-06-17 19:56:38 -05002634 memset(pcmd, 0, sizeof(RNID));
dea31012005-04-17 16:05:31 -05002635 rn = (RNID *) (pcmd);
2636 rn->Format = format;
James Smart92d7f7b2007-06-17 19:56:38 -05002637 rn->CommonLen = (2 * sizeof(struct lpfc_name));
2638 memcpy(&rn->portName, &vport->fc_portname, sizeof(struct lpfc_name));
2639 memcpy(&rn->nodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05002640 switch (format) {
2641 case 0:
2642 rn->SpecificLen = 0;
2643 break;
2644 case RNID_TOPOLOGY_DISC:
James Smart92d7f7b2007-06-17 19:56:38 -05002645 rn->SpecificLen = sizeof(RNID_TOP_DISC);
dea31012005-04-17 16:05:31 -05002646 memcpy(&rn->un.topologyDisc.portName,
James Smart92d7f7b2007-06-17 19:56:38 -05002647 &vport->fc_portname, sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05002648 rn->un.topologyDisc.unitType = RNID_HBA;
2649 rn->un.topologyDisc.physPort = 0;
2650 rn->un.topologyDisc.attachedNodes = 0;
2651 break;
2652 default:
2653 rn->CommonLen = 0;
2654 rn->SpecificLen = 0;
2655 break;
2656 }
2657
James Smart858c9f62007-06-17 19:56:39 -05002658 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2659 "Issue ACC RNID: did:x%x flg:x%x",
2660 ndlp->nlp_DID, ndlp->nlp_flag, 0);
2661
dea31012005-04-17 16:05:31 -05002662 phba->fc_stat.elsXmitACC++;
James Smart858c9f62007-06-17 19:56:39 -05002663 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
James Smart329f9bc2007-04-25 09:53:01 -04002664 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05002665 elsiocb->context1 = NULL; /* Don't need ndlp for cmpl,
2666 * it could be freed */
2667
dea31012005-04-17 16:05:31 -05002668 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
dea31012005-04-17 16:05:31 -05002669 if (rc == IOCB_ERROR) {
2670 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002671 return 1;
dea31012005-04-17 16:05:31 -05002672 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002673 return 0;
dea31012005-04-17 16:05:31 -05002674}
2675
2676int
James Smart2e0fef82007-06-17 19:56:36 -05002677lpfc_els_disc_adisc(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05002678{
James Smart2e0fef82007-06-17 19:56:36 -05002679 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05002680 struct lpfc_nodelist *ndlp, *next_ndlp;
James Smart2e0fef82007-06-17 19:56:36 -05002681 int sentadisc = 0;
dea31012005-04-17 16:05:31 -05002682
James Smart685f0bf2007-04-25 09:53:08 -04002683 /* go thru NPR nodes and issue any remaining ELS ADISCs */
James Smart2e0fef82007-06-17 19:56:36 -05002684 list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
James Smart685f0bf2007-04-25 09:53:08 -04002685 if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
2686 (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
2687 (ndlp->nlp_flag & NLP_NPR_ADISC) != 0) {
James Smart2e0fef82007-06-17 19:56:36 -05002688 spin_lock_irq(shost->host_lock);
James Smart685f0bf2007-04-25 09:53:08 -04002689 ndlp->nlp_flag &= ~NLP_NPR_ADISC;
James Smart2e0fef82007-06-17 19:56:36 -05002690 spin_unlock_irq(shost->host_lock);
James Smart685f0bf2007-04-25 09:53:08 -04002691 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002692 lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
2693 lpfc_issue_els_adisc(vport, ndlp, 0);
James Smart685f0bf2007-04-25 09:53:08 -04002694 sentadisc++;
James Smart2e0fef82007-06-17 19:56:36 -05002695 vport->num_disc_nodes++;
2696 if (vport->num_disc_nodes >=
James Smart3de2a652007-08-02 11:09:59 -04002697 vport->cfg_discovery_threads) {
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);
James Smart685f0bf2007-04-25 09:53:08 -04002701 break;
dea31012005-04-17 16:05:31 -05002702 }
2703 }
2704 }
2705 if (sentadisc == 0) {
James Smart2e0fef82007-06-17 19:56:36 -05002706 spin_lock_irq(shost->host_lock);
2707 vport->fc_flag &= ~FC_NLP_MORE;
2708 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05002709 }
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05002710 return sentadisc;
dea31012005-04-17 16:05:31 -05002711}
2712
2713int
James Smart2e0fef82007-06-17 19:56:36 -05002714lpfc_els_disc_plogi(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05002715{
James Smart2e0fef82007-06-17 19:56:36 -05002716 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05002717 struct lpfc_nodelist *ndlp, *next_ndlp;
James Smart2e0fef82007-06-17 19:56:36 -05002718 int sentplogi = 0;
dea31012005-04-17 16:05:31 -05002719
James Smart2e0fef82007-06-17 19:56:36 -05002720 /* go thru NPR nodes and issue any remaining ELS PLOGIs */
2721 list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
James Smart685f0bf2007-04-25 09:53:08 -04002722 if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
2723 (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
2724 (ndlp->nlp_flag & NLP_DELAY_TMO) == 0 &&
2725 (ndlp->nlp_flag & NLP_NPR_ADISC) == 0) {
2726 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002727 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
2728 lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
James Smart685f0bf2007-04-25 09:53:08 -04002729 sentplogi++;
James Smart2e0fef82007-06-17 19:56:36 -05002730 vport->num_disc_nodes++;
2731 if (vport->num_disc_nodes >=
James Smart3de2a652007-08-02 11:09:59 -04002732 vport->cfg_discovery_threads) {
James Smart2e0fef82007-06-17 19:56:36 -05002733 spin_lock_irq(shost->host_lock);
2734 vport->fc_flag |= FC_NLP_MORE;
2735 spin_unlock_irq(shost->host_lock);
James Smart685f0bf2007-04-25 09:53:08 -04002736 break;
dea31012005-04-17 16:05:31 -05002737 }
2738 }
2739 }
James Smart87af33f2007-10-27 13:37:43 -04002740 if (sentplogi) {
2741 lpfc_set_disctmo(vport);
2742 }
2743 else {
James Smart2e0fef82007-06-17 19:56:36 -05002744 spin_lock_irq(shost->host_lock);
2745 vport->fc_flag &= ~FC_NLP_MORE;
2746 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05002747 }
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05002748 return sentplogi;
dea31012005-04-17 16:05:31 -05002749}
2750
James Smart92d7f7b2007-06-17 19:56:38 -05002751void
James Smart2e0fef82007-06-17 19:56:36 -05002752lpfc_els_flush_rscn(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05002753{
James Smart2e0fef82007-06-17 19:56:36 -05002754 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
2755 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002756 int i;
2757
James Smart2e0fef82007-06-17 19:56:36 -05002758 for (i = 0; i < vport->fc_rscn_id_cnt; i++) {
James Smart92d7f7b2007-06-17 19:56:38 -05002759 lpfc_in_buf_free(phba, vport->fc_rscn_id_list[i]);
James Smart2e0fef82007-06-17 19:56:36 -05002760 vport->fc_rscn_id_list[i] = NULL;
dea31012005-04-17 16:05:31 -05002761 }
James Smart2e0fef82007-06-17 19:56:36 -05002762 spin_lock_irq(shost->host_lock);
2763 vport->fc_rscn_id_cnt = 0;
2764 vport->fc_flag &= ~(FC_RSCN_MODE | FC_RSCN_DISCOVERY);
2765 spin_unlock_irq(shost->host_lock);
2766 lpfc_can_disctmo(vport);
dea31012005-04-17 16:05:31 -05002767}
2768
2769int
James Smart2e0fef82007-06-17 19:56:36 -05002770lpfc_rscn_payload_check(struct lpfc_vport *vport, uint32_t did)
dea31012005-04-17 16:05:31 -05002771{
2772 D_ID ns_did;
2773 D_ID rscn_did;
dea31012005-04-17 16:05:31 -05002774 uint32_t *lp;
James Smart92d7f7b2007-06-17 19:56:38 -05002775 uint32_t payload_len, i;
dea31012005-04-17 16:05:31 -05002776
2777 ns_did.un.word = did;
dea31012005-04-17 16:05:31 -05002778
2779 /* Never match fabric nodes for RSCNs */
2780 if ((did & Fabric_DID_MASK) == Fabric_DID_MASK)
James Smart2e0fef82007-06-17 19:56:36 -05002781 return 0;
dea31012005-04-17 16:05:31 -05002782
2783 /* If we are doing a FULL RSCN rediscovery, match everything */
James Smart2e0fef82007-06-17 19:56:36 -05002784 if (vport->fc_flag & FC_RSCN_DISCOVERY)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002785 return did;
dea31012005-04-17 16:05:31 -05002786
James Smart2e0fef82007-06-17 19:56:36 -05002787 for (i = 0; i < vport->fc_rscn_id_cnt; i++) {
James Smart92d7f7b2007-06-17 19:56:38 -05002788 lp = vport->fc_rscn_id_list[i]->virt;
2789 payload_len = be32_to_cpu(*lp++ & ~ELS_CMD_MASK);
2790 payload_len -= sizeof(uint32_t); /* take off word 0 */
dea31012005-04-17 16:05:31 -05002791 while (payload_len) {
James Smart92d7f7b2007-06-17 19:56:38 -05002792 rscn_did.un.word = be32_to_cpu(*lp++);
2793 payload_len -= sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05002794 switch (rscn_did.un.b.resv) {
2795 case 0: /* Single N_Port ID effected */
James Smart2e0fef82007-06-17 19:56:36 -05002796 if (ns_did.un.word == rscn_did.un.word)
James Smart92d7f7b2007-06-17 19:56:38 -05002797 return did;
dea31012005-04-17 16:05:31 -05002798 break;
2799 case 1: /* Whole N_Port Area effected */
2800 if ((ns_did.un.b.domain == rscn_did.un.b.domain)
2801 && (ns_did.un.b.area == rscn_did.un.b.area))
James Smart92d7f7b2007-06-17 19:56:38 -05002802 return did;
dea31012005-04-17 16:05:31 -05002803 break;
2804 case 2: /* Whole N_Port Domain effected */
2805 if (ns_did.un.b.domain == rscn_did.un.b.domain)
James Smart92d7f7b2007-06-17 19:56:38 -05002806 return did;
dea31012005-04-17 16:05:31 -05002807 break;
2808 default:
James Smart2e0fef82007-06-17 19:56:36 -05002809 /* Unknown Identifier in RSCN node */
James Smarte8b62012007-08-02 11:10:09 -04002810 lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
2811 "0217 Unknown Identifier in "
2812 "RSCN payload Data: x%x\n",
2813 rscn_did.un.word);
James Smart92d7f7b2007-06-17 19:56:38 -05002814 case 3: /* Whole Fabric effected */
2815 return did;
dea31012005-04-17 16:05:31 -05002816 }
2817 }
James Smart92d7f7b2007-06-17 19:56:38 -05002818 }
2819 return 0;
dea31012005-04-17 16:05:31 -05002820}
2821
2822static int
James Smart2e0fef82007-06-17 19:56:36 -05002823lpfc_rscn_recovery_check(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05002824{
James Smart685f0bf2007-04-25 09:53:08 -04002825 struct lpfc_nodelist *ndlp = NULL;
dea31012005-04-17 16:05:31 -05002826
2827 /* Look at all nodes effected by pending RSCNs and move
James Smart685f0bf2007-04-25 09:53:08 -04002828 * them to NPR state.
dea31012005-04-17 16:05:31 -05002829 */
James Smart685f0bf2007-04-25 09:53:08 -04002830
James Smart2e0fef82007-06-17 19:56:36 -05002831 list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
James Smart685f0bf2007-04-25 09:53:08 -04002832 if (ndlp->nlp_state == NLP_STE_UNUSED_NODE ||
James Smart2e0fef82007-06-17 19:56:36 -05002833 lpfc_rscn_payload_check(vport, ndlp->nlp_DID) == 0)
dea31012005-04-17 16:05:31 -05002834 continue;
2835
James Smart2e0fef82007-06-17 19:56:36 -05002836 lpfc_disc_state_machine(vport, ndlp, NULL,
James Smart92d7f7b2007-06-17 19:56:38 -05002837 NLP_EVT_DEVICE_RECOVERY);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05002838
James Smart685f0bf2007-04-25 09:53:08 -04002839 /*
2840 * Make sure NLP_DELAY_TMO is NOT running after a device
2841 * recovery event.
2842 */
2843 if (ndlp->nlp_flag & NLP_DELAY_TMO)
James Smart2e0fef82007-06-17 19:56:36 -05002844 lpfc_cancel_retry_delay_tmo(vport, ndlp);
dea31012005-04-17 16:05:31 -05002845 }
James Smart685f0bf2007-04-25 09:53:08 -04002846
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002847 return 0;
dea31012005-04-17 16:05:31 -05002848}
2849
2850static int
James Smart2e0fef82007-06-17 19:56:36 -05002851lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
James Smart51ef4c22007-08-02 11:10:31 -04002852 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05002853{
James Smart2e0fef82007-06-17 19:56:36 -05002854 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
2855 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002856 struct lpfc_dmabuf *pcmd;
James Smart92d7f7b2007-06-17 19:56:38 -05002857 uint32_t *lp, *datap;
dea31012005-04-17 16:05:31 -05002858 IOCB_t *icmd;
James Smart92d7f7b2007-06-17 19:56:38 -05002859 uint32_t payload_len, length, nportid, *cmd;
2860 int rscn_cnt = vport->fc_rscn_id_cnt;
2861 int rscn_id = 0, hba_id = 0;
James Smartd2873e42006-08-18 17:46:43 -04002862 int i;
dea31012005-04-17 16:05:31 -05002863
2864 icmd = &cmdiocb->iocb;
2865 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
2866 lp = (uint32_t *) pcmd->virt;
2867
James Smart92d7f7b2007-06-17 19:56:38 -05002868 payload_len = be32_to_cpu(*lp++ & ~ELS_CMD_MASK);
2869 payload_len -= sizeof(uint32_t); /* take off word 0 */
dea31012005-04-17 16:05:31 -05002870 /* RSCN received */
James Smarte8b62012007-08-02 11:10:09 -04002871 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
2872 "0214 RSCN received Data: x%x x%x x%x x%x\n",
2873 vport->fc_flag, payload_len, *lp, rscn_cnt);
James Smartd2873e42006-08-18 17:46:43 -04002874 for (i = 0; i < payload_len/sizeof(uint32_t); i++)
James Smart2e0fef82007-06-17 19:56:36 -05002875 fc_host_post_event(shost, fc_get_event_number(),
James Smartd2873e42006-08-18 17:46:43 -04002876 FCH_EVT_RSCN, lp[i]);
2877
dea31012005-04-17 16:05:31 -05002878 /* If we are about to begin discovery, just ACC the RSCN.
2879 * Discovery processing will satisfy it.
2880 */
James Smart2e0fef82007-06-17 19:56:36 -05002881 if (vport->port_state <= LPFC_NS_QRY) {
James Smart858c9f62007-06-17 19:56:39 -05002882 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
2883 "RCV RSCN ignore: did:x%x/ste:x%x flg:x%x",
2884 ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
2885
James Smart51ef4c22007-08-02 11:10:31 -04002886 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002887 return 0;
dea31012005-04-17 16:05:31 -05002888 }
2889
James Smart92d7f7b2007-06-17 19:56:38 -05002890 /* If this RSCN just contains NPortIDs for other vports on this HBA,
2891 * just ACC and ignore it.
2892 */
2893 if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
James Smart3de2a652007-08-02 11:09:59 -04002894 !(vport->cfg_peer_port_login)) {
James Smart92d7f7b2007-06-17 19:56:38 -05002895 i = payload_len;
2896 datap = lp;
2897 while (i > 0) {
2898 nportid = *datap++;
2899 nportid = ((be32_to_cpu(nportid)) & Mask_DID);
2900 i -= sizeof(uint32_t);
2901 rscn_id++;
James Smart549e55c2007-08-02 11:09:51 -04002902 if (lpfc_find_vport_by_did(phba, nportid))
2903 hba_id++;
James Smart92d7f7b2007-06-17 19:56:38 -05002904 }
2905 if (rscn_id == hba_id) {
2906 /* ALL NPortIDs in RSCN are on HBA */
James Smarte8b62012007-08-02 11:10:09 -04002907 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
2908 "0214 Ignore RSCN "
2909 "Data: x%x x%x x%x x%x\n",
2910 vport->fc_flag, payload_len,
2911 *lp, rscn_cnt);
James Smart858c9f62007-06-17 19:56:39 -05002912 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
2913 "RCV RSCN vport: did:x%x/ste:x%x flg:x%x",
2914 ndlp->nlp_DID, vport->port_state,
2915 ndlp->nlp_flag);
2916
James Smart92d7f7b2007-06-17 19:56:38 -05002917 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb,
James Smart51ef4c22007-08-02 11:10:31 -04002918 ndlp, NULL);
James Smart92d7f7b2007-06-17 19:56:38 -05002919 return 0;
2920 }
2921 }
2922
dea31012005-04-17 16:05:31 -05002923 /* If we are already processing an RSCN, save the received
2924 * RSCN payload buffer, cmdiocb->context2 to process later.
2925 */
James Smart2e0fef82007-06-17 19:56:36 -05002926 if (vport->fc_flag & (FC_RSCN_MODE | FC_NDISC_ACTIVE)) {
James Smart858c9f62007-06-17 19:56:39 -05002927 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
2928 "RCV RSCN defer: did:x%x/ste:x%x flg:x%x",
2929 ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
2930
James Smart92d7f7b2007-06-17 19:56:38 -05002931 vport->fc_flag |= FC_RSCN_DEFERRED;
2932 if ((rscn_cnt < FC_MAX_HOLD_RSCN) &&
James Smart2e0fef82007-06-17 19:56:36 -05002933 !(vport->fc_flag & FC_RSCN_DISCOVERY)) {
2934 spin_lock_irq(shost->host_lock);
2935 vport->fc_flag |= FC_RSCN_MODE;
2936 spin_unlock_irq(shost->host_lock);
James Smart92d7f7b2007-06-17 19:56:38 -05002937 if (rscn_cnt) {
2938 cmd = vport->fc_rscn_id_list[rscn_cnt-1]->virt;
2939 length = be32_to_cpu(*cmd & ~ELS_CMD_MASK);
2940 }
2941 if ((rscn_cnt) &&
2942 (payload_len + length <= LPFC_BPL_SIZE)) {
2943 *cmd &= ELS_CMD_MASK;
2944 *cmd |= be32_to_cpu(payload_len + length);
2945 memcpy(((uint8_t *)cmd) + length, lp,
2946 payload_len);
2947 } else {
2948 vport->fc_rscn_id_list[rscn_cnt] = pcmd;
2949 vport->fc_rscn_id_cnt++;
2950 /* If we zero, cmdiocb->context2, the calling
2951 * routine will not try to free it.
2952 */
2953 cmdiocb->context2 = NULL;
2954 }
dea31012005-04-17 16:05:31 -05002955
2956 /* Deferred RSCN */
James Smarte8b62012007-08-02 11:10:09 -04002957 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
2958 "0235 Deferred RSCN "
2959 "Data: x%x x%x x%x\n",
2960 vport->fc_rscn_id_cnt, vport->fc_flag,
2961 vport->port_state);
dea31012005-04-17 16:05:31 -05002962 } else {
James Smart2e0fef82007-06-17 19:56:36 -05002963 spin_lock_irq(shost->host_lock);
2964 vport->fc_flag |= FC_RSCN_DISCOVERY;
2965 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05002966 /* ReDiscovery RSCN */
James Smarte8b62012007-08-02 11:10:09 -04002967 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
2968 "0234 ReDiscovery RSCN "
2969 "Data: x%x x%x x%x\n",
2970 vport->fc_rscn_id_cnt, vport->fc_flag,
2971 vport->port_state);
dea31012005-04-17 16:05:31 -05002972 }
2973 /* Send back ACC */
James Smart51ef4c22007-08-02 11:10:31 -04002974 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
dea31012005-04-17 16:05:31 -05002975
2976 /* send RECOVERY event for ALL nodes that match RSCN payload */
James Smart2e0fef82007-06-17 19:56:36 -05002977 lpfc_rscn_recovery_check(vport);
James Smart92d7f7b2007-06-17 19:56:38 -05002978 vport->fc_flag &= ~FC_RSCN_DEFERRED;
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002979 return 0;
dea31012005-04-17 16:05:31 -05002980 }
2981
James Smart858c9f62007-06-17 19:56:39 -05002982 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
2983 "RCV RSCN: did:x%x/ste:x%x flg:x%x",
2984 ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
2985
James Smart2e0fef82007-06-17 19:56:36 -05002986 spin_lock_irq(shost->host_lock);
2987 vport->fc_flag |= FC_RSCN_MODE;
2988 spin_unlock_irq(shost->host_lock);
2989 vport->fc_rscn_id_list[vport->fc_rscn_id_cnt++] = pcmd;
dea31012005-04-17 16:05:31 -05002990 /*
2991 * If we zero, cmdiocb->context2, the calling routine will
2992 * not try to free it.
2993 */
2994 cmdiocb->context2 = NULL;
2995
James Smart2e0fef82007-06-17 19:56:36 -05002996 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -05002997
2998 /* Send back ACC */
James Smart51ef4c22007-08-02 11:10:31 -04002999 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
dea31012005-04-17 16:05:31 -05003000
3001 /* send RECOVERY event for ALL nodes that match RSCN payload */
James Smart2e0fef82007-06-17 19:56:36 -05003002 lpfc_rscn_recovery_check(vport);
dea31012005-04-17 16:05:31 -05003003
James Smart2e0fef82007-06-17 19:56:36 -05003004 return lpfc_els_handle_rscn(vport);
dea31012005-04-17 16:05:31 -05003005}
3006
3007int
James Smart2e0fef82007-06-17 19:56:36 -05003008lpfc_els_handle_rscn(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05003009{
3010 struct lpfc_nodelist *ndlp;
James Smart2e0fef82007-06-17 19:56:36 -05003011 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05003012
James Smart92d7f7b2007-06-17 19:56:38 -05003013 /* Ignore RSCN if the port is being torn down. */
3014 if (vport->load_flag & FC_UNLOADING) {
3015 lpfc_els_flush_rscn(vport);
3016 return 0;
3017 }
3018
dea31012005-04-17 16:05:31 -05003019 /* Start timer for RSCN processing */
James Smart2e0fef82007-06-17 19:56:36 -05003020 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -05003021
3022 /* RSCN processed */
James Smarte8b62012007-08-02 11:10:09 -04003023 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
3024 "0215 RSCN processed Data: x%x x%x x%x x%x\n",
3025 vport->fc_flag, 0, vport->fc_rscn_id_cnt,
3026 vport->port_state);
dea31012005-04-17 16:05:31 -05003027
3028 /* To process RSCN, first compare RSCN data with NameServer */
James Smart2e0fef82007-06-17 19:56:36 -05003029 vport->fc_ns_retry = 0;
3030 ndlp = lpfc_findnode_did(vport, NameServer_DID);
James Smart685f0bf2007-04-25 09:53:08 -04003031 if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
dea31012005-04-17 16:05:31 -05003032 /* Good ndlp, issue CT Request to NameServer */
James Smart92d7f7b2007-06-17 19:56:38 -05003033 if (lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, 0, 0) == 0)
dea31012005-04-17 16:05:31 -05003034 /* Wait for NameServer query cmpl before we can
3035 continue */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003036 return 1;
dea31012005-04-17 16:05:31 -05003037 } else {
3038 /* If login to NameServer does not exist, issue one */
3039 /* Good status, issue PLOGI to NameServer */
James Smart2e0fef82007-06-17 19:56:36 -05003040 ndlp = lpfc_findnode_did(vport, NameServer_DID);
3041 if (ndlp)
dea31012005-04-17 16:05:31 -05003042 /* Wait for NameServer login cmpl before we can
3043 continue */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003044 return 1;
James Smart2e0fef82007-06-17 19:56:36 -05003045
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003046 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
3047 if (!ndlp) {
James Smart2e0fef82007-06-17 19:56:36 -05003048 lpfc_els_flush_rscn(vport);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003049 return 0;
dea31012005-04-17 16:05:31 -05003050 } else {
James Smart2e0fef82007-06-17 19:56:36 -05003051 lpfc_nlp_init(vport, ndlp, NameServer_DID);
dea31012005-04-17 16:05:31 -05003052 ndlp->nlp_type |= NLP_FABRIC;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003053 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05003054 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
3055 lpfc_issue_els_plogi(vport, NameServer_DID, 0);
dea31012005-04-17 16:05:31 -05003056 /* Wait for NameServer login cmpl before we can
3057 continue */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003058 return 1;
dea31012005-04-17 16:05:31 -05003059 }
3060 }
3061
James Smart2e0fef82007-06-17 19:56:36 -05003062 lpfc_els_flush_rscn(vport);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003063 return 0;
dea31012005-04-17 16:05:31 -05003064}
3065
3066static int
James Smart2e0fef82007-06-17 19:56:36 -05003067lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
James Smart51ef4c22007-08-02 11:10:31 -04003068 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05003069{
James Smart2e0fef82007-06-17 19:56:36 -05003070 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
3071 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05003072 struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3073 uint32_t *lp = (uint32_t *) pcmd->virt;
3074 IOCB_t *icmd = &cmdiocb->iocb;
3075 struct serv_parm *sp;
3076 LPFC_MBOXQ_t *mbox;
3077 struct ls_rjt stat;
3078 uint32_t cmd, did;
3079 int rc;
3080
3081 cmd = *lp++;
3082 sp = (struct serv_parm *) lp;
3083
3084 /* FLOGI received */
3085
James Smart2e0fef82007-06-17 19:56:36 -05003086 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -05003087
3088 if (phba->fc_topology == TOPOLOGY_LOOP) {
3089 /* We should never receive a FLOGI in loop mode, ignore it */
3090 did = icmd->un.elsreq64.remoteID;
3091
3092 /* An FLOGI ELS command <elsCmd> was received from DID <did> in
3093 Loop Mode */
James Smarte8b62012007-08-02 11:10:09 -04003094 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
3095 "0113 An FLOGI ELS command x%x was "
3096 "received from DID x%x in Loop Mode\n",
3097 cmd, did);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003098 return 1;
dea31012005-04-17 16:05:31 -05003099 }
3100
3101 did = Fabric_DID;
3102
James Smart2e0fef82007-06-17 19:56:36 -05003103 if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3))) {
dea31012005-04-17 16:05:31 -05003104 /* For a FLOGI we accept, then if our portname is greater
3105 * then the remote portname we initiate Nport login.
3106 */
3107
James Smart2e0fef82007-06-17 19:56:36 -05003108 rc = memcmp(&vport->fc_portname, &sp->portName,
James Smart92d7f7b2007-06-17 19:56:38 -05003109 sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05003110
3111 if (!rc) {
James Smart2e0fef82007-06-17 19:56:36 -05003112 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
3113 if (!mbox)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003114 return 1;
James Smart2e0fef82007-06-17 19:56:36 -05003115
dea31012005-04-17 16:05:31 -05003116 lpfc_linkdown(phba);
3117 lpfc_init_link(phba, mbox,
3118 phba->cfg_topology,
3119 phba->cfg_link_speed);
3120 mbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
3121 mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
James Smarted957682007-06-17 19:56:37 -05003122 mbox->vport = vport;
James Smart0b727fe2007-10-27 13:37:25 -04003123 rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
James Smart5b8bd0c2007-04-25 09:52:49 -04003124 lpfc_set_loopback_flag(phba);
dea31012005-04-17 16:05:31 -05003125 if (rc == MBX_NOT_FINISHED) {
James Smart329f9bc2007-04-25 09:53:01 -04003126 mempool_free(mbox, phba->mbox_mem_pool);
dea31012005-04-17 16:05:31 -05003127 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003128 return 1;
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05003129 } else if (rc > 0) { /* greater than */
James Smart2e0fef82007-06-17 19:56:36 -05003130 spin_lock_irq(shost->host_lock);
3131 vport->fc_flag |= FC_PT2PT_PLOGI;
3132 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05003133 }
James Smart2e0fef82007-06-17 19:56:36 -05003134 spin_lock_irq(shost->host_lock);
3135 vport->fc_flag |= FC_PT2PT;
3136 vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
3137 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05003138 } else {
3139 /* Reject this request because invalid parameters */
3140 stat.un.b.lsRjtRsvd0 = 0;
3141 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
3142 stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
3143 stat.un.b.vendorUnique = 0;
James Smart858c9f62007-06-17 19:56:39 -05003144 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
3145 NULL);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003146 return 1;
dea31012005-04-17 16:05:31 -05003147 }
3148
3149 /* Send back ACC */
James Smart51ef4c22007-08-02 11:10:31 -04003150 lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL);
dea31012005-04-17 16:05:31 -05003151
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003152 return 0;
dea31012005-04-17 16:05:31 -05003153}
3154
3155static int
James Smart2e0fef82007-06-17 19:56:36 -05003156lpfc_els_rcv_rnid(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3157 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05003158{
3159 struct lpfc_dmabuf *pcmd;
3160 uint32_t *lp;
3161 IOCB_t *icmd;
3162 RNID *rn;
3163 struct ls_rjt stat;
3164 uint32_t cmd, did;
3165
3166 icmd = &cmdiocb->iocb;
3167 did = icmd->un.elsreq64.remoteID;
3168 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3169 lp = (uint32_t *) pcmd->virt;
3170
3171 cmd = *lp++;
3172 rn = (RNID *) lp;
3173
3174 /* RNID received */
3175
3176 switch (rn->Format) {
3177 case 0:
3178 case RNID_TOPOLOGY_DISC:
3179 /* Send back ACC */
James Smart2e0fef82007-06-17 19:56:36 -05003180 lpfc_els_rsp_rnid_acc(vport, rn->Format, cmdiocb, ndlp);
dea31012005-04-17 16:05:31 -05003181 break;
3182 default:
3183 /* Reject this request because format not supported */
3184 stat.un.b.lsRjtRsvd0 = 0;
3185 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
3186 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
3187 stat.un.b.vendorUnique = 0;
James Smart858c9f62007-06-17 19:56:39 -05003188 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
3189 NULL);
dea31012005-04-17 16:05:31 -05003190 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003191 return 0;
dea31012005-04-17 16:05:31 -05003192}
3193
3194static int
James Smart2e0fef82007-06-17 19:56:36 -05003195lpfc_els_rcv_lirr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3196 struct lpfc_nodelist *ndlp)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003197{
3198 struct ls_rjt stat;
3199
3200 /* For now, unconditionally reject this command */
3201 stat.un.b.lsRjtRsvd0 = 0;
3202 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
3203 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
3204 stat.un.b.vendorUnique = 0;
James Smart858c9f62007-06-17 19:56:39 -05003205 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003206 return 0;
3207}
3208
Jamie Wellnitz082c0262006-02-28 19:25:30 -05003209static void
James Smart329f9bc2007-04-25 09:53:01 -04003210lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003211{
James Smart2e0fef82007-06-17 19:56:36 -05003212 struct lpfc_sli *psli = &phba->sli;
3213 struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003214 MAILBOX_t *mb;
3215 IOCB_t *icmd;
3216 RPS_RSP *rps_rsp;
3217 uint8_t *pcmd;
3218 struct lpfc_iocbq *elsiocb;
3219 struct lpfc_nodelist *ndlp;
3220 uint16_t xri, status;
3221 uint32_t cmdsize;
3222
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003223 mb = &pmb->mb;
3224
3225 ndlp = (struct lpfc_nodelist *) pmb->context2;
3226 xri = (uint16_t) ((unsigned long)(pmb->context1));
Randy Dunlap041976f2006-06-25 01:58:51 -07003227 pmb->context1 = NULL;
3228 pmb->context2 = NULL;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003229
3230 if (mb->mbxStatus) {
James Smart329f9bc2007-04-25 09:53:01 -04003231 mempool_free(pmb, phba->mbox_mem_pool);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003232 return;
3233 }
3234
3235 cmdsize = sizeof(RPS_RSP) + sizeof(uint32_t);
James Smart329f9bc2007-04-25 09:53:01 -04003236 mempool_free(pmb, phba->mbox_mem_pool);
James Smart2e0fef82007-06-17 19:56:36 -05003237 elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize,
3238 lpfc_max_els_tries, ndlp,
3239 ndlp->nlp_DID, ELS_CMD_ACC);
James Smart329f9bc2007-04-25 09:53:01 -04003240 lpfc_nlp_put(ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003241 if (!elsiocb)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003242 return;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003243
3244 icmd = &elsiocb->iocb;
3245 icmd->ulpContext = xri;
3246
3247 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
3248 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
James Smart92d7f7b2007-06-17 19:56:38 -05003249 pcmd += sizeof(uint32_t); /* Skip past command */
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003250 rps_rsp = (RPS_RSP *)pcmd;
3251
3252 if (phba->fc_topology != TOPOLOGY_LOOP)
3253 status = 0x10;
3254 else
3255 status = 0x8;
James Smart2e0fef82007-06-17 19:56:36 -05003256 if (phba->pport->fc_flag & FC_FABRIC)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003257 status |= 0x4;
3258
3259 rps_rsp->rsvd1 = 0;
3260 rps_rsp->portStatus = be16_to_cpu(status);
3261 rps_rsp->linkFailureCnt = be32_to_cpu(mb->un.varRdLnk.linkFailureCnt);
3262 rps_rsp->lossSyncCnt = be32_to_cpu(mb->un.varRdLnk.lossSyncCnt);
3263 rps_rsp->lossSignalCnt = be32_to_cpu(mb->un.varRdLnk.lossSignalCnt);
3264 rps_rsp->primSeqErrCnt = be32_to_cpu(mb->un.varRdLnk.primSeqErrCnt);
3265 rps_rsp->invalidXmitWord = be32_to_cpu(mb->un.varRdLnk.invalidXmitWord);
3266 rps_rsp->crcCnt = be32_to_cpu(mb->un.varRdLnk.crcCnt);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003267 /* Xmit ELS RPS ACC response tag <ulpIoTag> */
James Smarte8b62012007-08-02 11:10:09 -04003268 lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS,
3269 "0118 Xmit ELS RPS ACC response tag x%x xri x%x, "
3270 "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
3271 elsiocb->iotag, elsiocb->iocb.ulpContext,
3272 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
3273 ndlp->nlp_rpi);
James Smart858c9f62007-06-17 19:56:39 -05003274 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003275 phba->fc_stat.elsXmitACC++;
James Smarted957682007-06-17 19:56:37 -05003276 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003277 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003278 return;
3279}
3280
3281static int
James Smart2e0fef82007-06-17 19:56:36 -05003282lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3283 struct lpfc_nodelist *ndlp)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003284{
James Smart2e0fef82007-06-17 19:56:36 -05003285 struct lpfc_hba *phba = vport->phba;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003286 uint32_t *lp;
3287 uint8_t flag;
3288 LPFC_MBOXQ_t *mbox;
3289 struct lpfc_dmabuf *pcmd;
3290 RPS *rps;
3291 struct ls_rjt stat;
3292
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05003293 if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
3294 (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) {
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003295 stat.un.b.lsRjtRsvd0 = 0;
3296 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
3297 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
3298 stat.un.b.vendorUnique = 0;
James Smart858c9f62007-06-17 19:56:39 -05003299 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
3300 NULL);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003301 }
3302
3303 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3304 lp = (uint32_t *) pcmd->virt;
3305 flag = (be32_to_cpu(*lp++) & 0xf);
3306 rps = (RPS *) lp;
3307
3308 if ((flag == 0) ||
3309 ((flag == 1) && (be32_to_cpu(rps->un.portNum) == 0)) ||
James Smart2e0fef82007-06-17 19:56:36 -05003310 ((flag == 2) && (memcmp(&rps->un.portName, &vport->fc_portname,
James Smart92d7f7b2007-06-17 19:56:38 -05003311 sizeof(struct lpfc_name)) == 0))) {
James Smart2e0fef82007-06-17 19:56:36 -05003312
James Smart92d7f7b2007-06-17 19:56:38 -05003313 printk("Fix me....\n");
3314 dump_stack();
James Smart2e0fef82007-06-17 19:56:36 -05003315 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC);
3316 if (mbox) {
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003317 lpfc_read_lnk_stat(phba, mbox);
3318 mbox->context1 =
James Smart92d7f7b2007-06-17 19:56:38 -05003319 (void *)((unsigned long) cmdiocb->iocb.ulpContext);
James Smart329f9bc2007-04-25 09:53:01 -04003320 mbox->context2 = lpfc_nlp_get(ndlp);
James Smart92d7f7b2007-06-17 19:56:38 -05003321 mbox->vport = vport;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003322 mbox->mbox_cmpl = lpfc_els_rsp_rps_acc;
James Smart0b727fe2007-10-27 13:37:25 -04003323 if (lpfc_sli_issue_mbox (phba, mbox, MBX_NOWAIT)
3324 != MBX_NOT_FINISHED)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003325 /* Mbox completion will send ELS Response */
3326 return 0;
James Smart2e0fef82007-06-17 19:56:36 -05003327
James Smart329f9bc2007-04-25 09:53:01 -04003328 lpfc_nlp_put(ndlp);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003329 mempool_free(mbox, phba->mbox_mem_pool);
3330 }
3331 }
3332 stat.un.b.lsRjtRsvd0 = 0;
3333 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
3334 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
3335 stat.un.b.vendorUnique = 0;
James Smart858c9f62007-06-17 19:56:39 -05003336 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003337 return 0;
3338}
3339
Jamie Wellnitz082c0262006-02-28 19:25:30 -05003340static int
James Smart2e0fef82007-06-17 19:56:36 -05003341lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize,
3342 struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003343{
James Smart2e0fef82007-06-17 19:56:36 -05003344 struct lpfc_hba *phba = vport->phba;
3345 IOCB_t *icmd, *oldcmd;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003346 RPL_RSP rpl_rsp;
3347 struct lpfc_iocbq *elsiocb;
James Smart2e0fef82007-06-17 19:56:36 -05003348 struct lpfc_sli *psli = &phba->sli;
3349 struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003350 uint8_t *pcmd;
3351
James Smart2e0fef82007-06-17 19:56:36 -05003352 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
3353 ndlp->nlp_DID, ELS_CMD_ACC);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003354
James Smart488d1462006-03-07 15:02:37 -05003355 if (!elsiocb)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003356 return 1;
James Smart488d1462006-03-07 15:02:37 -05003357
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003358 icmd = &elsiocb->iocb;
3359 oldcmd = &oldiocb->iocb;
3360 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
3361
3362 pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
3363 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
James Smart92d7f7b2007-06-17 19:56:38 -05003364 pcmd += sizeof(uint16_t);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003365 *((uint16_t *)(pcmd)) = be16_to_cpu(cmdsize);
3366 pcmd += sizeof(uint16_t);
3367
3368 /* Setup the RPL ACC payload */
3369 rpl_rsp.listLen = be32_to_cpu(1);
3370 rpl_rsp.index = 0;
3371 rpl_rsp.port_num_blk.portNum = 0;
James Smart2e0fef82007-06-17 19:56:36 -05003372 rpl_rsp.port_num_blk.portID = be32_to_cpu(vport->fc_myDID);
3373 memcpy(&rpl_rsp.port_num_blk.portName, &vport->fc_portname,
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003374 sizeof(struct lpfc_name));
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003375 memcpy(pcmd, &rpl_rsp, cmdsize - sizeof(uint32_t));
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003376 /* Xmit ELS RPL ACC response tag <ulpIoTag> */
James Smarte8b62012007-08-02 11:10:09 -04003377 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
3378 "0120 Xmit ELS RPL ACC response tag x%x "
3379 "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, "
3380 "rpi x%x\n",
3381 elsiocb->iotag, elsiocb->iocb.ulpContext,
3382 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
3383 ndlp->nlp_rpi);
James Smart858c9f62007-06-17 19:56:39 -05003384 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003385 phba->fc_stat.elsXmitACC++;
3386 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
3387 lpfc_els_free_iocb(phba, elsiocb);
3388 return 1;
3389 }
3390 return 0;
3391}
3392
3393static int
James Smart2e0fef82007-06-17 19:56:36 -05003394lpfc_els_rcv_rpl(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3395 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05003396{
3397 struct lpfc_dmabuf *pcmd;
3398 uint32_t *lp;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003399 uint32_t maxsize;
3400 uint16_t cmdsize;
3401 RPL *rpl;
3402 struct ls_rjt stat;
dea31012005-04-17 16:05:31 -05003403
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05003404 if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
3405 (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) {
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003406 stat.un.b.lsRjtRsvd0 = 0;
3407 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
3408 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
3409 stat.un.b.vendorUnique = 0;
James Smart858c9f62007-06-17 19:56:39 -05003410 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
3411 NULL);
dea31012005-04-17 16:05:31 -05003412 }
3413
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003414 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3415 lp = (uint32_t *) pcmd->virt;
3416 rpl = (RPL *) (lp + 1);
3417
3418 maxsize = be32_to_cpu(rpl->maxsize);
3419
3420 /* We support only one port */
3421 if ((rpl->index == 0) &&
3422 ((maxsize == 0) ||
3423 ((maxsize * sizeof(uint32_t)) >= sizeof(RPL_RSP)))) {
3424 cmdsize = sizeof(uint32_t) + sizeof(RPL_RSP);
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05003425 } else {
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003426 cmdsize = sizeof(uint32_t) + maxsize * sizeof(uint32_t);
3427 }
James Smart2e0fef82007-06-17 19:56:36 -05003428 lpfc_els_rsp_rpl_acc(vport, cmdsize, cmdiocb, ndlp);
dea31012005-04-17 16:05:31 -05003429
3430 return 0;
3431}
3432
3433static int
James Smart2e0fef82007-06-17 19:56:36 -05003434lpfc_els_rcv_farp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3435 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05003436{
3437 struct lpfc_dmabuf *pcmd;
3438 uint32_t *lp;
3439 IOCB_t *icmd;
3440 FARP *fp;
3441 uint32_t cmd, cnt, did;
3442
3443 icmd = &cmdiocb->iocb;
3444 did = icmd->un.elsreq64.remoteID;
3445 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3446 lp = (uint32_t *) pcmd->virt;
3447
3448 cmd = *lp++;
3449 fp = (FARP *) lp;
dea31012005-04-17 16:05:31 -05003450 /* FARP-REQ received from DID <did> */
James Smarte8b62012007-08-02 11:10:09 -04003451 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
3452 "0601 FARP-REQ received from DID x%x\n", did);
dea31012005-04-17 16:05:31 -05003453 /* We will only support match on WWPN or WWNN */
3454 if (fp->Mflags & ~(FARP_MATCH_NODE | FARP_MATCH_PORT)) {
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003455 return 0;
dea31012005-04-17 16:05:31 -05003456 }
3457
3458 cnt = 0;
3459 /* If this FARP command is searching for my portname */
3460 if (fp->Mflags & FARP_MATCH_PORT) {
James Smart2e0fef82007-06-17 19:56:36 -05003461 if (memcmp(&fp->RportName, &vport->fc_portname,
James Smart92d7f7b2007-06-17 19:56:38 -05003462 sizeof(struct lpfc_name)) == 0)
dea31012005-04-17 16:05:31 -05003463 cnt = 1;
3464 }
3465
3466 /* If this FARP command is searching for my nodename */
3467 if (fp->Mflags & FARP_MATCH_NODE) {
James Smart2e0fef82007-06-17 19:56:36 -05003468 if (memcmp(&fp->RnodeName, &vport->fc_nodename,
James Smart92d7f7b2007-06-17 19:56:38 -05003469 sizeof(struct lpfc_name)) == 0)
dea31012005-04-17 16:05:31 -05003470 cnt = 1;
3471 }
3472
3473 if (cnt) {
3474 if ((ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) ||
3475 (ndlp->nlp_state == NLP_STE_MAPPED_NODE)) {
3476 /* Log back into the node before sending the FARP. */
3477 if (fp->Rflags & FARP_REQUEST_PLOGI) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003478 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05003479 lpfc_nlp_set_state(vport, ndlp,
James Smartde0c5b32007-04-25 09:52:27 -04003480 NLP_STE_PLOGI_ISSUE);
James Smart2e0fef82007-06-17 19:56:36 -05003481 lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
dea31012005-04-17 16:05:31 -05003482 }
3483
3484 /* Send a FARP response to that node */
James Smart2e0fef82007-06-17 19:56:36 -05003485 if (fp->Rflags & FARP_REQUEST_FARPR)
3486 lpfc_issue_els_farpr(vport, did, 0);
dea31012005-04-17 16:05:31 -05003487 }
3488 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003489 return 0;
dea31012005-04-17 16:05:31 -05003490}
3491
3492static int
James Smart2e0fef82007-06-17 19:56:36 -05003493lpfc_els_rcv_farpr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3494 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05003495{
3496 struct lpfc_dmabuf *pcmd;
3497 uint32_t *lp;
3498 IOCB_t *icmd;
3499 uint32_t cmd, did;
3500
3501 icmd = &cmdiocb->iocb;
3502 did = icmd->un.elsreq64.remoteID;
3503 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3504 lp = (uint32_t *) pcmd->virt;
3505
3506 cmd = *lp++;
3507 /* FARP-RSP received from DID <did> */
James Smarte8b62012007-08-02 11:10:09 -04003508 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
3509 "0600 FARP-RSP received from DID x%x\n", did);
dea31012005-04-17 16:05:31 -05003510 /* ACCEPT the Farp resp request */
James Smart51ef4c22007-08-02 11:10:31 -04003511 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
dea31012005-04-17 16:05:31 -05003512
3513 return 0;
3514}
3515
3516static int
James Smart2e0fef82007-06-17 19:56:36 -05003517lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3518 struct lpfc_nodelist *fan_ndlp)
dea31012005-04-17 16:05:31 -05003519{
3520 struct lpfc_dmabuf *pcmd;
3521 uint32_t *lp;
3522 IOCB_t *icmd;
dea31012005-04-17 16:05:31 -05003523 uint32_t cmd, did;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003524 FAN *fp;
3525 struct lpfc_nodelist *ndlp, *next_ndlp;
James Smart2e0fef82007-06-17 19:56:36 -05003526 struct lpfc_hba *phba = vport->phba;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003527
3528 /* FAN received */
James Smarte8b62012007-08-02 11:10:09 -04003529 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
3530 "0265 FAN received\n");
dea31012005-04-17 16:05:31 -05003531 icmd = &cmdiocb->iocb;
3532 did = icmd->un.elsreq64.remoteID;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003533 pcmd = (struct lpfc_dmabuf *)cmdiocb->context2;
3534 lp = (uint32_t *)pcmd->virt;
dea31012005-04-17 16:05:31 -05003535
3536 cmd = *lp++;
James Smart92d7f7b2007-06-17 19:56:38 -05003537 fp = (FAN *) lp;
dea31012005-04-17 16:05:31 -05003538
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003539 /* FAN received; Fan does not have a reply sequence */
dea31012005-04-17 16:05:31 -05003540
James Smart2e0fef82007-06-17 19:56:36 -05003541 if (phba->pport->port_state == LPFC_LOCAL_CFG_LINK) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003542 if ((memcmp(&phba->fc_fabparam.nodeName, &fp->FnodeName,
3543 sizeof(struct lpfc_name)) != 0) ||
3544 (memcmp(&phba->fc_fabparam.portName, &fp->FportName,
3545 sizeof(struct lpfc_name)) != 0)) {
3546 /*
3547 * This node has switched fabrics. FLOGI is required
3548 * Clean up the old rpi's
dea31012005-04-17 16:05:31 -05003549 */
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003550
3551 list_for_each_entry_safe(ndlp, next_ndlp,
James Smart2e0fef82007-06-17 19:56:36 -05003552 &vport->fc_nodes, nlp_listp) {
James Smart685f0bf2007-04-25 09:53:08 -04003553 if (ndlp->nlp_state != NLP_STE_NPR_NODE)
3554 continue;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003555 if (ndlp->nlp_type & NLP_FABRIC) {
3556 /*
3557 * Clean up old Fabric, Nameserver and
3558 * other NLP_FABRIC logins
3559 */
James Smart2e0fef82007-06-17 19:56:36 -05003560 lpfc_drop_node(vport, ndlp);
James Smart87af33f2007-10-27 13:37:43 -04003561
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05003562 } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003563 /* Fail outstanding I/O now since this
3564 * device is marked for PLOGI
3565 */
James Smart2e0fef82007-06-17 19:56:36 -05003566 lpfc_unreg_rpi(vport, ndlp);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003567 }
3568 }
3569
James Smart2e0fef82007-06-17 19:56:36 -05003570 lpfc_initial_flogi(vport);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003571 return 0;
dea31012005-04-17 16:05:31 -05003572 }
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003573 /* Discovery not needed,
3574 * move the nodes to their original state.
3575 */
James Smart2e0fef82007-06-17 19:56:36 -05003576 list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
James Smart685f0bf2007-04-25 09:53:08 -04003577 nlp_listp) {
3578 if (ndlp->nlp_state != NLP_STE_NPR_NODE)
3579 continue;
dea31012005-04-17 16:05:31 -05003580
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003581 switch (ndlp->nlp_prev_state) {
3582 case NLP_STE_UNMAPPED_NODE:
3583 ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
James Smart2e0fef82007-06-17 19:56:36 -05003584 lpfc_nlp_set_state(vport, ndlp,
James Smartde0c5b32007-04-25 09:52:27 -04003585 NLP_STE_UNMAPPED_NODE);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003586 break;
3587
3588 case NLP_STE_MAPPED_NODE:
3589 ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
James Smart2e0fef82007-06-17 19:56:36 -05003590 lpfc_nlp_set_state(vport, ndlp,
James Smartde0c5b32007-04-25 09:52:27 -04003591 NLP_STE_MAPPED_NODE);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003592 break;
3593
3594 default:
3595 break;
3596 }
3597 }
3598
3599 /* Start discovery - this should just do CLEAR_LA */
James Smart2e0fef82007-06-17 19:56:36 -05003600 lpfc_disc_start(vport);
dea31012005-04-17 16:05:31 -05003601 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003602 return 0;
dea31012005-04-17 16:05:31 -05003603}
3604
3605void
3606lpfc_els_timeout(unsigned long ptr)
3607{
James Smart2e0fef82007-06-17 19:56:36 -05003608 struct lpfc_vport *vport = (struct lpfc_vport *) ptr;
3609 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05003610 unsigned long iflag;
3611
James Smart2e0fef82007-06-17 19:56:36 -05003612 spin_lock_irqsave(&vport->work_port_lock, iflag);
3613 if ((vport->work_port_events & WORKER_ELS_TMO) == 0) {
3614 vport->work_port_events |= WORKER_ELS_TMO;
James Smart92d7f7b2007-06-17 19:56:38 -05003615 spin_unlock_irqrestore(&vport->work_port_lock, iflag);
3616
3617 spin_lock_irqsave(&phba->hbalock, iflag);
dea31012005-04-17 16:05:31 -05003618 if (phba->work_wait)
James Smart92d7f7b2007-06-17 19:56:38 -05003619 lpfc_worker_wake_up(phba);
3620 spin_unlock_irqrestore(&phba->hbalock, iflag);
dea31012005-04-17 16:05:31 -05003621 }
James Smart92d7f7b2007-06-17 19:56:38 -05003622 else
3623 spin_unlock_irqrestore(&vport->work_port_lock, iflag);
dea31012005-04-17 16:05:31 -05003624 return;
3625}
3626
3627void
James Smart2e0fef82007-06-17 19:56:36 -05003628lpfc_els_timeout_handler(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05003629{
James Smart2e0fef82007-06-17 19:56:36 -05003630 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05003631 struct lpfc_sli_ring *pring;
3632 struct lpfc_iocbq *tmp_iocb, *piocb;
3633 IOCB_t *cmd = NULL;
3634 struct lpfc_dmabuf *pcmd;
James Smart2e0fef82007-06-17 19:56:36 -05003635 uint32_t els_command = 0;
dea31012005-04-17 16:05:31 -05003636 uint32_t timeout;
James Smart2e0fef82007-06-17 19:56:36 -05003637 uint32_t remote_ID = 0xffffffff;
dea31012005-04-17 16:05:31 -05003638
dea31012005-04-17 16:05:31 -05003639 /* If the timer is already canceled do nothing */
James Smart2e0fef82007-06-17 19:56:36 -05003640 if ((vport->work_port_events & WORKER_ELS_TMO) == 0) {
dea31012005-04-17 16:05:31 -05003641 return;
3642 }
James Smart2e0fef82007-06-17 19:56:36 -05003643 spin_lock_irq(&phba->hbalock);
dea31012005-04-17 16:05:31 -05003644 timeout = (uint32_t)(phba->fc_ratov << 1);
3645
3646 pring = &phba->sli.ring[LPFC_ELS_RING];
dea31012005-04-17 16:05:31 -05003647
3648 list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
3649 cmd = &piocb->iocb;
3650
James Smart2e0fef82007-06-17 19:56:36 -05003651 if ((piocb->iocb_flag & LPFC_IO_LIBDFC) != 0 ||
3652 piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN ||
3653 piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)
dea31012005-04-17 16:05:31 -05003654 continue;
James Smart2e0fef82007-06-17 19:56:36 -05003655
3656 if (piocb->vport != vport)
3657 continue;
3658
dea31012005-04-17 16:05:31 -05003659 pcmd = (struct lpfc_dmabuf *) piocb->context2;
James Smart2e0fef82007-06-17 19:56:36 -05003660 if (pcmd)
3661 els_command = *(uint32_t *) (pcmd->virt);
dea31012005-04-17 16:05:31 -05003662
James Smart92d7f7b2007-06-17 19:56:38 -05003663 if (els_command == ELS_CMD_FARP ||
3664 els_command == ELS_CMD_FARPR ||
3665 els_command == ELS_CMD_FDISC)
dea31012005-04-17 16:05:31 -05003666 continue;
James Smart92d7f7b2007-06-17 19:56:38 -05003667
3668 if (vport != piocb->vport)
3669 continue;
dea31012005-04-17 16:05:31 -05003670
3671 if (piocb->drvrTimeout > 0) {
James Smart92d7f7b2007-06-17 19:56:38 -05003672 if (piocb->drvrTimeout >= timeout)
dea31012005-04-17 16:05:31 -05003673 piocb->drvrTimeout -= timeout;
James Smart92d7f7b2007-06-17 19:56:38 -05003674 else
dea31012005-04-17 16:05:31 -05003675 piocb->drvrTimeout = 0;
dea31012005-04-17 16:05:31 -05003676 continue;
3677 }
3678
James Smart2e0fef82007-06-17 19:56:36 -05003679 remote_ID = 0xffffffff;
3680 if (cmd->ulpCommand != CMD_GEN_REQUEST64_CR)
dea31012005-04-17 16:05:31 -05003681 remote_ID = cmd->un.elsreq64.remoteID;
James Smart2e0fef82007-06-17 19:56:36 -05003682 else {
3683 struct lpfc_nodelist *ndlp;
3684 ndlp = __lpfc_findnode_rpi(vport, cmd->ulpContext);
3685 if (ndlp)
3686 remote_ID = ndlp->nlp_DID;
dea31012005-04-17 16:05:31 -05003687 }
James Smarte8b62012007-08-02 11:10:09 -04003688 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
3689 "0127 ELS timeout Data: x%x x%x x%x "
3690 "x%x\n", els_command,
3691 remote_ID, cmd->ulpCommand, cmd->ulpIoTag);
James Smart07951072007-04-25 09:51:38 -04003692 lpfc_sli_issue_abort_iotag(phba, pring, piocb);
dea31012005-04-17 16:05:31 -05003693 }
James Smart2e0fef82007-06-17 19:56:36 -05003694 spin_unlock_irq(&phba->hbalock);
James Smart5a0e3262006-07-06 15:49:16 -04003695
James Smart2e0fef82007-06-17 19:56:36 -05003696 if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt)
3697 mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout);
dea31012005-04-17 16:05:31 -05003698}
3699
3700void
James Smart2e0fef82007-06-17 19:56:36 -05003701lpfc_els_flush_cmd(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05003702{
James Smart2534ba72007-04-25 09:52:20 -04003703 LIST_HEAD(completions);
James Smart2e0fef82007-06-17 19:56:36 -05003704 struct lpfc_hba *phba = vport->phba;
James Smart329f9bc2007-04-25 09:53:01 -04003705 struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
dea31012005-04-17 16:05:31 -05003706 struct lpfc_iocbq *tmp_iocb, *piocb;
3707 IOCB_t *cmd = NULL;
James Smart92d7f7b2007-06-17 19:56:38 -05003708
3709 lpfc_fabric_abort_vport(vport);
dea31012005-04-17 16:05:31 -05003710
James Smart2e0fef82007-06-17 19:56:36 -05003711 spin_lock_irq(&phba->hbalock);
dea31012005-04-17 16:05:31 -05003712 list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
3713 cmd = &piocb->iocb;
3714
3715 if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
3716 continue;
3717 }
3718
3719 /* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */
James Smart329f9bc2007-04-25 09:53:01 -04003720 if (cmd->ulpCommand == CMD_QUE_RING_BUF_CN ||
3721 cmd->ulpCommand == CMD_QUE_RING_BUF64_CN ||
3722 cmd->ulpCommand == CMD_CLOSE_XRI_CN ||
3723 cmd->ulpCommand == CMD_ABORT_XRI_CN)
dea31012005-04-17 16:05:31 -05003724 continue;
dea31012005-04-17 16:05:31 -05003725
James Smart2e0fef82007-06-17 19:56:36 -05003726 if (piocb->vport != vport)
3727 continue;
3728
James Smart2534ba72007-04-25 09:52:20 -04003729 list_move_tail(&piocb->list, &completions);
James Smart1dcb58e2007-04-25 09:51:30 -04003730 pring->txq_cnt--;
dea31012005-04-17 16:05:31 -05003731 }
3732
3733 list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
dea31012005-04-17 16:05:31 -05003734 if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
3735 continue;
3736 }
dea31012005-04-17 16:05:31 -05003737
James Smart2e0fef82007-06-17 19:56:36 -05003738 if (piocb->vport != vport)
3739 continue;
3740
James Smart07951072007-04-25 09:51:38 -04003741 lpfc_sli_issue_abort_iotag(phba, pring, piocb);
dea31012005-04-17 16:05:31 -05003742 }
James Smart2e0fef82007-06-17 19:56:36 -05003743 spin_unlock_irq(&phba->hbalock);
James Smart2534ba72007-04-25 09:52:20 -04003744
James Smart2e0fef82007-06-17 19:56:36 -05003745 while (!list_empty(&completions)) {
James Smart2534ba72007-04-25 09:52:20 -04003746 piocb = list_get_first(&completions, struct lpfc_iocbq, list);
3747 cmd = &piocb->iocb;
James Smart92d7f7b2007-06-17 19:56:38 -05003748 list_del_init(&piocb->list);
James Smart2534ba72007-04-25 09:52:20 -04003749
James Smart2e0fef82007-06-17 19:56:36 -05003750 if (!piocb->iocb_cmpl)
3751 lpfc_sli_release_iocbq(phba, piocb);
3752 else {
James Smart2534ba72007-04-25 09:52:20 -04003753 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
3754 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
3755 (piocb->iocb_cmpl) (phba, piocb, piocb);
James Smart2e0fef82007-06-17 19:56:36 -05003756 }
James Smart2534ba72007-04-25 09:52:20 -04003757 }
3758
dea31012005-04-17 16:05:31 -05003759 return;
3760}
3761
James Smart549e55c2007-08-02 11:09:51 -04003762void
3763lpfc_els_flush_all_cmd(struct lpfc_hba *phba)
3764{
3765 LIST_HEAD(completions);
3766 struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
3767 struct lpfc_iocbq *tmp_iocb, *piocb;
3768 IOCB_t *cmd = NULL;
3769
3770 lpfc_fabric_abort_hba(phba);
3771 spin_lock_irq(&phba->hbalock);
3772 list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
3773 cmd = &piocb->iocb;
3774 if (piocb->iocb_flag & LPFC_IO_LIBDFC)
3775 continue;
3776 /* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */
3777 if (cmd->ulpCommand == CMD_QUE_RING_BUF_CN ||
3778 cmd->ulpCommand == CMD_QUE_RING_BUF64_CN ||
3779 cmd->ulpCommand == CMD_CLOSE_XRI_CN ||
3780 cmd->ulpCommand == CMD_ABORT_XRI_CN)
3781 continue;
3782 list_move_tail(&piocb->list, &completions);
3783 pring->txq_cnt--;
3784 }
3785 list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
3786 if (piocb->iocb_flag & LPFC_IO_LIBDFC)
3787 continue;
3788 lpfc_sli_issue_abort_iotag(phba, pring, piocb);
3789 }
3790 spin_unlock_irq(&phba->hbalock);
3791 while (!list_empty(&completions)) {
3792 piocb = list_get_first(&completions, struct lpfc_iocbq, list);
3793 cmd = &piocb->iocb;
3794 list_del_init(&piocb->list);
3795 if (!piocb->iocb_cmpl)
3796 lpfc_sli_release_iocbq(phba, piocb);
3797 else {
3798 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
3799 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
3800 (piocb->iocb_cmpl) (phba, piocb, piocb);
3801 }
3802 }
3803 return;
3804}
3805
James Smarted957682007-06-17 19:56:37 -05003806static void
3807lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
James Smart92d7f7b2007-06-17 19:56:38 -05003808 struct lpfc_vport *vport, struct lpfc_iocbq *elsiocb)
dea31012005-04-17 16:05:31 -05003809{
James Smart87af33f2007-10-27 13:37:43 -04003810 struct Scsi_Host *shost;
dea31012005-04-17 16:05:31 -05003811 struct lpfc_nodelist *ndlp;
dea31012005-04-17 16:05:31 -05003812 struct ls_rjt stat;
James Smart92d7f7b2007-06-17 19:56:38 -05003813 uint32_t *payload;
James Smart2e0fef82007-06-17 19:56:36 -05003814 uint32_t cmd, did, newnode, rjt_err = 0;
James Smarted957682007-06-17 19:56:37 -05003815 IOCB_t *icmd = &elsiocb->iocb;
dea31012005-04-17 16:05:31 -05003816
James Smart92d7f7b2007-06-17 19:56:38 -05003817 if (vport == NULL || elsiocb->context2 == NULL)
dea31012005-04-17 16:05:31 -05003818 goto dropit;
James Smart2e0fef82007-06-17 19:56:36 -05003819
dea31012005-04-17 16:05:31 -05003820 newnode = 0;
James Smart92d7f7b2007-06-17 19:56:38 -05003821 payload = ((struct lpfc_dmabuf *)elsiocb->context2)->virt;
3822 cmd = *payload;
James Smarted957682007-06-17 19:56:37 -05003823 if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) == 0)
3824 lpfc_post_buffer(phba, pring, 1, 1);
dea31012005-04-17 16:05:31 -05003825
James Smart858c9f62007-06-17 19:56:39 -05003826 did = icmd->un.rcvels.remoteID;
3827 if (icmd->ulpStatus) {
3828 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3829 "RCV Unsol ELS: status:x%x/x%x did:x%x",
3830 icmd->ulpStatus, icmd->un.ulpWord[4], did);
dea31012005-04-17 16:05:31 -05003831 goto dropit;
James Smart858c9f62007-06-17 19:56:39 -05003832 }
dea31012005-04-17 16:05:31 -05003833
3834 /* Check to see if link went down during discovery */
James Smarted957682007-06-17 19:56:37 -05003835 if (lpfc_els_chk_latt(vport))
dea31012005-04-17 16:05:31 -05003836 goto dropit;
dea31012005-04-17 16:05:31 -05003837
James Smart92d7f7b2007-06-17 19:56:38 -05003838 /* Ignore traffic recevied during vport shutdown. */
3839 if (vport->load_flag & FC_UNLOADING)
3840 goto dropit;
3841
James Smart2e0fef82007-06-17 19:56:36 -05003842 ndlp = lpfc_findnode_did(vport, did);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003843 if (!ndlp) {
dea31012005-04-17 16:05:31 -05003844 /* Cannot find existing Fabric ndlp, so allocate a new one */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003845 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
James Smarted957682007-06-17 19:56:37 -05003846 if (!ndlp)
dea31012005-04-17 16:05:31 -05003847 goto dropit;
dea31012005-04-17 16:05:31 -05003848
James Smart2e0fef82007-06-17 19:56:36 -05003849 lpfc_nlp_init(vport, ndlp, did);
James Smart98c9ea52007-10-27 13:37:33 -04003850 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
dea31012005-04-17 16:05:31 -05003851 newnode = 1;
3852 if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) {
3853 ndlp->nlp_type |= NLP_FABRIC;
3854 }
3855 }
James Smart87af33f2007-10-27 13:37:43 -04003856 else {
3857 if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) {
3858 /* This is simular to the new node path */
3859 lpfc_nlp_get(ndlp);
3860 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
3861 newnode = 1;
3862 }
3863 }
dea31012005-04-17 16:05:31 -05003864
3865 phba->fc_stat.elsRcvFrame++;
James Smart329f9bc2007-04-25 09:53:01 -04003866 if (elsiocb->context1)
3867 lpfc_nlp_put(elsiocb->context1);
3868 elsiocb->context1 = lpfc_nlp_get(ndlp);
James Smart2e0fef82007-06-17 19:56:36 -05003869 elsiocb->vport = vport;
dea31012005-04-17 16:05:31 -05003870
3871 if ((cmd & ELS_CMD_MASK) == ELS_CMD_RSCN) {
3872 cmd &= ELS_CMD_MASK;
3873 }
3874 /* ELS command <elsCmd> received from NPORT <did> */
James Smarte8b62012007-08-02 11:10:09 -04003875 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
3876 "0112 ELS command x%x received from NPORT x%x "
3877 "Data: x%x\n", cmd, did, vport->port_state);
dea31012005-04-17 16:05:31 -05003878 switch (cmd) {
3879 case ELS_CMD_PLOGI:
James Smart858c9f62007-06-17 19:56:39 -05003880 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3881 "RCV PLOGI: did:x%x/ste:x%x flg:x%x",
3882 did, vport->port_state, ndlp->nlp_flag);
3883
dea31012005-04-17 16:05:31 -05003884 phba->fc_stat.elsRcvPLOGI++;
James Smart858c9f62007-06-17 19:56:39 -05003885 ndlp = lpfc_plogi_confirm_nport(phba, payload, ndlp);
3886
3887 if (vport->port_state < LPFC_DISC_AUTH) {
3888 rjt_err = LSRJT_UNABLE_TPC;
dea31012005-04-17 16:05:31 -05003889 break;
3890 }
James Smart87af33f2007-10-27 13:37:43 -04003891
3892 shost = lpfc_shost_from_vport(vport);
3893 spin_lock_irq(shost->host_lock);
3894 ndlp->nlp_flag &= ~NLP_TARGET_REMOVE;
3895 spin_unlock_irq(shost->host_lock);
3896
James Smart2e0fef82007-06-17 19:56:36 -05003897 lpfc_disc_state_machine(vport, ndlp, elsiocb,
3898 NLP_EVT_RCV_PLOGI);
James Smart858c9f62007-06-17 19:56:39 -05003899
dea31012005-04-17 16:05:31 -05003900 break;
3901 case ELS_CMD_FLOGI:
James Smart858c9f62007-06-17 19:56:39 -05003902 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3903 "RCV FLOGI: did:x%x/ste:x%x flg:x%x",
3904 did, vport->port_state, ndlp->nlp_flag);
3905
dea31012005-04-17 16:05:31 -05003906 phba->fc_stat.elsRcvFLOGI++;
James Smart51ef4c22007-08-02 11:10:31 -04003907 lpfc_els_rcv_flogi(vport, elsiocb, ndlp);
James Smart87af33f2007-10-27 13:37:43 -04003908 if (newnode)
James Smart98c9ea52007-10-27 13:37:33 -04003909 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05003910 break;
3911 case ELS_CMD_LOGO:
James Smart858c9f62007-06-17 19:56:39 -05003912 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3913 "RCV LOGO: did:x%x/ste:x%x flg:x%x",
3914 did, vport->port_state, ndlp->nlp_flag);
3915
dea31012005-04-17 16:05:31 -05003916 phba->fc_stat.elsRcvLOGO++;
James Smart2e0fef82007-06-17 19:56:36 -05003917 if (vport->port_state < LPFC_DISC_AUTH) {
James Smart858c9f62007-06-17 19:56:39 -05003918 rjt_err = LSRJT_UNABLE_TPC;
dea31012005-04-17 16:05:31 -05003919 break;
3920 }
James Smart2e0fef82007-06-17 19:56:36 -05003921 lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_LOGO);
dea31012005-04-17 16:05:31 -05003922 break;
3923 case ELS_CMD_PRLO:
James Smart858c9f62007-06-17 19:56:39 -05003924 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3925 "RCV PRLO: did:x%x/ste:x%x flg:x%x",
3926 did, vport->port_state, ndlp->nlp_flag);
3927
dea31012005-04-17 16:05:31 -05003928 phba->fc_stat.elsRcvPRLO++;
James Smart2e0fef82007-06-17 19:56:36 -05003929 if (vport->port_state < LPFC_DISC_AUTH) {
James Smart858c9f62007-06-17 19:56:39 -05003930 rjt_err = LSRJT_UNABLE_TPC;
dea31012005-04-17 16:05:31 -05003931 break;
3932 }
James Smart2e0fef82007-06-17 19:56:36 -05003933 lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PRLO);
dea31012005-04-17 16:05:31 -05003934 break;
3935 case ELS_CMD_RSCN:
3936 phba->fc_stat.elsRcvRSCN++;
James Smart51ef4c22007-08-02 11:10:31 -04003937 lpfc_els_rcv_rscn(vport, elsiocb, ndlp);
James Smart87af33f2007-10-27 13:37:43 -04003938 if (newnode)
James Smart98c9ea52007-10-27 13:37:33 -04003939 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05003940 break;
3941 case ELS_CMD_ADISC:
James Smart858c9f62007-06-17 19:56:39 -05003942 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3943 "RCV ADISC: did:x%x/ste:x%x flg:x%x",
3944 did, vport->port_state, ndlp->nlp_flag);
3945
dea31012005-04-17 16:05:31 -05003946 phba->fc_stat.elsRcvADISC++;
James Smart2e0fef82007-06-17 19:56:36 -05003947 if (vport->port_state < LPFC_DISC_AUTH) {
James Smart858c9f62007-06-17 19:56:39 -05003948 rjt_err = LSRJT_UNABLE_TPC;
dea31012005-04-17 16:05:31 -05003949 break;
3950 }
James Smart2e0fef82007-06-17 19:56:36 -05003951 lpfc_disc_state_machine(vport, ndlp, elsiocb,
3952 NLP_EVT_RCV_ADISC);
dea31012005-04-17 16:05:31 -05003953 break;
3954 case ELS_CMD_PDISC:
James Smart858c9f62007-06-17 19:56:39 -05003955 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3956 "RCV PDISC: did:x%x/ste:x%x flg:x%x",
3957 did, vport->port_state, ndlp->nlp_flag);
3958
dea31012005-04-17 16:05:31 -05003959 phba->fc_stat.elsRcvPDISC++;
James Smart2e0fef82007-06-17 19:56:36 -05003960 if (vport->port_state < LPFC_DISC_AUTH) {
James Smart858c9f62007-06-17 19:56:39 -05003961 rjt_err = LSRJT_UNABLE_TPC;
dea31012005-04-17 16:05:31 -05003962 break;
3963 }
James Smart2e0fef82007-06-17 19:56:36 -05003964 lpfc_disc_state_machine(vport, ndlp, elsiocb,
3965 NLP_EVT_RCV_PDISC);
dea31012005-04-17 16:05:31 -05003966 break;
3967 case ELS_CMD_FARPR:
James Smart858c9f62007-06-17 19:56:39 -05003968 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3969 "RCV FARPR: 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.elsRcvFARPR++;
James Smart2e0fef82007-06-17 19:56:36 -05003973 lpfc_els_rcv_farpr(vport, elsiocb, ndlp);
dea31012005-04-17 16:05:31 -05003974 break;
3975 case ELS_CMD_FARP:
James Smart858c9f62007-06-17 19:56:39 -05003976 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3977 "RCV FARP: 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.elsRcvFARP++;
James Smart2e0fef82007-06-17 19:56:36 -05003981 lpfc_els_rcv_farp(vport, elsiocb, ndlp);
dea31012005-04-17 16:05:31 -05003982 break;
3983 case ELS_CMD_FAN:
James Smart858c9f62007-06-17 19:56:39 -05003984 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3985 "RCV FAN: 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.elsRcvFAN++;
James Smart2e0fef82007-06-17 19:56:36 -05003989 lpfc_els_rcv_fan(vport, elsiocb, ndlp);
dea31012005-04-17 16:05:31 -05003990 break;
dea31012005-04-17 16:05:31 -05003991 case ELS_CMD_PRLI:
James Smart858c9f62007-06-17 19:56:39 -05003992 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3993 "RCV PRLI: did:x%x/ste:x%x flg:x%x",
3994 did, vport->port_state, ndlp->nlp_flag);
3995
dea31012005-04-17 16:05:31 -05003996 phba->fc_stat.elsRcvPRLI++;
James Smart2e0fef82007-06-17 19:56:36 -05003997 if (vport->port_state < LPFC_DISC_AUTH) {
James Smart858c9f62007-06-17 19:56:39 -05003998 rjt_err = LSRJT_UNABLE_TPC;
dea31012005-04-17 16:05:31 -05003999 break;
4000 }
James Smart2e0fef82007-06-17 19:56:36 -05004001 lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PRLI);
dea31012005-04-17 16:05:31 -05004002 break;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05004003 case ELS_CMD_LIRR:
James Smart858c9f62007-06-17 19:56:39 -05004004 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
4005 "RCV LIRR: did:x%x/ste:x%x flg:x%x",
4006 did, vport->port_state, ndlp->nlp_flag);
4007
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05004008 phba->fc_stat.elsRcvLIRR++;
James Smart2e0fef82007-06-17 19:56:36 -05004009 lpfc_els_rcv_lirr(vport, elsiocb, ndlp);
James Smart87af33f2007-10-27 13:37:43 -04004010 if (newnode)
James Smart98c9ea52007-10-27 13:37:33 -04004011 lpfc_nlp_put(ndlp);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05004012 break;
4013 case ELS_CMD_RPS:
James Smart858c9f62007-06-17 19:56:39 -05004014 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
4015 "RCV RPS: did:x%x/ste:x%x flg:x%x",
4016 did, vport->port_state, ndlp->nlp_flag);
4017
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05004018 phba->fc_stat.elsRcvRPS++;
James Smart2e0fef82007-06-17 19:56:36 -05004019 lpfc_els_rcv_rps(vport, elsiocb, ndlp);
James Smart87af33f2007-10-27 13:37:43 -04004020 if (newnode)
James Smart98c9ea52007-10-27 13:37:33 -04004021 lpfc_nlp_put(ndlp);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05004022 break;
4023 case ELS_CMD_RPL:
James Smart858c9f62007-06-17 19:56:39 -05004024 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
4025 "RCV RPL: did:x%x/ste:x%x flg:x%x",
4026 did, vport->port_state, ndlp->nlp_flag);
4027
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05004028 phba->fc_stat.elsRcvRPL++;
James Smart2e0fef82007-06-17 19:56:36 -05004029 lpfc_els_rcv_rpl(vport, elsiocb, ndlp);
James Smart87af33f2007-10-27 13:37:43 -04004030 if (newnode)
James Smart98c9ea52007-10-27 13:37:33 -04004031 lpfc_nlp_put(ndlp);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05004032 break;
dea31012005-04-17 16:05:31 -05004033 case ELS_CMD_RNID:
James Smart858c9f62007-06-17 19:56:39 -05004034 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
4035 "RCV RNID: did:x%x/ste:x%x flg:x%x",
4036 did, vport->port_state, ndlp->nlp_flag);
4037
dea31012005-04-17 16:05:31 -05004038 phba->fc_stat.elsRcvRNID++;
James Smart2e0fef82007-06-17 19:56:36 -05004039 lpfc_els_rcv_rnid(vport, elsiocb, ndlp);
James Smart87af33f2007-10-27 13:37:43 -04004040 if (newnode)
James Smart98c9ea52007-10-27 13:37:33 -04004041 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05004042 break;
4043 default:
James Smart858c9f62007-06-17 19:56:39 -05004044 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
4045 "RCV ELS cmd: cmd:x%x did:x%x/ste:x%x",
4046 cmd, did, vport->port_state);
4047
dea31012005-04-17 16:05:31 -05004048 /* Unsupported ELS command, reject */
James Smart858c9f62007-06-17 19:56:39 -05004049 rjt_err = LSRJT_INVALID_CMD;
dea31012005-04-17 16:05:31 -05004050
4051 /* Unknown ELS command <elsCmd> received from NPORT <did> */
James Smarte8b62012007-08-02 11:10:09 -04004052 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
4053 "0115 Unknown ELS command x%x "
4054 "received from NPORT x%x\n", cmd, did);
James Smart87af33f2007-10-27 13:37:43 -04004055 if (newnode)
James Smart98c9ea52007-10-27 13:37:33 -04004056 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05004057 break;
4058 }
4059
4060 /* check if need to LS_RJT received ELS cmd */
4061 if (rjt_err) {
James Smart92d7f7b2007-06-17 19:56:38 -05004062 memset(&stat, 0, sizeof(stat));
James Smart858c9f62007-06-17 19:56:39 -05004063 stat.un.b.lsRjtRsnCode = rjt_err;
James.Smart@Emulex.Com1f679ca2005-06-25 10:34:27 -04004064 stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
James Smart858c9f62007-06-17 19:56:39 -05004065 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, elsiocb, ndlp,
4066 NULL);
dea31012005-04-17 16:05:31 -05004067 }
4068
James Smarted957682007-06-17 19:56:37 -05004069 return;
4070
4071dropit:
James Smart98c9ea52007-10-27 13:37:33 -04004072 if (vport && !(vport->load_flag & FC_UNLOADING))
4073 lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
James Smarte8b62012007-08-02 11:10:09 -04004074 "(%d):0111 Dropping received ELS cmd "
James Smarted957682007-06-17 19:56:37 -05004075 "Data: x%x x%x x%x\n",
James Smart98c9ea52007-10-27 13:37:33 -04004076 vport->vpi, icmd->ulpStatus,
James Smarte8b62012007-08-02 11:10:09 -04004077 icmd->un.ulpWord[4], icmd->ulpTimeout);
James Smarted957682007-06-17 19:56:37 -05004078 phba->fc_stat.elsRcvDrop++;
4079}
4080
James Smart92d7f7b2007-06-17 19:56:38 -05004081static struct lpfc_vport *
4082lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi)
4083{
4084 struct lpfc_vport *vport;
James Smart549e55c2007-08-02 11:09:51 -04004085 unsigned long flags;
James Smart92d7f7b2007-06-17 19:56:38 -05004086
James Smart549e55c2007-08-02 11:09:51 -04004087 spin_lock_irqsave(&phba->hbalock, flags);
James Smart92d7f7b2007-06-17 19:56:38 -05004088 list_for_each_entry(vport, &phba->port_list, listentry) {
James Smart549e55c2007-08-02 11:09:51 -04004089 if (vport->vpi == vpi) {
4090 spin_unlock_irqrestore(&phba->hbalock, flags);
James Smart92d7f7b2007-06-17 19:56:38 -05004091 return vport;
James Smart549e55c2007-08-02 11:09:51 -04004092 }
James Smart92d7f7b2007-06-17 19:56:38 -05004093 }
James Smart549e55c2007-08-02 11:09:51 -04004094 spin_unlock_irqrestore(&phba->hbalock, flags);
James Smart92d7f7b2007-06-17 19:56:38 -05004095 return NULL;
4096}
James Smarted957682007-06-17 19:56:37 -05004097
4098void
4099lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
4100 struct lpfc_iocbq *elsiocb)
4101{
4102 struct lpfc_vport *vport = phba->pport;
James Smarted957682007-06-17 19:56:37 -05004103 IOCB_t *icmd = &elsiocb->iocb;
James Smarted957682007-06-17 19:56:37 -05004104 dma_addr_t paddr;
James Smart92d7f7b2007-06-17 19:56:38 -05004105 struct lpfc_dmabuf *bdeBuf1 = elsiocb->context2;
4106 struct lpfc_dmabuf *bdeBuf2 = elsiocb->context3;
James Smarted957682007-06-17 19:56:37 -05004107
James Smart92d7f7b2007-06-17 19:56:38 -05004108 elsiocb->context2 = NULL;
4109 elsiocb->context3 = NULL;
4110
4111 if (icmd->ulpStatus == IOSTAT_NEED_BUFFER) {
4112 lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
4113 } else if (icmd->ulpStatus == IOSTAT_LOCAL_REJECT &&
4114 (icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING) {
James Smarted957682007-06-17 19:56:37 -05004115 phba->fc_stat.NoRcvBuf++;
4116 /* Not enough posted buffers; Try posting more buffers */
James Smart92d7f7b2007-06-17 19:56:38 -05004117 if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED))
James Smarted957682007-06-17 19:56:37 -05004118 lpfc_post_buffer(phba, pring, 0, 1);
4119 return;
4120 }
4121
James Smart92d7f7b2007-06-17 19:56:38 -05004122 if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
4123 (icmd->ulpCommand == CMD_IOCB_RCV_ELS64_CX ||
4124 icmd->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) {
4125 if (icmd->unsli3.rcvsli3.vpi == 0xffff)
4126 vport = phba->pport;
4127 else {
4128 uint16_t vpi = icmd->unsli3.rcvsli3.vpi;
4129 vport = lpfc_find_vport_by_vpid(phba, vpi);
4130 }
4131 }
4132 /* If there are no BDEs associated
4133 * with this IOCB, there is nothing to do.
4134 */
James Smarted957682007-06-17 19:56:37 -05004135 if (icmd->ulpBdeCount == 0)
4136 return;
4137
James Smart92d7f7b2007-06-17 19:56:38 -05004138 /* type of ELS cmd is first 32bit word
4139 * in packet
4140 */
James Smarted957682007-06-17 19:56:37 -05004141 if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
James Smart92d7f7b2007-06-17 19:56:38 -05004142 elsiocb->context2 = bdeBuf1;
James Smarted957682007-06-17 19:56:37 -05004143 } else {
4144 paddr = getPaddr(icmd->un.cont64[0].addrHigh,
4145 icmd->un.cont64[0].addrLow);
James Smart92d7f7b2007-06-17 19:56:38 -05004146 elsiocb->context2 = lpfc_sli_ringpostbuf_get(phba, pring,
4147 paddr);
James Smarted957682007-06-17 19:56:37 -05004148 }
4149
James Smart92d7f7b2007-06-17 19:56:38 -05004150 lpfc_els_unsol_buffer(phba, pring, vport, elsiocb);
4151 /*
4152 * The different unsolicited event handlers would tell us
4153 * if they are done with "mp" by setting context2 to NULL.
4154 */
James Smart329f9bc2007-04-25 09:53:01 -04004155 lpfc_nlp_put(elsiocb->context1);
4156 elsiocb->context1 = NULL;
dea31012005-04-17 16:05:31 -05004157 if (elsiocb->context2) {
James Smart92d7f7b2007-06-17 19:56:38 -05004158 lpfc_in_buf_free(phba, (struct lpfc_dmabuf *)elsiocb->context2);
4159 elsiocb->context2 = NULL;
dea31012005-04-17 16:05:31 -05004160 }
James Smarted957682007-06-17 19:56:37 -05004161
4162 /* RCV_ELS64_CX provide for 2 BDEs - process 2nd if included */
James Smart92d7f7b2007-06-17 19:56:38 -05004163 if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) &&
James Smarted957682007-06-17 19:56:37 -05004164 icmd->ulpBdeCount == 2) {
James Smart92d7f7b2007-06-17 19:56:38 -05004165 elsiocb->context2 = bdeBuf2;
4166 lpfc_els_unsol_buffer(phba, pring, vport, elsiocb);
James Smarted957682007-06-17 19:56:37 -05004167 /* free mp if we are done with it */
4168 if (elsiocb->context2) {
James Smart92d7f7b2007-06-17 19:56:38 -05004169 lpfc_in_buf_free(phba, elsiocb->context2);
4170 elsiocb->context2 = NULL;
James Smarted957682007-06-17 19:56:37 -05004171 }
dea31012005-04-17 16:05:31 -05004172 }
dea31012005-04-17 16:05:31 -05004173}
James Smart92d7f7b2007-06-17 19:56:38 -05004174
4175void
4176lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport)
4177{
4178 struct lpfc_nodelist *ndlp, *ndlp_fdmi;
4179
4180 ndlp = lpfc_findnode_did(vport, NameServer_DID);
4181 if (!ndlp) {
4182 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
4183 if (!ndlp) {
4184 if (phba->fc_topology == TOPOLOGY_LOOP) {
4185 lpfc_disc_start(vport);
4186 return;
4187 }
4188 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
James Smarte8b62012007-08-02 11:10:09 -04004189 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
4190 "0251 NameServer login: no memory\n");
James Smart92d7f7b2007-06-17 19:56:38 -05004191 return;
4192 }
4193 lpfc_nlp_init(vport, ndlp, NameServer_DID);
4194 ndlp->nlp_type |= NLP_FABRIC;
4195 }
4196
4197 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
4198
4199 if (lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0)) {
4200 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
James Smarte8b62012007-08-02 11:10:09 -04004201 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
4202 "0252 Cannot issue NameServer login\n");
James Smart92d7f7b2007-06-17 19:56:38 -05004203 return;
4204 }
4205
James Smart3de2a652007-08-02 11:09:59 -04004206 if (vport->cfg_fdmi_on) {
James Smart92d7f7b2007-06-17 19:56:38 -05004207 ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
4208 GFP_KERNEL);
4209 if (ndlp_fdmi) {
4210 lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID);
4211 ndlp_fdmi->nlp_type |= NLP_FABRIC;
4212 ndlp_fdmi->nlp_state =
4213 NLP_STE_PLOGI_ISSUE;
4214 lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID,
4215 0);
4216 }
4217 }
4218 return;
4219}
4220
4221static void
4222lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
4223{
4224 struct lpfc_vport *vport = pmb->vport;
4225 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
4226 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
4227 MAILBOX_t *mb = &pmb->mb;
4228
4229 vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
4230 lpfc_nlp_put(ndlp);
4231
4232 if (mb->mbxStatus) {
James Smarte8b62012007-08-02 11:10:09 -04004233 lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
4234 "0915 Register VPI failed: 0x%x\n",
4235 mb->mbxStatus);
James Smart92d7f7b2007-06-17 19:56:38 -05004236
4237 switch (mb->mbxStatus) {
4238 case 0x11: /* unsupported feature */
4239 case 0x9603: /* max_vpi exceeded */
4240 /* giving up on vport registration */
4241 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
4242 spin_lock_irq(shost->host_lock);
4243 vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
4244 spin_unlock_irq(shost->host_lock);
4245 lpfc_can_disctmo(vport);
4246 break;
4247 default:
4248 /* Try to recover from this error */
4249 lpfc_mbx_unreg_vpi(vport);
4250 vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
4251 lpfc_initial_fdisc(vport);
4252 break;
4253 }
4254
4255 } else {
4256 if (vport == phba->pport)
4257 lpfc_issue_fabric_reglogin(vport);
4258 else
4259 lpfc_do_scr_ns_plogi(phba, vport);
4260 }
4261 mempool_free(pmb, phba->mbox_mem_pool);
4262 return;
4263}
4264
Adrian Bunka6ababd2007-11-05 18:07:33 +01004265static void
James Smart92d7f7b2007-06-17 19:56:38 -05004266lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport,
4267 struct lpfc_nodelist *ndlp)
4268{
4269 LPFC_MBOXQ_t *mbox;
4270
4271 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
4272 if (mbox) {
4273 lpfc_reg_vpi(phba, vport->vpi, vport->fc_myDID, mbox);
4274 mbox->vport = vport;
4275 mbox->context2 = lpfc_nlp_get(ndlp);
4276 mbox->mbox_cmpl = lpfc_cmpl_reg_new_vport;
James Smart0b727fe2007-10-27 13:37:25 -04004277 if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
James Smart92d7f7b2007-06-17 19:56:38 -05004278 == MBX_NOT_FINISHED) {
4279 mempool_free(mbox, phba->mbox_mem_pool);
4280 vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
4281
4282 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
James Smarte8b62012007-08-02 11:10:09 -04004283 lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
4284 "0253 Register VPI: Can't send mbox\n");
James Smart92d7f7b2007-06-17 19:56:38 -05004285 }
4286 } else {
4287 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
4288
James Smarte8b62012007-08-02 11:10:09 -04004289 lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
4290 "0254 Register VPI: no memory\n");
James Smart92d7f7b2007-06-17 19:56:38 -05004291
4292 vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
4293 lpfc_nlp_put(ndlp);
4294 }
4295}
4296
4297static void
4298lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
4299 struct lpfc_iocbq *rspiocb)
4300{
4301 struct lpfc_vport *vport = cmdiocb->vport;
4302 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
4303 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
4304 struct lpfc_nodelist *np;
4305 struct lpfc_nodelist *next_np;
4306 IOCB_t *irsp = &rspiocb->iocb;
4307 struct lpfc_iocbq *piocb;
4308
James Smarte8b62012007-08-02 11:10:09 -04004309 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
4310 "0123 FDISC completes. x%x/x%x prevDID: x%x\n",
4311 irsp->ulpStatus, irsp->un.ulpWord[4],
4312 vport->fc_prevDID);
James Smart92d7f7b2007-06-17 19:56:38 -05004313 /* Since all FDISCs are being single threaded, we
4314 * must reset the discovery timer for ALL vports
4315 * waiting to send FDISC when one completes.
4316 */
4317 list_for_each_entry(piocb, &phba->fabric_iocb_list, list) {
4318 lpfc_set_disctmo(piocb->vport);
4319 }
4320
James Smart858c9f62007-06-17 19:56:39 -05004321 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
4322 "FDISC cmpl: status:x%x/x%x prevdid:x%x",
4323 irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_prevDID);
4324
James Smart92d7f7b2007-06-17 19:56:38 -05004325 if (irsp->ulpStatus) {
4326 /* Check for retry */
4327 if (lpfc_els_retry(phba, cmdiocb, rspiocb))
4328 goto out;
James Smart92d7f7b2007-06-17 19:56:38 -05004329 /* FDISC failed */
James Smarte8b62012007-08-02 11:10:09 -04004330 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
4331 "0124 FDISC failed. (%d/%d)\n",
4332 irsp->ulpStatus, irsp->un.ulpWord[4]);
James Smart92d7f7b2007-06-17 19:56:38 -05004333 if (vport->fc_vport->vport_state == FC_VPORT_INITIALIZING)
4334 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
4335
4336 lpfc_nlp_put(ndlp);
4337 /* giving up on FDISC. Cancel discovery timer */
4338 lpfc_can_disctmo(vport);
4339 } else {
4340 spin_lock_irq(shost->host_lock);
4341 vport->fc_flag |= FC_FABRIC;
4342 if (vport->phba->fc_topology == TOPOLOGY_LOOP)
4343 vport->fc_flag |= FC_PUBLIC_LOOP;
4344 spin_unlock_irq(shost->host_lock);
4345
4346 vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID;
4347 lpfc_vport_set_state(vport, FC_VPORT_ACTIVE);
4348 if ((vport->fc_prevDID != vport->fc_myDID) &&
4349 !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) {
4350 /* If our NportID changed, we need to ensure all
4351 * remaining NPORTs get unreg_login'ed so we can
4352 * issue unreg_vpi.
4353 */
4354 list_for_each_entry_safe(np, next_np,
4355 &vport->fc_nodes, nlp_listp) {
4356 if (np->nlp_state != NLP_STE_NPR_NODE
4357 || !(np->nlp_flag & NLP_NPR_ADISC))
4358 continue;
4359 spin_lock_irq(shost->host_lock);
4360 np->nlp_flag &= ~NLP_NPR_ADISC;
4361 spin_unlock_irq(shost->host_lock);
4362 lpfc_unreg_rpi(vport, np);
4363 }
4364 lpfc_mbx_unreg_vpi(vport);
4365 vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
4366 }
4367
4368 if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)
4369 lpfc_register_new_vport(phba, vport, ndlp);
4370 else
4371 lpfc_do_scr_ns_plogi(phba, vport);
4372
4373 lpfc_nlp_put(ndlp); /* Free Fabric ndlp for vports */
4374 }
4375
4376out:
4377 lpfc_els_free_iocb(phba, cmdiocb);
4378}
4379
Adrian Bunka6ababd2007-11-05 18:07:33 +01004380static int
James Smart92d7f7b2007-06-17 19:56:38 -05004381lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
4382 uint8_t retry)
4383{
4384 struct lpfc_hba *phba = vport->phba;
4385 IOCB_t *icmd;
4386 struct lpfc_iocbq *elsiocb;
4387 struct serv_parm *sp;
4388 uint8_t *pcmd;
4389 uint16_t cmdsize;
4390 int did = ndlp->nlp_DID;
4391 int rc;
James Smart92d7f7b2007-06-17 19:56:38 -05004392
4393 cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
4394 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did,
4395 ELS_CMD_FDISC);
4396 if (!elsiocb) {
James Smart92d7f7b2007-06-17 19:56:38 -05004397 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
James Smarte8b62012007-08-02 11:10:09 -04004398 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
4399 "0255 Issue FDISC: no IOCB\n");
James Smart92d7f7b2007-06-17 19:56:38 -05004400 return 1;
4401 }
4402
4403 icmd = &elsiocb->iocb;
4404 icmd->un.elsreq64.myID = 0;
4405 icmd->un.elsreq64.fl = 1;
4406
4407 /* For FDISC, Let FDISC rsp set the NPortID for this VPI */
4408 icmd->ulpCt_h = 1;
4409 icmd->ulpCt_l = 0;
4410
4411 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
4412 *((uint32_t *) (pcmd)) = ELS_CMD_FDISC;
4413 pcmd += sizeof(uint32_t); /* CSP Word 1 */
4414 memcpy(pcmd, &vport->phba->pport->fc_sparam, sizeof(struct serv_parm));
4415 sp = (struct serv_parm *) pcmd;
4416 /* Setup CSPs accordingly for Fabric */
4417 sp->cmn.e_d_tov = 0;
4418 sp->cmn.w2.r_a_tov = 0;
4419 sp->cls1.classValid = 0;
4420 sp->cls2.seqDelivery = 1;
4421 sp->cls3.seqDelivery = 1;
4422
4423 pcmd += sizeof(uint32_t); /* CSP Word 2 */
4424 pcmd += sizeof(uint32_t); /* CSP Word 3 */
4425 pcmd += sizeof(uint32_t); /* CSP Word 4 */
4426 pcmd += sizeof(uint32_t); /* Port Name */
4427 memcpy(pcmd, &vport->fc_portname, 8);
4428 pcmd += sizeof(uint32_t); /* Node Name */
4429 pcmd += sizeof(uint32_t); /* Node Name */
4430 memcpy(pcmd, &vport->fc_nodename, 8);
4431
4432 lpfc_set_disctmo(vport);
4433
4434 phba->fc_stat.elsXmitFDISC++;
4435 elsiocb->iocb_cmpl = lpfc_cmpl_els_fdisc;
4436
James Smart858c9f62007-06-17 19:56:39 -05004437 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
4438 "Issue FDISC: did:x%x",
4439 did, 0, 0);
4440
James Smart92d7f7b2007-06-17 19:56:38 -05004441 rc = lpfc_issue_fabric_iocb(phba, elsiocb);
4442 if (rc == IOCB_ERROR) {
4443 lpfc_els_free_iocb(phba, elsiocb);
James Smart92d7f7b2007-06-17 19:56:38 -05004444 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
James Smarte8b62012007-08-02 11:10:09 -04004445 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
4446 "0256 Issue FDISC: Cannot send IOCB\n");
James Smart92d7f7b2007-06-17 19:56:38 -05004447 return 1;
4448 }
4449 lpfc_vport_set_state(vport, FC_VPORT_INITIALIZING);
4450 vport->port_state = LPFC_FDISC;
4451 return 0;
4452}
4453
4454static void
4455lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
4456 struct lpfc_iocbq *rspiocb)
4457{
4458 struct lpfc_vport *vport = cmdiocb->vport;
James Smart858c9f62007-06-17 19:56:39 -05004459 IOCB_t *irsp;
4460
4461 irsp = &rspiocb->iocb;
4462 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
4463 "LOGO npiv cmpl: status:x%x/x%x did:x%x",
4464 irsp->ulpStatus, irsp->un.ulpWord[4], irsp->un.rcvels.remoteID);
James Smart92d7f7b2007-06-17 19:56:38 -05004465
4466 lpfc_els_free_iocb(phba, cmdiocb);
4467 vport->unreg_vpi_cmpl = VPORT_ERROR;
4468}
4469
4470int
4471lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
4472{
4473 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
4474 struct lpfc_hba *phba = vport->phba;
4475 struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
4476 IOCB_t *icmd;
4477 struct lpfc_iocbq *elsiocb;
4478 uint8_t *pcmd;
4479 uint16_t cmdsize;
4480
4481 cmdsize = 2 * sizeof(uint32_t) + sizeof(struct lpfc_name);
4482 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, ndlp->nlp_DID,
4483 ELS_CMD_LOGO);
4484 if (!elsiocb)
4485 return 1;
4486
4487 icmd = &elsiocb->iocb;
4488 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
4489 *((uint32_t *) (pcmd)) = ELS_CMD_LOGO;
4490 pcmd += sizeof(uint32_t);
4491
4492 /* Fill in LOGO payload */
4493 *((uint32_t *) (pcmd)) = be32_to_cpu(vport->fc_myDID);
4494 pcmd += sizeof(uint32_t);
4495 memcpy(pcmd, &vport->fc_portname, sizeof(struct lpfc_name));
4496
James Smart858c9f62007-06-17 19:56:39 -05004497 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
4498 "Issue LOGO npiv did:x%x flg:x%x",
4499 ndlp->nlp_DID, ndlp->nlp_flag, 0);
4500
James Smart92d7f7b2007-06-17 19:56:38 -05004501 elsiocb->iocb_cmpl = lpfc_cmpl_els_npiv_logo;
4502 spin_lock_irq(shost->host_lock);
4503 ndlp->nlp_flag |= NLP_LOGO_SND;
4504 spin_unlock_irq(shost->host_lock);
4505 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
4506 spin_lock_irq(shost->host_lock);
4507 ndlp->nlp_flag &= ~NLP_LOGO_SND;
4508 spin_unlock_irq(shost->host_lock);
4509 lpfc_els_free_iocb(phba, elsiocb);
4510 return 1;
4511 }
4512 return 0;
4513}
4514
4515void
4516lpfc_fabric_block_timeout(unsigned long ptr)
4517{
4518 struct lpfc_hba *phba = (struct lpfc_hba *) ptr;
4519 unsigned long iflags;
4520 uint32_t tmo_posted;
4521 spin_lock_irqsave(&phba->pport->work_port_lock, iflags);
4522 tmo_posted = phba->pport->work_port_events & WORKER_FABRIC_BLOCK_TMO;
4523 if (!tmo_posted)
4524 phba->pport->work_port_events |= WORKER_FABRIC_BLOCK_TMO;
4525 spin_unlock_irqrestore(&phba->pport->work_port_lock, iflags);
4526
4527 if (!tmo_posted) {
4528 spin_lock_irqsave(&phba->hbalock, iflags);
4529 if (phba->work_wait)
4530 lpfc_worker_wake_up(phba);
4531 spin_unlock_irqrestore(&phba->hbalock, iflags);
4532 }
4533}
4534
4535static void
4536lpfc_resume_fabric_iocbs(struct lpfc_hba *phba)
4537{
4538 struct lpfc_iocbq *iocb;
4539 unsigned long iflags;
4540 int ret;
4541 struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
4542 IOCB_t *cmd;
4543
4544repeat:
4545 iocb = NULL;
4546 spin_lock_irqsave(&phba->hbalock, iflags);
4547 /* Post any pending iocb to the SLI layer */
4548 if (atomic_read(&phba->fabric_iocb_count) == 0) {
4549 list_remove_head(&phba->fabric_iocb_list, iocb, typeof(*iocb),
4550 list);
4551 if (iocb)
4552 atomic_inc(&phba->fabric_iocb_count);
4553 }
4554 spin_unlock_irqrestore(&phba->hbalock, iflags);
4555 if (iocb) {
4556 iocb->fabric_iocb_cmpl = iocb->iocb_cmpl;
4557 iocb->iocb_cmpl = lpfc_cmpl_fabric_iocb;
4558 iocb->iocb_flag |= LPFC_IO_FABRIC;
4559
James Smart858c9f62007-06-17 19:56:39 -05004560 lpfc_debugfs_disc_trc(iocb->vport, LPFC_DISC_TRC_ELS_CMD,
4561 "Fabric sched1: ste:x%x",
4562 iocb->vport->port_state, 0, 0);
4563
James Smart92d7f7b2007-06-17 19:56:38 -05004564 ret = lpfc_sli_issue_iocb(phba, pring, iocb, 0);
4565
4566 if (ret == IOCB_ERROR) {
4567 iocb->iocb_cmpl = iocb->fabric_iocb_cmpl;
4568 iocb->fabric_iocb_cmpl = NULL;
4569 iocb->iocb_flag &= ~LPFC_IO_FABRIC;
4570 cmd = &iocb->iocb;
4571 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
4572 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
4573 iocb->iocb_cmpl(phba, iocb, iocb);
4574
4575 atomic_dec(&phba->fabric_iocb_count);
4576 goto repeat;
4577 }
4578 }
4579
4580 return;
4581}
4582
4583void
4584lpfc_unblock_fabric_iocbs(struct lpfc_hba *phba)
4585{
4586 clear_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags);
4587
4588 lpfc_resume_fabric_iocbs(phba);
4589 return;
4590}
4591
4592static void
4593lpfc_block_fabric_iocbs(struct lpfc_hba *phba)
4594{
4595 int blocked;
4596
4597 blocked = test_and_set_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags);
4598 /* Start a timer to unblock fabric
4599 * iocbs after 100ms
4600 */
4601 if (!blocked)
4602 mod_timer(&phba->fabric_block_timer, jiffies + HZ/10 );
4603
4604 return;
4605}
4606
4607static void
4608lpfc_cmpl_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
4609 struct lpfc_iocbq *rspiocb)
4610{
4611 struct ls_rjt stat;
4612
4613 if ((cmdiocb->iocb_flag & LPFC_IO_FABRIC) != LPFC_IO_FABRIC)
4614 BUG();
4615
4616 switch (rspiocb->iocb.ulpStatus) {
4617 case IOSTAT_NPORT_RJT:
4618 case IOSTAT_FABRIC_RJT:
4619 if (rspiocb->iocb.un.ulpWord[4] & RJT_UNAVAIL_TEMP) {
4620 lpfc_block_fabric_iocbs(phba);
4621 }
4622 break;
4623
4624 case IOSTAT_NPORT_BSY:
4625 case IOSTAT_FABRIC_BSY:
4626 lpfc_block_fabric_iocbs(phba);
4627 break;
4628
4629 case IOSTAT_LS_RJT:
4630 stat.un.lsRjtError =
4631 be32_to_cpu(rspiocb->iocb.un.ulpWord[4]);
4632 if ((stat.un.b.lsRjtRsnCode == LSRJT_UNABLE_TPC) ||
4633 (stat.un.b.lsRjtRsnCode == LSRJT_LOGICAL_BSY))
4634 lpfc_block_fabric_iocbs(phba);
4635 break;
4636 }
4637
4638 if (atomic_read(&phba->fabric_iocb_count) == 0)
4639 BUG();
4640
4641 cmdiocb->iocb_cmpl = cmdiocb->fabric_iocb_cmpl;
4642 cmdiocb->fabric_iocb_cmpl = NULL;
4643 cmdiocb->iocb_flag &= ~LPFC_IO_FABRIC;
4644 cmdiocb->iocb_cmpl(phba, cmdiocb, rspiocb);
4645
4646 atomic_dec(&phba->fabric_iocb_count);
4647 if (!test_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags)) {
4648 /* Post any pending iocbs to HBA */
4649 lpfc_resume_fabric_iocbs(phba);
4650 }
4651}
4652
Adrian Bunka6ababd2007-11-05 18:07:33 +01004653static int
James Smart92d7f7b2007-06-17 19:56:38 -05004654lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb)
4655{
4656 unsigned long iflags;
4657 struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
4658 int ready;
4659 int ret;
4660
4661 if (atomic_read(&phba->fabric_iocb_count) > 1)
4662 BUG();
4663
4664 spin_lock_irqsave(&phba->hbalock, iflags);
4665 ready = atomic_read(&phba->fabric_iocb_count) == 0 &&
4666 !test_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags);
4667
4668 spin_unlock_irqrestore(&phba->hbalock, iflags);
4669 if (ready) {
4670 iocb->fabric_iocb_cmpl = iocb->iocb_cmpl;
4671 iocb->iocb_cmpl = lpfc_cmpl_fabric_iocb;
4672 iocb->iocb_flag |= LPFC_IO_FABRIC;
4673
James Smart858c9f62007-06-17 19:56:39 -05004674 lpfc_debugfs_disc_trc(iocb->vport, LPFC_DISC_TRC_ELS_CMD,
4675 "Fabric sched2: ste:x%x",
4676 iocb->vport->port_state, 0, 0);
4677
James Smart92d7f7b2007-06-17 19:56:38 -05004678 atomic_inc(&phba->fabric_iocb_count);
4679 ret = lpfc_sli_issue_iocb(phba, pring, iocb, 0);
4680
4681 if (ret == IOCB_ERROR) {
4682 iocb->iocb_cmpl = iocb->fabric_iocb_cmpl;
4683 iocb->fabric_iocb_cmpl = NULL;
4684 iocb->iocb_flag &= ~LPFC_IO_FABRIC;
4685 atomic_dec(&phba->fabric_iocb_count);
4686 }
4687 } else {
4688 spin_lock_irqsave(&phba->hbalock, iflags);
4689 list_add_tail(&iocb->list, &phba->fabric_iocb_list);
4690 spin_unlock_irqrestore(&phba->hbalock, iflags);
4691 ret = IOCB_SUCCESS;
4692 }
4693 return ret;
4694}
4695
4696
Adrian Bunka6ababd2007-11-05 18:07:33 +01004697static void lpfc_fabric_abort_vport(struct lpfc_vport *vport)
James Smart92d7f7b2007-06-17 19:56:38 -05004698{
4699 LIST_HEAD(completions);
4700 struct lpfc_hba *phba = vport->phba;
4701 struct lpfc_iocbq *tmp_iocb, *piocb;
4702 IOCB_t *cmd;
4703
4704 spin_lock_irq(&phba->hbalock);
4705 list_for_each_entry_safe(piocb, tmp_iocb, &phba->fabric_iocb_list,
4706 list) {
4707
4708 if (piocb->vport != vport)
4709 continue;
4710
4711 list_move_tail(&piocb->list, &completions);
4712 }
4713 spin_unlock_irq(&phba->hbalock);
4714
4715 while (!list_empty(&completions)) {
4716 piocb = list_get_first(&completions, struct lpfc_iocbq, list);
4717 list_del_init(&piocb->list);
4718
4719 cmd = &piocb->iocb;
4720 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
4721 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
4722 (piocb->iocb_cmpl) (phba, piocb, piocb);
4723 }
4724}
4725
4726void lpfc_fabric_abort_nport(struct lpfc_nodelist *ndlp)
4727{
4728 LIST_HEAD(completions);
4729 struct lpfc_hba *phba = ndlp->vport->phba;
4730 struct lpfc_iocbq *tmp_iocb, *piocb;
4731 struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
4732 IOCB_t *cmd;
4733
4734 spin_lock_irq(&phba->hbalock);
4735 list_for_each_entry_safe(piocb, tmp_iocb, &phba->fabric_iocb_list,
4736 list) {
4737 if ((lpfc_check_sli_ndlp(phba, pring, piocb, ndlp))) {
4738
4739 list_move_tail(&piocb->list, &completions);
4740 }
4741 }
4742 spin_unlock_irq(&phba->hbalock);
4743
4744 while (!list_empty(&completions)) {
4745 piocb = list_get_first(&completions, struct lpfc_iocbq, list);
4746 list_del_init(&piocb->list);
4747
4748 cmd = &piocb->iocb;
4749 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
4750 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
4751 (piocb->iocb_cmpl) (phba, piocb, piocb);
4752 }
4753}
4754
4755void lpfc_fabric_abort_hba(struct lpfc_hba *phba)
4756{
4757 LIST_HEAD(completions);
4758 struct lpfc_iocbq *piocb;
4759 IOCB_t *cmd;
4760
4761 spin_lock_irq(&phba->hbalock);
4762 list_splice_init(&phba->fabric_iocb_list, &completions);
4763 spin_unlock_irq(&phba->hbalock);
4764
4765 while (!list_empty(&completions)) {
4766 piocb = list_get_first(&completions, struct lpfc_iocbq, list);
4767 list_del_init(&piocb->list);
4768
4769 cmd = &piocb->iocb;
4770 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
4771 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
4772 (piocb->iocb_cmpl) (phba, piocb, piocb);
4773 }
4774}
4775
4776
Adrian Bunka6ababd2007-11-05 18:07:33 +01004777#if 0
James Smart92d7f7b2007-06-17 19:56:38 -05004778void lpfc_fabric_abort_flogi(struct lpfc_hba *phba)
4779{
4780 LIST_HEAD(completions);
4781 struct lpfc_iocbq *tmp_iocb, *piocb;
4782 IOCB_t *cmd;
4783 struct lpfc_nodelist *ndlp;
4784
4785 spin_lock_irq(&phba->hbalock);
4786 list_for_each_entry_safe(piocb, tmp_iocb, &phba->fabric_iocb_list,
4787 list) {
4788
4789 cmd = &piocb->iocb;
4790 ndlp = (struct lpfc_nodelist *) piocb->context1;
4791 if (cmd->ulpCommand == CMD_ELS_REQUEST64_CR &&
4792 ndlp != NULL &&
4793 ndlp->nlp_DID == Fabric_DID)
4794 list_move_tail(&piocb->list, &completions);
4795 }
4796 spin_unlock_irq(&phba->hbalock);
4797
4798 while (!list_empty(&completions)) {
4799 piocb = list_get_first(&completions, struct lpfc_iocbq, list);
4800 list_del_init(&piocb->list);
4801
4802 cmd = &piocb->iocb;
4803 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
4804 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
4805 (piocb->iocb_cmpl) (phba, piocb, piocb);
4806 }
4807}
Adrian Bunka6ababd2007-11-05 18:07:33 +01004808#endif /* 0 */
James Smart92d7f7b2007-06-17 19:56:38 -05004809
4810