blob: 8da6e8be9d83e24465c42dd00d5489e9f200bc49 [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 *******************************************************************/
James Smart09372822008-01-11 01:52:54 -050021/* See Fibre Channel protocol T11 FC-LS for details */
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);
James Smart09372822008-01-11 01:52:54 -0500395 spin_lock_irq(shost->host_lock);
James Smart92d7f7b2007-06-17 19:56:38 -0500396 vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
James Smart09372822008-01-11 01:52:54 -0500397 spin_unlock_irq(shost->host_lock);
James Smart92d7f7b2007-06-17 19:56:38 -0500398 }
399 }
400
James Smart92d7f7b2007-06-17 19:56:38 -0500401 lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE);
James Smart2e0fef82007-06-17 19:56:36 -0500402
James Smart92d7f7b2007-06-17 19:56:38 -0500403 if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED &&
404 vport->fc_flag & FC_VPORT_NEEDS_REG_VPI) {
405 lpfc_register_new_vport(phba, vport, ndlp);
406 return 0;
407 }
408 lpfc_issue_fabric_reglogin(vport);
dea31012005-04-17 16:05:31 -0500409 return 0;
dea31012005-04-17 16:05:31 -0500410}
411
412/*
413 * We FLOGIed into an NPort, initiate pt2pt protocol
414 */
415static int
James Smart2e0fef82007-06-17 19:56:36 -0500416lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
417 struct serv_parm *sp)
dea31012005-04-17 16:05:31 -0500418{
James Smart2e0fef82007-06-17 19:56:36 -0500419 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
420 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500421 LPFC_MBOXQ_t *mbox;
422 int rc;
423
James Smart2e0fef82007-06-17 19:56:36 -0500424 spin_lock_irq(shost->host_lock);
425 vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
426 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500427
428 phba->fc_edtov = FF_DEF_EDTOV;
429 phba->fc_ratov = FF_DEF_RATOV;
James Smart2e0fef82007-06-17 19:56:36 -0500430 rc = memcmp(&vport->fc_portname, &sp->portName,
James Smart92d7f7b2007-06-17 19:56:38 -0500431 sizeof(vport->fc_portname));
dea31012005-04-17 16:05:31 -0500432 if (rc >= 0) {
433 /* This side will initiate the PLOGI */
James Smart2e0fef82007-06-17 19:56:36 -0500434 spin_lock_irq(shost->host_lock);
435 vport->fc_flag |= FC_PT2PT_PLOGI;
436 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500437
438 /*
439 * N_Port ID cannot be 0, set our to LocalID the other
440 * side will be RemoteID.
441 */
442
443 /* not equal */
444 if (rc)
James Smart2e0fef82007-06-17 19:56:36 -0500445 vport->fc_myDID = PT2PT_LocalID;
dea31012005-04-17 16:05:31 -0500446
447 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
448 if (!mbox)
449 goto fail;
450
451 lpfc_config_link(phba, mbox);
452
453 mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
James Smarted957682007-06-17 19:56:37 -0500454 mbox->vport = vport;
James Smart0b727fe2007-10-27 13:37:25 -0400455 rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
dea31012005-04-17 16:05:31 -0500456 if (rc == MBX_NOT_FINISHED) {
457 mempool_free(mbox, phba->mbox_mem_pool);
458 goto fail;
459 }
James Smart329f9bc2007-04-25 09:53:01 -0400460 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -0500461
James Smart2e0fef82007-06-17 19:56:36 -0500462 ndlp = lpfc_findnode_did(vport, PT2PT_RemoteID);
dea31012005-04-17 16:05:31 -0500463 if (!ndlp) {
464 /*
465 * Cannot find existing Fabric ndlp, so allocate a
466 * new one
467 */
468 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
469 if (!ndlp)
470 goto fail;
471
James Smart2e0fef82007-06-17 19:56:36 -0500472 lpfc_nlp_init(vport, ndlp, PT2PT_RemoteID);
dea31012005-04-17 16:05:31 -0500473 }
474
475 memcpy(&ndlp->nlp_portname, &sp->portName,
James Smart2e0fef82007-06-17 19:56:36 -0500476 sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -0500477 memcpy(&ndlp->nlp_nodename, &sp->nodeName,
James Smart2e0fef82007-06-17 19:56:36 -0500478 sizeof(struct lpfc_name));
479 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
480 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500481 ndlp->nlp_flag |= NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -0500482 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500483 } else {
484 /* This side will wait for the PLOGI */
James Smart329f9bc2007-04-25 09:53:01 -0400485 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -0500486 }
487
James Smart09372822008-01-11 01:52:54 -0500488 /* If we are pt2pt with another NPort, force NPIV off! */
489 phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED;
490
James Smart2e0fef82007-06-17 19:56:36 -0500491 spin_lock_irq(shost->host_lock);
492 vport->fc_flag |= FC_PT2PT;
493 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500494
495 /* Start discovery - this should just do CLEAR_LA */
James Smart2e0fef82007-06-17 19:56:36 -0500496 lpfc_disc_start(vport);
dea31012005-04-17 16:05:31 -0500497 return 0;
James Smart92d7f7b2007-06-17 19:56:38 -0500498fail:
dea31012005-04-17 16:05:31 -0500499 return -ENXIO;
500}
501
502static void
James Smart329f9bc2007-04-25 09:53:01 -0400503lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
504 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -0500505{
James Smart2e0fef82007-06-17 19:56:36 -0500506 struct lpfc_vport *vport = cmdiocb->vport;
507 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -0500508 IOCB_t *irsp = &rspiocb->iocb;
509 struct lpfc_nodelist *ndlp = cmdiocb->context1;
510 struct lpfc_dmabuf *pcmd = cmdiocb->context2, *prsp;
511 struct serv_parm *sp;
512 int rc;
513
514 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -0500515 if (lpfc_els_chk_latt(vport)) {
James Smart329f9bc2007-04-25 09:53:01 -0400516 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -0500517 goto out;
518 }
519
James Smart858c9f62007-06-17 19:56:39 -0500520 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
521 "FLOGI cmpl: status:x%x/x%x state:x%x",
522 irsp->ulpStatus, irsp->un.ulpWord[4],
523 vport->port_state);
524
dea31012005-04-17 16:05:31 -0500525 if (irsp->ulpStatus) {
526 /* Check for retry */
James Smart2e0fef82007-06-17 19:56:36 -0500527 if (lpfc_els_retry(phba, cmdiocb, rspiocb))
dea31012005-04-17 16:05:31 -0500528 goto out;
James Smart2e0fef82007-06-17 19:56:36 -0500529
dea31012005-04-17 16:05:31 -0500530 /* FLOGI failed, so there is no fabric */
James Smart2e0fef82007-06-17 19:56:36 -0500531 spin_lock_irq(shost->host_lock);
532 vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
533 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500534
James Smart329f9bc2007-04-25 09:53:01 -0400535 /* If private loop, then allow max outstanding els to be
dea31012005-04-17 16:05:31 -0500536 * LPFC_MAX_DISC_THREADS (32). Scanning in the case of no
537 * alpa map would take too long otherwise.
538 */
539 if (phba->alpa_map[0] == 0) {
James Smart3de2a652007-08-02 11:09:59 -0400540 vport->cfg_discovery_threads = LPFC_MAX_DISC_THREADS;
dea31012005-04-17 16:05:31 -0500541 }
542
543 /* FLOGI failure */
James Smarte8b62012007-08-02 11:10:09 -0400544 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
545 "0100 FLOGI failure Data: x%x x%x "
546 "x%x\n",
547 irsp->ulpStatus, irsp->un.ulpWord[4],
548 irsp->ulpTimeout);
dea31012005-04-17 16:05:31 -0500549 goto flogifail;
550 }
551
552 /*
553 * The FLogI succeeded. Sync the data for the CPU before
554 * accessing it.
555 */
556 prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list);
557
558 sp = prsp->virt + sizeof(uint32_t);
559
560 /* FLOGI completes successfully */
James Smarte8b62012007-08-02 11:10:09 -0400561 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
562 "0101 FLOGI completes sucessfully "
563 "Data: x%x x%x x%x x%x\n",
564 irsp->un.ulpWord[4], sp->cmn.e_d_tov,
565 sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution);
dea31012005-04-17 16:05:31 -0500566
James Smart2e0fef82007-06-17 19:56:36 -0500567 if (vport->port_state == LPFC_FLOGI) {
dea31012005-04-17 16:05:31 -0500568 /*
569 * If Common Service Parameters indicate Nport
570 * we are point to point, if Fport we are Fabric.
571 */
572 if (sp->cmn.fPort)
James Smart2e0fef82007-06-17 19:56:36 -0500573 rc = lpfc_cmpl_els_flogi_fabric(vport, ndlp, sp, irsp);
dea31012005-04-17 16:05:31 -0500574 else
James Smart2e0fef82007-06-17 19:56:36 -0500575 rc = lpfc_cmpl_els_flogi_nport(vport, ndlp, sp);
dea31012005-04-17 16:05:31 -0500576
577 if (!rc)
578 goto out;
579 }
580
581flogifail:
James Smart329f9bc2007-04-25 09:53:01 -0400582 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -0500583
James Smart858c9f62007-06-17 19:56:39 -0500584 if (!lpfc_error_lost_link(irsp)) {
dea31012005-04-17 16:05:31 -0500585 /* FLOGI failed, so just use loop map to make discovery list */
James Smart2e0fef82007-06-17 19:56:36 -0500586 lpfc_disc_list_loopmap(vport);
dea31012005-04-17 16:05:31 -0500587
588 /* Start discovery */
James Smart2e0fef82007-06-17 19:56:36 -0500589 lpfc_disc_start(vport);
James Smart87af33f2007-10-27 13:37:43 -0400590 } else if (((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
591 ((irsp->un.ulpWord[4] != IOERR_SLI_ABORTED) &&
592 (irsp->un.ulpWord[4] != IOERR_SLI_DOWN))) &&
593 (phba->link_state != LPFC_CLEAR_LA)) {
594 /* If FLOGI failed enable link interrupt. */
595 lpfc_issue_clear_la(phba, vport);
dea31012005-04-17 16:05:31 -0500596 }
dea31012005-04-17 16:05:31 -0500597out:
598 lpfc_els_free_iocb(phba, cmdiocb);
599}
600
601static int
James Smart2e0fef82007-06-17 19:56:36 -0500602lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
dea31012005-04-17 16:05:31 -0500603 uint8_t retry)
604{
James Smart2e0fef82007-06-17 19:56:36 -0500605 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500606 struct serv_parm *sp;
607 IOCB_t *icmd;
608 struct lpfc_iocbq *elsiocb;
609 struct lpfc_sli_ring *pring;
610 uint8_t *pcmd;
611 uint16_t cmdsize;
612 uint32_t tmo;
613 int rc;
614
615 pring = &phba->sli.ring[LPFC_ELS_RING];
616
James Smart92d7f7b2007-06-17 19:56:38 -0500617 cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
James Smart2e0fef82007-06-17 19:56:36 -0500618 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
619 ndlp->nlp_DID, ELS_CMD_FLOGI);
James Smart92d7f7b2007-06-17 19:56:38 -0500620
James Smart488d1462006-03-07 15:02:37 -0500621 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500622 return 1;
dea31012005-04-17 16:05:31 -0500623
624 icmd = &elsiocb->iocb;
625 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
626
627 /* For FLOGI request, remainder of payload is service parameters */
628 *((uint32_t *) (pcmd)) = ELS_CMD_FLOGI;
James Smart92d7f7b2007-06-17 19:56:38 -0500629 pcmd += sizeof(uint32_t);
630 memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
dea31012005-04-17 16:05:31 -0500631 sp = (struct serv_parm *) pcmd;
632
633 /* Setup CSPs accordingly for Fabric */
634 sp->cmn.e_d_tov = 0;
635 sp->cmn.w2.r_a_tov = 0;
636 sp->cls1.classValid = 0;
637 sp->cls2.seqDelivery = 1;
638 sp->cls3.seqDelivery = 1;
639 if (sp->cmn.fcphLow < FC_PH3)
640 sp->cmn.fcphLow = FC_PH3;
641 if (sp->cmn.fcphHigh < FC_PH3)
642 sp->cmn.fcphHigh = FC_PH3;
643
James Smart92d7f7b2007-06-17 19:56:38 -0500644 if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
645 sp->cmn.request_multiple_Nport = 1;
646
647 /* For FLOGI, Let FLOGI rsp set the NPortID for VPI 0 */
648 icmd->ulpCt_h = 1;
649 icmd->ulpCt_l = 0;
650 }
651
James Smart858c9f62007-06-17 19:56:39 -0500652 if (phba->fc_topology != TOPOLOGY_LOOP) {
653 icmd->un.elsreq64.myID = 0;
654 icmd->un.elsreq64.fl = 1;
655 }
656
dea31012005-04-17 16:05:31 -0500657 tmo = phba->fc_ratov;
658 phba->fc_ratov = LPFC_DISC_FLOGI_TMO;
James Smart2e0fef82007-06-17 19:56:36 -0500659 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -0500660 phba->fc_ratov = tmo;
661
662 phba->fc_stat.elsXmitFLOGI++;
663 elsiocb->iocb_cmpl = lpfc_cmpl_els_flogi;
James Smart858c9f62007-06-17 19:56:39 -0500664
665 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
666 "Issue FLOGI: opt:x%x",
667 phba->sli3_options, 0, 0);
668
James Smart92d7f7b2007-06-17 19:56:38 -0500669 rc = lpfc_issue_fabric_iocb(phba, elsiocb);
dea31012005-04-17 16:05:31 -0500670 if (rc == IOCB_ERROR) {
671 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500672 return 1;
dea31012005-04-17 16:05:31 -0500673 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500674 return 0;
dea31012005-04-17 16:05:31 -0500675}
676
677int
James Smart2e0fef82007-06-17 19:56:36 -0500678lpfc_els_abort_flogi(struct lpfc_hba *phba)
dea31012005-04-17 16:05:31 -0500679{
680 struct lpfc_sli_ring *pring;
681 struct lpfc_iocbq *iocb, *next_iocb;
682 struct lpfc_nodelist *ndlp;
683 IOCB_t *icmd;
684
685 /* Abort outstanding I/O on NPort <nlp_DID> */
686 lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
James Smarte8b62012007-08-02 11:10:09 -0400687 "0201 Abort outstanding I/O on NPort x%x\n",
688 Fabric_DID);
dea31012005-04-17 16:05:31 -0500689
690 pring = &phba->sli.ring[LPFC_ELS_RING];
691
692 /*
693 * Check the txcmplq for an iocb that matches the nport the driver is
694 * searching for.
695 */
James Smart2e0fef82007-06-17 19:56:36 -0500696 spin_lock_irq(&phba->hbalock);
dea31012005-04-17 16:05:31 -0500697 list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
698 icmd = &iocb->iocb;
James Smart2e0fef82007-06-17 19:56:36 -0500699 if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR &&
700 icmd->un.elsreq64.bdl.ulpIoTag32) {
dea31012005-04-17 16:05:31 -0500701 ndlp = (struct lpfc_nodelist *)(iocb->context1);
James Smart92d7f7b2007-06-17 19:56:38 -0500702 if (ndlp && (ndlp->nlp_DID == Fabric_DID)) {
James Smart07951072007-04-25 09:51:38 -0400703 lpfc_sli_issue_abort_iotag(phba, pring, iocb);
James Smart92d7f7b2007-06-17 19:56:38 -0500704 }
dea31012005-04-17 16:05:31 -0500705 }
706 }
James Smart2e0fef82007-06-17 19:56:36 -0500707 spin_unlock_irq(&phba->hbalock);
dea31012005-04-17 16:05:31 -0500708
709 return 0;
710}
711
712int
James Smart2e0fef82007-06-17 19:56:36 -0500713lpfc_initial_flogi(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -0500714{
James Smart2e0fef82007-06-17 19:56:36 -0500715 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500716 struct lpfc_nodelist *ndlp;
717
James Smart98c9ea52007-10-27 13:37:33 -0400718 vport->port_state = LPFC_FLOGI;
719 lpfc_set_disctmo(vport);
720
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500721 /* First look for the Fabric ndlp */
James Smart2e0fef82007-06-17 19:56:36 -0500722 ndlp = lpfc_findnode_did(vport, Fabric_DID);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500723 if (!ndlp) {
dea31012005-04-17 16:05:31 -0500724 /* Cannot find existing Fabric ndlp, so allocate a new one */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500725 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
726 if (!ndlp)
727 return 0;
James Smart2e0fef82007-06-17 19:56:36 -0500728 lpfc_nlp_init(vport, ndlp, Fabric_DID);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500729 } else {
James Smart2e0fef82007-06-17 19:56:36 -0500730 lpfc_dequeue_node(vport, ndlp);
dea31012005-04-17 16:05:31 -0500731 }
James Smart87af33f2007-10-27 13:37:43 -0400732
James Smart2e0fef82007-06-17 19:56:36 -0500733 if (lpfc_issue_els_flogi(vport, ndlp, 0)) {
James Smart329f9bc2007-04-25 09:53:01 -0400734 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -0500735 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500736 return 1;
dea31012005-04-17 16:05:31 -0500737}
738
James Smart92d7f7b2007-06-17 19:56:38 -0500739int
740lpfc_initial_fdisc(struct lpfc_vport *vport)
741{
742 struct lpfc_hba *phba = vport->phba;
743 struct lpfc_nodelist *ndlp;
744
745 /* First look for the Fabric ndlp */
746 ndlp = lpfc_findnode_did(vport, Fabric_DID);
747 if (!ndlp) {
748 /* Cannot find existing Fabric ndlp, so allocate a new one */
749 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
750 if (!ndlp)
751 return 0;
752 lpfc_nlp_init(vport, ndlp, Fabric_DID);
753 } else {
754 lpfc_dequeue_node(vport, ndlp);
755 }
756 if (lpfc_issue_els_fdisc(vport, ndlp, 0)) {
757 lpfc_nlp_put(ndlp);
758 }
759 return 1;
760}
James Smart87af33f2007-10-27 13:37:43 -0400761
762void
James Smart2e0fef82007-06-17 19:56:36 -0500763lpfc_more_plogi(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -0500764{
765 int sentplogi;
766
James Smart2e0fef82007-06-17 19:56:36 -0500767 if (vport->num_disc_nodes)
768 vport->num_disc_nodes--;
dea31012005-04-17 16:05:31 -0500769
770 /* Continue discovery with <num_disc_nodes> PLOGIs to go */
James Smarte8b62012007-08-02 11:10:09 -0400771 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
772 "0232 Continue discovery with %d PLOGIs to go "
773 "Data: x%x x%x x%x\n",
774 vport->num_disc_nodes, vport->fc_plogi_cnt,
775 vport->fc_flag, vport->port_state);
dea31012005-04-17 16:05:31 -0500776 /* Check to see if there are more PLOGIs to be sent */
James Smart2e0fef82007-06-17 19:56:36 -0500777 if (vport->fc_flag & FC_NLP_MORE)
778 /* go thru NPR nodes and issue any remaining ELS PLOGIs */
779 sentplogi = lpfc_els_disc_plogi(vport);
780
dea31012005-04-17 16:05:31 -0500781 return;
782}
783
James Smart488d1462006-03-07 15:02:37 -0500784static struct lpfc_nodelist *
James Smart92d7f7b2007-06-17 19:56:38 -0500785lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
James Smart488d1462006-03-07 15:02:37 -0500786 struct lpfc_nodelist *ndlp)
787{
James Smart2e0fef82007-06-17 19:56:36 -0500788 struct lpfc_vport *vport = ndlp->vport;
James Smart488d1462006-03-07 15:02:37 -0500789 struct lpfc_nodelist *new_ndlp;
James Smart0ff10d42008-01-11 01:52:36 -0500790 struct lpfc_rport_data *rdata;
791 struct fc_rport *rport;
James Smart488d1462006-03-07 15:02:37 -0500792 struct serv_parm *sp;
James Smart92d7f7b2007-06-17 19:56:38 -0500793 uint8_t name[sizeof(struct lpfc_name)];
James Smart488d1462006-03-07 15:02:37 -0500794 uint32_t rc;
795
James Smart2fb9bd82006-12-02 13:33:57 -0500796 /* Fabric nodes can have the same WWPN so we don't bother searching
797 * by WWPN. Just return the ndlp that was given to us.
798 */
799 if (ndlp->nlp_type & NLP_FABRIC)
800 return ndlp;
801
James Smart92d7f7b2007-06-17 19:56:38 -0500802 sp = (struct serv_parm *) ((uint8_t *) prsp + sizeof(uint32_t));
James Smart685f0bf2007-04-25 09:53:08 -0400803 memset(name, 0, sizeof(struct lpfc_name));
James Smart488d1462006-03-07 15:02:37 -0500804
James Smart685f0bf2007-04-25 09:53:08 -0400805 /* Now we find out if the NPort we are logging into, matches the WWPN
James Smart488d1462006-03-07 15:02:37 -0500806 * we have for that ndlp. If not, we have some work to do.
807 */
James Smart2e0fef82007-06-17 19:56:36 -0500808 new_ndlp = lpfc_findnode_wwpn(vport, &sp->portName);
James Smart488d1462006-03-07 15:02:37 -0500809
James Smart92795652006-07-06 15:50:02 -0400810 if (new_ndlp == ndlp)
James Smart488d1462006-03-07 15:02:37 -0500811 return ndlp;
James Smart488d1462006-03-07 15:02:37 -0500812
813 if (!new_ndlp) {
James Smart2e0fef82007-06-17 19:56:36 -0500814 rc = memcmp(&ndlp->nlp_portname, name,
815 sizeof(struct lpfc_name));
James Smart92795652006-07-06 15:50:02 -0400816 if (!rc)
817 return ndlp;
James Smart488d1462006-03-07 15:02:37 -0500818 new_ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC);
819 if (!new_ndlp)
820 return ndlp;
821
James Smart2e0fef82007-06-17 19:56:36 -0500822 lpfc_nlp_init(vport, new_ndlp, ndlp->nlp_DID);
James Smart488d1462006-03-07 15:02:37 -0500823 }
824
James Smart2e0fef82007-06-17 19:56:36 -0500825 lpfc_unreg_rpi(vport, new_ndlp);
James Smart488d1462006-03-07 15:02:37 -0500826 new_ndlp->nlp_DID = ndlp->nlp_DID;
James Smart92795652006-07-06 15:50:02 -0400827 new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
James Smart0ff10d42008-01-11 01:52:36 -0500828
829 if (ndlp->nlp_flag & NLP_NPR_2B_DISC)
830 new_ndlp->nlp_flag |= NLP_NPR_2B_DISC;
831 ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
832
James Smart2e0fef82007-06-17 19:56:36 -0500833 lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state);
James Smart488d1462006-03-07 15:02:37 -0500834
James Smart2e0fef82007-06-17 19:56:36 -0500835 /* Move this back to NPR state */
James Smart87af33f2007-10-27 13:37:43 -0400836 if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) {
837 /* The new_ndlp is replacing ndlp totally, so we need
838 * to put ndlp on UNUSED list and try to free it.
839 */
James Smart0ff10d42008-01-11 01:52:36 -0500840
841 /* Fix up the rport accordingly */
842 rport = ndlp->rport;
843 if (rport) {
844 rdata = rport->dd_data;
845 if (rdata->pnode == ndlp) {
846 lpfc_nlp_put(ndlp);
847 ndlp->rport = NULL;
848 rdata->pnode = lpfc_nlp_get(new_ndlp);
849 new_ndlp->rport = rport;
850 }
851 new_ndlp->nlp_type = ndlp->nlp_type;
852 }
853
James Smart2e0fef82007-06-17 19:56:36 -0500854 lpfc_drop_node(vport, ndlp);
James Smart87af33f2007-10-27 13:37:43 -0400855 }
James Smart92795652006-07-06 15:50:02 -0400856 else {
James Smart2e0fef82007-06-17 19:56:36 -0500857 lpfc_unreg_rpi(vport, ndlp);
James Smart92795652006-07-06 15:50:02 -0400858 ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
James Smart2e0fef82007-06-17 19:56:36 -0500859 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
James Smart92795652006-07-06 15:50:02 -0400860 }
James Smart488d1462006-03-07 15:02:37 -0500861 return new_ndlp;
862}
863
James Smart87af33f2007-10-27 13:37:43 -0400864void
865lpfc_end_rscn(struct lpfc_vport *vport)
866{
867 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
868
869 if (vport->fc_flag & FC_RSCN_MODE) {
870 /*
871 * Check to see if more RSCNs came in while we were
872 * processing this one.
873 */
874 if (vport->fc_rscn_id_cnt ||
875 (vport->fc_flag & FC_RSCN_DISCOVERY) != 0)
876 lpfc_els_handle_rscn(vport);
877 else {
878 spin_lock_irq(shost->host_lock);
879 vport->fc_flag &= ~FC_RSCN_MODE;
880 spin_unlock_irq(shost->host_lock);
881 }
882 }
883}
884
dea31012005-04-17 16:05:31 -0500885static void
James Smart2e0fef82007-06-17 19:56:36 -0500886lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
887 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -0500888{
James Smart2e0fef82007-06-17 19:56:36 -0500889 struct lpfc_vport *vport = cmdiocb->vport;
890 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -0500891 IOCB_t *irsp;
dea31012005-04-17 16:05:31 -0500892 struct lpfc_nodelist *ndlp;
James Smart92795652006-07-06 15:50:02 -0400893 struct lpfc_dmabuf *prsp;
dea31012005-04-17 16:05:31 -0500894 int disc, rc, did, type;
895
dea31012005-04-17 16:05:31 -0500896 /* we pass cmdiocb to state machine which needs rspiocb as well */
897 cmdiocb->context_un.rsp_iocb = rspiocb;
898
899 irsp = &rspiocb->iocb;
James Smart858c9f62007-06-17 19:56:39 -0500900 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
901 "PLOGI cmpl: status:x%x/x%x did:x%x",
902 irsp->ulpStatus, irsp->un.ulpWord[4],
903 irsp->un.elsreq64.remoteID);
904
James Smart2e0fef82007-06-17 19:56:36 -0500905 ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID);
James Smarted957682007-06-17 19:56:37 -0500906 if (!ndlp) {
James Smarte8b62012007-08-02 11:10:09 -0400907 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
908 "0136 PLOGI completes to NPort x%x "
909 "with no ndlp. Data: x%x x%x x%x\n",
910 irsp->un.elsreq64.remoteID,
911 irsp->ulpStatus, irsp->un.ulpWord[4],
912 irsp->ulpIoTag);
James Smart488d1462006-03-07 15:02:37 -0500913 goto out;
James Smarted957682007-06-17 19:56:37 -0500914 }
dea31012005-04-17 16:05:31 -0500915
916 /* Since ndlp can be freed in the disc state machine, note if this node
917 * is being used during discovery.
918 */
James Smart2e0fef82007-06-17 19:56:36 -0500919 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500920 disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
James Smart488d1462006-03-07 15:02:37 -0500921 ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -0500922 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500923 rc = 0;
924
925 /* PLOGI completes to NPort <nlp_DID> */
James Smarte8b62012007-08-02 11:10:09 -0400926 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
927 "0102 PLOGI completes to NPort x%x "
928 "Data: x%x x%x x%x x%x x%x\n",
929 ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4],
930 irsp->ulpTimeout, disc, vport->num_disc_nodes);
dea31012005-04-17 16:05:31 -0500931 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -0500932 if (lpfc_els_chk_latt(vport)) {
933 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500934 ndlp->nlp_flag |= NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -0500935 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500936 goto out;
937 }
938
939 /* ndlp could be freed in DSM, save these values now */
940 type = ndlp->nlp_type;
941 did = ndlp->nlp_DID;
942
943 if (irsp->ulpStatus) {
944 /* Check for retry */
945 if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
946 /* ELS command is being retried */
947 if (disc) {
James Smart2e0fef82007-06-17 19:56:36 -0500948 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500949 ndlp->nlp_flag |= NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -0500950 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500951 }
952 goto out;
953 }
dea31012005-04-17 16:05:31 -0500954 /* PLOGI failed */
955 /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
James Smart858c9f62007-06-17 19:56:39 -0500956 if (lpfc_error_lost_link(irsp)) {
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500957 rc = NLP_STE_FREED_NODE;
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -0500958 } else {
James Smart2e0fef82007-06-17 19:56:36 -0500959 rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart92d7f7b2007-06-17 19:56:38 -0500960 NLP_EVT_CMPL_PLOGI);
dea31012005-04-17 16:05:31 -0500961 }
962 } else {
963 /* Good status, call state machine */
James Smart92795652006-07-06 15:50:02 -0400964 prsp = list_entry(((struct lpfc_dmabuf *)
James Smart92d7f7b2007-06-17 19:56:38 -0500965 cmdiocb->context2)->list.next,
966 struct lpfc_dmabuf, list);
967 ndlp = lpfc_plogi_confirm_nport(phba, prsp->virt, ndlp);
James Smart2e0fef82007-06-17 19:56:36 -0500968 rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart92d7f7b2007-06-17 19:56:38 -0500969 NLP_EVT_CMPL_PLOGI);
dea31012005-04-17 16:05:31 -0500970 }
971
James Smart2e0fef82007-06-17 19:56:36 -0500972 if (disc && vport->num_disc_nodes) {
dea31012005-04-17 16:05:31 -0500973 /* Check to see if there are more PLOGIs to be sent */
James Smart2e0fef82007-06-17 19:56:36 -0500974 lpfc_more_plogi(vport);
dea31012005-04-17 16:05:31 -0500975
James Smart2e0fef82007-06-17 19:56:36 -0500976 if (vport->num_disc_nodes == 0) {
977 spin_lock_irq(shost->host_lock);
978 vport->fc_flag &= ~FC_NDISC_ACTIVE;
979 spin_unlock_irq(shost->host_lock);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500980
James Smart2e0fef82007-06-17 19:56:36 -0500981 lpfc_can_disctmo(vport);
James Smart87af33f2007-10-27 13:37:43 -0400982 lpfc_end_rscn(vport);
dea31012005-04-17 16:05:31 -0500983 }
984 }
985
986out:
987 lpfc_els_free_iocb(phba, cmdiocb);
988 return;
989}
990
991int
James Smart2e0fef82007-06-17 19:56:36 -0500992lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
dea31012005-04-17 16:05:31 -0500993{
James Smart2e0fef82007-06-17 19:56:36 -0500994 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500995 struct serv_parm *sp;
996 IOCB_t *icmd;
James Smart98c9ea52007-10-27 13:37:33 -0400997 struct lpfc_nodelist *ndlp;
dea31012005-04-17 16:05:31 -0500998 struct lpfc_iocbq *elsiocb;
999 struct lpfc_sli_ring *pring;
1000 struct lpfc_sli *psli;
1001 uint8_t *pcmd;
1002 uint16_t cmdsize;
James Smart92d7f7b2007-06-17 19:56:38 -05001003 int ret;
dea31012005-04-17 16:05:31 -05001004
1005 psli = &phba->sli;
1006 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
1007
James Smart98c9ea52007-10-27 13:37:33 -04001008 ndlp = lpfc_findnode_did(vport, did);
1009 /* If ndlp if not NULL, we will bump the reference count on it */
1010
James Smart92d7f7b2007-06-17 19:56:38 -05001011 cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
James Smart98c9ea52007-10-27 13:37:33 -04001012 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did,
James Smart2e0fef82007-06-17 19:56:36 -05001013 ELS_CMD_PLOGI);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001014 if (!elsiocb)
1015 return 1;
dea31012005-04-17 16:05:31 -05001016
1017 icmd = &elsiocb->iocb;
1018 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1019
1020 /* For PLOGI request, remainder of payload is service parameters */
1021 *((uint32_t *) (pcmd)) = ELS_CMD_PLOGI;
James Smart92d7f7b2007-06-17 19:56:38 -05001022 pcmd += sizeof(uint32_t);
1023 memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
dea31012005-04-17 16:05:31 -05001024 sp = (struct serv_parm *) pcmd;
1025
1026 if (sp->cmn.fcphLow < FC_PH_4_3)
1027 sp->cmn.fcphLow = FC_PH_4_3;
1028
1029 if (sp->cmn.fcphHigh < FC_PH3)
1030 sp->cmn.fcphHigh = FC_PH3;
1031
James Smart858c9f62007-06-17 19:56:39 -05001032 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1033 "Issue PLOGI: did:x%x",
1034 did, 0, 0);
1035
dea31012005-04-17 16:05:31 -05001036 phba->fc_stat.elsXmitPLOGI++;
1037 elsiocb->iocb_cmpl = lpfc_cmpl_els_plogi;
James Smart92d7f7b2007-06-17 19:56:38 -05001038 ret = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
1039
1040 if (ret == IOCB_ERROR) {
dea31012005-04-17 16:05:31 -05001041 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001042 return 1;
dea31012005-04-17 16:05:31 -05001043 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001044 return 0;
dea31012005-04-17 16:05:31 -05001045}
1046
1047static void
James Smart2e0fef82007-06-17 19:56:36 -05001048lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1049 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05001050{
James Smart2e0fef82007-06-17 19:56:36 -05001051 struct lpfc_vport *vport = cmdiocb->vport;
1052 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05001053 IOCB_t *irsp;
1054 struct lpfc_sli *psli;
1055 struct lpfc_nodelist *ndlp;
1056
1057 psli = &phba->sli;
1058 /* we pass cmdiocb to state machine which needs rspiocb as well */
1059 cmdiocb->context_un.rsp_iocb = rspiocb;
1060
1061 irsp = &(rspiocb->iocb);
1062 ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
James Smart2e0fef82007-06-17 19:56:36 -05001063 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001064 ndlp->nlp_flag &= ~NLP_PRLI_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001065 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001066
James Smart858c9f62007-06-17 19:56:39 -05001067 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1068 "PRLI cmpl: status:x%x/x%x did:x%x",
1069 irsp->ulpStatus, irsp->un.ulpWord[4],
1070 ndlp->nlp_DID);
dea31012005-04-17 16:05:31 -05001071 /* PRLI completes to NPort <nlp_DID> */
James Smarte8b62012007-08-02 11:10:09 -04001072 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
1073 "0103 PRLI completes to NPort x%x "
1074 "Data: x%x x%x x%x x%x\n",
1075 ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4],
1076 irsp->ulpTimeout, vport->num_disc_nodes);
dea31012005-04-17 16:05:31 -05001077
James Smart2e0fef82007-06-17 19:56:36 -05001078 vport->fc_prli_sent--;
dea31012005-04-17 16:05:31 -05001079 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -05001080 if (lpfc_els_chk_latt(vport))
dea31012005-04-17 16:05:31 -05001081 goto out;
1082
1083 if (irsp->ulpStatus) {
1084 /* Check for retry */
1085 if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
1086 /* ELS command is being retried */
1087 goto out;
1088 }
1089 /* PRLI failed */
1090 /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
James Smart858c9f62007-06-17 19:56:39 -05001091 if (lpfc_error_lost_link(irsp)) {
dea31012005-04-17 16:05:31 -05001092 goto out;
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05001093 } else {
James Smart2e0fef82007-06-17 19:56:36 -05001094 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart92d7f7b2007-06-17 19:56:38 -05001095 NLP_EVT_CMPL_PRLI);
dea31012005-04-17 16:05:31 -05001096 }
1097 } else {
1098 /* Good status, call state machine */
James Smart2e0fef82007-06-17 19:56:36 -05001099 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart92d7f7b2007-06-17 19:56:38 -05001100 NLP_EVT_CMPL_PRLI);
dea31012005-04-17 16:05:31 -05001101 }
1102
1103out:
1104 lpfc_els_free_iocb(phba, cmdiocb);
1105 return;
1106}
1107
1108int
James Smart2e0fef82007-06-17 19:56:36 -05001109lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
dea31012005-04-17 16:05:31 -05001110 uint8_t retry)
1111{
James Smart2e0fef82007-06-17 19:56:36 -05001112 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1113 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001114 PRLI *npr;
1115 IOCB_t *icmd;
1116 struct lpfc_iocbq *elsiocb;
1117 struct lpfc_sli_ring *pring;
1118 struct lpfc_sli *psli;
1119 uint8_t *pcmd;
1120 uint16_t cmdsize;
1121
1122 psli = &phba->sli;
1123 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
1124
James Smart92d7f7b2007-06-17 19:56:38 -05001125 cmdsize = (sizeof(uint32_t) + sizeof(PRLI));
James Smart2e0fef82007-06-17 19:56:36 -05001126 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
1127 ndlp->nlp_DID, ELS_CMD_PRLI);
James Smart488d1462006-03-07 15:02:37 -05001128 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001129 return 1;
dea31012005-04-17 16:05:31 -05001130
1131 icmd = &elsiocb->iocb;
1132 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1133
1134 /* For PRLI request, remainder of payload is service parameters */
James Smart92d7f7b2007-06-17 19:56:38 -05001135 memset(pcmd, 0, (sizeof(PRLI) + sizeof(uint32_t)));
dea31012005-04-17 16:05:31 -05001136 *((uint32_t *) (pcmd)) = ELS_CMD_PRLI;
James Smart92d7f7b2007-06-17 19:56:38 -05001137 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05001138
1139 /* For PRLI, remainder of payload is PRLI parameter page */
1140 npr = (PRLI *) pcmd;
1141 /*
1142 * If our firmware version is 3.20 or later,
1143 * set the following bits for FC-TAPE support.
1144 */
1145 if (phba->vpd.rev.feaLevelHigh >= 0x02) {
1146 npr->ConfmComplAllowed = 1;
1147 npr->Retry = 1;
1148 npr->TaskRetryIdReq = 1;
1149 }
1150 npr->estabImagePair = 1;
1151 npr->readXferRdyDis = 1;
1152
1153 /* For FCP support */
1154 npr->prliType = PRLI_FCP_TYPE;
1155 npr->initiatorFunc = 1;
1156
James Smart858c9f62007-06-17 19:56:39 -05001157 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1158 "Issue PRLI: did:x%x",
1159 ndlp->nlp_DID, 0, 0);
1160
dea31012005-04-17 16:05:31 -05001161 phba->fc_stat.elsXmitPRLI++;
1162 elsiocb->iocb_cmpl = lpfc_cmpl_els_prli;
James Smart2e0fef82007-06-17 19:56:36 -05001163 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001164 ndlp->nlp_flag |= NLP_PRLI_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001165 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001166 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
James Smart2e0fef82007-06-17 19:56:36 -05001167 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001168 ndlp->nlp_flag &= ~NLP_PRLI_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001169 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001170 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001171 return 1;
dea31012005-04-17 16:05:31 -05001172 }
James Smart2e0fef82007-06-17 19:56:36 -05001173 vport->fc_prli_sent++;
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001174 return 0;
dea31012005-04-17 16:05:31 -05001175}
1176
James Smart0ff10d42008-01-11 01:52:36 -05001177void
James Smart2e0fef82007-06-17 19:56:36 -05001178lpfc_more_adisc(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05001179{
1180 int sentadisc;
1181
James Smart2e0fef82007-06-17 19:56:36 -05001182 if (vport->num_disc_nodes)
1183 vport->num_disc_nodes--;
dea31012005-04-17 16:05:31 -05001184 /* Continue discovery with <num_disc_nodes> ADISCs to go */
James Smarte8b62012007-08-02 11:10:09 -04001185 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
1186 "0210 Continue discovery with %d ADISCs to go "
1187 "Data: x%x x%x x%x\n",
1188 vport->num_disc_nodes, vport->fc_adisc_cnt,
1189 vport->fc_flag, vport->port_state);
dea31012005-04-17 16:05:31 -05001190 /* Check to see if there are more ADISCs to be sent */
James Smart2e0fef82007-06-17 19:56:36 -05001191 if (vport->fc_flag & FC_NLP_MORE) {
1192 lpfc_set_disctmo(vport);
1193 /* go thru NPR nodes and issue any remaining ELS ADISCs */
1194 sentadisc = lpfc_els_disc_adisc(vport);
dea31012005-04-17 16:05:31 -05001195 }
1196 return;
1197}
1198
1199static void
James Smart2e0fef82007-06-17 19:56:36 -05001200lpfc_rscn_disc(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05001201{
James Smart858c9f62007-06-17 19:56:39 -05001202 lpfc_can_disctmo(vport);
1203
dea31012005-04-17 16:05:31 -05001204 /* RSCN discovery */
James Smart2e0fef82007-06-17 19:56:36 -05001205 /* go thru NPR nodes and issue ELS PLOGIs */
1206 if (vport->fc_npr_cnt)
1207 if (lpfc_els_disc_plogi(vport))
dea31012005-04-17 16:05:31 -05001208 return;
James Smart2e0fef82007-06-17 19:56:36 -05001209
James Smart87af33f2007-10-27 13:37:43 -04001210 lpfc_end_rscn(vport);
dea31012005-04-17 16:05:31 -05001211}
1212
1213static void
James Smart2e0fef82007-06-17 19:56:36 -05001214lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1215 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05001216{
James Smart2e0fef82007-06-17 19:56:36 -05001217 struct lpfc_vport *vport = cmdiocb->vport;
1218 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05001219 IOCB_t *irsp;
dea31012005-04-17 16:05:31 -05001220 struct lpfc_nodelist *ndlp;
James Smart2e0fef82007-06-17 19:56:36 -05001221 int disc;
dea31012005-04-17 16:05:31 -05001222
1223 /* we pass cmdiocb to state machine which needs rspiocb as well */
1224 cmdiocb->context_un.rsp_iocb = rspiocb;
1225
1226 irsp = &(rspiocb->iocb);
1227 ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
dea31012005-04-17 16:05:31 -05001228
James Smart858c9f62007-06-17 19:56:39 -05001229 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1230 "ADISC cmpl: status:x%x/x%x did:x%x",
1231 irsp->ulpStatus, irsp->un.ulpWord[4],
1232 ndlp->nlp_DID);
1233
dea31012005-04-17 16:05:31 -05001234 /* Since ndlp can be freed in the disc state machine, note if this node
1235 * is being used during discovery.
1236 */
James Smart2e0fef82007-06-17 19:56:36 -05001237 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001238 disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001239 ndlp->nlp_flag &= ~(NLP_ADISC_SND | NLP_NPR_2B_DISC);
James Smart2e0fef82007-06-17 19:56:36 -05001240 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001241 /* ADISC completes to NPort <nlp_DID> */
James Smarte8b62012007-08-02 11:10:09 -04001242 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
1243 "0104 ADISC completes to NPort x%x "
1244 "Data: x%x x%x x%x x%x x%x\n",
1245 ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4],
1246 irsp->ulpTimeout, disc, vport->num_disc_nodes);
dea31012005-04-17 16:05:31 -05001247 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -05001248 if (lpfc_els_chk_latt(vport)) {
1249 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001250 ndlp->nlp_flag |= NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -05001251 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001252 goto out;
1253 }
1254
1255 if (irsp->ulpStatus) {
1256 /* Check for retry */
1257 if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
1258 /* ELS command is being retried */
1259 if (disc) {
James Smart2e0fef82007-06-17 19:56:36 -05001260 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001261 ndlp->nlp_flag |= NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -05001262 spin_unlock_irq(shost->host_lock);
1263 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -05001264 }
1265 goto out;
1266 }
1267 /* ADISC failed */
1268 /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
James Smart858c9f62007-06-17 19:56:39 -05001269 if (!lpfc_error_lost_link(irsp)) {
James Smart2e0fef82007-06-17 19:56:36 -05001270 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart858c9f62007-06-17 19:56:39 -05001271 NLP_EVT_CMPL_ADISC);
dea31012005-04-17 16:05:31 -05001272 }
1273 } else {
1274 /* Good status, call state machine */
James Smart2e0fef82007-06-17 19:56:36 -05001275 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
dea31012005-04-17 16:05:31 -05001276 NLP_EVT_CMPL_ADISC);
1277 }
1278
James Smart2e0fef82007-06-17 19:56:36 -05001279 if (disc && vport->num_disc_nodes) {
dea31012005-04-17 16:05:31 -05001280 /* Check to see if there are more ADISCs to be sent */
James Smart2e0fef82007-06-17 19:56:36 -05001281 lpfc_more_adisc(vport);
dea31012005-04-17 16:05:31 -05001282
1283 /* Check to see if we are done with ADISC authentication */
James Smart2e0fef82007-06-17 19:56:36 -05001284 if (vport->num_disc_nodes == 0) {
James Smart92d7f7b2007-06-17 19:56:38 -05001285 /* If we get here, there is nothing left to ADISC */
1286 /*
1287 * For NPIV, cmpl_reg_vpi will set port_state to READY,
1288 * and continue discovery.
1289 */
1290 if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
1291 !(vport->fc_flag & FC_RSCN_MODE)) {
1292 lpfc_issue_reg_vpi(phba, vport);
1293 goto out;
1294 }
1295 /*
1296 * For SLI2, we need to set port_state to READY
1297 * and continue discovery.
1298 */
1299 if (vport->port_state < LPFC_VPORT_READY) {
1300 /* If we get here, there is nothing to ADISC */
James Smarted957682007-06-17 19:56:37 -05001301 if (vport->port_type == LPFC_PHYSICAL_PORT)
James Smart2e0fef82007-06-17 19:56:36 -05001302 lpfc_issue_clear_la(phba, vport);
James Smart92d7f7b2007-06-17 19:56:38 -05001303
1304 if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) {
1305 vport->num_disc_nodes = 0;
1306 /* go thru NPR list, issue ELS PLOGIs */
1307 if (vport->fc_npr_cnt)
1308 lpfc_els_disc_plogi(vport);
1309
1310 if (!vport->num_disc_nodes) {
1311 spin_lock_irq(shost->host_lock);
1312 vport->fc_flag &=
1313 ~FC_NDISC_ACTIVE;
1314 spin_unlock_irq(
1315 shost->host_lock);
1316 lpfc_can_disctmo(vport);
1317 }
1318 }
1319 vport->port_state = LPFC_VPORT_READY;
dea31012005-04-17 16:05:31 -05001320 } else {
James Smart2e0fef82007-06-17 19:56:36 -05001321 lpfc_rscn_disc(vport);
dea31012005-04-17 16:05:31 -05001322 }
1323 }
1324 }
dea31012005-04-17 16:05:31 -05001325out:
1326 lpfc_els_free_iocb(phba, cmdiocb);
1327 return;
1328}
1329
1330int
James Smart2e0fef82007-06-17 19:56:36 -05001331lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
dea31012005-04-17 16:05:31 -05001332 uint8_t retry)
1333{
James Smart2e0fef82007-06-17 19:56:36 -05001334 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1335 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001336 ADISC *ap;
1337 IOCB_t *icmd;
1338 struct lpfc_iocbq *elsiocb;
James Smart2e0fef82007-06-17 19:56:36 -05001339 struct lpfc_sli *psli = &phba->sli;
1340 struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
dea31012005-04-17 16:05:31 -05001341 uint8_t *pcmd;
1342 uint16_t cmdsize;
1343
James Smart92d7f7b2007-06-17 19:56:38 -05001344 cmdsize = (sizeof(uint32_t) + sizeof(ADISC));
James Smart2e0fef82007-06-17 19:56:36 -05001345 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
1346 ndlp->nlp_DID, ELS_CMD_ADISC);
James Smart488d1462006-03-07 15:02:37 -05001347 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001348 return 1;
dea31012005-04-17 16:05:31 -05001349
1350 icmd = &elsiocb->iocb;
1351 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1352
1353 /* For ADISC request, remainder of payload is service parameters */
1354 *((uint32_t *) (pcmd)) = ELS_CMD_ADISC;
James Smart92d7f7b2007-06-17 19:56:38 -05001355 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05001356
1357 /* Fill in ADISC payload */
1358 ap = (ADISC *) pcmd;
1359 ap->hardAL_PA = phba->fc_pref_ALPA;
James Smart92d7f7b2007-06-17 19:56:38 -05001360 memcpy(&ap->portName, &vport->fc_portname, sizeof(struct lpfc_name));
1361 memcpy(&ap->nodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
James Smart2e0fef82007-06-17 19:56:36 -05001362 ap->DID = be32_to_cpu(vport->fc_myDID);
dea31012005-04-17 16:05:31 -05001363
James Smart858c9f62007-06-17 19:56:39 -05001364 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1365 "Issue ADISC: did:x%x",
1366 ndlp->nlp_DID, 0, 0);
1367
dea31012005-04-17 16:05:31 -05001368 phba->fc_stat.elsXmitADISC++;
1369 elsiocb->iocb_cmpl = lpfc_cmpl_els_adisc;
James Smart2e0fef82007-06-17 19:56:36 -05001370 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001371 ndlp->nlp_flag |= NLP_ADISC_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001372 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001373 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
James Smart2e0fef82007-06-17 19:56:36 -05001374 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001375 ndlp->nlp_flag &= ~NLP_ADISC_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001376 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001377 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001378 return 1;
dea31012005-04-17 16:05:31 -05001379 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001380 return 0;
dea31012005-04-17 16:05:31 -05001381}
1382
1383static void
James Smart2e0fef82007-06-17 19:56:36 -05001384lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1385 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05001386{
James Smart2e0fef82007-06-17 19:56:36 -05001387 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
1388 struct lpfc_vport *vport = ndlp->vport;
1389 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05001390 IOCB_t *irsp;
1391 struct lpfc_sli *psli;
dea31012005-04-17 16:05:31 -05001392
1393 psli = &phba->sli;
1394 /* we pass cmdiocb to state machine which needs rspiocb as well */
1395 cmdiocb->context_un.rsp_iocb = rspiocb;
1396
1397 irsp = &(rspiocb->iocb);
James Smart2e0fef82007-06-17 19:56:36 -05001398 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001399 ndlp->nlp_flag &= ~NLP_LOGO_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001400 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001401
James Smart858c9f62007-06-17 19:56:39 -05001402 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1403 "LOGO cmpl: status:x%x/x%x did:x%x",
1404 irsp->ulpStatus, irsp->un.ulpWord[4],
1405 ndlp->nlp_DID);
dea31012005-04-17 16:05:31 -05001406 /* LOGO completes to NPort <nlp_DID> */
James Smarte8b62012007-08-02 11:10:09 -04001407 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
1408 "0105 LOGO completes to NPort x%x "
1409 "Data: x%x x%x x%x x%x\n",
1410 ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4],
1411 irsp->ulpTimeout, vport->num_disc_nodes);
dea31012005-04-17 16:05:31 -05001412 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -05001413 if (lpfc_els_chk_latt(vport))
dea31012005-04-17 16:05:31 -05001414 goto out;
1415
James Smart92d7f7b2007-06-17 19:56:38 -05001416 if (ndlp->nlp_flag & NLP_TARGET_REMOVE) {
1417 /* NLP_EVT_DEVICE_RM should unregister the RPI
1418 * which should abort all outstanding IOs.
1419 */
1420 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
1421 NLP_EVT_DEVICE_RM);
1422 goto out;
1423 }
1424
dea31012005-04-17 16:05:31 -05001425 if (irsp->ulpStatus) {
1426 /* Check for retry */
James Smart2e0fef82007-06-17 19:56:36 -05001427 if (lpfc_els_retry(phba, cmdiocb, rspiocb))
dea31012005-04-17 16:05:31 -05001428 /* ELS command is being retried */
1429 goto out;
dea31012005-04-17 16:05:31 -05001430 /* LOGO failed */
1431 /* Do not call DSM for lpfc_els_abort'ed ELS cmds */
James Smart858c9f62007-06-17 19:56:39 -05001432 if (lpfc_error_lost_link(irsp))
dea31012005-04-17 16:05:31 -05001433 goto out;
James Smart858c9f62007-06-17 19:56:39 -05001434 else
James Smart2e0fef82007-06-17 19:56:36 -05001435 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart92d7f7b2007-06-17 19:56:38 -05001436 NLP_EVT_CMPL_LOGO);
dea31012005-04-17 16:05:31 -05001437 } else {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001438 /* Good status, call state machine.
1439 * This will unregister the rpi if needed.
1440 */
James Smart2e0fef82007-06-17 19:56:36 -05001441 lpfc_disc_state_machine(vport, ndlp, cmdiocb,
James Smart92d7f7b2007-06-17 19:56:38 -05001442 NLP_EVT_CMPL_LOGO);
dea31012005-04-17 16:05:31 -05001443 }
1444
1445out:
1446 lpfc_els_free_iocb(phba, cmdiocb);
1447 return;
1448}
1449
1450int
James Smart2e0fef82007-06-17 19:56:36 -05001451lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
dea31012005-04-17 16:05:31 -05001452 uint8_t retry)
1453{
James Smart2e0fef82007-06-17 19:56:36 -05001454 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1455 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001456 IOCB_t *icmd;
1457 struct lpfc_iocbq *elsiocb;
1458 struct lpfc_sli_ring *pring;
1459 struct lpfc_sli *psli;
1460 uint8_t *pcmd;
1461 uint16_t cmdsize;
James Smart92d7f7b2007-06-17 19:56:38 -05001462 int rc;
dea31012005-04-17 16:05:31 -05001463
1464 psli = &phba->sli;
1465 pring = &psli->ring[LPFC_ELS_RING];
1466
James Smart98c9ea52007-10-27 13:37:33 -04001467 spin_lock_irq(shost->host_lock);
1468 if (ndlp->nlp_flag & NLP_LOGO_SND) {
1469 spin_unlock_irq(shost->host_lock);
1470 return 0;
1471 }
1472 spin_unlock_irq(shost->host_lock);
1473
James Smart92d7f7b2007-06-17 19:56:38 -05001474 cmdsize = (2 * sizeof(uint32_t)) + sizeof(struct lpfc_name);
James Smart2e0fef82007-06-17 19:56:36 -05001475 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
1476 ndlp->nlp_DID, ELS_CMD_LOGO);
James Smart488d1462006-03-07 15:02:37 -05001477 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001478 return 1;
dea31012005-04-17 16:05:31 -05001479
1480 icmd = &elsiocb->iocb;
1481 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1482 *((uint32_t *) (pcmd)) = ELS_CMD_LOGO;
James Smart92d7f7b2007-06-17 19:56:38 -05001483 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05001484
1485 /* Fill in LOGO payload */
James Smart2e0fef82007-06-17 19:56:36 -05001486 *((uint32_t *) (pcmd)) = be32_to_cpu(vport->fc_myDID);
James Smart92d7f7b2007-06-17 19:56:38 -05001487 pcmd += sizeof(uint32_t);
1488 memcpy(pcmd, &vport->fc_portname, sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05001489
James Smart858c9f62007-06-17 19:56:39 -05001490 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1491 "Issue LOGO: did:x%x",
1492 ndlp->nlp_DID, 0, 0);
1493
dea31012005-04-17 16:05:31 -05001494 phba->fc_stat.elsXmitLOGO++;
1495 elsiocb->iocb_cmpl = lpfc_cmpl_els_logo;
James Smart2e0fef82007-06-17 19:56:36 -05001496 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001497 ndlp->nlp_flag |= NLP_LOGO_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001498 spin_unlock_irq(shost->host_lock);
James Smart92d7f7b2007-06-17 19:56:38 -05001499 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
1500
1501 if (rc == IOCB_ERROR) {
James Smart2e0fef82007-06-17 19:56:36 -05001502 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001503 ndlp->nlp_flag &= ~NLP_LOGO_SND;
James Smart2e0fef82007-06-17 19:56:36 -05001504 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001505 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001506 return 1;
dea31012005-04-17 16:05:31 -05001507 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001508 return 0;
dea31012005-04-17 16:05:31 -05001509}
1510
1511static void
James Smart2e0fef82007-06-17 19:56:36 -05001512lpfc_cmpl_els_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1513 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05001514{
James Smart2e0fef82007-06-17 19:56:36 -05001515 struct lpfc_vport *vport = cmdiocb->vport;
dea31012005-04-17 16:05:31 -05001516 IOCB_t *irsp;
1517
1518 irsp = &rspiocb->iocb;
1519
James Smart858c9f62007-06-17 19:56:39 -05001520 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1521 "ELS cmd cmpl: status:x%x/x%x did:x%x",
1522 irsp->ulpStatus, irsp->un.ulpWord[4],
1523 irsp->un.elsreq64.remoteID);
dea31012005-04-17 16:05:31 -05001524 /* ELS cmd tag <ulpIoTag> completes */
James Smarte8b62012007-08-02 11:10:09 -04001525 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
1526 "0106 ELS cmd tag x%x completes Data: x%x x%x x%x\n",
1527 irsp->ulpIoTag, irsp->ulpStatus,
1528 irsp->un.ulpWord[4], irsp->ulpTimeout);
dea31012005-04-17 16:05:31 -05001529 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -05001530 lpfc_els_chk_latt(vport);
dea31012005-04-17 16:05:31 -05001531 lpfc_els_free_iocb(phba, cmdiocb);
1532 return;
1533}
1534
1535int
James Smart2e0fef82007-06-17 19:56:36 -05001536lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
dea31012005-04-17 16:05:31 -05001537{
James Smart2e0fef82007-06-17 19:56:36 -05001538 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001539 IOCB_t *icmd;
1540 struct lpfc_iocbq *elsiocb;
1541 struct lpfc_sli_ring *pring;
1542 struct lpfc_sli *psli;
1543 uint8_t *pcmd;
1544 uint16_t cmdsize;
1545 struct lpfc_nodelist *ndlp;
1546
1547 psli = &phba->sli;
1548 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
James Smart92d7f7b2007-06-17 19:56:38 -05001549 cmdsize = (sizeof(uint32_t) + sizeof(SCR));
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001550 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
1551 if (!ndlp)
1552 return 1;
dea31012005-04-17 16:05:31 -05001553
James Smart2e0fef82007-06-17 19:56:36 -05001554 lpfc_nlp_init(vport, ndlp, nportid);
dea31012005-04-17 16:05:31 -05001555
James Smart2e0fef82007-06-17 19:56:36 -05001556 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
1557 ndlp->nlp_DID, ELS_CMD_SCR);
1558
James Smart488d1462006-03-07 15:02:37 -05001559 if (!elsiocb) {
James Smart329f9bc2007-04-25 09:53:01 -04001560 lpfc_nlp_put(ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001561 return 1;
dea31012005-04-17 16:05:31 -05001562 }
1563
1564 icmd = &elsiocb->iocb;
1565 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1566
1567 *((uint32_t *) (pcmd)) = ELS_CMD_SCR;
James Smart92d7f7b2007-06-17 19:56:38 -05001568 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05001569
1570 /* For SCR, remainder of payload is SCR parameter page */
James Smart92d7f7b2007-06-17 19:56:38 -05001571 memset(pcmd, 0, sizeof(SCR));
dea31012005-04-17 16:05:31 -05001572 ((SCR *) pcmd)->Function = SCR_FUNC_FULL;
1573
James Smart858c9f62007-06-17 19:56:39 -05001574 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1575 "Issue SCR: did:x%x",
1576 ndlp->nlp_DID, 0, 0);
1577
dea31012005-04-17 16:05:31 -05001578 phba->fc_stat.elsXmitSCR++;
1579 elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
dea31012005-04-17 16:05:31 -05001580 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
James Smart329f9bc2007-04-25 09:53:01 -04001581 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05001582 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001583 return 1;
dea31012005-04-17 16:05:31 -05001584 }
James Smart329f9bc2007-04-25 09:53:01 -04001585 lpfc_nlp_put(ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001586 return 0;
dea31012005-04-17 16:05:31 -05001587}
1588
1589static int
James Smart2e0fef82007-06-17 19:56:36 -05001590lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
dea31012005-04-17 16:05:31 -05001591{
James Smart2e0fef82007-06-17 19:56:36 -05001592 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001593 IOCB_t *icmd;
1594 struct lpfc_iocbq *elsiocb;
1595 struct lpfc_sli_ring *pring;
1596 struct lpfc_sli *psli;
1597 FARP *fp;
1598 uint8_t *pcmd;
1599 uint32_t *lp;
1600 uint16_t cmdsize;
1601 struct lpfc_nodelist *ondlp;
1602 struct lpfc_nodelist *ndlp;
1603
1604 psli = &phba->sli;
1605 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
James Smart92d7f7b2007-06-17 19:56:38 -05001606 cmdsize = (sizeof(uint32_t) + sizeof(FARP));
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001607 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
1608 if (!ndlp)
1609 return 1;
dea31012005-04-17 16:05:31 -05001610
James Smart2e0fef82007-06-17 19:56:36 -05001611 lpfc_nlp_init(vport, ndlp, nportid);
1612
1613 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
1614 ndlp->nlp_DID, ELS_CMD_RNID);
James Smart488d1462006-03-07 15:02:37 -05001615 if (!elsiocb) {
James Smart329f9bc2007-04-25 09:53:01 -04001616 lpfc_nlp_put(ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001617 return 1;
dea31012005-04-17 16:05:31 -05001618 }
1619
1620 icmd = &elsiocb->iocb;
1621 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
1622
1623 *((uint32_t *) (pcmd)) = ELS_CMD_FARPR;
James Smart92d7f7b2007-06-17 19:56:38 -05001624 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05001625
1626 /* Fill in FARPR payload */
1627 fp = (FARP *) (pcmd);
James Smart92d7f7b2007-06-17 19:56:38 -05001628 memset(fp, 0, sizeof(FARP));
dea31012005-04-17 16:05:31 -05001629 lp = (uint32_t *) pcmd;
1630 *lp++ = be32_to_cpu(nportid);
James Smart2e0fef82007-06-17 19:56:36 -05001631 *lp++ = be32_to_cpu(vport->fc_myDID);
dea31012005-04-17 16:05:31 -05001632 fp->Rflags = 0;
1633 fp->Mflags = (FARP_MATCH_PORT | FARP_MATCH_NODE);
1634
James Smart92d7f7b2007-06-17 19:56:38 -05001635 memcpy(&fp->RportName, &vport->fc_portname, sizeof(struct lpfc_name));
1636 memcpy(&fp->RnodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
James Smart2e0fef82007-06-17 19:56:36 -05001637 ondlp = lpfc_findnode_did(vport, nportid);
1638 if (ondlp) {
dea31012005-04-17 16:05:31 -05001639 memcpy(&fp->OportName, &ondlp->nlp_portname,
James Smart92d7f7b2007-06-17 19:56:38 -05001640 sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05001641 memcpy(&fp->OnodeName, &ondlp->nlp_nodename,
James Smart92d7f7b2007-06-17 19:56:38 -05001642 sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05001643 }
1644
James Smart858c9f62007-06-17 19:56:39 -05001645 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1646 "Issue FARPR: did:x%x",
1647 ndlp->nlp_DID, 0, 0);
1648
dea31012005-04-17 16:05:31 -05001649 phba->fc_stat.elsXmitFARPR++;
1650 elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
dea31012005-04-17 16:05:31 -05001651 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
James Smart329f9bc2007-04-25 09:53:01 -04001652 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05001653 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001654 return 1;
dea31012005-04-17 16:05:31 -05001655 }
James Smart329f9bc2007-04-25 09:53:01 -04001656 lpfc_nlp_put(ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001657 return 0;
dea31012005-04-17 16:05:31 -05001658}
1659
1660void
James Smart2e0fef82007-06-17 19:56:36 -05001661lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp)
James Smartfdcebe22006-03-07 15:04:01 -05001662{
James Smart2e0fef82007-06-17 19:56:36 -05001663 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1664
1665 spin_lock_irq(shost->host_lock);
James Smartfdcebe22006-03-07 15:04:01 -05001666 nlp->nlp_flag &= ~NLP_DELAY_TMO;
James Smart2e0fef82007-06-17 19:56:36 -05001667 spin_unlock_irq(shost->host_lock);
James Smartfdcebe22006-03-07 15:04:01 -05001668 del_timer_sync(&nlp->nlp_delayfunc);
1669 nlp->nlp_last_elscmd = 0;
1670
1671 if (!list_empty(&nlp->els_retry_evt.evt_listp))
1672 list_del_init(&nlp->els_retry_evt.evt_listp);
1673
1674 if (nlp->nlp_flag & NLP_NPR_2B_DISC) {
James Smart2e0fef82007-06-17 19:56:36 -05001675 spin_lock_irq(shost->host_lock);
James Smartfdcebe22006-03-07 15:04:01 -05001676 nlp->nlp_flag &= ~NLP_NPR_2B_DISC;
James Smart2e0fef82007-06-17 19:56:36 -05001677 spin_unlock_irq(shost->host_lock);
1678 if (vport->num_disc_nodes) {
James Smartfdcebe22006-03-07 15:04:01 -05001679 /* Check to see if there are more
1680 * PLOGIs to be sent
1681 */
James Smart2e0fef82007-06-17 19:56:36 -05001682 lpfc_more_plogi(vport);
James Smartfdcebe22006-03-07 15:04:01 -05001683
James Smart2e0fef82007-06-17 19:56:36 -05001684 if (vport->num_disc_nodes == 0) {
1685 spin_lock_irq(shost->host_lock);
1686 vport->fc_flag &= ~FC_NDISC_ACTIVE;
1687 spin_unlock_irq(shost->host_lock);
1688 lpfc_can_disctmo(vport);
James Smarted957682007-06-17 19:56:37 -05001689 lpfc_end_rscn(vport);
James Smartfdcebe22006-03-07 15:04:01 -05001690 }
1691 }
1692 }
1693 return;
1694}
1695
1696void
dea31012005-04-17 16:05:31 -05001697lpfc_els_retry_delay(unsigned long ptr)
1698{
James Smart2e0fef82007-06-17 19:56:36 -05001699 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) ptr;
1700 struct lpfc_vport *vport = ndlp->vport;
James Smart2e0fef82007-06-17 19:56:36 -05001701 struct lpfc_hba *phba = vport->phba;
James Smart92d7f7b2007-06-17 19:56:38 -05001702 unsigned long flags;
James Smart2e0fef82007-06-17 19:56:36 -05001703 struct lpfc_work_evt *evtp = &ndlp->els_retry_evt;
dea31012005-04-17 16:05:31 -05001704
James Smart2e0fef82007-06-17 19:56:36 -05001705 ndlp = (struct lpfc_nodelist *) ptr;
1706 phba = ndlp->vport->phba;
dea31012005-04-17 16:05:31 -05001707 evtp = &ndlp->els_retry_evt;
1708
James Smart92d7f7b2007-06-17 19:56:38 -05001709 spin_lock_irqsave(&phba->hbalock, flags);
dea31012005-04-17 16:05:31 -05001710 if (!list_empty(&evtp->evt_listp)) {
James Smart92d7f7b2007-06-17 19:56:38 -05001711 spin_unlock_irqrestore(&phba->hbalock, flags);
dea31012005-04-17 16:05:31 -05001712 return;
1713 }
1714
1715 evtp->evt_arg1 = ndlp;
1716 evtp->evt = LPFC_EVT_ELS_RETRY;
1717 list_add_tail(&evtp->evt_listp, &phba->work_list);
1718 if (phba->work_wait)
James Smart92d7f7b2007-06-17 19:56:38 -05001719 lpfc_worker_wake_up(phba);
dea31012005-04-17 16:05:31 -05001720
James Smart92d7f7b2007-06-17 19:56:38 -05001721 spin_unlock_irqrestore(&phba->hbalock, flags);
dea31012005-04-17 16:05:31 -05001722 return;
1723}
1724
1725void
1726lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp)
1727{
James Smart2e0fef82007-06-17 19:56:36 -05001728 struct lpfc_vport *vport = ndlp->vport;
1729 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1730 uint32_t cmd, did, retry;
dea31012005-04-17 16:05:31 -05001731
James Smart2e0fef82007-06-17 19:56:36 -05001732 spin_lock_irq(shost->host_lock);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001733 did = ndlp->nlp_DID;
1734 cmd = ndlp->nlp_last_elscmd;
1735 ndlp->nlp_last_elscmd = 0;
dea31012005-04-17 16:05:31 -05001736
1737 if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
James Smart2e0fef82007-06-17 19:56:36 -05001738 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001739 return;
1740 }
1741
1742 ndlp->nlp_flag &= ~NLP_DELAY_TMO;
James Smart2e0fef82007-06-17 19:56:36 -05001743 spin_unlock_irq(shost->host_lock);
James Smart1a169682006-03-07 15:04:06 -05001744 /*
1745 * If a discovery event readded nlp_delayfunc after timer
1746 * firing and before processing the timer, cancel the
1747 * nlp_delayfunc.
1748 */
1749 del_timer_sync(&ndlp->nlp_delayfunc);
dea31012005-04-17 16:05:31 -05001750 retry = ndlp->nlp_retry;
1751
1752 switch (cmd) {
1753 case ELS_CMD_FLOGI:
James Smart2e0fef82007-06-17 19:56:36 -05001754 lpfc_issue_els_flogi(vport, ndlp, retry);
dea31012005-04-17 16:05:31 -05001755 break;
1756 case ELS_CMD_PLOGI:
James Smart2e0fef82007-06-17 19:56:36 -05001757 if (!lpfc_issue_els_plogi(vport, ndlp->nlp_DID, retry)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001758 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001759 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
Jamie Wellnitz6ad42532006-02-28 19:25:16 -05001760 }
dea31012005-04-17 16:05:31 -05001761 break;
1762 case ELS_CMD_ADISC:
James Smart2e0fef82007-06-17 19:56:36 -05001763 if (!lpfc_issue_els_adisc(vport, ndlp, retry)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001764 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001765 lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
Jamie Wellnitz6ad42532006-02-28 19:25:16 -05001766 }
dea31012005-04-17 16:05:31 -05001767 break;
1768 case ELS_CMD_PRLI:
James Smart2e0fef82007-06-17 19:56:36 -05001769 if (!lpfc_issue_els_prli(vport, ndlp, retry)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001770 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001771 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
Jamie Wellnitz6ad42532006-02-28 19:25:16 -05001772 }
dea31012005-04-17 16:05:31 -05001773 break;
1774 case ELS_CMD_LOGO:
James Smart2e0fef82007-06-17 19:56:36 -05001775 if (!lpfc_issue_els_logo(vport, ndlp, retry)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001776 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001777 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
Jamie Wellnitz6ad42532006-02-28 19:25:16 -05001778 }
dea31012005-04-17 16:05:31 -05001779 break;
James Smart92d7f7b2007-06-17 19:56:38 -05001780 case ELS_CMD_FDISC:
1781 lpfc_issue_els_fdisc(vport, ndlp, retry);
1782 break;
dea31012005-04-17 16:05:31 -05001783 }
1784 return;
1785}
1786
1787static int
James Smart2e0fef82007-06-17 19:56:36 -05001788lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
1789 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05001790{
James Smart2e0fef82007-06-17 19:56:36 -05001791 struct lpfc_vport *vport = cmdiocb->vport;
1792 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1793 IOCB_t *irsp = &rspiocb->iocb;
1794 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
1795 struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
dea31012005-04-17 16:05:31 -05001796 uint32_t *elscmd;
1797 struct ls_rjt stat;
James Smart2e0fef82007-06-17 19:56:36 -05001798 int retry = 0, maxretry = lpfc_max_els_tries, delay = 0;
James Smart98c9ea52007-10-27 13:37:33 -04001799 int logerr = 0;
James Smart2e0fef82007-06-17 19:56:36 -05001800 uint32_t cmd = 0;
James Smart488d1462006-03-07 15:02:37 -05001801 uint32_t did;
dea31012005-04-17 16:05:31 -05001802
James Smart488d1462006-03-07 15:02:37 -05001803
dea31012005-04-17 16:05:31 -05001804 /* Note: context2 may be 0 for internal driver abort
1805 * of delays ELS command.
1806 */
1807
1808 if (pcmd && pcmd->virt) {
1809 elscmd = (uint32_t *) (pcmd->virt);
1810 cmd = *elscmd++;
1811 }
1812
James Smart329f9bc2007-04-25 09:53:01 -04001813 if (ndlp)
James Smart488d1462006-03-07 15:02:37 -05001814 did = ndlp->nlp_DID;
1815 else {
1816 /* We should only hit this case for retrying PLOGI */
1817 did = irsp->un.elsreq64.remoteID;
James Smart2e0fef82007-06-17 19:56:36 -05001818 ndlp = lpfc_findnode_did(vport, did);
James Smart488d1462006-03-07 15:02:37 -05001819 if (!ndlp && (cmd != ELS_CMD_PLOGI))
1820 return 1;
1821 }
1822
James Smart858c9f62007-06-17 19:56:39 -05001823 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
1824 "Retry ELS: wd7:x%x wd4:x%x did:x%x",
1825 *(((uint32_t *) irsp) + 7), irsp->un.ulpWord[4], ndlp->nlp_DID);
1826
dea31012005-04-17 16:05:31 -05001827 switch (irsp->ulpStatus) {
1828 case IOSTAT_FCP_RSP_ERROR:
1829 case IOSTAT_REMOTE_STOP:
1830 break;
1831
1832 case IOSTAT_LOCAL_REJECT:
1833 switch ((irsp->un.ulpWord[4] & 0xff)) {
1834 case IOERR_LOOP_OPEN_FAILURE:
James Smart2e0fef82007-06-17 19:56:36 -05001835 if (cmd == ELS_CMD_PLOGI && cmdiocb->retry == 0)
James Smart92d7f7b2007-06-17 19:56:38 -05001836 delay = 1000;
dea31012005-04-17 16:05:31 -05001837 retry = 1;
1838 break;
1839
James Smart92d7f7b2007-06-17 19:56:38 -05001840 case IOERR_ILLEGAL_COMMAND:
1841 if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) &&
1842 (cmd == ELS_CMD_FDISC)) {
James Smarte8b62012007-08-02 11:10:09 -04001843 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
1844 "0124 FDISC failed (3/6) "
1845 "retrying...\n");
James Smart92d7f7b2007-06-17 19:56:38 -05001846 lpfc_mbx_unreg_vpi(vport);
1847 retry = 1;
James Smart51ef4c22007-08-02 11:10:31 -04001848 /* FDISC retry policy */
1849 maxretry = 48;
1850 if (cmdiocb->retry >= 32)
1851 delay = 1000;
James Smart92d7f7b2007-06-17 19:56:38 -05001852 }
1853 break;
1854
dea31012005-04-17 16:05:31 -05001855 case IOERR_NO_RESOURCES:
James Smart98c9ea52007-10-27 13:37:33 -04001856 logerr = 1; /* HBA out of resources */
James Smart858c9f62007-06-17 19:56:39 -05001857 retry = 1;
1858 if (cmdiocb->retry > 100)
1859 delay = 100;
1860 maxretry = 250;
1861 break;
1862
1863 case IOERR_ILLEGAL_FRAME:
James Smart92d7f7b2007-06-17 19:56:38 -05001864 delay = 100;
dea31012005-04-17 16:05:31 -05001865 retry = 1;
1866 break;
1867
James Smart858c9f62007-06-17 19:56:39 -05001868 case IOERR_SEQUENCE_TIMEOUT:
dea31012005-04-17 16:05:31 -05001869 case IOERR_INVALID_RPI:
1870 retry = 1;
1871 break;
1872 }
1873 break;
1874
1875 case IOSTAT_NPORT_RJT:
1876 case IOSTAT_FABRIC_RJT:
1877 if (irsp->un.ulpWord[4] & RJT_UNAVAIL_TEMP) {
1878 retry = 1;
1879 break;
1880 }
1881 break;
1882
1883 case IOSTAT_NPORT_BSY:
1884 case IOSTAT_FABRIC_BSY:
James Smart98c9ea52007-10-27 13:37:33 -04001885 logerr = 1; /* Fabric / Remote NPort out of resources */
dea31012005-04-17 16:05:31 -05001886 retry = 1;
1887 break;
1888
1889 case IOSTAT_LS_RJT:
1890 stat.un.lsRjtError = be32_to_cpu(irsp->un.ulpWord[4]);
1891 /* Added for Vendor specifc support
1892 * Just keep retrying for these Rsn / Exp codes
1893 */
1894 switch (stat.un.b.lsRjtRsnCode) {
1895 case LSRJT_UNABLE_TPC:
1896 if (stat.un.b.lsRjtRsnCodeExp ==
1897 LSEXP_CMD_IN_PROGRESS) {
1898 if (cmd == ELS_CMD_PLOGI) {
James Smart92d7f7b2007-06-17 19:56:38 -05001899 delay = 1000;
dea31012005-04-17 16:05:31 -05001900 maxretry = 48;
1901 }
1902 retry = 1;
1903 break;
1904 }
1905 if (cmd == ELS_CMD_PLOGI) {
James Smart92d7f7b2007-06-17 19:56:38 -05001906 delay = 1000;
dea31012005-04-17 16:05:31 -05001907 maxretry = lpfc_max_els_tries + 1;
1908 retry = 1;
1909 break;
1910 }
James Smart92d7f7b2007-06-17 19:56:38 -05001911 if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
1912 (cmd == ELS_CMD_FDISC) &&
1913 (stat.un.b.lsRjtRsnCodeExp == LSEXP_OUT_OF_RESOURCE)){
James Smarte8b62012007-08-02 11:10:09 -04001914 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
1915 "0125 FDISC Failed (x%x). "
1916 "Fabric out of resources\n",
1917 stat.un.lsRjtError);
James Smart92d7f7b2007-06-17 19:56:38 -05001918 lpfc_vport_set_state(vport,
1919 FC_VPORT_NO_FABRIC_RSCS);
1920 }
dea31012005-04-17 16:05:31 -05001921 break;
1922
1923 case LSRJT_LOGICAL_BSY:
James Smart858c9f62007-06-17 19:56:39 -05001924 if ((cmd == ELS_CMD_PLOGI) ||
1925 (cmd == ELS_CMD_PRLI)) {
James Smart92d7f7b2007-06-17 19:56:38 -05001926 delay = 1000;
dea31012005-04-17 16:05:31 -05001927 maxretry = 48;
James Smart92d7f7b2007-06-17 19:56:38 -05001928 } else if (cmd == ELS_CMD_FDISC) {
James Smart51ef4c22007-08-02 11:10:31 -04001929 /* FDISC retry policy */
1930 maxretry = 48;
1931 if (cmdiocb->retry >= 32)
1932 delay = 1000;
dea31012005-04-17 16:05:31 -05001933 }
1934 retry = 1;
1935 break;
James Smart92d7f7b2007-06-17 19:56:38 -05001936
1937 case LSRJT_LOGICAL_ERR:
1938 case LSRJT_PROTOCOL_ERR:
1939 if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
1940 (cmd == ELS_CMD_FDISC) &&
1941 ((stat.un.b.lsRjtRsnCodeExp == LSEXP_INVALID_PNAME) ||
1942 (stat.un.b.lsRjtRsnCodeExp == LSEXP_INVALID_NPORT_ID))
1943 ) {
James Smarte8b62012007-08-02 11:10:09 -04001944 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
1945 "0123 FDISC Failed (x%x). "
1946 "Fabric Detected Bad WWN\n",
1947 stat.un.lsRjtError);
James Smart92d7f7b2007-06-17 19:56:38 -05001948 lpfc_vport_set_state(vport,
1949 FC_VPORT_FABRIC_REJ_WWN);
1950 }
1951 break;
dea31012005-04-17 16:05:31 -05001952 }
1953 break;
1954
1955 case IOSTAT_INTERMED_RSP:
1956 case IOSTAT_BA_RJT:
1957 break;
1958
1959 default:
1960 break;
1961 }
1962
James Smart488d1462006-03-07 15:02:37 -05001963 if (did == FDMI_DID)
dea31012005-04-17 16:05:31 -05001964 retry = 1;
dea31012005-04-17 16:05:31 -05001965
James Smart98c9ea52007-10-27 13:37:33 -04001966 if ((cmd == ELS_CMD_FLOGI) &&
1967 (phba->fc_topology != TOPOLOGY_LOOP)) {
1968 /* FLOGI retry policy */
1969 retry = 1;
1970 maxretry = 48;
1971 if (cmdiocb->retry >= 32)
1972 delay = 1000;
1973 }
1974
dea31012005-04-17 16:05:31 -05001975 if ((++cmdiocb->retry) >= maxretry) {
1976 phba->fc_stat.elsRetryExceeded++;
1977 retry = 0;
1978 }
1979
James Smarted957682007-06-17 19:56:37 -05001980 if ((vport->load_flag & FC_UNLOADING) != 0)
1981 retry = 0;
1982
dea31012005-04-17 16:05:31 -05001983 if (retry) {
1984
1985 /* Retry ELS command <elsCmd> to remote NPORT <did> */
James Smarte8b62012007-08-02 11:10:09 -04001986 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
1987 "0107 Retry ELS command x%x to remote "
1988 "NPORT x%x Data: x%x x%x\n",
1989 cmd, did, cmdiocb->retry, delay);
dea31012005-04-17 16:05:31 -05001990
James Smart858c9f62007-06-17 19:56:39 -05001991 if (((cmd == ELS_CMD_PLOGI) || (cmd == ELS_CMD_ADISC)) &&
1992 ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
1993 ((irsp->un.ulpWord[4] & 0xff) != IOERR_NO_RESOURCES))) {
1994 /* Don't reset timer for no resources */
1995
dea31012005-04-17 16:05:31 -05001996 /* If discovery / RSCN timer is running, reset it */
James Smart2e0fef82007-06-17 19:56:36 -05001997 if (timer_pending(&vport->fc_disctmo) ||
James Smart92d7f7b2007-06-17 19:56:38 -05001998 (vport->fc_flag & FC_RSCN_MODE))
James Smart2e0fef82007-06-17 19:56:36 -05001999 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -05002000 }
2001
2002 phba->fc_stat.elsXmitRetry++;
James Smart488d1462006-03-07 15:02:37 -05002003 if (ndlp && delay) {
dea31012005-04-17 16:05:31 -05002004 phba->fc_stat.elsDelayRetry++;
2005 ndlp->nlp_retry = cmdiocb->retry;
2006
James Smart92d7f7b2007-06-17 19:56:38 -05002007 /* delay is specified in milliseconds */
2008 mod_timer(&ndlp->nlp_delayfunc,
2009 jiffies + msecs_to_jiffies(delay));
James Smart2e0fef82007-06-17 19:56:36 -05002010 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05002011 ndlp->nlp_flag |= NLP_DELAY_TMO;
James Smart2e0fef82007-06-17 19:56:36 -05002012 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05002013
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05002014 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart858c9f62007-06-17 19:56:39 -05002015 if (cmd == ELS_CMD_PRLI)
2016 lpfc_nlp_set_state(vport, ndlp,
2017 NLP_STE_REG_LOGIN_ISSUE);
2018 else
2019 lpfc_nlp_set_state(vport, ndlp,
2020 NLP_STE_NPR_NODE);
dea31012005-04-17 16:05:31 -05002021 ndlp->nlp_last_elscmd = cmd;
2022
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002023 return 1;
dea31012005-04-17 16:05:31 -05002024 }
2025 switch (cmd) {
2026 case ELS_CMD_FLOGI:
James Smart2e0fef82007-06-17 19:56:36 -05002027 lpfc_issue_els_flogi(vport, ndlp, cmdiocb->retry);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002028 return 1;
James Smart92d7f7b2007-06-17 19:56:38 -05002029 case ELS_CMD_FDISC:
2030 lpfc_issue_els_fdisc(vport, ndlp, cmdiocb->retry);
2031 return 1;
dea31012005-04-17 16:05:31 -05002032 case ELS_CMD_PLOGI:
James Smart488d1462006-03-07 15:02:37 -05002033 if (ndlp) {
2034 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002035 lpfc_nlp_set_state(vport, ndlp,
James Smartde0c5b32007-04-25 09:52:27 -04002036 NLP_STE_PLOGI_ISSUE);
James Smart488d1462006-03-07 15:02:37 -05002037 }
James Smart2e0fef82007-06-17 19:56:36 -05002038 lpfc_issue_els_plogi(vport, did, cmdiocb->retry);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002039 return 1;
dea31012005-04-17 16:05:31 -05002040 case ELS_CMD_ADISC:
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05002041 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002042 lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
2043 lpfc_issue_els_adisc(vport, ndlp, cmdiocb->retry);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002044 return 1;
dea31012005-04-17 16:05:31 -05002045 case ELS_CMD_PRLI:
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05002046 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002047 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
2048 lpfc_issue_els_prli(vport, ndlp, cmdiocb->retry);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002049 return 1;
dea31012005-04-17 16:05:31 -05002050 case ELS_CMD_LOGO:
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05002051 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002052 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
2053 lpfc_issue_els_logo(vport, ndlp, cmdiocb->retry);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002054 return 1;
dea31012005-04-17 16:05:31 -05002055 }
2056 }
dea31012005-04-17 16:05:31 -05002057 /* No retry ELS command <elsCmd> to remote NPORT <did> */
James Smart98c9ea52007-10-27 13:37:33 -04002058 if (logerr) {
2059 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
2060 "0137 No retry ELS command x%x to remote "
2061 "NPORT x%x: Out of Resources: Error:x%x/%x\n",
2062 cmd, did, irsp->ulpStatus,
2063 irsp->un.ulpWord[4]);
2064 }
2065 else {
2066 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
James Smarta58cbd52007-08-02 11:09:43 -04002067 "0108 No retry ELS command x%x to remote "
2068 "NPORT x%x Retried:%d Error:x%x/%x\n",
2069 cmd, did, cmdiocb->retry, irsp->ulpStatus,
2070 irsp->un.ulpWord[4]);
James Smart98c9ea52007-10-27 13:37:33 -04002071 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002072 return 0;
dea31012005-04-17 16:05:31 -05002073}
2074
James Smart09372822008-01-11 01:52:54 -05002075static int
James Smart87af33f2007-10-27 13:37:43 -04002076lpfc_els_free_data(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr1)
2077{
2078 struct lpfc_dmabuf *buf_ptr;
2079
2080 /* Free the response before processing the command. */
2081 if (!list_empty(&buf_ptr1->list)) {
2082 list_remove_head(&buf_ptr1->list, buf_ptr,
2083 struct lpfc_dmabuf,
2084 list);
2085 lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
2086 kfree(buf_ptr);
2087 }
2088 lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys);
2089 kfree(buf_ptr1);
2090 return 0;
2091}
2092
James Smart09372822008-01-11 01:52:54 -05002093static int
James Smart87af33f2007-10-27 13:37:43 -04002094lpfc_els_free_bpl(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr)
2095{
2096 lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
2097 kfree(buf_ptr);
2098 return 0;
2099}
2100
2101int
James Smart329f9bc2007-04-25 09:53:01 -04002102lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
dea31012005-04-17 16:05:31 -05002103{
2104 struct lpfc_dmabuf *buf_ptr, *buf_ptr1;
James Smarta8adb832007-10-27 13:37:53 -04002105 struct lpfc_nodelist *ndlp;
dea31012005-04-17 16:05:31 -05002106
James Smarta8adb832007-10-27 13:37:53 -04002107 ndlp = (struct lpfc_nodelist *)elsiocb->context1;
2108 if (ndlp) {
2109 if (ndlp->nlp_flag & NLP_DEFER_RM) {
2110 lpfc_nlp_put(ndlp);
2111
2112 /* If the ndlp is not being used by another discovery
2113 * thread, free it.
2114 */
2115 if (!lpfc_nlp_not_used(ndlp)) {
2116 /* If ndlp is being used by another discovery
2117 * thread, just clear NLP_DEFER_RM
2118 */
2119 ndlp->nlp_flag &= ~NLP_DEFER_RM;
2120 }
2121 }
2122 else
2123 lpfc_nlp_put(ndlp);
James Smart329f9bc2007-04-25 09:53:01 -04002124 elsiocb->context1 = NULL;
2125 }
dea31012005-04-17 16:05:31 -05002126 /* context2 = cmd, context2->next = rsp, context3 = bpl */
2127 if (elsiocb->context2) {
James Smart0ff10d42008-01-11 01:52:36 -05002128 if (elsiocb->iocb_flag & LPFC_DELAY_MEM_FREE) {
2129 /* Firmware could still be in progress of DMAing
2130 * payload, so don't free data buffer till after
2131 * a hbeat.
2132 */
2133 elsiocb->iocb_flag &= ~LPFC_DELAY_MEM_FREE;
2134 buf_ptr = elsiocb->context2;
2135 elsiocb->context2 = NULL;
2136 if (buf_ptr) {
2137 buf_ptr1 = NULL;
2138 spin_lock_irq(&phba->hbalock);
2139 if (!list_empty(&buf_ptr->list)) {
2140 list_remove_head(&buf_ptr->list,
2141 buf_ptr1, struct lpfc_dmabuf,
2142 list);
2143 INIT_LIST_HEAD(&buf_ptr1->list);
2144 list_add_tail(&buf_ptr1->list,
2145 &phba->elsbuf);
2146 phba->elsbuf_cnt++;
2147 }
2148 INIT_LIST_HEAD(&buf_ptr->list);
2149 list_add_tail(&buf_ptr->list, &phba->elsbuf);
2150 phba->elsbuf_cnt++;
2151 spin_unlock_irq(&phba->hbalock);
2152 }
2153 } else {
2154 buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
2155 lpfc_els_free_data(phba, buf_ptr1);
2156 }
dea31012005-04-17 16:05:31 -05002157 }
2158
2159 if (elsiocb->context3) {
2160 buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3;
James Smart87af33f2007-10-27 13:37:43 -04002161 lpfc_els_free_bpl(phba, buf_ptr);
dea31012005-04-17 16:05:31 -05002162 }
James Bottomley604a3e32005-10-29 10:28:33 -05002163 lpfc_sli_release_iocbq(phba, elsiocb);
dea31012005-04-17 16:05:31 -05002164 return 0;
2165}
2166
2167static void
James Smart2e0fef82007-06-17 19:56:36 -05002168lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
2169 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05002170{
James Smart2e0fef82007-06-17 19:56:36 -05002171 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
2172 struct lpfc_vport *vport = cmdiocb->vport;
James Smart858c9f62007-06-17 19:56:39 -05002173 IOCB_t *irsp;
2174
2175 irsp = &rspiocb->iocb;
2176 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2177 "ACC LOGO cmpl: status:x%x/x%x did:x%x",
2178 irsp->ulpStatus, irsp->un.ulpWord[4], ndlp->nlp_DID);
dea31012005-04-17 16:05:31 -05002179 /* ACC to LOGO completes to NPort <nlp_DID> */
James Smarte8b62012007-08-02 11:10:09 -04002180 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
2181 "0109 ACC to LOGO completes to NPort x%x "
2182 "Data: x%x x%x x%x\n",
2183 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
2184 ndlp->nlp_rpi);
James Smart87af33f2007-10-27 13:37:43 -04002185
2186 if (ndlp->nlp_state == NLP_STE_NPR_NODE) {
2187 /* NPort Recovery mode or node is just allocated */
2188 if (!lpfc_nlp_not_used(ndlp)) {
2189 /* If the ndlp is being used by another discovery
2190 * thread, just unregister the RPI.
2191 */
2192 lpfc_unreg_rpi(vport, ndlp);
2193 }
dea31012005-04-17 16:05:31 -05002194 }
2195 lpfc_els_free_iocb(phba, cmdiocb);
2196 return;
2197}
2198
James Smart858c9f62007-06-17 19:56:39 -05002199void
2200lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
2201{
2202 struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
2203 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
2204
2205 pmb->context1 = NULL;
2206 lpfc_mbuf_free(phba, mp->virt, mp->phys);
2207 kfree(mp);
2208 mempool_free(pmb, phba->mbox_mem_pool);
James Smarta8adb832007-10-27 13:37:53 -04002209 if (ndlp) {
2210 lpfc_nlp_put(ndlp);
James Smart98c9ea52007-10-27 13:37:33 -04002211
James Smarta8adb832007-10-27 13:37:53 -04002212 /* This is the end of the default RPI cleanup logic for this
2213 * ndlp. If no other discovery threads are using this ndlp.
2214 * we should free all resources associated with it.
2215 */
2216 lpfc_nlp_not_used(ndlp);
2217 }
James Smart858c9f62007-06-17 19:56:39 -05002218 return;
2219}
2220
dea31012005-04-17 16:05:31 -05002221static void
James Smart858c9f62007-06-17 19:56:39 -05002222lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
James Smart329f9bc2007-04-25 09:53:01 -04002223 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -05002224{
James Smart2e0fef82007-06-17 19:56:36 -05002225 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
2226 struct lpfc_vport *vport = ndlp ? ndlp->vport : NULL;
2227 struct Scsi_Host *shost = vport ? lpfc_shost_from_vport(vport) : NULL;
James Smart87af33f2007-10-27 13:37:43 -04002228 IOCB_t *irsp;
2229 uint8_t *pcmd;
dea31012005-04-17 16:05:31 -05002230 LPFC_MBOXQ_t *mbox = NULL;
James Smart2e0fef82007-06-17 19:56:36 -05002231 struct lpfc_dmabuf *mp = NULL;
James Smart87af33f2007-10-27 13:37:43 -04002232 uint32_t ls_rjt = 0;
dea31012005-04-17 16:05:31 -05002233
James Smart33ccf8d2006-08-17 11:57:58 -04002234 irsp = &rspiocb->iocb;
2235
dea31012005-04-17 16:05:31 -05002236 if (cmdiocb->context_un.mbox)
2237 mbox = cmdiocb->context_un.mbox;
2238
James Smart87af33f2007-10-27 13:37:43 -04002239 /* First determine if this is a LS_RJT cmpl */
2240 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) cmdiocb->context2)->virt);
2241 if (*((uint32_t *) (pcmd)) == ELS_CMD_LS_RJT) {
2242 /* A LS_RJT associated with Default RPI cleanup
2243 * has its own seperate code path.
2244 */
2245 if (!(ndlp->nlp_flag & NLP_RM_DFLT_RPI))
2246 ls_rjt = 1;
2247 }
2248
dea31012005-04-17 16:05:31 -05002249 /* Check to see if link went down during discovery */
James Smart2e0fef82007-06-17 19:56:36 -05002250 if (!ndlp || lpfc_els_chk_latt(vport)) {
dea31012005-04-17 16:05:31 -05002251 if (mbox) {
James Smart14691152006-12-02 13:34:28 -05002252 mp = (struct lpfc_dmabuf *) mbox->context1;
2253 if (mp) {
2254 lpfc_mbuf_free(phba, mp->virt, mp->phys);
2255 kfree(mp);
2256 }
James Smart329f9bc2007-04-25 09:53:01 -04002257 mempool_free(mbox, phba->mbox_mem_pool);
dea31012005-04-17 16:05:31 -05002258 }
James Smart98c9ea52007-10-27 13:37:33 -04002259 if (ndlp && (ndlp->nlp_flag & NLP_RM_DFLT_RPI))
2260 if (lpfc_nlp_not_used(ndlp))
2261 ndlp = NULL;
dea31012005-04-17 16:05:31 -05002262 goto out;
2263 }
2264
James Smart858c9f62007-06-17 19:56:39 -05002265 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
James Smart51ef4c22007-08-02 11:10:31 -04002266 "ELS rsp cmpl: status:x%x/x%x did:x%x",
James Smart858c9f62007-06-17 19:56:39 -05002267 irsp->ulpStatus, irsp->un.ulpWord[4],
James Smart51ef4c22007-08-02 11:10:31 -04002268 cmdiocb->iocb.un.elsreq64.remoteID);
dea31012005-04-17 16:05:31 -05002269 /* ELS response tag <ulpIoTag> completes */
James Smarte8b62012007-08-02 11:10:09 -04002270 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
2271 "0110 ELS response tag x%x completes "
2272 "Data: x%x x%x x%x x%x x%x x%x x%x\n",
2273 cmdiocb->iocb.ulpIoTag, rspiocb->iocb.ulpStatus,
2274 rspiocb->iocb.un.ulpWord[4], rspiocb->iocb.ulpTimeout,
2275 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
2276 ndlp->nlp_rpi);
dea31012005-04-17 16:05:31 -05002277 if (mbox) {
2278 if ((rspiocb->iocb.ulpStatus == 0)
2279 && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) {
James Smart2e0fef82007-06-17 19:56:36 -05002280 lpfc_unreg_rpi(vport, ndlp);
James Smart329f9bc2007-04-25 09:53:01 -04002281 mbox->context2 = lpfc_nlp_get(ndlp);
James Smart2e0fef82007-06-17 19:56:36 -05002282 mbox->vport = vport;
James Smart858c9f62007-06-17 19:56:39 -05002283 if (ndlp->nlp_flag & NLP_RM_DFLT_RPI) {
2284 mbox->mbox_flag |= LPFC_MBX_IMED_UNREG;
2285 mbox->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;
2286 }
2287 else {
2288 mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
2289 ndlp->nlp_prev_state = ndlp->nlp_state;
2290 lpfc_nlp_set_state(vport, ndlp,
James Smart2e0fef82007-06-17 19:56:36 -05002291 NLP_STE_REG_LOGIN_ISSUE);
James Smart858c9f62007-06-17 19:56:39 -05002292 }
James Smart0b727fe2007-10-27 13:37:25 -04002293 if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
dea31012005-04-17 16:05:31 -05002294 != MBX_NOT_FINISHED) {
2295 goto out;
2296 }
James Smart98c9ea52007-10-27 13:37:33 -04002297
2298 /* ELS rsp: Cannot issue reg_login for <NPortid> */
2299 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
2300 "0138 ELS rsp: Cannot issue reg_login for x%x "
2301 "Data: x%x x%x x%x\n",
2302 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
2303 ndlp->nlp_rpi);
2304
2305 if (lpfc_nlp_not_used(ndlp))
2306 ndlp = NULL;
dea31012005-04-17 16:05:31 -05002307 } else {
James Smart858c9f62007-06-17 19:56:39 -05002308 /* Do not drop node for lpfc_els_abort'ed ELS cmds */
2309 if (!lpfc_error_lost_link(irsp) &&
2310 ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
James Smart98c9ea52007-10-27 13:37:33 -04002311 if (lpfc_nlp_not_used(ndlp))
2312 ndlp = NULL;
dea31012005-04-17 16:05:31 -05002313 }
2314 }
James Smart14691152006-12-02 13:34:28 -05002315 mp = (struct lpfc_dmabuf *) mbox->context1;
2316 if (mp) {
2317 lpfc_mbuf_free(phba, mp->virt, mp->phys);
2318 kfree(mp);
2319 }
2320 mempool_free(mbox, phba->mbox_mem_pool);
dea31012005-04-17 16:05:31 -05002321 }
2322out:
2323 if (ndlp) {
James Smart2e0fef82007-06-17 19:56:36 -05002324 spin_lock_irq(shost->host_lock);
James Smart858c9f62007-06-17 19:56:39 -05002325 ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI);
James Smart2e0fef82007-06-17 19:56:36 -05002326 spin_unlock_irq(shost->host_lock);
James Smart87af33f2007-10-27 13:37:43 -04002327
2328 /* If the node is not being used by another discovery thread,
2329 * and we are sending a reject, we are done with it.
2330 * Release driver reference count here and free associated
2331 * resources.
2332 */
2333 if (ls_rjt)
2334 lpfc_nlp_not_used(ndlp);
dea31012005-04-17 16:05:31 -05002335 }
James Smart87af33f2007-10-27 13:37:43 -04002336
dea31012005-04-17 16:05:31 -05002337 lpfc_els_free_iocb(phba, cmdiocb);
2338 return;
2339}
2340
2341int
James Smart2e0fef82007-06-17 19:56:36 -05002342lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
2343 struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp,
James Smart51ef4c22007-08-02 11:10:31 -04002344 LPFC_MBOXQ_t *mbox)
dea31012005-04-17 16:05:31 -05002345{
James Smart2e0fef82007-06-17 19:56:36 -05002346 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
2347 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002348 IOCB_t *icmd;
2349 IOCB_t *oldcmd;
2350 struct lpfc_iocbq *elsiocb;
2351 struct lpfc_sli_ring *pring;
2352 struct lpfc_sli *psli;
2353 uint8_t *pcmd;
2354 uint16_t cmdsize;
2355 int rc;
James Smart82d9a2a2006-04-15 11:53:05 -04002356 ELS_PKT *els_pkt_ptr;
dea31012005-04-17 16:05:31 -05002357
2358 psli = &phba->sli;
2359 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
2360 oldcmd = &oldiocb->iocb;
2361
2362 switch (flag) {
2363 case ELS_CMD_ACC:
James Smart92d7f7b2007-06-17 19:56:38 -05002364 cmdsize = sizeof(uint32_t);
James Smart2e0fef82007-06-17 19:56:36 -05002365 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
2366 ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
James Smart488d1462006-03-07 15:02:37 -05002367 if (!elsiocb) {
James Smart2e0fef82007-06-17 19:56:36 -05002368 spin_lock_irq(shost->host_lock);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05002369 ndlp->nlp_flag &= ~NLP_LOGO_ACC;
James Smart2e0fef82007-06-17 19:56:36 -05002370 spin_unlock_irq(shost->host_lock);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002371 return 1;
dea31012005-04-17 16:05:31 -05002372 }
James Smart2e0fef82007-06-17 19:56:36 -05002373
dea31012005-04-17 16:05:31 -05002374 icmd = &elsiocb->iocb;
2375 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
2376 pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2377 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
James Smart92d7f7b2007-06-17 19:56:38 -05002378 pcmd += sizeof(uint32_t);
James Smart858c9f62007-06-17 19:56:39 -05002379
2380 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2381 "Issue ACC: did:x%x flg:x%x",
2382 ndlp->nlp_DID, ndlp->nlp_flag, 0);
dea31012005-04-17 16:05:31 -05002383 break;
2384 case ELS_CMD_PLOGI:
James Smart92d7f7b2007-06-17 19:56:38 -05002385 cmdsize = (sizeof(struct serv_parm) + sizeof(uint32_t));
James Smart2e0fef82007-06-17 19:56:36 -05002386 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
2387 ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
James Smart488d1462006-03-07 15:02:37 -05002388 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002389 return 1;
James Smart488d1462006-03-07 15:02:37 -05002390
dea31012005-04-17 16:05:31 -05002391 icmd = &elsiocb->iocb;
2392 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
2393 pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2394
2395 if (mbox)
2396 elsiocb->context_un.mbox = mbox;
2397
2398 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
James Smart92d7f7b2007-06-17 19:56:38 -05002399 pcmd += sizeof(uint32_t);
2400 memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
James Smart858c9f62007-06-17 19:56:39 -05002401
2402 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2403 "Issue ACC PLOGI: did:x%x flg:x%x",
2404 ndlp->nlp_DID, ndlp->nlp_flag, 0);
dea31012005-04-17 16:05:31 -05002405 break;
James Smart82d9a2a2006-04-15 11:53:05 -04002406 case ELS_CMD_PRLO:
James Smart92d7f7b2007-06-17 19:56:38 -05002407 cmdsize = sizeof(uint32_t) + sizeof(PRLO);
James Smart2e0fef82007-06-17 19:56:36 -05002408 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
James Smart82d9a2a2006-04-15 11:53:05 -04002409 ndlp, ndlp->nlp_DID, ELS_CMD_PRLO);
2410 if (!elsiocb)
2411 return 1;
2412
2413 icmd = &elsiocb->iocb;
2414 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
2415 pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2416
2417 memcpy(pcmd, ((struct lpfc_dmabuf *) oldiocb->context2)->virt,
James Smart92d7f7b2007-06-17 19:56:38 -05002418 sizeof(uint32_t) + sizeof(PRLO));
James Smart82d9a2a2006-04-15 11:53:05 -04002419 *((uint32_t *) (pcmd)) = ELS_CMD_PRLO_ACC;
2420 els_pkt_ptr = (ELS_PKT *) pcmd;
2421 els_pkt_ptr->un.prlo.acceptRspCode = PRLO_REQ_EXECUTED;
James Smart858c9f62007-06-17 19:56:39 -05002422
2423 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2424 "Issue ACC PRLO: did:x%x flg:x%x",
2425 ndlp->nlp_DID, ndlp->nlp_flag, 0);
James Smart82d9a2a2006-04-15 11:53:05 -04002426 break;
dea31012005-04-17 16:05:31 -05002427 default:
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002428 return 1;
dea31012005-04-17 16:05:31 -05002429 }
dea31012005-04-17 16:05:31 -05002430 /* Xmit ELS ACC response tag <ulpIoTag> */
James Smarte8b62012007-08-02 11:10:09 -04002431 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
2432 "0128 Xmit ELS ACC response tag x%x, XRI: x%x, "
2433 "DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x\n",
2434 elsiocb->iotag, elsiocb->iocb.ulpContext,
2435 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
2436 ndlp->nlp_rpi);
dea31012005-04-17 16:05:31 -05002437 if (ndlp->nlp_flag & NLP_LOGO_ACC) {
James Smart2e0fef82007-06-17 19:56:36 -05002438 spin_lock_irq(shost->host_lock);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002439 ndlp->nlp_flag &= ~NLP_LOGO_ACC;
James Smart2e0fef82007-06-17 19:56:36 -05002440 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05002441 elsiocb->iocb_cmpl = lpfc_cmpl_els_logo_acc;
2442 } else {
James Smart858c9f62007-06-17 19:56:39 -05002443 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
dea31012005-04-17 16:05:31 -05002444 }
2445
2446 phba->fc_stat.elsXmitACC++;
dea31012005-04-17 16:05:31 -05002447 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
dea31012005-04-17 16:05:31 -05002448 if (rc == IOCB_ERROR) {
2449 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002450 return 1;
dea31012005-04-17 16:05:31 -05002451 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002452 return 0;
dea31012005-04-17 16:05:31 -05002453}
2454
2455int
James Smart2e0fef82007-06-17 19:56:36 -05002456lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
James Smart858c9f62007-06-17 19:56:39 -05002457 struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp,
2458 LPFC_MBOXQ_t *mbox)
dea31012005-04-17 16:05:31 -05002459{
James Smart2e0fef82007-06-17 19:56:36 -05002460 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002461 IOCB_t *icmd;
2462 IOCB_t *oldcmd;
2463 struct lpfc_iocbq *elsiocb;
2464 struct lpfc_sli_ring *pring;
2465 struct lpfc_sli *psli;
2466 uint8_t *pcmd;
2467 uint16_t cmdsize;
2468 int rc;
2469
2470 psli = &phba->sli;
2471 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
2472
James Smart92d7f7b2007-06-17 19:56:38 -05002473 cmdsize = 2 * sizeof(uint32_t);
James Smart2e0fef82007-06-17 19:56:36 -05002474 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
2475 ndlp->nlp_DID, ELS_CMD_LS_RJT);
James Smart488d1462006-03-07 15:02:37 -05002476 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002477 return 1;
dea31012005-04-17 16:05:31 -05002478
2479 icmd = &elsiocb->iocb;
2480 oldcmd = &oldiocb->iocb;
2481 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
2482 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2483
2484 *((uint32_t *) (pcmd)) = ELS_CMD_LS_RJT;
James Smart92d7f7b2007-06-17 19:56:38 -05002485 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05002486 *((uint32_t *) (pcmd)) = rejectError;
2487
James Smart51ef4c22007-08-02 11:10:31 -04002488 if (mbox)
James Smart858c9f62007-06-17 19:56:39 -05002489 elsiocb->context_un.mbox = mbox;
James Smart858c9f62007-06-17 19:56:39 -05002490
dea31012005-04-17 16:05:31 -05002491 /* Xmit ELS RJT <err> response tag <ulpIoTag> */
James Smarte8b62012007-08-02 11:10:09 -04002492 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
2493 "0129 Xmit ELS RJT x%x response tag x%x "
2494 "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, "
2495 "rpi x%x\n",
2496 rejectError, elsiocb->iotag,
2497 elsiocb->iocb.ulpContext, ndlp->nlp_DID,
2498 ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
James Smart858c9f62007-06-17 19:56:39 -05002499 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2500 "Issue LS_RJT: did:x%x flg:x%x err:x%x",
2501 ndlp->nlp_DID, ndlp->nlp_flag, rejectError);
2502
dea31012005-04-17 16:05:31 -05002503 phba->fc_stat.elsXmitLSRJT++;
James Smart858c9f62007-06-17 19:56:39 -05002504 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
dea31012005-04-17 16:05:31 -05002505 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
James Smart51ef4c22007-08-02 11:10:31 -04002506
dea31012005-04-17 16:05:31 -05002507 if (rc == IOCB_ERROR) {
2508 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002509 return 1;
dea31012005-04-17 16:05:31 -05002510 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002511 return 0;
dea31012005-04-17 16:05:31 -05002512}
2513
2514int
James Smart2e0fef82007-06-17 19:56:36 -05002515lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
2516 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05002517{
James Smart2e0fef82007-06-17 19:56:36 -05002518 struct lpfc_hba *phba = vport->phba;
2519 struct lpfc_sli *psli = &phba->sli;
2520 struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
dea31012005-04-17 16:05:31 -05002521 ADISC *ap;
James Smart2e0fef82007-06-17 19:56:36 -05002522 IOCB_t *icmd, *oldcmd;
dea31012005-04-17 16:05:31 -05002523 struct lpfc_iocbq *elsiocb;
dea31012005-04-17 16:05:31 -05002524 uint8_t *pcmd;
2525 uint16_t cmdsize;
2526 int rc;
2527
James Smart92d7f7b2007-06-17 19:56:38 -05002528 cmdsize = sizeof(uint32_t) + sizeof(ADISC);
James Smart2e0fef82007-06-17 19:56:36 -05002529 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
2530 ndlp->nlp_DID, ELS_CMD_ACC);
James Smart488d1462006-03-07 15:02:37 -05002531 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002532 return 1;
dea31012005-04-17 16:05:31 -05002533
dea31012005-04-17 16:05:31 -05002534 icmd = &elsiocb->iocb;
2535 oldcmd = &oldiocb->iocb;
2536 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
James Smart5b8bd0c2007-04-25 09:52:49 -04002537
2538 /* Xmit ADISC ACC response tag <ulpIoTag> */
James Smarte8b62012007-08-02 11:10:09 -04002539 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
2540 "0130 Xmit ADISC ACC response iotag x%x xri: "
2541 "x%x, did x%x, nlp_flag x%x, nlp_state x%x rpi x%x\n",
2542 elsiocb->iotag, elsiocb->iocb.ulpContext,
2543 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
2544 ndlp->nlp_rpi);
dea31012005-04-17 16:05:31 -05002545 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2546
2547 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
James Smart92d7f7b2007-06-17 19:56:38 -05002548 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05002549
2550 ap = (ADISC *) (pcmd);
2551 ap->hardAL_PA = phba->fc_pref_ALPA;
James Smart92d7f7b2007-06-17 19:56:38 -05002552 memcpy(&ap->portName, &vport->fc_portname, sizeof(struct lpfc_name));
2553 memcpy(&ap->nodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
James Smart2e0fef82007-06-17 19:56:36 -05002554 ap->DID = be32_to_cpu(vport->fc_myDID);
dea31012005-04-17 16:05:31 -05002555
James Smart858c9f62007-06-17 19:56:39 -05002556 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2557 "Issue ACC ADISC: did:x%x flg:x%x",
2558 ndlp->nlp_DID, ndlp->nlp_flag, 0);
2559
dea31012005-04-17 16:05:31 -05002560 phba->fc_stat.elsXmitACC++;
James Smart858c9f62007-06-17 19:56:39 -05002561 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
dea31012005-04-17 16:05:31 -05002562 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
dea31012005-04-17 16:05:31 -05002563 if (rc == IOCB_ERROR) {
2564 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002565 return 1;
dea31012005-04-17 16:05:31 -05002566 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002567 return 0;
dea31012005-04-17 16:05:31 -05002568}
2569
2570int
James Smart2e0fef82007-06-17 19:56:36 -05002571lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
James Smart5b8bd0c2007-04-25 09:52:49 -04002572 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05002573{
James Smart2e0fef82007-06-17 19:56:36 -05002574 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002575 PRLI *npr;
2576 lpfc_vpd_t *vpd;
2577 IOCB_t *icmd;
2578 IOCB_t *oldcmd;
2579 struct lpfc_iocbq *elsiocb;
2580 struct lpfc_sli_ring *pring;
2581 struct lpfc_sli *psli;
2582 uint8_t *pcmd;
2583 uint16_t cmdsize;
2584 int rc;
2585
2586 psli = &phba->sli;
2587 pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
2588
James Smart92d7f7b2007-06-17 19:56:38 -05002589 cmdsize = sizeof(uint32_t) + sizeof(PRLI);
James Smart2e0fef82007-06-17 19:56:36 -05002590 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
James Smart92d7f7b2007-06-17 19:56:38 -05002591 ndlp->nlp_DID, (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK)));
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002592 if (!elsiocb)
2593 return 1;
dea31012005-04-17 16:05:31 -05002594
dea31012005-04-17 16:05:31 -05002595 icmd = &elsiocb->iocb;
2596 oldcmd = &oldiocb->iocb;
2597 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
James Smart5b8bd0c2007-04-25 09:52:49 -04002598 /* Xmit PRLI ACC response tag <ulpIoTag> */
James Smarte8b62012007-08-02 11:10:09 -04002599 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
2600 "0131 Xmit PRLI ACC response tag x%x xri x%x, "
2601 "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
2602 elsiocb->iotag, elsiocb->iocb.ulpContext,
2603 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
2604 ndlp->nlp_rpi);
dea31012005-04-17 16:05:31 -05002605 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
2606
2607 *((uint32_t *) (pcmd)) = (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK));
James Smart92d7f7b2007-06-17 19:56:38 -05002608 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05002609
2610 /* For PRLI, remainder of payload is PRLI parameter page */
James Smart92d7f7b2007-06-17 19:56:38 -05002611 memset(pcmd, 0, sizeof(PRLI));
dea31012005-04-17 16:05:31 -05002612
2613 npr = (PRLI *) pcmd;
2614 vpd = &phba->vpd;
2615 /*
2616 * If our firmware version is 3.20 or later,
2617 * set the following bits for FC-TAPE support.
2618 */
2619 if (vpd->rev.feaLevelHigh >= 0x02) {
2620 npr->ConfmComplAllowed = 1;
2621 npr->Retry = 1;
2622 npr->TaskRetryIdReq = 1;
2623 }
2624
2625 npr->acceptRspCode = PRLI_REQ_EXECUTED;
2626 npr->estabImagePair = 1;
2627 npr->readXferRdyDis = 1;
2628 npr->ConfmComplAllowed = 1;
2629
2630 npr->prliType = PRLI_FCP_TYPE;
2631 npr->initiatorFunc = 1;
2632
James Smart858c9f62007-06-17 19:56:39 -05002633 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2634 "Issue ACC PRLI: did:x%x flg:x%x",
2635 ndlp->nlp_DID, ndlp->nlp_flag, 0);
2636
dea31012005-04-17 16:05:31 -05002637 phba->fc_stat.elsXmitACC++;
James Smart858c9f62007-06-17 19:56:39 -05002638 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
dea31012005-04-17 16:05:31 -05002639
dea31012005-04-17 16:05:31 -05002640 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
dea31012005-04-17 16:05:31 -05002641 if (rc == IOCB_ERROR) {
2642 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002643 return 1;
dea31012005-04-17 16:05:31 -05002644 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002645 return 0;
dea31012005-04-17 16:05:31 -05002646}
2647
2648static int
James Smart2e0fef82007-06-17 19:56:36 -05002649lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format,
James Smart329f9bc2007-04-25 09:53:01 -04002650 struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05002651{
James Smart2e0fef82007-06-17 19:56:36 -05002652 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002653 RNID *rn;
James Smart2e0fef82007-06-17 19:56:36 -05002654 IOCB_t *icmd, *oldcmd;
dea31012005-04-17 16:05:31 -05002655 struct lpfc_iocbq *elsiocb;
2656 struct lpfc_sli_ring *pring;
2657 struct lpfc_sli *psli;
2658 uint8_t *pcmd;
2659 uint16_t cmdsize;
2660 int rc;
2661
2662 psli = &phba->sli;
2663 pring = &psli->ring[LPFC_ELS_RING];
2664
James Smart92d7f7b2007-06-17 19:56:38 -05002665 cmdsize = sizeof(uint32_t) + sizeof(uint32_t)
2666 + (2 * sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05002667 if (format)
James Smart92d7f7b2007-06-17 19:56:38 -05002668 cmdsize += sizeof(RNID_TOP_DISC);
dea31012005-04-17 16:05:31 -05002669
James Smart2e0fef82007-06-17 19:56:36 -05002670 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
2671 ndlp->nlp_DID, ELS_CMD_ACC);
James Smart488d1462006-03-07 15:02:37 -05002672 if (!elsiocb)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002673 return 1;
dea31012005-04-17 16:05:31 -05002674
dea31012005-04-17 16:05:31 -05002675 icmd = &elsiocb->iocb;
2676 oldcmd = &oldiocb->iocb;
2677 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
James Smart5b8bd0c2007-04-25 09:52:49 -04002678 /* Xmit RNID ACC response tag <ulpIoTag> */
James Smarte8b62012007-08-02 11:10:09 -04002679 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
2680 "0132 Xmit RNID ACC response tag x%x xri x%x\n",
2681 elsiocb->iotag, elsiocb->iocb.ulpContext);
dea31012005-04-17 16:05:31 -05002682 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
dea31012005-04-17 16:05:31 -05002683 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
James Smart92d7f7b2007-06-17 19:56:38 -05002684 pcmd += sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05002685
James Smart92d7f7b2007-06-17 19:56:38 -05002686 memset(pcmd, 0, sizeof(RNID));
dea31012005-04-17 16:05:31 -05002687 rn = (RNID *) (pcmd);
2688 rn->Format = format;
James Smart92d7f7b2007-06-17 19:56:38 -05002689 rn->CommonLen = (2 * sizeof(struct lpfc_name));
2690 memcpy(&rn->portName, &vport->fc_portname, sizeof(struct lpfc_name));
2691 memcpy(&rn->nodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05002692 switch (format) {
2693 case 0:
2694 rn->SpecificLen = 0;
2695 break;
2696 case RNID_TOPOLOGY_DISC:
James Smart92d7f7b2007-06-17 19:56:38 -05002697 rn->SpecificLen = sizeof(RNID_TOP_DISC);
dea31012005-04-17 16:05:31 -05002698 memcpy(&rn->un.topologyDisc.portName,
James Smart92d7f7b2007-06-17 19:56:38 -05002699 &vport->fc_portname, sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05002700 rn->un.topologyDisc.unitType = RNID_HBA;
2701 rn->un.topologyDisc.physPort = 0;
2702 rn->un.topologyDisc.attachedNodes = 0;
2703 break;
2704 default:
2705 rn->CommonLen = 0;
2706 rn->SpecificLen = 0;
2707 break;
2708 }
2709
James Smart858c9f62007-06-17 19:56:39 -05002710 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
2711 "Issue ACC RNID: did:x%x flg:x%x",
2712 ndlp->nlp_DID, ndlp->nlp_flag, 0);
2713
dea31012005-04-17 16:05:31 -05002714 phba->fc_stat.elsXmitACC++;
James Smart858c9f62007-06-17 19:56:39 -05002715 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
James Smart329f9bc2007-04-25 09:53:01 -04002716 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05002717 elsiocb->context1 = NULL; /* Don't need ndlp for cmpl,
2718 * it could be freed */
2719
dea31012005-04-17 16:05:31 -05002720 rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
dea31012005-04-17 16:05:31 -05002721 if (rc == IOCB_ERROR) {
2722 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002723 return 1;
dea31012005-04-17 16:05:31 -05002724 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002725 return 0;
dea31012005-04-17 16:05:31 -05002726}
2727
2728int
James Smart2e0fef82007-06-17 19:56:36 -05002729lpfc_els_disc_adisc(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05002730{
James Smart2e0fef82007-06-17 19:56:36 -05002731 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05002732 struct lpfc_nodelist *ndlp, *next_ndlp;
James Smart2e0fef82007-06-17 19:56:36 -05002733 int sentadisc = 0;
dea31012005-04-17 16:05:31 -05002734
James Smart685f0bf2007-04-25 09:53:08 -04002735 /* go thru NPR nodes and issue any remaining ELS ADISCs */
James Smart2e0fef82007-06-17 19:56:36 -05002736 list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
James Smart685f0bf2007-04-25 09:53:08 -04002737 if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
2738 (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
2739 (ndlp->nlp_flag & NLP_NPR_ADISC) != 0) {
James Smart2e0fef82007-06-17 19:56:36 -05002740 spin_lock_irq(shost->host_lock);
James Smart685f0bf2007-04-25 09:53:08 -04002741 ndlp->nlp_flag &= ~NLP_NPR_ADISC;
James Smart2e0fef82007-06-17 19:56:36 -05002742 spin_unlock_irq(shost->host_lock);
James Smart685f0bf2007-04-25 09:53:08 -04002743 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002744 lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
2745 lpfc_issue_els_adisc(vport, ndlp, 0);
James Smart685f0bf2007-04-25 09:53:08 -04002746 sentadisc++;
James Smart2e0fef82007-06-17 19:56:36 -05002747 vport->num_disc_nodes++;
2748 if (vport->num_disc_nodes >=
James Smart3de2a652007-08-02 11:09:59 -04002749 vport->cfg_discovery_threads) {
James Smart2e0fef82007-06-17 19:56:36 -05002750 spin_lock_irq(shost->host_lock);
2751 vport->fc_flag |= FC_NLP_MORE;
2752 spin_unlock_irq(shost->host_lock);
James Smart685f0bf2007-04-25 09:53:08 -04002753 break;
dea31012005-04-17 16:05:31 -05002754 }
2755 }
2756 }
2757 if (sentadisc == 0) {
James Smart2e0fef82007-06-17 19:56:36 -05002758 spin_lock_irq(shost->host_lock);
2759 vport->fc_flag &= ~FC_NLP_MORE;
2760 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05002761 }
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05002762 return sentadisc;
dea31012005-04-17 16:05:31 -05002763}
2764
2765int
James Smart2e0fef82007-06-17 19:56:36 -05002766lpfc_els_disc_plogi(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05002767{
James Smart2e0fef82007-06-17 19:56:36 -05002768 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05002769 struct lpfc_nodelist *ndlp, *next_ndlp;
James Smart2e0fef82007-06-17 19:56:36 -05002770 int sentplogi = 0;
dea31012005-04-17 16:05:31 -05002771
James Smart2e0fef82007-06-17 19:56:36 -05002772 /* go thru NPR nodes and issue any remaining ELS PLOGIs */
2773 list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
James Smart685f0bf2007-04-25 09:53:08 -04002774 if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
2775 (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
2776 (ndlp->nlp_flag & NLP_DELAY_TMO) == 0 &&
2777 (ndlp->nlp_flag & NLP_NPR_ADISC) == 0) {
2778 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05002779 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
2780 lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
James Smart685f0bf2007-04-25 09:53:08 -04002781 sentplogi++;
James Smart2e0fef82007-06-17 19:56:36 -05002782 vport->num_disc_nodes++;
2783 if (vport->num_disc_nodes >=
James Smart3de2a652007-08-02 11:09:59 -04002784 vport->cfg_discovery_threads) {
James Smart2e0fef82007-06-17 19:56:36 -05002785 spin_lock_irq(shost->host_lock);
2786 vport->fc_flag |= FC_NLP_MORE;
2787 spin_unlock_irq(shost->host_lock);
James Smart685f0bf2007-04-25 09:53:08 -04002788 break;
dea31012005-04-17 16:05:31 -05002789 }
2790 }
2791 }
James Smart87af33f2007-10-27 13:37:43 -04002792 if (sentplogi) {
2793 lpfc_set_disctmo(vport);
2794 }
2795 else {
James Smart2e0fef82007-06-17 19:56:36 -05002796 spin_lock_irq(shost->host_lock);
2797 vport->fc_flag &= ~FC_NLP_MORE;
2798 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05002799 }
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05002800 return sentplogi;
dea31012005-04-17 16:05:31 -05002801}
2802
James Smart92d7f7b2007-06-17 19:56:38 -05002803void
James Smart2e0fef82007-06-17 19:56:36 -05002804lpfc_els_flush_rscn(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05002805{
James Smart2e0fef82007-06-17 19:56:36 -05002806 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
2807 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002808 int i;
2809
James Smart2e0fef82007-06-17 19:56:36 -05002810 for (i = 0; i < vport->fc_rscn_id_cnt; i++) {
James Smart92d7f7b2007-06-17 19:56:38 -05002811 lpfc_in_buf_free(phba, vport->fc_rscn_id_list[i]);
James Smart2e0fef82007-06-17 19:56:36 -05002812 vport->fc_rscn_id_list[i] = NULL;
dea31012005-04-17 16:05:31 -05002813 }
James Smart2e0fef82007-06-17 19:56:36 -05002814 spin_lock_irq(shost->host_lock);
2815 vport->fc_rscn_id_cnt = 0;
2816 vport->fc_flag &= ~(FC_RSCN_MODE | FC_RSCN_DISCOVERY);
2817 spin_unlock_irq(shost->host_lock);
2818 lpfc_can_disctmo(vport);
dea31012005-04-17 16:05:31 -05002819}
2820
2821int
James Smart2e0fef82007-06-17 19:56:36 -05002822lpfc_rscn_payload_check(struct lpfc_vport *vport, uint32_t did)
dea31012005-04-17 16:05:31 -05002823{
2824 D_ID ns_did;
2825 D_ID rscn_did;
dea31012005-04-17 16:05:31 -05002826 uint32_t *lp;
James Smart92d7f7b2007-06-17 19:56:38 -05002827 uint32_t payload_len, i;
dea31012005-04-17 16:05:31 -05002828
2829 ns_did.un.word = did;
dea31012005-04-17 16:05:31 -05002830
2831 /* Never match fabric nodes for RSCNs */
2832 if ((did & Fabric_DID_MASK) == Fabric_DID_MASK)
James Smart2e0fef82007-06-17 19:56:36 -05002833 return 0;
dea31012005-04-17 16:05:31 -05002834
2835 /* If we are doing a FULL RSCN rediscovery, match everything */
James Smart2e0fef82007-06-17 19:56:36 -05002836 if (vport->fc_flag & FC_RSCN_DISCOVERY)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002837 return did;
dea31012005-04-17 16:05:31 -05002838
James Smart2e0fef82007-06-17 19:56:36 -05002839 for (i = 0; i < vport->fc_rscn_id_cnt; i++) {
James Smart92d7f7b2007-06-17 19:56:38 -05002840 lp = vport->fc_rscn_id_list[i]->virt;
2841 payload_len = be32_to_cpu(*lp++ & ~ELS_CMD_MASK);
2842 payload_len -= sizeof(uint32_t); /* take off word 0 */
dea31012005-04-17 16:05:31 -05002843 while (payload_len) {
James Smart92d7f7b2007-06-17 19:56:38 -05002844 rscn_did.un.word = be32_to_cpu(*lp++);
2845 payload_len -= sizeof(uint32_t);
dea31012005-04-17 16:05:31 -05002846 switch (rscn_did.un.b.resv) {
2847 case 0: /* Single N_Port ID effected */
James Smart2e0fef82007-06-17 19:56:36 -05002848 if (ns_did.un.word == rscn_did.un.word)
James Smart92d7f7b2007-06-17 19:56:38 -05002849 return did;
dea31012005-04-17 16:05:31 -05002850 break;
2851 case 1: /* Whole N_Port Area effected */
2852 if ((ns_did.un.b.domain == rscn_did.un.b.domain)
2853 && (ns_did.un.b.area == rscn_did.un.b.area))
James Smart92d7f7b2007-06-17 19:56:38 -05002854 return did;
dea31012005-04-17 16:05:31 -05002855 break;
2856 case 2: /* Whole N_Port Domain effected */
2857 if (ns_did.un.b.domain == rscn_did.un.b.domain)
James Smart92d7f7b2007-06-17 19:56:38 -05002858 return did;
dea31012005-04-17 16:05:31 -05002859 break;
2860 default:
James Smart2e0fef82007-06-17 19:56:36 -05002861 /* Unknown Identifier in RSCN node */
James Smarte8b62012007-08-02 11:10:09 -04002862 lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
2863 "0217 Unknown Identifier in "
2864 "RSCN payload Data: x%x\n",
2865 rscn_did.un.word);
James Smart92d7f7b2007-06-17 19:56:38 -05002866 case 3: /* Whole Fabric effected */
2867 return did;
dea31012005-04-17 16:05:31 -05002868 }
2869 }
James Smart92d7f7b2007-06-17 19:56:38 -05002870 }
2871 return 0;
dea31012005-04-17 16:05:31 -05002872}
2873
2874static int
James Smart2e0fef82007-06-17 19:56:36 -05002875lpfc_rscn_recovery_check(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05002876{
James Smart685f0bf2007-04-25 09:53:08 -04002877 struct lpfc_nodelist *ndlp = NULL;
dea31012005-04-17 16:05:31 -05002878
2879 /* Look at all nodes effected by pending RSCNs and move
James Smart685f0bf2007-04-25 09:53:08 -04002880 * them to NPR state.
dea31012005-04-17 16:05:31 -05002881 */
James Smart685f0bf2007-04-25 09:53:08 -04002882
James Smart2e0fef82007-06-17 19:56:36 -05002883 list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
James Smart685f0bf2007-04-25 09:53:08 -04002884 if (ndlp->nlp_state == NLP_STE_UNUSED_NODE ||
James Smart2e0fef82007-06-17 19:56:36 -05002885 lpfc_rscn_payload_check(vport, ndlp->nlp_DID) == 0)
dea31012005-04-17 16:05:31 -05002886 continue;
2887
James Smart2e0fef82007-06-17 19:56:36 -05002888 lpfc_disc_state_machine(vport, ndlp, NULL,
James Smart92d7f7b2007-06-17 19:56:38 -05002889 NLP_EVT_DEVICE_RECOVERY);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05002890
James Smart685f0bf2007-04-25 09:53:08 -04002891 /*
2892 * Make sure NLP_DELAY_TMO is NOT running after a device
2893 * recovery event.
2894 */
2895 if (ndlp->nlp_flag & NLP_DELAY_TMO)
James Smart2e0fef82007-06-17 19:56:36 -05002896 lpfc_cancel_retry_delay_tmo(vport, ndlp);
dea31012005-04-17 16:05:31 -05002897 }
James Smart685f0bf2007-04-25 09:53:08 -04002898
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002899 return 0;
dea31012005-04-17 16:05:31 -05002900}
2901
2902static int
James Smart2e0fef82007-06-17 19:56:36 -05002903lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
James Smart51ef4c22007-08-02 11:10:31 -04002904 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05002905{
James Smart2e0fef82007-06-17 19:56:36 -05002906 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
2907 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05002908 struct lpfc_dmabuf *pcmd;
James Smart92d7f7b2007-06-17 19:56:38 -05002909 uint32_t *lp, *datap;
dea31012005-04-17 16:05:31 -05002910 IOCB_t *icmd;
James Smart92d7f7b2007-06-17 19:56:38 -05002911 uint32_t payload_len, length, nportid, *cmd;
2912 int rscn_cnt = vport->fc_rscn_id_cnt;
2913 int rscn_id = 0, hba_id = 0;
James Smartd2873e42006-08-18 17:46:43 -04002914 int i;
dea31012005-04-17 16:05:31 -05002915
2916 icmd = &cmdiocb->iocb;
2917 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
2918 lp = (uint32_t *) pcmd->virt;
2919
James Smart92d7f7b2007-06-17 19:56:38 -05002920 payload_len = be32_to_cpu(*lp++ & ~ELS_CMD_MASK);
2921 payload_len -= sizeof(uint32_t); /* take off word 0 */
dea31012005-04-17 16:05:31 -05002922 /* RSCN received */
James Smarte8b62012007-08-02 11:10:09 -04002923 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
2924 "0214 RSCN received Data: x%x x%x x%x x%x\n",
2925 vport->fc_flag, payload_len, *lp, rscn_cnt);
James Smartd2873e42006-08-18 17:46:43 -04002926 for (i = 0; i < payload_len/sizeof(uint32_t); i++)
James Smart2e0fef82007-06-17 19:56:36 -05002927 fc_host_post_event(shost, fc_get_event_number(),
James Smartd2873e42006-08-18 17:46:43 -04002928 FCH_EVT_RSCN, lp[i]);
2929
dea31012005-04-17 16:05:31 -05002930 /* If we are about to begin discovery, just ACC the RSCN.
2931 * Discovery processing will satisfy it.
2932 */
James Smart2e0fef82007-06-17 19:56:36 -05002933 if (vport->port_state <= LPFC_NS_QRY) {
James Smart858c9f62007-06-17 19:56:39 -05002934 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
2935 "RCV RSCN ignore: did:x%x/ste:x%x flg:x%x",
2936 ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
2937
James Smart51ef4c22007-08-02 11:10:31 -04002938 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002939 return 0;
dea31012005-04-17 16:05:31 -05002940 }
2941
James Smart92d7f7b2007-06-17 19:56:38 -05002942 /* If this RSCN just contains NPortIDs for other vports on this HBA,
2943 * just ACC and ignore it.
2944 */
2945 if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
James Smart3de2a652007-08-02 11:09:59 -04002946 !(vport->cfg_peer_port_login)) {
James Smart92d7f7b2007-06-17 19:56:38 -05002947 i = payload_len;
2948 datap = lp;
2949 while (i > 0) {
2950 nportid = *datap++;
2951 nportid = ((be32_to_cpu(nportid)) & Mask_DID);
2952 i -= sizeof(uint32_t);
2953 rscn_id++;
James Smart549e55c2007-08-02 11:09:51 -04002954 if (lpfc_find_vport_by_did(phba, nportid))
2955 hba_id++;
James Smart92d7f7b2007-06-17 19:56:38 -05002956 }
2957 if (rscn_id == hba_id) {
2958 /* ALL NPortIDs in RSCN are on HBA */
James Smarte8b62012007-08-02 11:10:09 -04002959 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
2960 "0214 Ignore RSCN "
2961 "Data: x%x x%x x%x x%x\n",
2962 vport->fc_flag, payload_len,
2963 *lp, rscn_cnt);
James Smart858c9f62007-06-17 19:56:39 -05002964 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
2965 "RCV RSCN vport: did:x%x/ste:x%x flg:x%x",
2966 ndlp->nlp_DID, vport->port_state,
2967 ndlp->nlp_flag);
2968
James Smart92d7f7b2007-06-17 19:56:38 -05002969 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb,
James Smart51ef4c22007-08-02 11:10:31 -04002970 ndlp, NULL);
James Smart92d7f7b2007-06-17 19:56:38 -05002971 return 0;
2972 }
2973 }
2974
dea31012005-04-17 16:05:31 -05002975 /* If we are already processing an RSCN, save the received
2976 * RSCN payload buffer, cmdiocb->context2 to process later.
2977 */
James Smart2e0fef82007-06-17 19:56:36 -05002978 if (vport->fc_flag & (FC_RSCN_MODE | FC_NDISC_ACTIVE)) {
James Smart858c9f62007-06-17 19:56:39 -05002979 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
2980 "RCV RSCN defer: did:x%x/ste:x%x flg:x%x",
2981 ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
2982
James Smart09372822008-01-11 01:52:54 -05002983 spin_lock_irq(shost->host_lock);
James Smart92d7f7b2007-06-17 19:56:38 -05002984 vport->fc_flag |= FC_RSCN_DEFERRED;
2985 if ((rscn_cnt < FC_MAX_HOLD_RSCN) &&
James Smart2e0fef82007-06-17 19:56:36 -05002986 !(vport->fc_flag & FC_RSCN_DISCOVERY)) {
James Smart2e0fef82007-06-17 19:56:36 -05002987 vport->fc_flag |= FC_RSCN_MODE;
2988 spin_unlock_irq(shost->host_lock);
James Smart92d7f7b2007-06-17 19:56:38 -05002989 if (rscn_cnt) {
2990 cmd = vport->fc_rscn_id_list[rscn_cnt-1]->virt;
2991 length = be32_to_cpu(*cmd & ~ELS_CMD_MASK);
2992 }
2993 if ((rscn_cnt) &&
2994 (payload_len + length <= LPFC_BPL_SIZE)) {
2995 *cmd &= ELS_CMD_MASK;
2996 *cmd |= be32_to_cpu(payload_len + length);
2997 memcpy(((uint8_t *)cmd) + length, lp,
2998 payload_len);
2999 } else {
3000 vport->fc_rscn_id_list[rscn_cnt] = pcmd;
3001 vport->fc_rscn_id_cnt++;
3002 /* If we zero, cmdiocb->context2, the calling
3003 * routine will not try to free it.
3004 */
3005 cmdiocb->context2 = NULL;
3006 }
dea31012005-04-17 16:05:31 -05003007
3008 /* Deferred RSCN */
James Smarte8b62012007-08-02 11:10:09 -04003009 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
3010 "0235 Deferred RSCN "
3011 "Data: x%x x%x x%x\n",
3012 vport->fc_rscn_id_cnt, vport->fc_flag,
3013 vport->port_state);
dea31012005-04-17 16:05:31 -05003014 } else {
James Smart2e0fef82007-06-17 19:56:36 -05003015 vport->fc_flag |= FC_RSCN_DISCOVERY;
3016 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05003017 /* ReDiscovery RSCN */
James Smarte8b62012007-08-02 11:10:09 -04003018 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
3019 "0234 ReDiscovery RSCN "
3020 "Data: x%x x%x x%x\n",
3021 vport->fc_rscn_id_cnt, vport->fc_flag,
3022 vport->port_state);
dea31012005-04-17 16:05:31 -05003023 }
3024 /* Send back ACC */
James Smart51ef4c22007-08-02 11:10:31 -04003025 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
dea31012005-04-17 16:05:31 -05003026
3027 /* send RECOVERY event for ALL nodes that match RSCN payload */
James Smart2e0fef82007-06-17 19:56:36 -05003028 lpfc_rscn_recovery_check(vport);
James Smart09372822008-01-11 01:52:54 -05003029 spin_lock_irq(shost->host_lock);
James Smart92d7f7b2007-06-17 19:56:38 -05003030 vport->fc_flag &= ~FC_RSCN_DEFERRED;
James Smart09372822008-01-11 01:52:54 -05003031 spin_unlock_irq(shost->host_lock);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003032 return 0;
dea31012005-04-17 16:05:31 -05003033 }
3034
James Smart858c9f62007-06-17 19:56:39 -05003035 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3036 "RCV RSCN: did:x%x/ste:x%x flg:x%x",
3037 ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
3038
James Smart2e0fef82007-06-17 19:56:36 -05003039 spin_lock_irq(shost->host_lock);
3040 vport->fc_flag |= FC_RSCN_MODE;
3041 spin_unlock_irq(shost->host_lock);
3042 vport->fc_rscn_id_list[vport->fc_rscn_id_cnt++] = pcmd;
dea31012005-04-17 16:05:31 -05003043 /*
3044 * If we zero, cmdiocb->context2, the calling routine will
3045 * not try to free it.
3046 */
3047 cmdiocb->context2 = NULL;
3048
James Smart2e0fef82007-06-17 19:56:36 -05003049 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -05003050
3051 /* Send back ACC */
James Smart51ef4c22007-08-02 11:10:31 -04003052 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
dea31012005-04-17 16:05:31 -05003053
3054 /* send RECOVERY event for ALL nodes that match RSCN payload */
James Smart2e0fef82007-06-17 19:56:36 -05003055 lpfc_rscn_recovery_check(vport);
dea31012005-04-17 16:05:31 -05003056
James Smart2e0fef82007-06-17 19:56:36 -05003057 return lpfc_els_handle_rscn(vport);
dea31012005-04-17 16:05:31 -05003058}
3059
3060int
James Smart2e0fef82007-06-17 19:56:36 -05003061lpfc_els_handle_rscn(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05003062{
3063 struct lpfc_nodelist *ndlp;
James Smart2e0fef82007-06-17 19:56:36 -05003064 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05003065
James Smart92d7f7b2007-06-17 19:56:38 -05003066 /* Ignore RSCN if the port is being torn down. */
3067 if (vport->load_flag & FC_UNLOADING) {
3068 lpfc_els_flush_rscn(vport);
3069 return 0;
3070 }
3071
dea31012005-04-17 16:05:31 -05003072 /* Start timer for RSCN processing */
James Smart2e0fef82007-06-17 19:56:36 -05003073 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -05003074
3075 /* RSCN processed */
James Smarte8b62012007-08-02 11:10:09 -04003076 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
3077 "0215 RSCN processed Data: x%x x%x x%x x%x\n",
3078 vport->fc_flag, 0, vport->fc_rscn_id_cnt,
3079 vport->port_state);
dea31012005-04-17 16:05:31 -05003080
3081 /* To process RSCN, first compare RSCN data with NameServer */
James Smart2e0fef82007-06-17 19:56:36 -05003082 vport->fc_ns_retry = 0;
James Smart0ff10d42008-01-11 01:52:36 -05003083 vport->num_disc_nodes = 0;
3084
James Smart2e0fef82007-06-17 19:56:36 -05003085 ndlp = lpfc_findnode_did(vport, NameServer_DID);
James Smart685f0bf2007-04-25 09:53:08 -04003086 if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
dea31012005-04-17 16:05:31 -05003087 /* Good ndlp, issue CT Request to NameServer */
James Smart92d7f7b2007-06-17 19:56:38 -05003088 if (lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, 0, 0) == 0)
dea31012005-04-17 16:05:31 -05003089 /* Wait for NameServer query cmpl before we can
3090 continue */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003091 return 1;
dea31012005-04-17 16:05:31 -05003092 } else {
3093 /* If login to NameServer does not exist, issue one */
3094 /* Good status, issue PLOGI to NameServer */
James Smart2e0fef82007-06-17 19:56:36 -05003095 ndlp = lpfc_findnode_did(vport, NameServer_DID);
3096 if (ndlp)
dea31012005-04-17 16:05:31 -05003097 /* Wait for NameServer login cmpl before we can
3098 continue */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003099 return 1;
James Smart2e0fef82007-06-17 19:56:36 -05003100
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003101 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
3102 if (!ndlp) {
James Smart2e0fef82007-06-17 19:56:36 -05003103 lpfc_els_flush_rscn(vport);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003104 return 0;
dea31012005-04-17 16:05:31 -05003105 } else {
James Smart2e0fef82007-06-17 19:56:36 -05003106 lpfc_nlp_init(vport, ndlp, NameServer_DID);
dea31012005-04-17 16:05:31 -05003107 ndlp->nlp_type |= NLP_FABRIC;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003108 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05003109 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
3110 lpfc_issue_els_plogi(vport, NameServer_DID, 0);
dea31012005-04-17 16:05:31 -05003111 /* Wait for NameServer login cmpl before we can
3112 continue */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003113 return 1;
dea31012005-04-17 16:05:31 -05003114 }
3115 }
3116
James Smart2e0fef82007-06-17 19:56:36 -05003117 lpfc_els_flush_rscn(vport);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003118 return 0;
dea31012005-04-17 16:05:31 -05003119}
3120
3121static int
James Smart2e0fef82007-06-17 19:56:36 -05003122lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
James Smart51ef4c22007-08-02 11:10:31 -04003123 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05003124{
James Smart2e0fef82007-06-17 19:56:36 -05003125 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
3126 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05003127 struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3128 uint32_t *lp = (uint32_t *) pcmd->virt;
3129 IOCB_t *icmd = &cmdiocb->iocb;
3130 struct serv_parm *sp;
3131 LPFC_MBOXQ_t *mbox;
3132 struct ls_rjt stat;
3133 uint32_t cmd, did;
3134 int rc;
3135
3136 cmd = *lp++;
3137 sp = (struct serv_parm *) lp;
3138
3139 /* FLOGI received */
3140
James Smart2e0fef82007-06-17 19:56:36 -05003141 lpfc_set_disctmo(vport);
dea31012005-04-17 16:05:31 -05003142
3143 if (phba->fc_topology == TOPOLOGY_LOOP) {
3144 /* We should never receive a FLOGI in loop mode, ignore it */
3145 did = icmd->un.elsreq64.remoteID;
3146
3147 /* An FLOGI ELS command <elsCmd> was received from DID <did> in
3148 Loop Mode */
James Smarte8b62012007-08-02 11:10:09 -04003149 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
3150 "0113 An FLOGI ELS command x%x was "
3151 "received from DID x%x in Loop Mode\n",
3152 cmd, did);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003153 return 1;
dea31012005-04-17 16:05:31 -05003154 }
3155
3156 did = Fabric_DID;
3157
James Smart2e0fef82007-06-17 19:56:36 -05003158 if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3))) {
dea31012005-04-17 16:05:31 -05003159 /* For a FLOGI we accept, then if our portname is greater
3160 * then the remote portname we initiate Nport login.
3161 */
3162
James Smart2e0fef82007-06-17 19:56:36 -05003163 rc = memcmp(&vport->fc_portname, &sp->portName,
James Smart92d7f7b2007-06-17 19:56:38 -05003164 sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05003165
3166 if (!rc) {
James Smart2e0fef82007-06-17 19:56:36 -05003167 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
3168 if (!mbox)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003169 return 1;
James Smart2e0fef82007-06-17 19:56:36 -05003170
dea31012005-04-17 16:05:31 -05003171 lpfc_linkdown(phba);
3172 lpfc_init_link(phba, mbox,
3173 phba->cfg_topology,
3174 phba->cfg_link_speed);
3175 mbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
3176 mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
James Smarted957682007-06-17 19:56:37 -05003177 mbox->vport = vport;
James Smart0b727fe2007-10-27 13:37:25 -04003178 rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
James Smart5b8bd0c2007-04-25 09:52:49 -04003179 lpfc_set_loopback_flag(phba);
dea31012005-04-17 16:05:31 -05003180 if (rc == MBX_NOT_FINISHED) {
James Smart329f9bc2007-04-25 09:53:01 -04003181 mempool_free(mbox, phba->mbox_mem_pool);
dea31012005-04-17 16:05:31 -05003182 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003183 return 1;
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05003184 } else if (rc > 0) { /* greater than */
James Smart2e0fef82007-06-17 19:56:36 -05003185 spin_lock_irq(shost->host_lock);
3186 vport->fc_flag |= FC_PT2PT_PLOGI;
3187 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05003188 }
James Smart2e0fef82007-06-17 19:56:36 -05003189 spin_lock_irq(shost->host_lock);
3190 vport->fc_flag |= FC_PT2PT;
3191 vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
3192 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05003193 } else {
3194 /* Reject this request because invalid parameters */
3195 stat.un.b.lsRjtRsvd0 = 0;
3196 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
3197 stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
3198 stat.un.b.vendorUnique = 0;
James Smart858c9f62007-06-17 19:56:39 -05003199 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
3200 NULL);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003201 return 1;
dea31012005-04-17 16:05:31 -05003202 }
3203
3204 /* Send back ACC */
James Smart51ef4c22007-08-02 11:10:31 -04003205 lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL);
dea31012005-04-17 16:05:31 -05003206
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003207 return 0;
dea31012005-04-17 16:05:31 -05003208}
3209
3210static int
James Smart2e0fef82007-06-17 19:56:36 -05003211lpfc_els_rcv_rnid(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3212 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05003213{
3214 struct lpfc_dmabuf *pcmd;
3215 uint32_t *lp;
3216 IOCB_t *icmd;
3217 RNID *rn;
3218 struct ls_rjt stat;
3219 uint32_t cmd, did;
3220
3221 icmd = &cmdiocb->iocb;
3222 did = icmd->un.elsreq64.remoteID;
3223 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3224 lp = (uint32_t *) pcmd->virt;
3225
3226 cmd = *lp++;
3227 rn = (RNID *) lp;
3228
3229 /* RNID received */
3230
3231 switch (rn->Format) {
3232 case 0:
3233 case RNID_TOPOLOGY_DISC:
3234 /* Send back ACC */
James Smart2e0fef82007-06-17 19:56:36 -05003235 lpfc_els_rsp_rnid_acc(vport, rn->Format, cmdiocb, ndlp);
dea31012005-04-17 16:05:31 -05003236 break;
3237 default:
3238 /* Reject this request because format not supported */
3239 stat.un.b.lsRjtRsvd0 = 0;
3240 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
3241 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
3242 stat.un.b.vendorUnique = 0;
James Smart858c9f62007-06-17 19:56:39 -05003243 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
3244 NULL);
dea31012005-04-17 16:05:31 -05003245 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003246 return 0;
dea31012005-04-17 16:05:31 -05003247}
3248
3249static int
James Smart2e0fef82007-06-17 19:56:36 -05003250lpfc_els_rcv_lirr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3251 struct lpfc_nodelist *ndlp)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003252{
3253 struct ls_rjt stat;
3254
3255 /* For now, unconditionally reject this command */
3256 stat.un.b.lsRjtRsvd0 = 0;
3257 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
3258 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
3259 stat.un.b.vendorUnique = 0;
James Smart858c9f62007-06-17 19:56:39 -05003260 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003261 return 0;
3262}
3263
Jamie Wellnitz082c0262006-02-28 19:25:30 -05003264static void
James Smart329f9bc2007-04-25 09:53:01 -04003265lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003266{
James Smart2e0fef82007-06-17 19:56:36 -05003267 struct lpfc_sli *psli = &phba->sli;
3268 struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003269 MAILBOX_t *mb;
3270 IOCB_t *icmd;
3271 RPS_RSP *rps_rsp;
3272 uint8_t *pcmd;
3273 struct lpfc_iocbq *elsiocb;
3274 struct lpfc_nodelist *ndlp;
3275 uint16_t xri, status;
3276 uint32_t cmdsize;
3277
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003278 mb = &pmb->mb;
3279
3280 ndlp = (struct lpfc_nodelist *) pmb->context2;
3281 xri = (uint16_t) ((unsigned long)(pmb->context1));
Randy Dunlap041976f2006-06-25 01:58:51 -07003282 pmb->context1 = NULL;
3283 pmb->context2 = NULL;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003284
3285 if (mb->mbxStatus) {
James Smart329f9bc2007-04-25 09:53:01 -04003286 mempool_free(pmb, phba->mbox_mem_pool);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003287 return;
3288 }
3289
3290 cmdsize = sizeof(RPS_RSP) + sizeof(uint32_t);
James Smart329f9bc2007-04-25 09:53:01 -04003291 mempool_free(pmb, phba->mbox_mem_pool);
James Smart2e0fef82007-06-17 19:56:36 -05003292 elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize,
3293 lpfc_max_els_tries, ndlp,
3294 ndlp->nlp_DID, ELS_CMD_ACC);
James Smart329f9bc2007-04-25 09:53:01 -04003295 lpfc_nlp_put(ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003296 if (!elsiocb)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003297 return;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003298
3299 icmd = &elsiocb->iocb;
3300 icmd->ulpContext = xri;
3301
3302 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
3303 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
James Smart92d7f7b2007-06-17 19:56:38 -05003304 pcmd += sizeof(uint32_t); /* Skip past command */
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003305 rps_rsp = (RPS_RSP *)pcmd;
3306
3307 if (phba->fc_topology != TOPOLOGY_LOOP)
3308 status = 0x10;
3309 else
3310 status = 0x8;
James Smart2e0fef82007-06-17 19:56:36 -05003311 if (phba->pport->fc_flag & FC_FABRIC)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003312 status |= 0x4;
3313
3314 rps_rsp->rsvd1 = 0;
James Smart09372822008-01-11 01:52:54 -05003315 rps_rsp->portStatus = cpu_to_be16(status);
3316 rps_rsp->linkFailureCnt = cpu_to_be32(mb->un.varRdLnk.linkFailureCnt);
3317 rps_rsp->lossSyncCnt = cpu_to_be32(mb->un.varRdLnk.lossSyncCnt);
3318 rps_rsp->lossSignalCnt = cpu_to_be32(mb->un.varRdLnk.lossSignalCnt);
3319 rps_rsp->primSeqErrCnt = cpu_to_be32(mb->un.varRdLnk.primSeqErrCnt);
3320 rps_rsp->invalidXmitWord = cpu_to_be32(mb->un.varRdLnk.invalidXmitWord);
3321 rps_rsp->crcCnt = cpu_to_be32(mb->un.varRdLnk.crcCnt);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003322 /* Xmit ELS RPS ACC response tag <ulpIoTag> */
James Smarte8b62012007-08-02 11:10:09 -04003323 lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS,
3324 "0118 Xmit ELS RPS ACC response tag x%x xri x%x, "
3325 "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
3326 elsiocb->iotag, elsiocb->iocb.ulpContext,
3327 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
3328 ndlp->nlp_rpi);
James Smart858c9f62007-06-17 19:56:39 -05003329 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003330 phba->fc_stat.elsXmitACC++;
James Smarted957682007-06-17 19:56:37 -05003331 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003332 lpfc_els_free_iocb(phba, elsiocb);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003333 return;
3334}
3335
3336static int
James Smart2e0fef82007-06-17 19:56:36 -05003337lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3338 struct lpfc_nodelist *ndlp)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003339{
James Smart2e0fef82007-06-17 19:56:36 -05003340 struct lpfc_hba *phba = vport->phba;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003341 uint32_t *lp;
3342 uint8_t flag;
3343 LPFC_MBOXQ_t *mbox;
3344 struct lpfc_dmabuf *pcmd;
3345 RPS *rps;
3346 struct ls_rjt stat;
3347
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05003348 if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
3349 (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) {
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003350 stat.un.b.lsRjtRsvd0 = 0;
3351 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
3352 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
3353 stat.un.b.vendorUnique = 0;
James Smart858c9f62007-06-17 19:56:39 -05003354 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
3355 NULL);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003356 }
3357
3358 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3359 lp = (uint32_t *) pcmd->virt;
3360 flag = (be32_to_cpu(*lp++) & 0xf);
3361 rps = (RPS *) lp;
3362
3363 if ((flag == 0) ||
3364 ((flag == 1) && (be32_to_cpu(rps->un.portNum) == 0)) ||
James Smart2e0fef82007-06-17 19:56:36 -05003365 ((flag == 2) && (memcmp(&rps->un.portName, &vport->fc_portname,
James Smart92d7f7b2007-06-17 19:56:38 -05003366 sizeof(struct lpfc_name)) == 0))) {
James Smart2e0fef82007-06-17 19:56:36 -05003367
James Smart92d7f7b2007-06-17 19:56:38 -05003368 printk("Fix me....\n");
3369 dump_stack();
James Smart2e0fef82007-06-17 19:56:36 -05003370 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC);
3371 if (mbox) {
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003372 lpfc_read_lnk_stat(phba, mbox);
3373 mbox->context1 =
James Smart92d7f7b2007-06-17 19:56:38 -05003374 (void *)((unsigned long) cmdiocb->iocb.ulpContext);
James Smart329f9bc2007-04-25 09:53:01 -04003375 mbox->context2 = lpfc_nlp_get(ndlp);
James Smart92d7f7b2007-06-17 19:56:38 -05003376 mbox->vport = vport;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003377 mbox->mbox_cmpl = lpfc_els_rsp_rps_acc;
James Smart0b727fe2007-10-27 13:37:25 -04003378 if (lpfc_sli_issue_mbox (phba, mbox, MBX_NOWAIT)
3379 != MBX_NOT_FINISHED)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003380 /* Mbox completion will send ELS Response */
3381 return 0;
James Smart2e0fef82007-06-17 19:56:36 -05003382
James Smart329f9bc2007-04-25 09:53:01 -04003383 lpfc_nlp_put(ndlp);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003384 mempool_free(mbox, phba->mbox_mem_pool);
3385 }
3386 }
3387 stat.un.b.lsRjtRsvd0 = 0;
3388 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
3389 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
3390 stat.un.b.vendorUnique = 0;
James Smart858c9f62007-06-17 19:56:39 -05003391 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003392 return 0;
3393}
3394
Jamie Wellnitz082c0262006-02-28 19:25:30 -05003395static int
James Smart2e0fef82007-06-17 19:56:36 -05003396lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize,
3397 struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003398{
James Smart2e0fef82007-06-17 19:56:36 -05003399 struct lpfc_hba *phba = vport->phba;
3400 IOCB_t *icmd, *oldcmd;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003401 RPL_RSP rpl_rsp;
3402 struct lpfc_iocbq *elsiocb;
James Smart2e0fef82007-06-17 19:56:36 -05003403 struct lpfc_sli *psli = &phba->sli;
3404 struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003405 uint8_t *pcmd;
3406
James Smart2e0fef82007-06-17 19:56:36 -05003407 elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
3408 ndlp->nlp_DID, ELS_CMD_ACC);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003409
James Smart488d1462006-03-07 15:02:37 -05003410 if (!elsiocb)
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003411 return 1;
James Smart488d1462006-03-07 15:02:37 -05003412
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003413 icmd = &elsiocb->iocb;
3414 oldcmd = &oldiocb->iocb;
3415 icmd->ulpContext = oldcmd->ulpContext; /* Xri */
3416
3417 pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
3418 *((uint32_t *) (pcmd)) = ELS_CMD_ACC;
James Smart92d7f7b2007-06-17 19:56:38 -05003419 pcmd += sizeof(uint16_t);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003420 *((uint16_t *)(pcmd)) = be16_to_cpu(cmdsize);
3421 pcmd += sizeof(uint16_t);
3422
3423 /* Setup the RPL ACC payload */
3424 rpl_rsp.listLen = be32_to_cpu(1);
3425 rpl_rsp.index = 0;
3426 rpl_rsp.port_num_blk.portNum = 0;
James Smart2e0fef82007-06-17 19:56:36 -05003427 rpl_rsp.port_num_blk.portID = be32_to_cpu(vport->fc_myDID);
3428 memcpy(&rpl_rsp.port_num_blk.portName, &vport->fc_portname,
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003429 sizeof(struct lpfc_name));
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003430 memcpy(pcmd, &rpl_rsp, cmdsize - sizeof(uint32_t));
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003431 /* Xmit ELS RPL ACC response tag <ulpIoTag> */
James Smarte8b62012007-08-02 11:10:09 -04003432 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
3433 "0120 Xmit ELS RPL ACC response tag x%x "
3434 "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, "
3435 "rpi x%x\n",
3436 elsiocb->iotag, elsiocb->iocb.ulpContext,
3437 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
3438 ndlp->nlp_rpi);
James Smart858c9f62007-06-17 19:56:39 -05003439 elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003440 phba->fc_stat.elsXmitACC++;
3441 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
3442 lpfc_els_free_iocb(phba, elsiocb);
3443 return 1;
3444 }
3445 return 0;
3446}
3447
3448static int
James Smart2e0fef82007-06-17 19:56:36 -05003449lpfc_els_rcv_rpl(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3450 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05003451{
3452 struct lpfc_dmabuf *pcmd;
3453 uint32_t *lp;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003454 uint32_t maxsize;
3455 uint16_t cmdsize;
3456 RPL *rpl;
3457 struct ls_rjt stat;
dea31012005-04-17 16:05:31 -05003458
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05003459 if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
3460 (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) {
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003461 stat.un.b.lsRjtRsvd0 = 0;
3462 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
3463 stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
3464 stat.un.b.vendorUnique = 0;
James Smart858c9f62007-06-17 19:56:39 -05003465 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
3466 NULL);
dea31012005-04-17 16:05:31 -05003467 }
3468
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003469 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3470 lp = (uint32_t *) pcmd->virt;
3471 rpl = (RPL *) (lp + 1);
3472
3473 maxsize = be32_to_cpu(rpl->maxsize);
3474
3475 /* We support only one port */
3476 if ((rpl->index == 0) &&
3477 ((maxsize == 0) ||
3478 ((maxsize * sizeof(uint32_t)) >= sizeof(RPL_RSP)))) {
3479 cmdsize = sizeof(uint32_t) + sizeof(RPL_RSP);
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05003480 } else {
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05003481 cmdsize = sizeof(uint32_t) + maxsize * sizeof(uint32_t);
3482 }
James Smart2e0fef82007-06-17 19:56:36 -05003483 lpfc_els_rsp_rpl_acc(vport, cmdsize, cmdiocb, ndlp);
dea31012005-04-17 16:05:31 -05003484
3485 return 0;
3486}
3487
3488static int
James Smart2e0fef82007-06-17 19:56:36 -05003489lpfc_els_rcv_farp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3490 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05003491{
3492 struct lpfc_dmabuf *pcmd;
3493 uint32_t *lp;
3494 IOCB_t *icmd;
3495 FARP *fp;
3496 uint32_t cmd, cnt, did;
3497
3498 icmd = &cmdiocb->iocb;
3499 did = icmd->un.elsreq64.remoteID;
3500 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3501 lp = (uint32_t *) pcmd->virt;
3502
3503 cmd = *lp++;
3504 fp = (FARP *) lp;
dea31012005-04-17 16:05:31 -05003505 /* FARP-REQ received from DID <did> */
James Smarte8b62012007-08-02 11:10:09 -04003506 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
3507 "0601 FARP-REQ received from DID x%x\n", did);
dea31012005-04-17 16:05:31 -05003508 /* We will only support match on WWPN or WWNN */
3509 if (fp->Mflags & ~(FARP_MATCH_NODE | FARP_MATCH_PORT)) {
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003510 return 0;
dea31012005-04-17 16:05:31 -05003511 }
3512
3513 cnt = 0;
3514 /* If this FARP command is searching for my portname */
3515 if (fp->Mflags & FARP_MATCH_PORT) {
James Smart2e0fef82007-06-17 19:56:36 -05003516 if (memcmp(&fp->RportName, &vport->fc_portname,
James Smart92d7f7b2007-06-17 19:56:38 -05003517 sizeof(struct lpfc_name)) == 0)
dea31012005-04-17 16:05:31 -05003518 cnt = 1;
3519 }
3520
3521 /* If this FARP command is searching for my nodename */
3522 if (fp->Mflags & FARP_MATCH_NODE) {
James Smart2e0fef82007-06-17 19:56:36 -05003523 if (memcmp(&fp->RnodeName, &vport->fc_nodename,
James Smart92d7f7b2007-06-17 19:56:38 -05003524 sizeof(struct lpfc_name)) == 0)
dea31012005-04-17 16:05:31 -05003525 cnt = 1;
3526 }
3527
3528 if (cnt) {
3529 if ((ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) ||
3530 (ndlp->nlp_state == NLP_STE_MAPPED_NODE)) {
3531 /* Log back into the node before sending the FARP. */
3532 if (fp->Rflags & FARP_REQUEST_PLOGI) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003533 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05003534 lpfc_nlp_set_state(vport, ndlp,
James Smartde0c5b32007-04-25 09:52:27 -04003535 NLP_STE_PLOGI_ISSUE);
James Smart2e0fef82007-06-17 19:56:36 -05003536 lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
dea31012005-04-17 16:05:31 -05003537 }
3538
3539 /* Send a FARP response to that node */
James Smart2e0fef82007-06-17 19:56:36 -05003540 if (fp->Rflags & FARP_REQUEST_FARPR)
3541 lpfc_issue_els_farpr(vport, did, 0);
dea31012005-04-17 16:05:31 -05003542 }
3543 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003544 return 0;
dea31012005-04-17 16:05:31 -05003545}
3546
3547static int
James Smart2e0fef82007-06-17 19:56:36 -05003548lpfc_els_rcv_farpr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3549 struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -05003550{
3551 struct lpfc_dmabuf *pcmd;
3552 uint32_t *lp;
3553 IOCB_t *icmd;
3554 uint32_t cmd, did;
3555
3556 icmd = &cmdiocb->iocb;
3557 did = icmd->un.elsreq64.remoteID;
3558 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
3559 lp = (uint32_t *) pcmd->virt;
3560
3561 cmd = *lp++;
3562 /* FARP-RSP received from DID <did> */
James Smarte8b62012007-08-02 11:10:09 -04003563 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
3564 "0600 FARP-RSP received from DID x%x\n", did);
dea31012005-04-17 16:05:31 -05003565 /* ACCEPT the Farp resp request */
James Smart51ef4c22007-08-02 11:10:31 -04003566 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
dea31012005-04-17 16:05:31 -05003567
3568 return 0;
3569}
3570
3571static int
James Smart2e0fef82007-06-17 19:56:36 -05003572lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
3573 struct lpfc_nodelist *fan_ndlp)
dea31012005-04-17 16:05:31 -05003574{
3575 struct lpfc_dmabuf *pcmd;
3576 uint32_t *lp;
3577 IOCB_t *icmd;
dea31012005-04-17 16:05:31 -05003578 uint32_t cmd, did;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003579 FAN *fp;
3580 struct lpfc_nodelist *ndlp, *next_ndlp;
James Smart2e0fef82007-06-17 19:56:36 -05003581 struct lpfc_hba *phba = vport->phba;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003582
3583 /* FAN received */
James Smarte8b62012007-08-02 11:10:09 -04003584 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
3585 "0265 FAN received\n");
dea31012005-04-17 16:05:31 -05003586 icmd = &cmdiocb->iocb;
3587 did = icmd->un.elsreq64.remoteID;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003588 pcmd = (struct lpfc_dmabuf *)cmdiocb->context2;
3589 lp = (uint32_t *)pcmd->virt;
dea31012005-04-17 16:05:31 -05003590
3591 cmd = *lp++;
James Smart92d7f7b2007-06-17 19:56:38 -05003592 fp = (FAN *) lp;
dea31012005-04-17 16:05:31 -05003593
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003594 /* FAN received; Fan does not have a reply sequence */
dea31012005-04-17 16:05:31 -05003595
James Smart2e0fef82007-06-17 19:56:36 -05003596 if (phba->pport->port_state == LPFC_LOCAL_CFG_LINK) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003597 if ((memcmp(&phba->fc_fabparam.nodeName, &fp->FnodeName,
3598 sizeof(struct lpfc_name)) != 0) ||
3599 (memcmp(&phba->fc_fabparam.portName, &fp->FportName,
3600 sizeof(struct lpfc_name)) != 0)) {
3601 /*
3602 * This node has switched fabrics. FLOGI is required
3603 * Clean up the old rpi's
dea31012005-04-17 16:05:31 -05003604 */
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003605
3606 list_for_each_entry_safe(ndlp, next_ndlp,
James Smart2e0fef82007-06-17 19:56:36 -05003607 &vport->fc_nodes, nlp_listp) {
James Smart685f0bf2007-04-25 09:53:08 -04003608 if (ndlp->nlp_state != NLP_STE_NPR_NODE)
3609 continue;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003610 if (ndlp->nlp_type & NLP_FABRIC) {
3611 /*
3612 * Clean up old Fabric, Nameserver and
3613 * other NLP_FABRIC logins
3614 */
James Smart2e0fef82007-06-17 19:56:36 -05003615 lpfc_drop_node(vport, ndlp);
James Smart87af33f2007-10-27 13:37:43 -04003616
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -05003617 } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003618 /* Fail outstanding I/O now since this
3619 * device is marked for PLOGI
3620 */
James Smart2e0fef82007-06-17 19:56:36 -05003621 lpfc_unreg_rpi(vport, ndlp);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003622 }
3623 }
3624
James Smart2e0fef82007-06-17 19:56:36 -05003625 lpfc_initial_flogi(vport);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003626 return 0;
dea31012005-04-17 16:05:31 -05003627 }
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003628 /* Discovery not needed,
3629 * move the nodes to their original state.
3630 */
James Smart2e0fef82007-06-17 19:56:36 -05003631 list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
James Smart685f0bf2007-04-25 09:53:08 -04003632 nlp_listp) {
3633 if (ndlp->nlp_state != NLP_STE_NPR_NODE)
3634 continue;
dea31012005-04-17 16:05:31 -05003635
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003636 switch (ndlp->nlp_prev_state) {
3637 case NLP_STE_UNMAPPED_NODE:
3638 ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
James Smart2e0fef82007-06-17 19:56:36 -05003639 lpfc_nlp_set_state(vport, ndlp,
James Smartde0c5b32007-04-25 09:52:27 -04003640 NLP_STE_UNMAPPED_NODE);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003641 break;
3642
3643 case NLP_STE_MAPPED_NODE:
3644 ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
James Smart2e0fef82007-06-17 19:56:36 -05003645 lpfc_nlp_set_state(vport, ndlp,
James Smartde0c5b32007-04-25 09:52:27 -04003646 NLP_STE_MAPPED_NODE);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05003647 break;
3648
3649 default:
3650 break;
3651 }
3652 }
3653
3654 /* Start discovery - this should just do CLEAR_LA */
James Smart2e0fef82007-06-17 19:56:36 -05003655 lpfc_disc_start(vport);
dea31012005-04-17 16:05:31 -05003656 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003657 return 0;
dea31012005-04-17 16:05:31 -05003658}
3659
3660void
3661lpfc_els_timeout(unsigned long ptr)
3662{
James Smart2e0fef82007-06-17 19:56:36 -05003663 struct lpfc_vport *vport = (struct lpfc_vport *) ptr;
3664 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05003665 unsigned long iflag;
3666
James Smart2e0fef82007-06-17 19:56:36 -05003667 spin_lock_irqsave(&vport->work_port_lock, iflag);
3668 if ((vport->work_port_events & WORKER_ELS_TMO) == 0) {
3669 vport->work_port_events |= WORKER_ELS_TMO;
James Smart92d7f7b2007-06-17 19:56:38 -05003670 spin_unlock_irqrestore(&vport->work_port_lock, iflag);
3671
3672 spin_lock_irqsave(&phba->hbalock, iflag);
dea31012005-04-17 16:05:31 -05003673 if (phba->work_wait)
James Smart92d7f7b2007-06-17 19:56:38 -05003674 lpfc_worker_wake_up(phba);
3675 spin_unlock_irqrestore(&phba->hbalock, iflag);
dea31012005-04-17 16:05:31 -05003676 }
James Smart92d7f7b2007-06-17 19:56:38 -05003677 else
3678 spin_unlock_irqrestore(&vport->work_port_lock, iflag);
dea31012005-04-17 16:05:31 -05003679 return;
3680}
3681
3682void
James Smart2e0fef82007-06-17 19:56:36 -05003683lpfc_els_timeout_handler(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05003684{
James Smart2e0fef82007-06-17 19:56:36 -05003685 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05003686 struct lpfc_sli_ring *pring;
3687 struct lpfc_iocbq *tmp_iocb, *piocb;
3688 IOCB_t *cmd = NULL;
3689 struct lpfc_dmabuf *pcmd;
James Smart2e0fef82007-06-17 19:56:36 -05003690 uint32_t els_command = 0;
dea31012005-04-17 16:05:31 -05003691 uint32_t timeout;
James Smart2e0fef82007-06-17 19:56:36 -05003692 uint32_t remote_ID = 0xffffffff;
dea31012005-04-17 16:05:31 -05003693
dea31012005-04-17 16:05:31 -05003694 /* If the timer is already canceled do nothing */
James Smart2e0fef82007-06-17 19:56:36 -05003695 if ((vport->work_port_events & WORKER_ELS_TMO) == 0) {
dea31012005-04-17 16:05:31 -05003696 return;
3697 }
James Smart2e0fef82007-06-17 19:56:36 -05003698 spin_lock_irq(&phba->hbalock);
dea31012005-04-17 16:05:31 -05003699 timeout = (uint32_t)(phba->fc_ratov << 1);
3700
3701 pring = &phba->sli.ring[LPFC_ELS_RING];
dea31012005-04-17 16:05:31 -05003702
3703 list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
3704 cmd = &piocb->iocb;
3705
James Smart2e0fef82007-06-17 19:56:36 -05003706 if ((piocb->iocb_flag & LPFC_IO_LIBDFC) != 0 ||
3707 piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN ||
3708 piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)
dea31012005-04-17 16:05:31 -05003709 continue;
James Smart2e0fef82007-06-17 19:56:36 -05003710
3711 if (piocb->vport != vport)
3712 continue;
3713
dea31012005-04-17 16:05:31 -05003714 pcmd = (struct lpfc_dmabuf *) piocb->context2;
James Smart2e0fef82007-06-17 19:56:36 -05003715 if (pcmd)
3716 els_command = *(uint32_t *) (pcmd->virt);
dea31012005-04-17 16:05:31 -05003717
James Smart92d7f7b2007-06-17 19:56:38 -05003718 if (els_command == ELS_CMD_FARP ||
3719 els_command == ELS_CMD_FARPR ||
3720 els_command == ELS_CMD_FDISC)
dea31012005-04-17 16:05:31 -05003721 continue;
James Smart92d7f7b2007-06-17 19:56:38 -05003722
3723 if (vport != piocb->vport)
3724 continue;
dea31012005-04-17 16:05:31 -05003725
3726 if (piocb->drvrTimeout > 0) {
James Smart92d7f7b2007-06-17 19:56:38 -05003727 if (piocb->drvrTimeout >= timeout)
dea31012005-04-17 16:05:31 -05003728 piocb->drvrTimeout -= timeout;
James Smart92d7f7b2007-06-17 19:56:38 -05003729 else
dea31012005-04-17 16:05:31 -05003730 piocb->drvrTimeout = 0;
dea31012005-04-17 16:05:31 -05003731 continue;
3732 }
3733
James Smart2e0fef82007-06-17 19:56:36 -05003734 remote_ID = 0xffffffff;
3735 if (cmd->ulpCommand != CMD_GEN_REQUEST64_CR)
dea31012005-04-17 16:05:31 -05003736 remote_ID = cmd->un.elsreq64.remoteID;
James Smart2e0fef82007-06-17 19:56:36 -05003737 else {
3738 struct lpfc_nodelist *ndlp;
3739 ndlp = __lpfc_findnode_rpi(vport, cmd->ulpContext);
3740 if (ndlp)
3741 remote_ID = ndlp->nlp_DID;
dea31012005-04-17 16:05:31 -05003742 }
James Smarte8b62012007-08-02 11:10:09 -04003743 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
3744 "0127 ELS timeout Data: x%x x%x x%x "
3745 "x%x\n", els_command,
3746 remote_ID, cmd->ulpCommand, cmd->ulpIoTag);
James Smart07951072007-04-25 09:51:38 -04003747 lpfc_sli_issue_abort_iotag(phba, pring, piocb);
dea31012005-04-17 16:05:31 -05003748 }
James Smart2e0fef82007-06-17 19:56:36 -05003749 spin_unlock_irq(&phba->hbalock);
James Smart5a0e3262006-07-06 15:49:16 -04003750
James Smart2e0fef82007-06-17 19:56:36 -05003751 if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt)
3752 mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout);
dea31012005-04-17 16:05:31 -05003753}
3754
3755void
James Smart2e0fef82007-06-17 19:56:36 -05003756lpfc_els_flush_cmd(struct lpfc_vport *vport)
dea31012005-04-17 16:05:31 -05003757{
James Smart2534ba72007-04-25 09:52:20 -04003758 LIST_HEAD(completions);
James Smart2e0fef82007-06-17 19:56:36 -05003759 struct lpfc_hba *phba = vport->phba;
James Smart329f9bc2007-04-25 09:53:01 -04003760 struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
dea31012005-04-17 16:05:31 -05003761 struct lpfc_iocbq *tmp_iocb, *piocb;
3762 IOCB_t *cmd = NULL;
James Smart92d7f7b2007-06-17 19:56:38 -05003763
3764 lpfc_fabric_abort_vport(vport);
dea31012005-04-17 16:05:31 -05003765
James Smart2e0fef82007-06-17 19:56:36 -05003766 spin_lock_irq(&phba->hbalock);
dea31012005-04-17 16:05:31 -05003767 list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
3768 cmd = &piocb->iocb;
3769
3770 if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
3771 continue;
3772 }
3773
3774 /* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */
James Smart329f9bc2007-04-25 09:53:01 -04003775 if (cmd->ulpCommand == CMD_QUE_RING_BUF_CN ||
3776 cmd->ulpCommand == CMD_QUE_RING_BUF64_CN ||
3777 cmd->ulpCommand == CMD_CLOSE_XRI_CN ||
3778 cmd->ulpCommand == CMD_ABORT_XRI_CN)
dea31012005-04-17 16:05:31 -05003779 continue;
dea31012005-04-17 16:05:31 -05003780
James Smart2e0fef82007-06-17 19:56:36 -05003781 if (piocb->vport != vport)
3782 continue;
3783
James Smart2534ba72007-04-25 09:52:20 -04003784 list_move_tail(&piocb->list, &completions);
James Smart1dcb58e2007-04-25 09:51:30 -04003785 pring->txq_cnt--;
dea31012005-04-17 16:05:31 -05003786 }
3787
3788 list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
dea31012005-04-17 16:05:31 -05003789 if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
3790 continue;
3791 }
dea31012005-04-17 16:05:31 -05003792
James Smart2e0fef82007-06-17 19:56:36 -05003793 if (piocb->vport != vport)
3794 continue;
3795
James Smart07951072007-04-25 09:51:38 -04003796 lpfc_sli_issue_abort_iotag(phba, pring, piocb);
dea31012005-04-17 16:05:31 -05003797 }
James Smart2e0fef82007-06-17 19:56:36 -05003798 spin_unlock_irq(&phba->hbalock);
James Smart2534ba72007-04-25 09:52:20 -04003799
James Smart2e0fef82007-06-17 19:56:36 -05003800 while (!list_empty(&completions)) {
James Smart2534ba72007-04-25 09:52:20 -04003801 piocb = list_get_first(&completions, struct lpfc_iocbq, list);
3802 cmd = &piocb->iocb;
James Smart92d7f7b2007-06-17 19:56:38 -05003803 list_del_init(&piocb->list);
James Smart2534ba72007-04-25 09:52:20 -04003804
James Smart2e0fef82007-06-17 19:56:36 -05003805 if (!piocb->iocb_cmpl)
3806 lpfc_sli_release_iocbq(phba, piocb);
3807 else {
James Smart2534ba72007-04-25 09:52:20 -04003808 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
3809 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
3810 (piocb->iocb_cmpl) (phba, piocb, piocb);
James Smart2e0fef82007-06-17 19:56:36 -05003811 }
James Smart2534ba72007-04-25 09:52:20 -04003812 }
3813
dea31012005-04-17 16:05:31 -05003814 return;
3815}
3816
James Smart549e55c2007-08-02 11:09:51 -04003817void
3818lpfc_els_flush_all_cmd(struct lpfc_hba *phba)
3819{
3820 LIST_HEAD(completions);
3821 struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
3822 struct lpfc_iocbq *tmp_iocb, *piocb;
3823 IOCB_t *cmd = NULL;
3824
3825 lpfc_fabric_abort_hba(phba);
3826 spin_lock_irq(&phba->hbalock);
3827 list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
3828 cmd = &piocb->iocb;
3829 if (piocb->iocb_flag & LPFC_IO_LIBDFC)
3830 continue;
3831 /* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */
3832 if (cmd->ulpCommand == CMD_QUE_RING_BUF_CN ||
3833 cmd->ulpCommand == CMD_QUE_RING_BUF64_CN ||
3834 cmd->ulpCommand == CMD_CLOSE_XRI_CN ||
3835 cmd->ulpCommand == CMD_ABORT_XRI_CN)
3836 continue;
3837 list_move_tail(&piocb->list, &completions);
3838 pring->txq_cnt--;
3839 }
3840 list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
3841 if (piocb->iocb_flag & LPFC_IO_LIBDFC)
3842 continue;
3843 lpfc_sli_issue_abort_iotag(phba, pring, piocb);
3844 }
3845 spin_unlock_irq(&phba->hbalock);
3846 while (!list_empty(&completions)) {
3847 piocb = list_get_first(&completions, struct lpfc_iocbq, list);
3848 cmd = &piocb->iocb;
3849 list_del_init(&piocb->list);
3850 if (!piocb->iocb_cmpl)
3851 lpfc_sli_release_iocbq(phba, piocb);
3852 else {
3853 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
3854 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
3855 (piocb->iocb_cmpl) (phba, piocb, piocb);
3856 }
3857 }
3858 return;
3859}
3860
James Smarted957682007-06-17 19:56:37 -05003861static void
3862lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
James Smart92d7f7b2007-06-17 19:56:38 -05003863 struct lpfc_vport *vport, struct lpfc_iocbq *elsiocb)
dea31012005-04-17 16:05:31 -05003864{
James Smart87af33f2007-10-27 13:37:43 -04003865 struct Scsi_Host *shost;
dea31012005-04-17 16:05:31 -05003866 struct lpfc_nodelist *ndlp;
dea31012005-04-17 16:05:31 -05003867 struct ls_rjt stat;
James Smart92d7f7b2007-06-17 19:56:38 -05003868 uint32_t *payload;
James Smart2e0fef82007-06-17 19:56:36 -05003869 uint32_t cmd, did, newnode, rjt_err = 0;
James Smarted957682007-06-17 19:56:37 -05003870 IOCB_t *icmd = &elsiocb->iocb;
dea31012005-04-17 16:05:31 -05003871
James Smart92d7f7b2007-06-17 19:56:38 -05003872 if (vport == NULL || elsiocb->context2 == NULL)
dea31012005-04-17 16:05:31 -05003873 goto dropit;
James Smart2e0fef82007-06-17 19:56:36 -05003874
dea31012005-04-17 16:05:31 -05003875 newnode = 0;
James Smart92d7f7b2007-06-17 19:56:38 -05003876 payload = ((struct lpfc_dmabuf *)elsiocb->context2)->virt;
3877 cmd = *payload;
James Smarted957682007-06-17 19:56:37 -05003878 if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) == 0)
3879 lpfc_post_buffer(phba, pring, 1, 1);
dea31012005-04-17 16:05:31 -05003880
James Smart858c9f62007-06-17 19:56:39 -05003881 did = icmd->un.rcvels.remoteID;
3882 if (icmd->ulpStatus) {
3883 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3884 "RCV Unsol ELS: status:x%x/x%x did:x%x",
3885 icmd->ulpStatus, icmd->un.ulpWord[4], did);
dea31012005-04-17 16:05:31 -05003886 goto dropit;
James Smart858c9f62007-06-17 19:56:39 -05003887 }
dea31012005-04-17 16:05:31 -05003888
3889 /* Check to see if link went down during discovery */
James Smarted957682007-06-17 19:56:37 -05003890 if (lpfc_els_chk_latt(vport))
dea31012005-04-17 16:05:31 -05003891 goto dropit;
dea31012005-04-17 16:05:31 -05003892
James Smart92d7f7b2007-06-17 19:56:38 -05003893 /* Ignore traffic recevied during vport shutdown. */
3894 if (vport->load_flag & FC_UNLOADING)
3895 goto dropit;
3896
James Smart2e0fef82007-06-17 19:56:36 -05003897 ndlp = lpfc_findnode_did(vport, did);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003898 if (!ndlp) {
dea31012005-04-17 16:05:31 -05003899 /* Cannot find existing Fabric ndlp, so allocate a new one */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05003900 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
James Smarted957682007-06-17 19:56:37 -05003901 if (!ndlp)
dea31012005-04-17 16:05:31 -05003902 goto dropit;
dea31012005-04-17 16:05:31 -05003903
James Smart2e0fef82007-06-17 19:56:36 -05003904 lpfc_nlp_init(vport, ndlp, did);
James Smart98c9ea52007-10-27 13:37:33 -04003905 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
dea31012005-04-17 16:05:31 -05003906 newnode = 1;
3907 if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) {
3908 ndlp->nlp_type |= NLP_FABRIC;
3909 }
3910 }
James Smart87af33f2007-10-27 13:37:43 -04003911 else {
3912 if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) {
3913 /* This is simular to the new node path */
3914 lpfc_nlp_get(ndlp);
3915 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
3916 newnode = 1;
3917 }
3918 }
dea31012005-04-17 16:05:31 -05003919
3920 phba->fc_stat.elsRcvFrame++;
James Smart329f9bc2007-04-25 09:53:01 -04003921 if (elsiocb->context1)
3922 lpfc_nlp_put(elsiocb->context1);
3923 elsiocb->context1 = lpfc_nlp_get(ndlp);
James Smart2e0fef82007-06-17 19:56:36 -05003924 elsiocb->vport = vport;
dea31012005-04-17 16:05:31 -05003925
3926 if ((cmd & ELS_CMD_MASK) == ELS_CMD_RSCN) {
3927 cmd &= ELS_CMD_MASK;
3928 }
3929 /* ELS command <elsCmd> received from NPORT <did> */
James Smarte8b62012007-08-02 11:10:09 -04003930 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
3931 "0112 ELS command x%x received from NPORT x%x "
3932 "Data: x%x\n", cmd, did, vport->port_state);
dea31012005-04-17 16:05:31 -05003933 switch (cmd) {
3934 case ELS_CMD_PLOGI:
James Smart858c9f62007-06-17 19:56:39 -05003935 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3936 "RCV PLOGI: did:x%x/ste:x%x flg:x%x",
3937 did, vport->port_state, ndlp->nlp_flag);
3938
dea31012005-04-17 16:05:31 -05003939 phba->fc_stat.elsRcvPLOGI++;
James Smart858c9f62007-06-17 19:56:39 -05003940 ndlp = lpfc_plogi_confirm_nport(phba, payload, ndlp);
3941
3942 if (vport->port_state < LPFC_DISC_AUTH) {
3943 rjt_err = LSRJT_UNABLE_TPC;
dea31012005-04-17 16:05:31 -05003944 break;
3945 }
James Smart87af33f2007-10-27 13:37:43 -04003946
3947 shost = lpfc_shost_from_vport(vport);
3948 spin_lock_irq(shost->host_lock);
3949 ndlp->nlp_flag &= ~NLP_TARGET_REMOVE;
3950 spin_unlock_irq(shost->host_lock);
3951
James Smart2e0fef82007-06-17 19:56:36 -05003952 lpfc_disc_state_machine(vport, ndlp, elsiocb,
3953 NLP_EVT_RCV_PLOGI);
James Smart858c9f62007-06-17 19:56:39 -05003954
dea31012005-04-17 16:05:31 -05003955 break;
3956 case ELS_CMD_FLOGI:
James Smart858c9f62007-06-17 19:56:39 -05003957 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3958 "RCV FLOGI: did:x%x/ste:x%x flg:x%x",
3959 did, vport->port_state, ndlp->nlp_flag);
3960
dea31012005-04-17 16:05:31 -05003961 phba->fc_stat.elsRcvFLOGI++;
James Smart51ef4c22007-08-02 11:10:31 -04003962 lpfc_els_rcv_flogi(vport, elsiocb, ndlp);
James Smart87af33f2007-10-27 13:37:43 -04003963 if (newnode)
James Smart98c9ea52007-10-27 13:37:33 -04003964 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05003965 break;
3966 case ELS_CMD_LOGO:
James Smart858c9f62007-06-17 19:56:39 -05003967 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3968 "RCV LOGO: did:x%x/ste:x%x flg:x%x",
3969 did, vport->port_state, ndlp->nlp_flag);
3970
dea31012005-04-17 16:05:31 -05003971 phba->fc_stat.elsRcvLOGO++;
James Smart2e0fef82007-06-17 19:56:36 -05003972 if (vport->port_state < LPFC_DISC_AUTH) {
James Smart858c9f62007-06-17 19:56:39 -05003973 rjt_err = LSRJT_UNABLE_TPC;
dea31012005-04-17 16:05:31 -05003974 break;
3975 }
James Smart2e0fef82007-06-17 19:56:36 -05003976 lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_LOGO);
dea31012005-04-17 16:05:31 -05003977 break;
3978 case ELS_CMD_PRLO:
James Smart858c9f62007-06-17 19:56:39 -05003979 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3980 "RCV PRLO: did:x%x/ste:x%x flg:x%x",
3981 did, vport->port_state, ndlp->nlp_flag);
3982
dea31012005-04-17 16:05:31 -05003983 phba->fc_stat.elsRcvPRLO++;
James Smart2e0fef82007-06-17 19:56:36 -05003984 if (vport->port_state < LPFC_DISC_AUTH) {
James Smart858c9f62007-06-17 19:56:39 -05003985 rjt_err = LSRJT_UNABLE_TPC;
dea31012005-04-17 16:05:31 -05003986 break;
3987 }
James Smart2e0fef82007-06-17 19:56:36 -05003988 lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PRLO);
dea31012005-04-17 16:05:31 -05003989 break;
3990 case ELS_CMD_RSCN:
3991 phba->fc_stat.elsRcvRSCN++;
James Smart51ef4c22007-08-02 11:10:31 -04003992 lpfc_els_rcv_rscn(vport, elsiocb, ndlp);
James Smart87af33f2007-10-27 13:37:43 -04003993 if (newnode)
James Smart98c9ea52007-10-27 13:37:33 -04003994 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05003995 break;
3996 case ELS_CMD_ADISC:
James Smart858c9f62007-06-17 19:56:39 -05003997 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
3998 "RCV ADISC: did:x%x/ste:x%x flg:x%x",
3999 did, vport->port_state, ndlp->nlp_flag);
4000
dea31012005-04-17 16:05:31 -05004001 phba->fc_stat.elsRcvADISC++;
James Smart2e0fef82007-06-17 19:56:36 -05004002 if (vport->port_state < LPFC_DISC_AUTH) {
James Smart858c9f62007-06-17 19:56:39 -05004003 rjt_err = LSRJT_UNABLE_TPC;
dea31012005-04-17 16:05:31 -05004004 break;
4005 }
James Smart2e0fef82007-06-17 19:56:36 -05004006 lpfc_disc_state_machine(vport, ndlp, elsiocb,
4007 NLP_EVT_RCV_ADISC);
dea31012005-04-17 16:05:31 -05004008 break;
4009 case ELS_CMD_PDISC:
James Smart858c9f62007-06-17 19:56:39 -05004010 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
4011 "RCV PDISC: did:x%x/ste:x%x flg:x%x",
4012 did, vport->port_state, ndlp->nlp_flag);
4013
dea31012005-04-17 16:05:31 -05004014 phba->fc_stat.elsRcvPDISC++;
James Smart2e0fef82007-06-17 19:56:36 -05004015 if (vport->port_state < LPFC_DISC_AUTH) {
James Smart858c9f62007-06-17 19:56:39 -05004016 rjt_err = LSRJT_UNABLE_TPC;
dea31012005-04-17 16:05:31 -05004017 break;
4018 }
James Smart2e0fef82007-06-17 19:56:36 -05004019 lpfc_disc_state_machine(vport, ndlp, elsiocb,
4020 NLP_EVT_RCV_PDISC);
dea31012005-04-17 16:05:31 -05004021 break;
4022 case ELS_CMD_FARPR:
James Smart858c9f62007-06-17 19:56:39 -05004023 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
4024 "RCV FARPR: did:x%x/ste:x%x flg:x%x",
4025 did, vport->port_state, ndlp->nlp_flag);
4026
dea31012005-04-17 16:05:31 -05004027 phba->fc_stat.elsRcvFARPR++;
James Smart2e0fef82007-06-17 19:56:36 -05004028 lpfc_els_rcv_farpr(vport, elsiocb, ndlp);
dea31012005-04-17 16:05:31 -05004029 break;
4030 case ELS_CMD_FARP:
James Smart858c9f62007-06-17 19:56:39 -05004031 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
4032 "RCV FARP: did:x%x/ste:x%x flg:x%x",
4033 did, vport->port_state, ndlp->nlp_flag);
4034
dea31012005-04-17 16:05:31 -05004035 phba->fc_stat.elsRcvFARP++;
James Smart2e0fef82007-06-17 19:56:36 -05004036 lpfc_els_rcv_farp(vport, elsiocb, ndlp);
dea31012005-04-17 16:05:31 -05004037 break;
4038 case ELS_CMD_FAN:
James Smart858c9f62007-06-17 19:56:39 -05004039 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
4040 "RCV FAN: did:x%x/ste:x%x flg:x%x",
4041 did, vport->port_state, ndlp->nlp_flag);
4042
dea31012005-04-17 16:05:31 -05004043 phba->fc_stat.elsRcvFAN++;
James Smart2e0fef82007-06-17 19:56:36 -05004044 lpfc_els_rcv_fan(vport, elsiocb, ndlp);
dea31012005-04-17 16:05:31 -05004045 break;
dea31012005-04-17 16:05:31 -05004046 case ELS_CMD_PRLI:
James Smart858c9f62007-06-17 19:56:39 -05004047 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
4048 "RCV PRLI: did:x%x/ste:x%x flg:x%x",
4049 did, vport->port_state, ndlp->nlp_flag);
4050
dea31012005-04-17 16:05:31 -05004051 phba->fc_stat.elsRcvPRLI++;
James Smart2e0fef82007-06-17 19:56:36 -05004052 if (vport->port_state < LPFC_DISC_AUTH) {
James Smart858c9f62007-06-17 19:56:39 -05004053 rjt_err = LSRJT_UNABLE_TPC;
dea31012005-04-17 16:05:31 -05004054 break;
4055 }
James Smart2e0fef82007-06-17 19:56:36 -05004056 lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PRLI);
dea31012005-04-17 16:05:31 -05004057 break;
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05004058 case ELS_CMD_LIRR:
James Smart858c9f62007-06-17 19:56:39 -05004059 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
4060 "RCV LIRR: did:x%x/ste:x%x flg:x%x",
4061 did, vport->port_state, ndlp->nlp_flag);
4062
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05004063 phba->fc_stat.elsRcvLIRR++;
James Smart2e0fef82007-06-17 19:56:36 -05004064 lpfc_els_rcv_lirr(vport, elsiocb, ndlp);
James Smart87af33f2007-10-27 13:37:43 -04004065 if (newnode)
James Smart98c9ea52007-10-27 13:37:33 -04004066 lpfc_nlp_put(ndlp);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05004067 break;
4068 case ELS_CMD_RPS:
James Smart858c9f62007-06-17 19:56:39 -05004069 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
4070 "RCV RPS: did:x%x/ste:x%x flg:x%x",
4071 did, vport->port_state, ndlp->nlp_flag);
4072
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05004073 phba->fc_stat.elsRcvRPS++;
James Smart2e0fef82007-06-17 19:56:36 -05004074 lpfc_els_rcv_rps(vport, elsiocb, ndlp);
James Smart87af33f2007-10-27 13:37:43 -04004075 if (newnode)
James Smart98c9ea52007-10-27 13:37:33 -04004076 lpfc_nlp_put(ndlp);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05004077 break;
4078 case ELS_CMD_RPL:
James Smart858c9f62007-06-17 19:56:39 -05004079 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
4080 "RCV RPL: did:x%x/ste:x%x flg:x%x",
4081 did, vport->port_state, ndlp->nlp_flag);
4082
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05004083 phba->fc_stat.elsRcvRPL++;
James Smart2e0fef82007-06-17 19:56:36 -05004084 lpfc_els_rcv_rpl(vport, elsiocb, ndlp);
James Smart87af33f2007-10-27 13:37:43 -04004085 if (newnode)
James Smart98c9ea52007-10-27 13:37:33 -04004086 lpfc_nlp_put(ndlp);
Jamie Wellnitz7bb3b132006-02-28 19:25:15 -05004087 break;
dea31012005-04-17 16:05:31 -05004088 case ELS_CMD_RNID:
James Smart858c9f62007-06-17 19:56:39 -05004089 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
4090 "RCV RNID: did:x%x/ste:x%x flg:x%x",
4091 did, vport->port_state, ndlp->nlp_flag);
4092
dea31012005-04-17 16:05:31 -05004093 phba->fc_stat.elsRcvRNID++;
James Smart2e0fef82007-06-17 19:56:36 -05004094 lpfc_els_rcv_rnid(vport, elsiocb, ndlp);
James Smart87af33f2007-10-27 13:37:43 -04004095 if (newnode)
James Smart98c9ea52007-10-27 13:37:33 -04004096 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05004097 break;
4098 default:
James Smart858c9f62007-06-17 19:56:39 -05004099 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
4100 "RCV ELS cmd: cmd:x%x did:x%x/ste:x%x",
4101 cmd, did, vport->port_state);
4102
dea31012005-04-17 16:05:31 -05004103 /* Unsupported ELS command, reject */
James Smart858c9f62007-06-17 19:56:39 -05004104 rjt_err = LSRJT_INVALID_CMD;
dea31012005-04-17 16:05:31 -05004105
4106 /* Unknown ELS command <elsCmd> received from NPORT <did> */
James Smarte8b62012007-08-02 11:10:09 -04004107 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
4108 "0115 Unknown ELS command x%x "
4109 "received from NPORT x%x\n", cmd, did);
James Smart87af33f2007-10-27 13:37:43 -04004110 if (newnode)
James Smart98c9ea52007-10-27 13:37:33 -04004111 lpfc_nlp_put(ndlp);
dea31012005-04-17 16:05:31 -05004112 break;
4113 }
4114
4115 /* check if need to LS_RJT received ELS cmd */
4116 if (rjt_err) {
James Smart92d7f7b2007-06-17 19:56:38 -05004117 memset(&stat, 0, sizeof(stat));
James Smart858c9f62007-06-17 19:56:39 -05004118 stat.un.b.lsRjtRsnCode = rjt_err;
James.Smart@Emulex.Com1f679ca2005-06-25 10:34:27 -04004119 stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
James Smart858c9f62007-06-17 19:56:39 -05004120 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, elsiocb, ndlp,
4121 NULL);
dea31012005-04-17 16:05:31 -05004122 }
4123
James Smarted957682007-06-17 19:56:37 -05004124 return;
4125
4126dropit:
James Smart98c9ea52007-10-27 13:37:33 -04004127 if (vport && !(vport->load_flag & FC_UNLOADING))
4128 lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
James Smarte8b62012007-08-02 11:10:09 -04004129 "(%d):0111 Dropping received ELS cmd "
James Smarted957682007-06-17 19:56:37 -05004130 "Data: x%x x%x x%x\n",
James Smart98c9ea52007-10-27 13:37:33 -04004131 vport->vpi, icmd->ulpStatus,
James Smarte8b62012007-08-02 11:10:09 -04004132 icmd->un.ulpWord[4], icmd->ulpTimeout);
James Smarted957682007-06-17 19:56:37 -05004133 phba->fc_stat.elsRcvDrop++;
4134}
4135
James Smart92d7f7b2007-06-17 19:56:38 -05004136static struct lpfc_vport *
4137lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi)
4138{
4139 struct lpfc_vport *vport;
James Smart549e55c2007-08-02 11:09:51 -04004140 unsigned long flags;
James Smart92d7f7b2007-06-17 19:56:38 -05004141
James Smart549e55c2007-08-02 11:09:51 -04004142 spin_lock_irqsave(&phba->hbalock, flags);
James Smart92d7f7b2007-06-17 19:56:38 -05004143 list_for_each_entry(vport, &phba->port_list, listentry) {
James Smart549e55c2007-08-02 11:09:51 -04004144 if (vport->vpi == vpi) {
4145 spin_unlock_irqrestore(&phba->hbalock, flags);
James Smart92d7f7b2007-06-17 19:56:38 -05004146 return vport;
James Smart549e55c2007-08-02 11:09:51 -04004147 }
James Smart92d7f7b2007-06-17 19:56:38 -05004148 }
James Smart549e55c2007-08-02 11:09:51 -04004149 spin_unlock_irqrestore(&phba->hbalock, flags);
James Smart92d7f7b2007-06-17 19:56:38 -05004150 return NULL;
4151}
James Smarted957682007-06-17 19:56:37 -05004152
4153void
4154lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
4155 struct lpfc_iocbq *elsiocb)
4156{
4157 struct lpfc_vport *vport = phba->pport;
James Smarted957682007-06-17 19:56:37 -05004158 IOCB_t *icmd = &elsiocb->iocb;
James Smarted957682007-06-17 19:56:37 -05004159 dma_addr_t paddr;
James Smart92d7f7b2007-06-17 19:56:38 -05004160 struct lpfc_dmabuf *bdeBuf1 = elsiocb->context2;
4161 struct lpfc_dmabuf *bdeBuf2 = elsiocb->context3;
James Smarted957682007-06-17 19:56:37 -05004162
James Smart92d7f7b2007-06-17 19:56:38 -05004163 elsiocb->context2 = NULL;
4164 elsiocb->context3 = NULL;
4165
4166 if (icmd->ulpStatus == IOSTAT_NEED_BUFFER) {
4167 lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
4168 } else if (icmd->ulpStatus == IOSTAT_LOCAL_REJECT &&
4169 (icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING) {
James Smarted957682007-06-17 19:56:37 -05004170 phba->fc_stat.NoRcvBuf++;
4171 /* Not enough posted buffers; Try posting more buffers */
James Smart92d7f7b2007-06-17 19:56:38 -05004172 if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED))
James Smarted957682007-06-17 19:56:37 -05004173 lpfc_post_buffer(phba, pring, 0, 1);
4174 return;
4175 }
4176
James Smart92d7f7b2007-06-17 19:56:38 -05004177 if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
4178 (icmd->ulpCommand == CMD_IOCB_RCV_ELS64_CX ||
4179 icmd->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) {
4180 if (icmd->unsli3.rcvsli3.vpi == 0xffff)
4181 vport = phba->pport;
4182 else {
4183 uint16_t vpi = icmd->unsli3.rcvsli3.vpi;
4184 vport = lpfc_find_vport_by_vpid(phba, vpi);
4185 }
4186 }
4187 /* If there are no BDEs associated
4188 * with this IOCB, there is nothing to do.
4189 */
James Smarted957682007-06-17 19:56:37 -05004190 if (icmd->ulpBdeCount == 0)
4191 return;
4192
James Smart92d7f7b2007-06-17 19:56:38 -05004193 /* type of ELS cmd is first 32bit word
4194 * in packet
4195 */
James Smarted957682007-06-17 19:56:37 -05004196 if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
James Smart92d7f7b2007-06-17 19:56:38 -05004197 elsiocb->context2 = bdeBuf1;
James Smarted957682007-06-17 19:56:37 -05004198 } else {
4199 paddr = getPaddr(icmd->un.cont64[0].addrHigh,
4200 icmd->un.cont64[0].addrLow);
James Smart92d7f7b2007-06-17 19:56:38 -05004201 elsiocb->context2 = lpfc_sli_ringpostbuf_get(phba, pring,
4202 paddr);
James Smarted957682007-06-17 19:56:37 -05004203 }
4204
James Smart92d7f7b2007-06-17 19:56:38 -05004205 lpfc_els_unsol_buffer(phba, pring, vport, elsiocb);
4206 /*
4207 * The different unsolicited event handlers would tell us
4208 * if they are done with "mp" by setting context2 to NULL.
4209 */
James Smart329f9bc2007-04-25 09:53:01 -04004210 lpfc_nlp_put(elsiocb->context1);
4211 elsiocb->context1 = NULL;
dea31012005-04-17 16:05:31 -05004212 if (elsiocb->context2) {
James Smart92d7f7b2007-06-17 19:56:38 -05004213 lpfc_in_buf_free(phba, (struct lpfc_dmabuf *)elsiocb->context2);
4214 elsiocb->context2 = NULL;
dea31012005-04-17 16:05:31 -05004215 }
James Smarted957682007-06-17 19:56:37 -05004216
4217 /* RCV_ELS64_CX provide for 2 BDEs - process 2nd if included */
James Smart92d7f7b2007-06-17 19:56:38 -05004218 if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) &&
James Smarted957682007-06-17 19:56:37 -05004219 icmd->ulpBdeCount == 2) {
James Smart92d7f7b2007-06-17 19:56:38 -05004220 elsiocb->context2 = bdeBuf2;
4221 lpfc_els_unsol_buffer(phba, pring, vport, elsiocb);
James Smarted957682007-06-17 19:56:37 -05004222 /* free mp if we are done with it */
4223 if (elsiocb->context2) {
James Smart92d7f7b2007-06-17 19:56:38 -05004224 lpfc_in_buf_free(phba, elsiocb->context2);
4225 elsiocb->context2 = NULL;
James Smarted957682007-06-17 19:56:37 -05004226 }
dea31012005-04-17 16:05:31 -05004227 }
dea31012005-04-17 16:05:31 -05004228}
James Smart92d7f7b2007-06-17 19:56:38 -05004229
4230void
4231lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport)
4232{
4233 struct lpfc_nodelist *ndlp, *ndlp_fdmi;
4234
4235 ndlp = lpfc_findnode_did(vport, NameServer_DID);
4236 if (!ndlp) {
4237 ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
4238 if (!ndlp) {
4239 if (phba->fc_topology == TOPOLOGY_LOOP) {
4240 lpfc_disc_start(vport);
4241 return;
4242 }
4243 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
James Smarte8b62012007-08-02 11:10:09 -04004244 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
4245 "0251 NameServer login: no memory\n");
James Smart92d7f7b2007-06-17 19:56:38 -05004246 return;
4247 }
4248 lpfc_nlp_init(vport, ndlp, NameServer_DID);
4249 ndlp->nlp_type |= NLP_FABRIC;
4250 }
4251
4252 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
4253
4254 if (lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0)) {
4255 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
James Smarte8b62012007-08-02 11:10:09 -04004256 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
4257 "0252 Cannot issue NameServer login\n");
James Smart92d7f7b2007-06-17 19:56:38 -05004258 return;
4259 }
4260
James Smart3de2a652007-08-02 11:09:59 -04004261 if (vport->cfg_fdmi_on) {
James Smart92d7f7b2007-06-17 19:56:38 -05004262 ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
4263 GFP_KERNEL);
4264 if (ndlp_fdmi) {
4265 lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID);
4266 ndlp_fdmi->nlp_type |= NLP_FABRIC;
4267 ndlp_fdmi->nlp_state =
4268 NLP_STE_PLOGI_ISSUE;
4269 lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID,
4270 0);
4271 }
4272 }
4273 return;
4274}
4275
4276static void
4277lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
4278{
4279 struct lpfc_vport *vport = pmb->vport;
4280 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
4281 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
4282 MAILBOX_t *mb = &pmb->mb;
4283
James Smart09372822008-01-11 01:52:54 -05004284 spin_lock_irq(shost->host_lock);
James Smart92d7f7b2007-06-17 19:56:38 -05004285 vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
James Smart09372822008-01-11 01:52:54 -05004286 spin_unlock_irq(shost->host_lock);
James Smart92d7f7b2007-06-17 19:56:38 -05004287 lpfc_nlp_put(ndlp);
4288
4289 if (mb->mbxStatus) {
James Smarte8b62012007-08-02 11:10:09 -04004290 lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
4291 "0915 Register VPI failed: 0x%x\n",
4292 mb->mbxStatus);
James Smart92d7f7b2007-06-17 19:56:38 -05004293
4294 switch (mb->mbxStatus) {
4295 case 0x11: /* unsupported feature */
4296 case 0x9603: /* max_vpi exceeded */
4297 /* giving up on vport registration */
4298 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
4299 spin_lock_irq(shost->host_lock);
4300 vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
4301 spin_unlock_irq(shost->host_lock);
4302 lpfc_can_disctmo(vport);
4303 break;
4304 default:
4305 /* Try to recover from this error */
4306 lpfc_mbx_unreg_vpi(vport);
James Smart09372822008-01-11 01:52:54 -05004307 spin_lock_irq(shost->host_lock);
James Smart92d7f7b2007-06-17 19:56:38 -05004308 vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
James Smart09372822008-01-11 01:52:54 -05004309 spin_unlock_irq(shost->host_lock);
James Smart92d7f7b2007-06-17 19:56:38 -05004310 lpfc_initial_fdisc(vport);
4311 break;
4312 }
4313
4314 } else {
4315 if (vport == phba->pport)
4316 lpfc_issue_fabric_reglogin(vport);
4317 else
4318 lpfc_do_scr_ns_plogi(phba, vport);
4319 }
4320 mempool_free(pmb, phba->mbox_mem_pool);
4321 return;
4322}
4323
Adrian Bunka6ababd2007-11-05 18:07:33 +01004324static void
James Smart92d7f7b2007-06-17 19:56:38 -05004325lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport,
4326 struct lpfc_nodelist *ndlp)
4327{
James Smart09372822008-01-11 01:52:54 -05004328 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
James Smart92d7f7b2007-06-17 19:56:38 -05004329 LPFC_MBOXQ_t *mbox;
4330
4331 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
4332 if (mbox) {
4333 lpfc_reg_vpi(phba, vport->vpi, vport->fc_myDID, mbox);
4334 mbox->vport = vport;
4335 mbox->context2 = lpfc_nlp_get(ndlp);
4336 mbox->mbox_cmpl = lpfc_cmpl_reg_new_vport;
James Smart0b727fe2007-10-27 13:37:25 -04004337 if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
James Smart92d7f7b2007-06-17 19:56:38 -05004338 == MBX_NOT_FINISHED) {
4339 mempool_free(mbox, phba->mbox_mem_pool);
James Smart09372822008-01-11 01:52:54 -05004340 spin_lock_irq(shost->host_lock);
James Smart92d7f7b2007-06-17 19:56:38 -05004341 vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
James Smart09372822008-01-11 01:52:54 -05004342 spin_unlock_irq(shost->host_lock);
James Smart92d7f7b2007-06-17 19:56:38 -05004343
4344 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
James Smarte8b62012007-08-02 11:10:09 -04004345 lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
4346 "0253 Register VPI: Can't send mbox\n");
James Smart92d7f7b2007-06-17 19:56:38 -05004347 }
4348 } else {
4349 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
4350
James Smarte8b62012007-08-02 11:10:09 -04004351 lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
4352 "0254 Register VPI: no memory\n");
James Smart92d7f7b2007-06-17 19:56:38 -05004353
James Smart09372822008-01-11 01:52:54 -05004354 spin_lock_irq(shost->host_lock);
James Smart92d7f7b2007-06-17 19:56:38 -05004355 vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
James Smart09372822008-01-11 01:52:54 -05004356 spin_unlock_irq(shost->host_lock);
James Smart92d7f7b2007-06-17 19:56:38 -05004357 lpfc_nlp_put(ndlp);
4358 }
4359}
4360
4361static void
4362lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
4363 struct lpfc_iocbq *rspiocb)
4364{
4365 struct lpfc_vport *vport = cmdiocb->vport;
4366 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
4367 struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
4368 struct lpfc_nodelist *np;
4369 struct lpfc_nodelist *next_np;
4370 IOCB_t *irsp = &rspiocb->iocb;
4371 struct lpfc_iocbq *piocb;
4372
James Smarte8b62012007-08-02 11:10:09 -04004373 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
4374 "0123 FDISC completes. x%x/x%x prevDID: x%x\n",
4375 irsp->ulpStatus, irsp->un.ulpWord[4],
4376 vport->fc_prevDID);
James Smart92d7f7b2007-06-17 19:56:38 -05004377 /* Since all FDISCs are being single threaded, we
4378 * must reset the discovery timer for ALL vports
4379 * waiting to send FDISC when one completes.
4380 */
4381 list_for_each_entry(piocb, &phba->fabric_iocb_list, list) {
4382 lpfc_set_disctmo(piocb->vport);
4383 }
4384
James Smart858c9f62007-06-17 19:56:39 -05004385 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
4386 "FDISC cmpl: status:x%x/x%x prevdid:x%x",
4387 irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_prevDID);
4388
James Smart92d7f7b2007-06-17 19:56:38 -05004389 if (irsp->ulpStatus) {
4390 /* Check for retry */
4391 if (lpfc_els_retry(phba, cmdiocb, rspiocb))
4392 goto out;
James Smart92d7f7b2007-06-17 19:56:38 -05004393 /* FDISC failed */
James Smarte8b62012007-08-02 11:10:09 -04004394 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
4395 "0124 FDISC failed. (%d/%d)\n",
4396 irsp->ulpStatus, irsp->un.ulpWord[4]);
James Smart92d7f7b2007-06-17 19:56:38 -05004397 if (vport->fc_vport->vport_state == FC_VPORT_INITIALIZING)
4398 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
4399
4400 lpfc_nlp_put(ndlp);
4401 /* giving up on FDISC. Cancel discovery timer */
4402 lpfc_can_disctmo(vport);
4403 } else {
4404 spin_lock_irq(shost->host_lock);
4405 vport->fc_flag |= FC_FABRIC;
4406 if (vport->phba->fc_topology == TOPOLOGY_LOOP)
4407 vport->fc_flag |= FC_PUBLIC_LOOP;
4408 spin_unlock_irq(shost->host_lock);
4409
4410 vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID;
4411 lpfc_vport_set_state(vport, FC_VPORT_ACTIVE);
4412 if ((vport->fc_prevDID != vport->fc_myDID) &&
4413 !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) {
4414 /* If our NportID changed, we need to ensure all
4415 * remaining NPORTs get unreg_login'ed so we can
4416 * issue unreg_vpi.
4417 */
4418 list_for_each_entry_safe(np, next_np,
4419 &vport->fc_nodes, nlp_listp) {
4420 if (np->nlp_state != NLP_STE_NPR_NODE
4421 || !(np->nlp_flag & NLP_NPR_ADISC))
4422 continue;
4423 spin_lock_irq(shost->host_lock);
4424 np->nlp_flag &= ~NLP_NPR_ADISC;
4425 spin_unlock_irq(shost->host_lock);
4426 lpfc_unreg_rpi(vport, np);
4427 }
4428 lpfc_mbx_unreg_vpi(vport);
James Smart09372822008-01-11 01:52:54 -05004429 spin_lock_irq(shost->host_lock);
James Smart92d7f7b2007-06-17 19:56:38 -05004430 vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
James Smart09372822008-01-11 01:52:54 -05004431 spin_unlock_irq(shost->host_lock);
James Smart92d7f7b2007-06-17 19:56:38 -05004432 }
4433
4434 if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)
4435 lpfc_register_new_vport(phba, vport, ndlp);
4436 else
4437 lpfc_do_scr_ns_plogi(phba, vport);
4438
4439 lpfc_nlp_put(ndlp); /* Free Fabric ndlp for vports */
4440 }
4441
4442out:
4443 lpfc_els_free_iocb(phba, cmdiocb);
4444}
4445
Adrian Bunka6ababd2007-11-05 18:07:33 +01004446static int
James Smart92d7f7b2007-06-17 19:56:38 -05004447lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
4448 uint8_t retry)
4449{
4450 struct lpfc_hba *phba = vport->phba;
4451 IOCB_t *icmd;
4452 struct lpfc_iocbq *elsiocb;
4453 struct serv_parm *sp;
4454 uint8_t *pcmd;
4455 uint16_t cmdsize;
4456 int did = ndlp->nlp_DID;
4457 int rc;
James Smart92d7f7b2007-06-17 19:56:38 -05004458
4459 cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
4460 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did,
4461 ELS_CMD_FDISC);
4462 if (!elsiocb) {
James Smart92d7f7b2007-06-17 19:56:38 -05004463 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
James Smarte8b62012007-08-02 11:10:09 -04004464 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
4465 "0255 Issue FDISC: no IOCB\n");
James Smart92d7f7b2007-06-17 19:56:38 -05004466 return 1;
4467 }
4468
4469 icmd = &elsiocb->iocb;
4470 icmd->un.elsreq64.myID = 0;
4471 icmd->un.elsreq64.fl = 1;
4472
4473 /* For FDISC, Let FDISC rsp set the NPortID for this VPI */
4474 icmd->ulpCt_h = 1;
4475 icmd->ulpCt_l = 0;
4476
4477 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
4478 *((uint32_t *) (pcmd)) = ELS_CMD_FDISC;
4479 pcmd += sizeof(uint32_t); /* CSP Word 1 */
4480 memcpy(pcmd, &vport->phba->pport->fc_sparam, sizeof(struct serv_parm));
4481 sp = (struct serv_parm *) pcmd;
4482 /* Setup CSPs accordingly for Fabric */
4483 sp->cmn.e_d_tov = 0;
4484 sp->cmn.w2.r_a_tov = 0;
4485 sp->cls1.classValid = 0;
4486 sp->cls2.seqDelivery = 1;
4487 sp->cls3.seqDelivery = 1;
4488
4489 pcmd += sizeof(uint32_t); /* CSP Word 2 */
4490 pcmd += sizeof(uint32_t); /* CSP Word 3 */
4491 pcmd += sizeof(uint32_t); /* CSP Word 4 */
4492 pcmd += sizeof(uint32_t); /* Port Name */
4493 memcpy(pcmd, &vport->fc_portname, 8);
4494 pcmd += sizeof(uint32_t); /* Node Name */
4495 pcmd += sizeof(uint32_t); /* Node Name */
4496 memcpy(pcmd, &vport->fc_nodename, 8);
4497
4498 lpfc_set_disctmo(vport);
4499
4500 phba->fc_stat.elsXmitFDISC++;
4501 elsiocb->iocb_cmpl = lpfc_cmpl_els_fdisc;
4502
James Smart858c9f62007-06-17 19:56:39 -05004503 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
4504 "Issue FDISC: did:x%x",
4505 did, 0, 0);
4506
James Smart92d7f7b2007-06-17 19:56:38 -05004507 rc = lpfc_issue_fabric_iocb(phba, elsiocb);
4508 if (rc == IOCB_ERROR) {
4509 lpfc_els_free_iocb(phba, elsiocb);
James Smart92d7f7b2007-06-17 19:56:38 -05004510 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
James Smarte8b62012007-08-02 11:10:09 -04004511 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
4512 "0256 Issue FDISC: Cannot send IOCB\n");
James Smart92d7f7b2007-06-17 19:56:38 -05004513 return 1;
4514 }
4515 lpfc_vport_set_state(vport, FC_VPORT_INITIALIZING);
4516 vport->port_state = LPFC_FDISC;
4517 return 0;
4518}
4519
4520static void
4521lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
4522 struct lpfc_iocbq *rspiocb)
4523{
4524 struct lpfc_vport *vport = cmdiocb->vport;
James Smart858c9f62007-06-17 19:56:39 -05004525 IOCB_t *irsp;
4526
4527 irsp = &rspiocb->iocb;
4528 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
4529 "LOGO npiv cmpl: status:x%x/x%x did:x%x",
4530 irsp->ulpStatus, irsp->un.ulpWord[4], irsp->un.rcvels.remoteID);
James Smart92d7f7b2007-06-17 19:56:38 -05004531
4532 lpfc_els_free_iocb(phba, cmdiocb);
4533 vport->unreg_vpi_cmpl = VPORT_ERROR;
4534}
4535
4536int
4537lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
4538{
4539 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
4540 struct lpfc_hba *phba = vport->phba;
4541 struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
4542 IOCB_t *icmd;
4543 struct lpfc_iocbq *elsiocb;
4544 uint8_t *pcmd;
4545 uint16_t cmdsize;
4546
4547 cmdsize = 2 * sizeof(uint32_t) + sizeof(struct lpfc_name);
4548 elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, ndlp->nlp_DID,
4549 ELS_CMD_LOGO);
4550 if (!elsiocb)
4551 return 1;
4552
4553 icmd = &elsiocb->iocb;
4554 pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
4555 *((uint32_t *) (pcmd)) = ELS_CMD_LOGO;
4556 pcmd += sizeof(uint32_t);
4557
4558 /* Fill in LOGO payload */
4559 *((uint32_t *) (pcmd)) = be32_to_cpu(vport->fc_myDID);
4560 pcmd += sizeof(uint32_t);
4561 memcpy(pcmd, &vport->fc_portname, sizeof(struct lpfc_name));
4562
James Smart858c9f62007-06-17 19:56:39 -05004563 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
4564 "Issue LOGO npiv did:x%x flg:x%x",
4565 ndlp->nlp_DID, ndlp->nlp_flag, 0);
4566
James Smart92d7f7b2007-06-17 19:56:38 -05004567 elsiocb->iocb_cmpl = lpfc_cmpl_els_npiv_logo;
4568 spin_lock_irq(shost->host_lock);
4569 ndlp->nlp_flag |= NLP_LOGO_SND;
4570 spin_unlock_irq(shost->host_lock);
4571 if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
4572 spin_lock_irq(shost->host_lock);
4573 ndlp->nlp_flag &= ~NLP_LOGO_SND;
4574 spin_unlock_irq(shost->host_lock);
4575 lpfc_els_free_iocb(phba, elsiocb);
4576 return 1;
4577 }
4578 return 0;
4579}
4580
4581void
4582lpfc_fabric_block_timeout(unsigned long ptr)
4583{
4584 struct lpfc_hba *phba = (struct lpfc_hba *) ptr;
4585 unsigned long iflags;
4586 uint32_t tmo_posted;
4587 spin_lock_irqsave(&phba->pport->work_port_lock, iflags);
4588 tmo_posted = phba->pport->work_port_events & WORKER_FABRIC_BLOCK_TMO;
4589 if (!tmo_posted)
4590 phba->pport->work_port_events |= WORKER_FABRIC_BLOCK_TMO;
4591 spin_unlock_irqrestore(&phba->pport->work_port_lock, iflags);
4592
4593 if (!tmo_posted) {
4594 spin_lock_irqsave(&phba->hbalock, iflags);
4595 if (phba->work_wait)
4596 lpfc_worker_wake_up(phba);
4597 spin_unlock_irqrestore(&phba->hbalock, iflags);
4598 }
4599}
4600
4601static void
4602lpfc_resume_fabric_iocbs(struct lpfc_hba *phba)
4603{
4604 struct lpfc_iocbq *iocb;
4605 unsigned long iflags;
4606 int ret;
4607 struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
4608 IOCB_t *cmd;
4609
4610repeat:
4611 iocb = NULL;
4612 spin_lock_irqsave(&phba->hbalock, iflags);
4613 /* Post any pending iocb to the SLI layer */
4614 if (atomic_read(&phba->fabric_iocb_count) == 0) {
4615 list_remove_head(&phba->fabric_iocb_list, iocb, typeof(*iocb),
4616 list);
4617 if (iocb)
4618 atomic_inc(&phba->fabric_iocb_count);
4619 }
4620 spin_unlock_irqrestore(&phba->hbalock, iflags);
4621 if (iocb) {
4622 iocb->fabric_iocb_cmpl = iocb->iocb_cmpl;
4623 iocb->iocb_cmpl = lpfc_cmpl_fabric_iocb;
4624 iocb->iocb_flag |= LPFC_IO_FABRIC;
4625
James Smart858c9f62007-06-17 19:56:39 -05004626 lpfc_debugfs_disc_trc(iocb->vport, LPFC_DISC_TRC_ELS_CMD,
4627 "Fabric sched1: ste:x%x",
4628 iocb->vport->port_state, 0, 0);
4629
James Smart92d7f7b2007-06-17 19:56:38 -05004630 ret = lpfc_sli_issue_iocb(phba, pring, iocb, 0);
4631
4632 if (ret == IOCB_ERROR) {
4633 iocb->iocb_cmpl = iocb->fabric_iocb_cmpl;
4634 iocb->fabric_iocb_cmpl = NULL;
4635 iocb->iocb_flag &= ~LPFC_IO_FABRIC;
4636 cmd = &iocb->iocb;
4637 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
4638 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
4639 iocb->iocb_cmpl(phba, iocb, iocb);
4640
4641 atomic_dec(&phba->fabric_iocb_count);
4642 goto repeat;
4643 }
4644 }
4645
4646 return;
4647}
4648
4649void
4650lpfc_unblock_fabric_iocbs(struct lpfc_hba *phba)
4651{
4652 clear_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags);
4653
4654 lpfc_resume_fabric_iocbs(phba);
4655 return;
4656}
4657
4658static void
4659lpfc_block_fabric_iocbs(struct lpfc_hba *phba)
4660{
4661 int blocked;
4662
4663 blocked = test_and_set_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags);
4664 /* Start a timer to unblock fabric
4665 * iocbs after 100ms
4666 */
4667 if (!blocked)
4668 mod_timer(&phba->fabric_block_timer, jiffies + HZ/10 );
4669
4670 return;
4671}
4672
4673static void
4674lpfc_cmpl_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
4675 struct lpfc_iocbq *rspiocb)
4676{
4677 struct ls_rjt stat;
4678
4679 if ((cmdiocb->iocb_flag & LPFC_IO_FABRIC) != LPFC_IO_FABRIC)
4680 BUG();
4681
4682 switch (rspiocb->iocb.ulpStatus) {
4683 case IOSTAT_NPORT_RJT:
4684 case IOSTAT_FABRIC_RJT:
4685 if (rspiocb->iocb.un.ulpWord[4] & RJT_UNAVAIL_TEMP) {
4686 lpfc_block_fabric_iocbs(phba);
4687 }
4688 break;
4689
4690 case IOSTAT_NPORT_BSY:
4691 case IOSTAT_FABRIC_BSY:
4692 lpfc_block_fabric_iocbs(phba);
4693 break;
4694
4695 case IOSTAT_LS_RJT:
4696 stat.un.lsRjtError =
4697 be32_to_cpu(rspiocb->iocb.un.ulpWord[4]);
4698 if ((stat.un.b.lsRjtRsnCode == LSRJT_UNABLE_TPC) ||
4699 (stat.un.b.lsRjtRsnCode == LSRJT_LOGICAL_BSY))
4700 lpfc_block_fabric_iocbs(phba);
4701 break;
4702 }
4703
4704 if (atomic_read(&phba->fabric_iocb_count) == 0)
4705 BUG();
4706
4707 cmdiocb->iocb_cmpl = cmdiocb->fabric_iocb_cmpl;
4708 cmdiocb->fabric_iocb_cmpl = NULL;
4709 cmdiocb->iocb_flag &= ~LPFC_IO_FABRIC;
4710 cmdiocb->iocb_cmpl(phba, cmdiocb, rspiocb);
4711
4712 atomic_dec(&phba->fabric_iocb_count);
4713 if (!test_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags)) {
4714 /* Post any pending iocbs to HBA */
4715 lpfc_resume_fabric_iocbs(phba);
4716 }
4717}
4718
Adrian Bunka6ababd2007-11-05 18:07:33 +01004719static int
James Smart92d7f7b2007-06-17 19:56:38 -05004720lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb)
4721{
4722 unsigned long iflags;
4723 struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
4724 int ready;
4725 int ret;
4726
4727 if (atomic_read(&phba->fabric_iocb_count) > 1)
4728 BUG();
4729
4730 spin_lock_irqsave(&phba->hbalock, iflags);
4731 ready = atomic_read(&phba->fabric_iocb_count) == 0 &&
4732 !test_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags);
4733
4734 spin_unlock_irqrestore(&phba->hbalock, iflags);
4735 if (ready) {
4736 iocb->fabric_iocb_cmpl = iocb->iocb_cmpl;
4737 iocb->iocb_cmpl = lpfc_cmpl_fabric_iocb;
4738 iocb->iocb_flag |= LPFC_IO_FABRIC;
4739
James Smart858c9f62007-06-17 19:56:39 -05004740 lpfc_debugfs_disc_trc(iocb->vport, LPFC_DISC_TRC_ELS_CMD,
4741 "Fabric sched2: ste:x%x",
4742 iocb->vport->port_state, 0, 0);
4743
James Smart92d7f7b2007-06-17 19:56:38 -05004744 atomic_inc(&phba->fabric_iocb_count);
4745 ret = lpfc_sli_issue_iocb(phba, pring, iocb, 0);
4746
4747 if (ret == IOCB_ERROR) {
4748 iocb->iocb_cmpl = iocb->fabric_iocb_cmpl;
4749 iocb->fabric_iocb_cmpl = NULL;
4750 iocb->iocb_flag &= ~LPFC_IO_FABRIC;
4751 atomic_dec(&phba->fabric_iocb_count);
4752 }
4753 } else {
4754 spin_lock_irqsave(&phba->hbalock, iflags);
4755 list_add_tail(&iocb->list, &phba->fabric_iocb_list);
4756 spin_unlock_irqrestore(&phba->hbalock, iflags);
4757 ret = IOCB_SUCCESS;
4758 }
4759 return ret;
4760}
4761
4762
Adrian Bunka6ababd2007-11-05 18:07:33 +01004763static void lpfc_fabric_abort_vport(struct lpfc_vport *vport)
James Smart92d7f7b2007-06-17 19:56:38 -05004764{
4765 LIST_HEAD(completions);
4766 struct lpfc_hba *phba = vport->phba;
4767 struct lpfc_iocbq *tmp_iocb, *piocb;
4768 IOCB_t *cmd;
4769
4770 spin_lock_irq(&phba->hbalock);
4771 list_for_each_entry_safe(piocb, tmp_iocb, &phba->fabric_iocb_list,
4772 list) {
4773
4774 if (piocb->vport != vport)
4775 continue;
4776
4777 list_move_tail(&piocb->list, &completions);
4778 }
4779 spin_unlock_irq(&phba->hbalock);
4780
4781 while (!list_empty(&completions)) {
4782 piocb = list_get_first(&completions, struct lpfc_iocbq, list);
4783 list_del_init(&piocb->list);
4784
4785 cmd = &piocb->iocb;
4786 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
4787 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
4788 (piocb->iocb_cmpl) (phba, piocb, piocb);
4789 }
4790}
4791
4792void lpfc_fabric_abort_nport(struct lpfc_nodelist *ndlp)
4793{
4794 LIST_HEAD(completions);
4795 struct lpfc_hba *phba = ndlp->vport->phba;
4796 struct lpfc_iocbq *tmp_iocb, *piocb;
4797 struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
4798 IOCB_t *cmd;
4799
4800 spin_lock_irq(&phba->hbalock);
4801 list_for_each_entry_safe(piocb, tmp_iocb, &phba->fabric_iocb_list,
4802 list) {
4803 if ((lpfc_check_sli_ndlp(phba, pring, piocb, ndlp))) {
4804
4805 list_move_tail(&piocb->list, &completions);
4806 }
4807 }
4808 spin_unlock_irq(&phba->hbalock);
4809
4810 while (!list_empty(&completions)) {
4811 piocb = list_get_first(&completions, struct lpfc_iocbq, list);
4812 list_del_init(&piocb->list);
4813
4814 cmd = &piocb->iocb;
4815 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
4816 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
4817 (piocb->iocb_cmpl) (phba, piocb, piocb);
4818 }
4819}
4820
4821void lpfc_fabric_abort_hba(struct lpfc_hba *phba)
4822{
4823 LIST_HEAD(completions);
4824 struct lpfc_iocbq *piocb;
4825 IOCB_t *cmd;
4826
4827 spin_lock_irq(&phba->hbalock);
4828 list_splice_init(&phba->fabric_iocb_list, &completions);
4829 spin_unlock_irq(&phba->hbalock);
4830
4831 while (!list_empty(&completions)) {
4832 piocb = list_get_first(&completions, struct lpfc_iocbq, list);
4833 list_del_init(&piocb->list);
4834
4835 cmd = &piocb->iocb;
4836 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
4837 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
4838 (piocb->iocb_cmpl) (phba, piocb, piocb);
4839 }
4840}
4841
4842
Adrian Bunka6ababd2007-11-05 18:07:33 +01004843#if 0
James Smart92d7f7b2007-06-17 19:56:38 -05004844void lpfc_fabric_abort_flogi(struct lpfc_hba *phba)
4845{
4846 LIST_HEAD(completions);
4847 struct lpfc_iocbq *tmp_iocb, *piocb;
4848 IOCB_t *cmd;
4849 struct lpfc_nodelist *ndlp;
4850
4851 spin_lock_irq(&phba->hbalock);
4852 list_for_each_entry_safe(piocb, tmp_iocb, &phba->fabric_iocb_list,
4853 list) {
4854
4855 cmd = &piocb->iocb;
4856 ndlp = (struct lpfc_nodelist *) piocb->context1;
4857 if (cmd->ulpCommand == CMD_ELS_REQUEST64_CR &&
4858 ndlp != NULL &&
4859 ndlp->nlp_DID == Fabric_DID)
4860 list_move_tail(&piocb->list, &completions);
4861 }
4862 spin_unlock_irq(&phba->hbalock);
4863
4864 while (!list_empty(&completions)) {
4865 piocb = list_get_first(&completions, struct lpfc_iocbq, list);
4866 list_del_init(&piocb->list);
4867
4868 cmd = &piocb->iocb;
4869 cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
4870 cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
4871 (piocb->iocb_cmpl) (phba, piocb, piocb);
4872 }
4873}
Adrian Bunka6ababd2007-11-05 18:07:33 +01004874#endif /* 0 */
James Smart92d7f7b2007-06-17 19:56:38 -05004875
4876