blob: 2ed6af1949327c75764b5804570b5f2d6081dcb5 [file] [log] [blame]
James Smart92d7f7b2007-06-17 19:56:38 -05001 /*******************************************************************
dea31012005-04-17 16:05:31 -05002 * 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 Smartd8e93df2009-05-22 14:53:05 -04004 * Copyright (C) 2004-2009 Emulex. All rights reserved. *
James.Smart@Emulex.Comc44ce172005-06-25 10:34:39 -04005 * EMULEX and SLI are trademarks of Emulex. *
dea31012005-04-17 16:05:31 -05006 * www.emulex.com *
James.Smart@Emulex.Comc44ce172005-06-25 10:34:39 -04007 * Portions Copyright (C) 2004-2005 Christoph Hellwig *
dea31012005-04-17 16:05:31 -05008 * *
9 * This program is free software; you can redistribute it and/or *
James.Smart@Emulex.Comc44ce172005-06-25 10:34:39 -040010 * modify it under the terms of version 2 of the GNU General *
11 * Public License as published by the Free Software Foundation. *
12 * This program is distributed in the hope that it will be useful. *
13 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
14 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
15 * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
16 * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
17 * TO BE LEGALLY INVALID. See the GNU General Public License for *
18 * more details, a copy of which can be found in the file COPYING *
19 * included with this package. *
dea31012005-04-17 16:05:31 -050020 *******************************************************************/
21
dea31012005-04-17 16:05:31 -050022#include <linux/blkdev.h>
23#include <linux/pci.h>
24#include <linux/interrupt.h>
25
James.Smart@Emulex.Com91886522005-08-10 15:03:09 -040026#include <scsi/scsi.h>
dea31012005-04-17 16:05:31 -050027#include <scsi/scsi_device.h>
28#include <scsi/scsi_host.h>
29#include <scsi/scsi_transport_fc.h>
30
James Smartda0436e2009-05-22 14:51:39 -040031#include "lpfc_hw4.h"
dea31012005-04-17 16:05:31 -050032#include "lpfc_hw.h"
33#include "lpfc_sli.h"
James Smartda0436e2009-05-22 14:51:39 -040034#include "lpfc_sli4.h"
James Smartea2151b2008-09-07 11:52:10 -040035#include "lpfc_nl.h"
dea31012005-04-17 16:05:31 -050036#include "lpfc_disc.h"
37#include "lpfc_scsi.h"
38#include "lpfc.h"
39#include "lpfc_logmsg.h"
40#include "lpfc_crtn.h"
James Smart92d7f7b2007-06-17 19:56:38 -050041#include "lpfc_vport.h"
James Smart858c9f62007-06-17 19:56:39 -050042#include "lpfc_debugfs.h"
dea31012005-04-17 16:05:31 -050043
44
45/* Called to verify a rcv'ed ADISC was intended for us. */
46static int
James Smart2e0fef82007-06-17 19:56:36 -050047lpfc_check_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
48 struct lpfc_name *nn, struct lpfc_name *pn)
dea31012005-04-17 16:05:31 -050049{
50 /* Compare the ADISC rsp WWNN / WWPN matches our internal node
51 * table entry for that node.
52 */
James Smart2e0fef82007-06-17 19:56:36 -050053 if (memcmp(nn, &ndlp->nlp_nodename, sizeof (struct lpfc_name)))
Jamie Wellnitzc9f87352006-02-28 19:25:23 -050054 return 0;
dea31012005-04-17 16:05:31 -050055
James Smart2e0fef82007-06-17 19:56:36 -050056 if (memcmp(pn, &ndlp->nlp_portname, sizeof (struct lpfc_name)))
Jamie Wellnitzc9f87352006-02-28 19:25:23 -050057 return 0;
dea31012005-04-17 16:05:31 -050058
59 /* we match, return success */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -050060 return 1;
dea31012005-04-17 16:05:31 -050061}
62
dea31012005-04-17 16:05:31 -050063int
James Smart2e0fef82007-06-17 19:56:36 -050064lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
65 struct serv_parm * sp, uint32_t class)
dea31012005-04-17 16:05:31 -050066{
James Smart2e0fef82007-06-17 19:56:36 -050067 volatile struct serv_parm *hsp = &vport->fc_sparam;
James.Smart@Emulex.Com2fb70f72005-11-28 11:41:24 -050068 uint16_t hsp_value, ssp_value = 0;
dea31012005-04-17 16:05:31 -050069
James.Smart@Emulex.Com2fb70f72005-11-28 11:41:24 -050070 /*
71 * The receive data field size and buffer-to-buffer receive data field
72 * size entries are 16 bits but are represented as two 8-bit fields in
73 * the driver data structure to account for rsvd bits and other control
74 * bits. Reconstruct and compare the fields as a 16-bit values before
75 * correcting the byte values.
76 */
dea31012005-04-17 16:05:31 -050077 if (sp->cls1.classValid) {
James.Smart@Emulex.Com2fb70f72005-11-28 11:41:24 -050078 hsp_value = (hsp->cls1.rcvDataSizeMsb << 8) |
79 hsp->cls1.rcvDataSizeLsb;
80 ssp_value = (sp->cls1.rcvDataSizeMsb << 8) |
81 sp->cls1.rcvDataSizeLsb;
James Smart92d7f7b2007-06-17 19:56:38 -050082 if (!ssp_value)
83 goto bad_service_param;
James.Smart@Emulex.Com2fb70f72005-11-28 11:41:24 -050084 if (ssp_value > hsp_value) {
dea31012005-04-17 16:05:31 -050085 sp->cls1.rcvDataSizeLsb = hsp->cls1.rcvDataSizeLsb;
James.Smart@Emulex.Com2fb70f72005-11-28 11:41:24 -050086 sp->cls1.rcvDataSizeMsb = hsp->cls1.rcvDataSizeMsb;
87 }
dea31012005-04-17 16:05:31 -050088 } else if (class == CLASS1) {
James Smart92d7f7b2007-06-17 19:56:38 -050089 goto bad_service_param;
dea31012005-04-17 16:05:31 -050090 }
91
92 if (sp->cls2.classValid) {
James.Smart@Emulex.Com2fb70f72005-11-28 11:41:24 -050093 hsp_value = (hsp->cls2.rcvDataSizeMsb << 8) |
94 hsp->cls2.rcvDataSizeLsb;
95 ssp_value = (sp->cls2.rcvDataSizeMsb << 8) |
96 sp->cls2.rcvDataSizeLsb;
James Smart92d7f7b2007-06-17 19:56:38 -050097 if (!ssp_value)
98 goto bad_service_param;
James.Smart@Emulex.Com2fb70f72005-11-28 11:41:24 -050099 if (ssp_value > hsp_value) {
dea31012005-04-17 16:05:31 -0500100 sp->cls2.rcvDataSizeLsb = hsp->cls2.rcvDataSizeLsb;
James.Smart@Emulex.Com2fb70f72005-11-28 11:41:24 -0500101 sp->cls2.rcvDataSizeMsb = hsp->cls2.rcvDataSizeMsb;
102 }
dea31012005-04-17 16:05:31 -0500103 } else if (class == CLASS2) {
James Smart92d7f7b2007-06-17 19:56:38 -0500104 goto bad_service_param;
dea31012005-04-17 16:05:31 -0500105 }
106
107 if (sp->cls3.classValid) {
James.Smart@Emulex.Com2fb70f72005-11-28 11:41:24 -0500108 hsp_value = (hsp->cls3.rcvDataSizeMsb << 8) |
109 hsp->cls3.rcvDataSizeLsb;
110 ssp_value = (sp->cls3.rcvDataSizeMsb << 8) |
111 sp->cls3.rcvDataSizeLsb;
James Smart92d7f7b2007-06-17 19:56:38 -0500112 if (!ssp_value)
113 goto bad_service_param;
James.Smart@Emulex.Com2fb70f72005-11-28 11:41:24 -0500114 if (ssp_value > hsp_value) {
dea31012005-04-17 16:05:31 -0500115 sp->cls3.rcvDataSizeLsb = hsp->cls3.rcvDataSizeLsb;
James.Smart@Emulex.Com2fb70f72005-11-28 11:41:24 -0500116 sp->cls3.rcvDataSizeMsb = hsp->cls3.rcvDataSizeMsb;
117 }
dea31012005-04-17 16:05:31 -0500118 } else if (class == CLASS3) {
James Smart92d7f7b2007-06-17 19:56:38 -0500119 goto bad_service_param;
dea31012005-04-17 16:05:31 -0500120 }
121
James.Smart@Emulex.Com2fb70f72005-11-28 11:41:24 -0500122 /*
123 * Preserve the upper four bits of the MSB from the PLOGI response.
124 * These bits contain the Buffer-to-Buffer State Change Number
125 * from the target and need to be passed to the FW.
126 */
127 hsp_value = (hsp->cmn.bbRcvSizeMsb << 8) | hsp->cmn.bbRcvSizeLsb;
128 ssp_value = (sp->cmn.bbRcvSizeMsb << 8) | sp->cmn.bbRcvSizeLsb;
129 if (ssp_value > hsp_value) {
dea31012005-04-17 16:05:31 -0500130 sp->cmn.bbRcvSizeLsb = hsp->cmn.bbRcvSizeLsb;
James.Smart@Emulex.Com2fb70f72005-11-28 11:41:24 -0500131 sp->cmn.bbRcvSizeMsb = (sp->cmn.bbRcvSizeMsb & 0xF0) |
132 (hsp->cmn.bbRcvSizeMsb & 0x0F);
133 }
dea31012005-04-17 16:05:31 -0500134
dea31012005-04-17 16:05:31 -0500135 memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof (struct lpfc_name));
136 memcpy(&ndlp->nlp_portname, &sp->portName, sizeof (struct lpfc_name));
James.Smart@Emulex.Com2fb70f72005-11-28 11:41:24 -0500137 return 1;
James Smart92d7f7b2007-06-17 19:56:38 -0500138bad_service_param:
James Smarte8b62012007-08-02 11:10:09 -0400139 lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
140 "0207 Device %x "
141 "(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x) sent "
142 "invalid service parameters. Ignoring device.\n",
143 ndlp->nlp_DID,
144 sp->nodeName.u.wwn[0], sp->nodeName.u.wwn[1],
145 sp->nodeName.u.wwn[2], sp->nodeName.u.wwn[3],
146 sp->nodeName.u.wwn[4], sp->nodeName.u.wwn[5],
147 sp->nodeName.u.wwn[6], sp->nodeName.u.wwn[7]);
James Smart92d7f7b2007-06-17 19:56:38 -0500148 return 0;
dea31012005-04-17 16:05:31 -0500149}
150
151static void *
James Smart2e0fef82007-06-17 19:56:36 -0500152lpfc_check_elscmpl_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
James Smart92d7f7b2007-06-17 19:56:38 -0500153 struct lpfc_iocbq *rspiocb)
dea31012005-04-17 16:05:31 -0500154{
155 struct lpfc_dmabuf *pcmd, *prsp;
156 uint32_t *lp;
157 void *ptr = NULL;
158 IOCB_t *irsp;
159
160 irsp = &rspiocb->iocb;
161 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
162
163 /* For lpfc_els_abort, context2 could be zero'ed to delay
164 * freeing associated memory till after ABTS completes.
165 */
166 if (pcmd) {
167 prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf,
168 list);
169 if (prsp) {
170 lp = (uint32_t *) prsp->virt;
171 ptr = (void *)((uint8_t *)lp + sizeof(uint32_t));
172 }
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -0500173 } else {
dea31012005-04-17 16:05:31 -0500174 /* Force ulpStatus error since we are returning NULL ptr */
175 if (!(irsp->ulpStatus)) {
176 irsp->ulpStatus = IOSTAT_LOCAL_REJECT;
177 irsp->un.ulpWord[4] = IOERR_SLI_ABORTED;
178 }
179 ptr = NULL;
180 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500181 return ptr;
dea31012005-04-17 16:05:31 -0500182}
183
184
185/*
186 * Free resources / clean up outstanding I/Os
187 * associated with a LPFC_NODELIST entry. This
188 * routine effectively results in a "software abort".
189 */
190int
James Smart2e0fef82007-06-17 19:56:36 -0500191lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -0500192{
James Smart2534ba72007-04-25 09:52:20 -0400193 LIST_HEAD(completions);
James Smart2e0fef82007-06-17 19:56:36 -0500194 struct lpfc_sli *psli = &phba->sli;
195 struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
dea31012005-04-17 16:05:31 -0500196 struct lpfc_iocbq *iocb, *next_iocb;
dea31012005-04-17 16:05:31 -0500197
198 /* Abort outstanding I/O on NPort <nlp_DID> */
James Smarte8b62012007-08-02 11:10:09 -0400199 lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_DISCOVERY,
200 "0205 Abort outstanding I/O on NPort x%x "
201 "Data: x%x x%x x%x\n",
202 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
203 ndlp->nlp_rpi);
James Smart92d7f7b2007-06-17 19:56:38 -0500204
205 lpfc_fabric_abort_nport(ndlp);
dea31012005-04-17 16:05:31 -0500206
dea31012005-04-17 16:05:31 -0500207 /* First check the txq */
James Smart2e0fef82007-06-17 19:56:36 -0500208 spin_lock_irq(&phba->hbalock);
James Smart2534ba72007-04-25 09:52:20 -0400209 list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
James Smart858c9f62007-06-17 19:56:39 -0500210 /* Check to see if iocb matches the nport we are looking for */
James Smart2534ba72007-04-25 09:52:20 -0400211 if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
James Smart858c9f62007-06-17 19:56:39 -0500212 /* It matches, so deque and call compl with anp error */
James Smart2534ba72007-04-25 09:52:20 -0400213 list_move_tail(&iocb->list, &completions);
214 pring->txq_cnt--;
dea31012005-04-17 16:05:31 -0500215 }
James Smart2534ba72007-04-25 09:52:20 -0400216 }
dea31012005-04-17 16:05:31 -0500217
dea31012005-04-17 16:05:31 -0500218 /* Next check the txcmplq */
James Smart07951072007-04-25 09:51:38 -0400219 list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
James Smart858c9f62007-06-17 19:56:39 -0500220 /* Check to see if iocb matches the nport we are looking for */
James Smart92d7f7b2007-06-17 19:56:38 -0500221 if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
James Smart07951072007-04-25 09:51:38 -0400222 lpfc_sli_issue_abort_iotag(phba, pring, iocb);
James Smart92d7f7b2007-06-17 19:56:38 -0500223 }
James Smart07951072007-04-25 09:51:38 -0400224 }
James Smart2e0fef82007-06-17 19:56:36 -0500225 spin_unlock_irq(&phba->hbalock);
dea31012005-04-17 16:05:31 -0500226
James Smarta257bf92009-04-06 18:48:10 -0400227 /* Cancel all the IOCBs from the completions list */
228 lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
229 IOERR_SLI_ABORTED);
James Smart2534ba72007-04-25 09:52:20 -0400230
James Smart0d2b6b82008-06-14 22:52:47 -0400231 lpfc_cancel_retry_delay_tmo(phba->pport, ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500232 return 0;
dea31012005-04-17 16:05:31 -0500233}
234
235static int
James Smart2e0fef82007-06-17 19:56:36 -0500236lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
James Smart92d7f7b2007-06-17 19:56:38 -0500237 struct lpfc_iocbq *cmdiocb)
dea31012005-04-17 16:05:31 -0500238{
James Smart2e0fef82007-06-17 19:56:36 -0500239 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
240 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500241 struct lpfc_dmabuf *pcmd;
242 uint32_t *lp;
243 IOCB_t *icmd;
244 struct serv_parm *sp;
245 LPFC_MBOXQ_t *mbox;
246 struct ls_rjt stat;
247 int rc;
248
249 memset(&stat, 0, sizeof (struct ls_rjt));
James Smart2e0fef82007-06-17 19:56:36 -0500250 if (vport->port_state <= LPFC_FLOGI) {
dea31012005-04-17 16:05:31 -0500251 /* Before responding to PLOGI, check for pt2pt mode.
252 * If we are pt2pt, with an outstanding FLOGI, abort
253 * the FLOGI and resend it first.
254 */
James Smart2e0fef82007-06-17 19:56:36 -0500255 if (vport->fc_flag & FC_PT2PT) {
James Smart92d7f7b2007-06-17 19:56:38 -0500256 lpfc_els_abort_flogi(phba);
James Smart2e0fef82007-06-17 19:56:36 -0500257 if (!(vport->fc_flag & FC_PT2PT_PLOGI)) {
dea31012005-04-17 16:05:31 -0500258 /* If the other side is supposed to initiate
259 * the PLOGI anyway, just ACC it now and
260 * move on with discovery.
261 */
262 phba->fc_edtov = FF_DEF_EDTOV;
263 phba->fc_ratov = FF_DEF_RATOV;
264 /* Start discovery - this should just do
265 CLEAR_LA */
James Smart2e0fef82007-06-17 19:56:36 -0500266 lpfc_disc_start(vport);
James Smarted957682007-06-17 19:56:37 -0500267 } else
James Smart2e0fef82007-06-17 19:56:36 -0500268 lpfc_initial_flogi(vport);
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -0500269 } else {
dea31012005-04-17 16:05:31 -0500270 stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY;
271 stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
James Smart2e0fef82007-06-17 19:56:36 -0500272 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
James Smart858c9f62007-06-17 19:56:39 -0500273 ndlp, NULL);
dea31012005-04-17 16:05:31 -0500274 return 0;
275 }
276 }
277 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
278 lp = (uint32_t *) pcmd->virt;
279 sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
James Smarta8adb832007-10-27 13:37:53 -0400280 if (wwn_to_u64(sp->portName.u.wwn) == 0) {
281 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
282 "0140 PLOGI Reject: invalid nname\n");
283 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
284 stat.un.b.lsRjtRsnCodeExp = LSEXP_INVALID_PNAME;
285 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
286 NULL);
287 return 0;
288 }
289 if (wwn_to_u64(sp->nodeName.u.wwn) == 0) {
290 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
291 "0141 PLOGI Reject: invalid pname\n");
292 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
293 stat.un.b.lsRjtRsnCodeExp = LSEXP_INVALID_NNAME;
294 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
295 NULL);
296 return 0;
297 }
James Smart2e0fef82007-06-17 19:56:36 -0500298 if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3) == 0)) {
dea31012005-04-17 16:05:31 -0500299 /* Reject this request because invalid parameters */
300 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
301 stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
James Smart858c9f62007-06-17 19:56:39 -0500302 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
303 NULL);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500304 return 0;
dea31012005-04-17 16:05:31 -0500305 }
306 icmd = &cmdiocb->iocb;
307
308 /* PLOGI chkparm OK */
James Smarte8b62012007-08-02 11:10:09 -0400309 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
310 "0114 PLOGI chkparm OK Data: x%x x%x x%x x%x\n",
311 ndlp->nlp_DID, ndlp->nlp_state, ndlp->nlp_flag,
312 ndlp->nlp_rpi);
dea31012005-04-17 16:05:31 -0500313
James Smart3de2a652007-08-02 11:09:59 -0400314 if (vport->cfg_fcp_class == 2 && sp->cls2.classValid)
dea31012005-04-17 16:05:31 -0500315 ndlp->nlp_fcp_info |= CLASS2;
James Smarted957682007-06-17 19:56:37 -0500316 else
dea31012005-04-17 16:05:31 -0500317 ndlp->nlp_fcp_info |= CLASS3;
James Smart2e0fef82007-06-17 19:56:36 -0500318
dea31012005-04-17 16:05:31 -0500319 ndlp->nlp_class_sup = 0;
320 if (sp->cls1.classValid)
321 ndlp->nlp_class_sup |= FC_COS_CLASS1;
322 if (sp->cls2.classValid)
323 ndlp->nlp_class_sup |= FC_COS_CLASS2;
324 if (sp->cls3.classValid)
325 ndlp->nlp_class_sup |= FC_COS_CLASS3;
326 if (sp->cls4.classValid)
327 ndlp->nlp_class_sup |= FC_COS_CLASS4;
328 ndlp->nlp_maxframe =
329 ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb;
330
331 /* no need to reg_login if we are already in one of these states */
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -0500332 switch (ndlp->nlp_state) {
dea31012005-04-17 16:05:31 -0500333 case NLP_STE_NPR_NODE:
334 if (!(ndlp->nlp_flag & NLP_NPR_ADISC))
335 break;
336 case NLP_STE_REG_LOGIN_ISSUE:
337 case NLP_STE_PRLI_ISSUE:
338 case NLP_STE_UNMAPPED_NODE:
339 case NLP_STE_MAPPED_NODE:
James Smart51ef4c22007-08-02 11:10:31 -0400340 lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500341 return 1;
dea31012005-04-17 16:05:31 -0500342 }
343
James Smart92d7f7b2007-06-17 19:56:38 -0500344 if ((vport->fc_flag & FC_PT2PT) &&
345 !(vport->fc_flag & FC_PT2PT_PLOGI)) {
dea31012005-04-17 16:05:31 -0500346 /* rcv'ed PLOGI decides what our NPortId will be */
James Smart2e0fef82007-06-17 19:56:36 -0500347 vport->fc_myDID = icmd->un.rcvels.parmRo;
dea31012005-04-17 16:05:31 -0500348 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
349 if (mbox == NULL)
350 goto out;
351 lpfc_config_link(phba, mbox);
352 mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
James Smarted957682007-06-17 19:56:37 -0500353 mbox->vport = vport;
James Smart0b727fe2007-10-27 13:37:25 -0400354 rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
dea31012005-04-17 16:05:31 -0500355 if (rc == MBX_NOT_FINISHED) {
James Smart92d7f7b2007-06-17 19:56:38 -0500356 mempool_free(mbox, phba->mbox_mem_pool);
dea31012005-04-17 16:05:31 -0500357 goto out;
358 }
359
James Smart2e0fef82007-06-17 19:56:36 -0500360 lpfc_can_disctmo(vport);
dea31012005-04-17 16:05:31 -0500361 }
362 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
James Smart2e0fef82007-06-17 19:56:36 -0500363 if (!mbox)
dea31012005-04-17 16:05:31 -0500364 goto out;
365
James Smart6fb120a2009-05-22 14:52:59 -0400366 rc = lpfc_reg_rpi(phba, vport->vpi, icmd->un.rcvels.remoteID,
James Smart92d7f7b2007-06-17 19:56:38 -0500367 (uint8_t *) sp, mbox, 0);
James Smart2e0fef82007-06-17 19:56:36 -0500368 if (rc) {
369 mempool_free(mbox, phba->mbox_mem_pool);
dea31012005-04-17 16:05:31 -0500370 goto out;
371 }
372
373 /* ACC PLOGI rsp command needs to execute first,
374 * queue this mbox command to be processed later.
375 */
376 mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
James Smart329f9bc2007-04-25 09:53:01 -0400377 /*
378 * mbox->context2 = lpfc_nlp_get(ndlp) deferred until mailbox
379 * command issued in lpfc_cmpl_els_acc().
380 */
James Smart2e0fef82007-06-17 19:56:36 -0500381 mbox->vport = vport;
382 spin_lock_irq(shost->host_lock);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -0500383 ndlp->nlp_flag |= (NLP_ACC_REGLOGIN | NLP_RCV_PLOGI);
James Smart2e0fef82007-06-17 19:56:36 -0500384 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500385
James Smart33ccf8d2006-08-17 11:57:58 -0400386 /*
387 * If there is an outstanding PLOGI issued, abort it before
388 * sending ACC rsp for received PLOGI. If pending plogi
389 * is not canceled here, the plogi will be rejected by
390 * remote port and will be retried. On a configuration with
391 * single discovery thread, this will cause a huge delay in
392 * discovery. Also this will cause multiple state machines
393 * running in parallel for this node.
394 */
395 if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) {
396 /* software abort outstanding PLOGI */
James Smart07951072007-04-25 09:51:38 -0400397 lpfc_els_abort(phba, ndlp);
James Smart33ccf8d2006-08-17 11:57:58 -0400398 }
399
James Smart858c9f62007-06-17 19:56:39 -0500400 if ((vport->port_type == LPFC_NPIV_PORT &&
James Smart3de2a652007-08-02 11:09:59 -0400401 vport->cfg_restrict_login)) {
James Smart858c9f62007-06-17 19:56:39 -0500402
403 /* In order to preserve RPIs, we want to cleanup
404 * the default RPI the firmware created to rcv
405 * this ELS request. The only way to do this is
406 * to register, then unregister the RPI.
407 */
408 spin_lock_irq(shost->host_lock);
409 ndlp->nlp_flag |= NLP_RM_DFLT_RPI;
410 spin_unlock_irq(shost->host_lock);
411 stat.un.b.lsRjtRsnCode = LSRJT_INVALID_CMD;
412 stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
413 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
414 ndlp, mbox);
415 return 1;
416 }
James Smart51ef4c22007-08-02 11:10:31 -0400417 lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500418 return 1;
dea31012005-04-17 16:05:31 -0500419out:
420 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
421 stat.un.b.lsRjtRsnCodeExp = LSEXP_OUT_OF_RESOURCE;
James Smart858c9f62007-06-17 19:56:39 -0500422 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500423 return 0;
dea31012005-04-17 16:05:31 -0500424}
425
426static int
James Smart2e0fef82007-06-17 19:56:36 -0500427lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
dea31012005-04-17 16:05:31 -0500428 struct lpfc_iocbq *cmdiocb)
429{
James Smart2e0fef82007-06-17 19:56:36 -0500430 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -0500431 struct lpfc_dmabuf *pcmd;
James Smart2e0fef82007-06-17 19:56:36 -0500432 struct serv_parm *sp;
433 struct lpfc_name *pnn, *ppn;
dea31012005-04-17 16:05:31 -0500434 struct ls_rjt stat;
435 ADISC *ap;
436 IOCB_t *icmd;
437 uint32_t *lp;
438 uint32_t cmd;
439
440 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
441 lp = (uint32_t *) pcmd->virt;
442
443 cmd = *lp++;
444 if (cmd == ELS_CMD_ADISC) {
445 ap = (ADISC *) lp;
446 pnn = (struct lpfc_name *) & ap->nodeName;
447 ppn = (struct lpfc_name *) & ap->portName;
448 } else {
449 sp = (struct serv_parm *) lp;
450 pnn = (struct lpfc_name *) & sp->nodeName;
451 ppn = (struct lpfc_name *) & sp->portName;
452 }
453
454 icmd = &cmdiocb->iocb;
James Smart2e0fef82007-06-17 19:56:36 -0500455 if (icmd->ulpStatus == 0 && lpfc_check_adisc(vport, ndlp, pnn, ppn)) {
dea31012005-04-17 16:05:31 -0500456 if (cmd == ELS_CMD_ADISC) {
James Smart2e0fef82007-06-17 19:56:36 -0500457 lpfc_els_rsp_adisc_acc(vport, cmdiocb, ndlp);
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -0500458 } else {
James Smart2e0fef82007-06-17 19:56:36 -0500459 lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp,
James Smart51ef4c22007-08-02 11:10:31 -0400460 NULL);
dea31012005-04-17 16:05:31 -0500461 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500462 return 1;
dea31012005-04-17 16:05:31 -0500463 }
464 /* Reject this request because invalid parameters */
465 stat.un.b.lsRjtRsvd0 = 0;
466 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
467 stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
468 stat.un.b.vendorUnique = 0;
James Smart858c9f62007-06-17 19:56:39 -0500469 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
dea31012005-04-17 16:05:31 -0500470
dea31012005-04-17 16:05:31 -0500471 /* 1 sec timeout */
472 mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
473
James Smart2e0fef82007-06-17 19:56:36 -0500474 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500475 ndlp->nlp_flag |= NLP_DELAY_TMO;
James Smart2e0fef82007-06-17 19:56:36 -0500476 spin_unlock_irq(shost->host_lock);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -0500477 ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
478 ndlp->nlp_prev_state = ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -0500479 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500480 return 0;
dea31012005-04-17 16:05:31 -0500481}
482
483static int
James Smart2e0fef82007-06-17 19:56:36 -0500484lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
485 struct lpfc_iocbq *cmdiocb, uint32_t els_cmd)
dea31012005-04-17 16:05:31 -0500486{
James Smart2e0fef82007-06-17 19:56:36 -0500487 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
488
489 /* Put ndlp in NPR state with 1 sec timeout for plogi, ACC logo */
dea31012005-04-17 16:05:31 -0500490 /* Only call LOGO ACC for first LOGO, this avoids sending unnecessary
491 * PLOGIs during LOGO storms from a device.
492 */
James Smart2e0fef82007-06-17 19:56:36 -0500493 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500494 ndlp->nlp_flag |= NLP_LOGO_ACC;
James Smart2e0fef82007-06-17 19:56:36 -0500495 spin_unlock_irq(shost->host_lock);
James Smart82d9a2a2006-04-15 11:53:05 -0400496 if (els_cmd == ELS_CMD_PRLO)
James Smart51ef4c22007-08-02 11:10:31 -0400497 lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
James Smart82d9a2a2006-04-15 11:53:05 -0400498 else
James Smart51ef4c22007-08-02 11:10:31 -0400499 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
James Smart0c287582009-06-10 17:22:56 -0400500 if ((ndlp->nlp_DID == Fabric_DID) &&
James Smart6fb120a2009-05-22 14:52:59 -0400501 vport->port_type == LPFC_NPIV_PORT) {
502 lpfc_linkdown_port(vport);
503 mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
504 spin_lock_irq(shost->host_lock);
505 ndlp->nlp_flag |= NLP_DELAY_TMO;
506 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500507
James Smart6fb120a2009-05-22 14:52:59 -0400508 ndlp->nlp_last_elscmd = ELS_CMD_FDISC;
509 } else if ((!(ndlp->nlp_type & NLP_FABRIC) &&
510 ((ndlp->nlp_type & NLP_FCP_TARGET) ||
511 !(ndlp->nlp_type & NLP_FCP_INITIATOR))) ||
512 (ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) {
dea31012005-04-17 16:05:31 -0500513 /* Only try to re-login if this is NOT a Fabric Node */
dea31012005-04-17 16:05:31 -0500514 mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
James Smart2e0fef82007-06-17 19:56:36 -0500515 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500516 ndlp->nlp_flag |= NLP_DELAY_TMO;
James Smart2e0fef82007-06-17 19:56:36 -0500517 spin_unlock_irq(shost->host_lock);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500518
Jamie Wellnitz5024ab12006-02-28 19:25:28 -0500519 ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
dea31012005-04-17 16:05:31 -0500520 }
James Smart87af33f2007-10-27 13:37:43 -0400521 ndlp->nlp_prev_state = ndlp->nlp_state;
522 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
dea31012005-04-17 16:05:31 -0500523
James Smart2e0fef82007-06-17 19:56:36 -0500524 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500525 ndlp->nlp_flag &= ~NLP_NPR_ADISC;
James Smart2e0fef82007-06-17 19:56:36 -0500526 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500527 /* The driver has to wait until the ACC completes before it continues
528 * processing the LOGO. The action will resume in
529 * lpfc_cmpl_els_logo_acc routine. Since part of processing includes an
530 * unreg_login, the driver waits so the ACC does not get aborted.
531 */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500532 return 0;
dea31012005-04-17 16:05:31 -0500533}
534
535static void
James Smart2e0fef82007-06-17 19:56:36 -0500536lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
537 struct lpfc_iocbq *cmdiocb)
dea31012005-04-17 16:05:31 -0500538{
539 struct lpfc_dmabuf *pcmd;
540 uint32_t *lp;
541 PRLI *npr;
542 struct fc_rport *rport = ndlp->rport;
543 u32 roles;
544
545 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
546 lp = (uint32_t *) pcmd->virt;
547 npr = (PRLI *) ((uint8_t *) lp + sizeof (uint32_t));
548
549 ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
550 ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
James Smart92d7f7b2007-06-17 19:56:38 -0500551 if (npr->prliType == PRLI_FCP_TYPE) {
dea31012005-04-17 16:05:31 -0500552 if (npr->initiatorFunc)
553 ndlp->nlp_type |= NLP_FCP_INITIATOR;
554 if (npr->targetFunc)
555 ndlp->nlp_type |= NLP_FCP_TARGET;
556 if (npr->Retry)
557 ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE;
558 }
559 if (rport) {
560 /* We need to update the rport role values */
561 roles = FC_RPORT_ROLE_UNKNOWN;
562 if (ndlp->nlp_type & NLP_FCP_INITIATOR)
563 roles |= FC_RPORT_ROLE_FCP_INITIATOR;
564 if (ndlp->nlp_type & NLP_FCP_TARGET)
565 roles |= FC_RPORT_ROLE_FCP_TARGET;
James Smart858c9f62007-06-17 19:56:39 -0500566
567 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
568 "rport rolechg: role:x%x did:x%x flg:x%x",
569 roles, ndlp->nlp_DID, ndlp->nlp_flag);
570
dea31012005-04-17 16:05:31 -0500571 fc_remote_port_rolechg(rport, roles);
572 }
573}
574
575static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -0500576lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
dea31012005-04-17 16:05:31 -0500577{
James Smart2e0fef82007-06-17 19:56:36 -0500578 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
James Smart2e0fef82007-06-17 19:56:36 -0500579
James Smart6fb120a2009-05-22 14:52:59 -0400580 if (!(ndlp->nlp_flag & NLP_RPI_VALID)) {
James Smart51ef4c22007-08-02 11:10:31 -0400581 ndlp->nlp_flag &= ~NLP_NPR_ADISC;
582 return 0;
583 }
584
James Smart1b32f6a2008-02-08 18:49:39 -0500585 if (!(vport->fc_flag & FC_PT2PT)) {
586 /* Check config parameter use-adisc or FCP-2 */
587 if ((vport->cfg_use_adisc && (vport->fc_flag & FC_RSCN_MODE)) ||
588 ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) {
589 spin_lock_irq(shost->host_lock);
590 ndlp->nlp_flag |= NLP_NPR_ADISC;
591 spin_unlock_irq(shost->host_lock);
592 return 1;
593 }
James Smart92d7f7b2007-06-17 19:56:38 -0500594 }
595 ndlp->nlp_flag &= ~NLP_NPR_ADISC;
596 lpfc_unreg_rpi(vport, ndlp);
597 return 0;
dea31012005-04-17 16:05:31 -0500598}
599
600static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -0500601lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
602 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -0500603{
James Smarte8b62012007-08-02 11:10:09 -0400604 lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
James Smarte47c9092008-02-08 18:49:26 -0500605 "0271 Illegal State Transition: node x%x "
James Smarte8b62012007-08-02 11:10:09 -0400606 "event x%x, state x%x Data: x%x x%x\n",
607 ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi,
608 ndlp->nlp_flag);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500609 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -0500610}
611
James Smart87af33f2007-10-27 13:37:43 -0400612static uint32_t
613lpfc_cmpl_plogi_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
614 void *arg, uint32_t evt)
615{
616 /* This transition is only legal if we previously
617 * rcv'ed a PLOGI. Since we don't want 2 discovery threads
618 * working on the same NPortID, do nothing for this thread
619 * to stop it.
620 */
621 if (!(ndlp->nlp_flag & NLP_RCV_PLOGI)) {
622 lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
James Smarte47c9092008-02-08 18:49:26 -0500623 "0272 Illegal State Transition: node x%x "
James Smart87af33f2007-10-27 13:37:43 -0400624 "event x%x, state x%x Data: x%x x%x\n",
625 ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi,
626 ndlp->nlp_flag);
627 }
628 return ndlp->nlp_state;
629}
630
dea31012005-04-17 16:05:31 -0500631/* Start of Discovery State Machine routines */
632
633static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -0500634lpfc_rcv_plogi_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
635 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -0500636{
637 struct lpfc_iocbq *cmdiocb;
638
639 cmdiocb = (struct lpfc_iocbq *) arg;
640
James Smart2e0fef82007-06-17 19:56:36 -0500641 if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) {
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500642 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -0500643 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500644 return NLP_STE_FREED_NODE;
dea31012005-04-17 16:05:31 -0500645}
646
647static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -0500648lpfc_rcv_els_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
649 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -0500650{
James Smart2e0fef82007-06-17 19:56:36 -0500651 lpfc_issue_els_logo(vport, ndlp, 0);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500652 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -0500653}
654
655static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -0500656lpfc_rcv_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
657 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -0500658{
James Smart2e0fef82007-06-17 19:56:36 -0500659 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
660 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
dea31012005-04-17 16:05:31 -0500661
James Smart2e0fef82007-06-17 19:56:36 -0500662 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500663 ndlp->nlp_flag |= NLP_LOGO_ACC;
James Smart2e0fef82007-06-17 19:56:36 -0500664 spin_unlock_irq(shost->host_lock);
James Smart51ef4c22007-08-02 11:10:31 -0400665 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
dea31012005-04-17 16:05:31 -0500666
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500667 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -0500668}
669
670static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -0500671lpfc_cmpl_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
dea31012005-04-17 16:05:31 -0500672 void *arg, uint32_t evt)
673{
James Smart2e0fef82007-06-17 19:56:36 -0500674 return NLP_STE_FREED_NODE;
675}
676
677static uint32_t
678lpfc_device_rm_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
679 void *arg, uint32_t evt)
680{
James Smart2e0fef82007-06-17 19:56:36 -0500681 return NLP_STE_FREED_NODE;
682}
683
684static uint32_t
685lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
686 void *arg, uint32_t evt)
687{
James Smart0d2b6b82008-06-14 22:52:47 -0400688 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
James Smart2e0fef82007-06-17 19:56:36 -0500689 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500690 struct lpfc_iocbq *cmdiocb = arg;
James Smart2e0fef82007-06-17 19:56:36 -0500691 struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
692 uint32_t *lp = (uint32_t *) pcmd->virt;
693 struct serv_parm *sp = (struct serv_parm *) (lp + 1);
dea31012005-04-17 16:05:31 -0500694 struct ls_rjt stat;
695 int port_cmp;
696
dea31012005-04-17 16:05:31 -0500697 memset(&stat, 0, sizeof (struct ls_rjt));
698
699 /* For a PLOGI, we only accept if our portname is less
700 * than the remote portname.
701 */
702 phba->fc_stat.elsLogiCol++;
James Smart2e0fef82007-06-17 19:56:36 -0500703 port_cmp = memcmp(&vport->fc_portname, &sp->portName,
James Smart92d7f7b2007-06-17 19:56:38 -0500704 sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -0500705
706 if (port_cmp >= 0) {
707 /* Reject this request because the remote node will accept
708 ours */
709 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
710 stat.un.b.lsRjtRsnCodeExp = LSEXP_CMD_IN_PROGRESS;
James Smart858c9f62007-06-17 19:56:39 -0500711 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
712 NULL);
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -0500713 } else {
James Smart0d2b6b82008-06-14 22:52:47 -0400714 if (lpfc_rcv_plogi(vport, ndlp, cmdiocb) &&
715 (ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
716 (vport->num_disc_nodes)) {
717 spin_lock_irq(shost->host_lock);
718 ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
719 spin_unlock_irq(shost->host_lock);
720 /* Check if there are more PLOGIs to be sent */
721 lpfc_more_plogi(vport);
722 if (vport->num_disc_nodes == 0) {
723 spin_lock_irq(shost->host_lock);
724 vport->fc_flag &= ~FC_NDISC_ACTIVE;
725 spin_unlock_irq(shost->host_lock);
726 lpfc_can_disctmo(vport);
727 lpfc_end_rscn(vport);
728 }
729 }
James Smart2e0fef82007-06-17 19:56:36 -0500730 } /* If our portname was less */
dea31012005-04-17 16:05:31 -0500731
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500732 return ndlp->nlp_state;
733}
734
735static uint32_t
James Smart92d7f7b2007-06-17 19:56:38 -0500736lpfc_rcv_prli_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
737 void *arg, uint32_t evt)
738{
739 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
740 struct ls_rjt stat;
741
742 memset(&stat, 0, sizeof (struct ls_rjt));
743 stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY;
744 stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
James Smart858c9f62007-06-17 19:56:39 -0500745 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
James Smart92d7f7b2007-06-17 19:56:38 -0500746 return ndlp->nlp_state;
747}
748
749static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -0500750lpfc_rcv_logo_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
751 void *arg, uint32_t evt)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500752{
James Smart2e0fef82007-06-17 19:56:36 -0500753 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500754
James Smart92d7f7b2007-06-17 19:56:38 -0500755 /* software abort outstanding PLOGI */
James Smart2e0fef82007-06-17 19:56:36 -0500756 lpfc_els_abort(vport->phba, ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500757
James Smart2e0fef82007-06-17 19:56:36 -0500758 lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500759 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -0500760}
761
762static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -0500763lpfc_rcv_els_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
764 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -0500765{
James Smart2e0fef82007-06-17 19:56:36 -0500766 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
767 struct lpfc_hba *phba = vport->phba;
768 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
dea31012005-04-17 16:05:31 -0500769
770 /* software abort outstanding PLOGI */
James Smart07951072007-04-25 09:51:38 -0400771 lpfc_els_abort(phba, ndlp);
dea31012005-04-17 16:05:31 -0500772
773 if (evt == NLP_EVT_RCV_LOGO) {
James Smart51ef4c22007-08-02 11:10:31 -0400774 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -0500775 } else {
James Smart2e0fef82007-06-17 19:56:36 -0500776 lpfc_issue_els_logo(vport, ndlp, 0);
dea31012005-04-17 16:05:31 -0500777 }
778
James Smart2e0fef82007-06-17 19:56:36 -0500779 /* Put ndlp in npr state set plogi timer for 1 sec */
Jamie Wellnitz5024ab12006-02-28 19:25:28 -0500780 mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
James Smart2e0fef82007-06-17 19:56:36 -0500781 spin_lock_irq(shost->host_lock);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -0500782 ndlp->nlp_flag |= NLP_DELAY_TMO;
James Smart2e0fef82007-06-17 19:56:36 -0500783 spin_unlock_irq(shost->host_lock);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -0500784 ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
785 ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE;
James Smart2e0fef82007-06-17 19:56:36 -0500786 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
dea31012005-04-17 16:05:31 -0500787
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500788 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -0500789}
790
791static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -0500792lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
793 struct lpfc_nodelist *ndlp,
794 void *arg,
dea31012005-04-17 16:05:31 -0500795 uint32_t evt)
796{
James Smart2e0fef82007-06-17 19:56:36 -0500797 struct lpfc_hba *phba = vport->phba;
James Smart0ff10d42008-01-11 01:52:36 -0500798 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
James Smart2e0fef82007-06-17 19:56:36 -0500799 struct lpfc_iocbq *cmdiocb, *rspiocb;
James Smart14691152006-12-02 13:34:28 -0500800 struct lpfc_dmabuf *pcmd, *prsp, *mp;
dea31012005-04-17 16:05:31 -0500801 uint32_t *lp;
802 IOCB_t *irsp;
803 struct serv_parm *sp;
804 LPFC_MBOXQ_t *mbox;
805
806 cmdiocb = (struct lpfc_iocbq *) arg;
807 rspiocb = cmdiocb->context_un.rsp_iocb;
808
809 if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -0500810 /* Recovery from PLOGI collision logic */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500811 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -0500812 }
813
814 irsp = &rspiocb->iocb;
815
816 if (irsp->ulpStatus)
817 goto out;
818
819 pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
820
James Smart2e0fef82007-06-17 19:56:36 -0500821 prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list);
dea31012005-04-17 16:05:31 -0500822
James Smart2e0fef82007-06-17 19:56:36 -0500823 lp = (uint32_t *) prsp->virt;
dea31012005-04-17 16:05:31 -0500824 sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
James Smart58da1ff2008-04-07 10:15:56 -0400825
826 /* Some switches have FDMI servers returning 0 for WWN */
827 if ((ndlp->nlp_DID != FDMI_DID) &&
828 (wwn_to_u64(sp->portName.u.wwn) == 0 ||
829 wwn_to_u64(sp->nodeName.u.wwn) == 0)) {
James Smarta8adb832007-10-27 13:37:53 -0400830 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
831 "0142 PLOGI RSP: Invalid WWN.\n");
832 goto out;
833 }
James Smart2e0fef82007-06-17 19:56:36 -0500834 if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3))
dea31012005-04-17 16:05:31 -0500835 goto out;
dea31012005-04-17 16:05:31 -0500836 /* PLOGI chkparm OK */
James Smarte8b62012007-08-02 11:10:09 -0400837 lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
838 "0121 PLOGI chkparm OK Data: x%x x%x x%x x%x\n",
839 ndlp->nlp_DID, ndlp->nlp_state,
840 ndlp->nlp_flag, ndlp->nlp_rpi);
James Smart3de2a652007-08-02 11:09:59 -0400841 if (vport->cfg_fcp_class == 2 && (sp->cls2.classValid))
dea31012005-04-17 16:05:31 -0500842 ndlp->nlp_fcp_info |= CLASS2;
James Smart2e0fef82007-06-17 19:56:36 -0500843 else
dea31012005-04-17 16:05:31 -0500844 ndlp->nlp_fcp_info |= CLASS3;
James Smart2e0fef82007-06-17 19:56:36 -0500845
dea31012005-04-17 16:05:31 -0500846 ndlp->nlp_class_sup = 0;
847 if (sp->cls1.classValid)
848 ndlp->nlp_class_sup |= FC_COS_CLASS1;
849 if (sp->cls2.classValid)
850 ndlp->nlp_class_sup |= FC_COS_CLASS2;
851 if (sp->cls3.classValid)
852 ndlp->nlp_class_sup |= FC_COS_CLASS3;
853 if (sp->cls4.classValid)
854 ndlp->nlp_class_sup |= FC_COS_CLASS4;
855 ndlp->nlp_maxframe =
James Smart2e0fef82007-06-17 19:56:36 -0500856 ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb;
dea31012005-04-17 16:05:31 -0500857
James Smart2e0fef82007-06-17 19:56:36 -0500858 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
James Smart92d7f7b2007-06-17 19:56:38 -0500859 if (!mbox) {
James Smarte8b62012007-08-02 11:10:09 -0400860 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
861 "0133 PLOGI: no memory for reg_login "
James Smart92d7f7b2007-06-17 19:56:38 -0500862 "Data: x%x x%x x%x x%x\n",
James Smart92d7f7b2007-06-17 19:56:38 -0500863 ndlp->nlp_DID, ndlp->nlp_state,
864 ndlp->nlp_flag, ndlp->nlp_rpi);
dea31012005-04-17 16:05:31 -0500865 goto out;
James Smart92d7f7b2007-06-17 19:56:38 -0500866 }
dea31012005-04-17 16:05:31 -0500867
James Smart2e0fef82007-06-17 19:56:36 -0500868 lpfc_unreg_rpi(vport, ndlp);
869
James Smart6fb120a2009-05-22 14:52:59 -0400870 if (lpfc_reg_rpi(phba, vport->vpi, irsp->un.elsreq64.remoteID,
James Smart92d7f7b2007-06-17 19:56:38 -0500871 (uint8_t *) sp, mbox, 0) == 0) {
Jamie Wellnitz2fe165b2006-02-28 19:25:31 -0500872 switch (ndlp->nlp_DID) {
dea31012005-04-17 16:05:31 -0500873 case NameServer_DID:
James Smartde0c5b32007-04-25 09:52:27 -0400874 mbox->mbox_cmpl = lpfc_mbx_cmpl_ns_reg_login;
dea31012005-04-17 16:05:31 -0500875 break;
876 case FDMI_DID:
James Smartde0c5b32007-04-25 09:52:27 -0400877 mbox->mbox_cmpl = lpfc_mbx_cmpl_fdmi_reg_login;
dea31012005-04-17 16:05:31 -0500878 break;
879 default:
James Smartde0c5b32007-04-25 09:52:27 -0400880 mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
dea31012005-04-17 16:05:31 -0500881 }
James Smart329f9bc2007-04-25 09:53:01 -0400882 mbox->context2 = lpfc_nlp_get(ndlp);
James Smart2e0fef82007-06-17 19:56:36 -0500883 mbox->vport = vport;
James Smart0b727fe2007-10-27 13:37:25 -0400884 if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
dea31012005-04-17 16:05:31 -0500885 != MBX_NOT_FINISHED) {
James Smart2e0fef82007-06-17 19:56:36 -0500886 lpfc_nlp_set_state(vport, ndlp,
887 NLP_STE_REG_LOGIN_ISSUE);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500888 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -0500889 }
James Smartfa4066b2008-01-11 01:53:27 -0500890 /* decrement node reference count to the failed mbox
891 * command
892 */
James Smart329f9bc2007-04-25 09:53:01 -0400893 lpfc_nlp_put(ndlp);
James Smart92d7f7b2007-06-17 19:56:38 -0500894 mp = (struct lpfc_dmabuf *) mbox->context1;
James Smart14691152006-12-02 13:34:28 -0500895 lpfc_mbuf_free(phba, mp->virt, mp->phys);
896 kfree(mp);
dea31012005-04-17 16:05:31 -0500897 mempool_free(mbox, phba->mbox_mem_pool);
James Smart92d7f7b2007-06-17 19:56:38 -0500898
James Smarte8b62012007-08-02 11:10:09 -0400899 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
900 "0134 PLOGI: cannot issue reg_login "
901 "Data: x%x x%x x%x x%x\n",
902 ndlp->nlp_DID, ndlp->nlp_state,
903 ndlp->nlp_flag, ndlp->nlp_rpi);
dea31012005-04-17 16:05:31 -0500904 } else {
905 mempool_free(mbox, phba->mbox_mem_pool);
James Smart92d7f7b2007-06-17 19:56:38 -0500906
James Smarte8b62012007-08-02 11:10:09 -0400907 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
908 "0135 PLOGI: cannot format reg_login "
909 "Data: x%x x%x x%x x%x\n",
910 ndlp->nlp_DID, ndlp->nlp_state,
911 ndlp->nlp_flag, ndlp->nlp_rpi);
dea31012005-04-17 16:05:31 -0500912 }
913
914
James Smart92d7f7b2007-06-17 19:56:38 -0500915out:
916 if (ndlp->nlp_DID == NameServer_DID) {
917 lpfc_vport_set_state(vport, FC_VPORT_FAILED);
James Smarte8b62012007-08-02 11:10:09 -0400918 lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
919 "0261 Cannot Register NameServer login\n");
James Smart92d7f7b2007-06-17 19:56:38 -0500920 }
921
James Smart0ff10d42008-01-11 01:52:36 -0500922 spin_lock_irq(shost->host_lock);
James Smarta8adb832007-10-27 13:37:53 -0400923 ndlp->nlp_flag |= NLP_DEFER_RM;
James Smart0ff10d42008-01-11 01:52:36 -0500924 spin_unlock_irq(shost->host_lock);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500925 return NLP_STE_FREED_NODE;
dea31012005-04-17 16:05:31 -0500926}
927
928static uint32_t
James Smart0ff10d42008-01-11 01:52:36 -0500929lpfc_cmpl_logo_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
930 void *arg, uint32_t evt)
931{
932 return ndlp->nlp_state;
933}
934
935static uint32_t
936lpfc_cmpl_reglogin_plogi_issue(struct lpfc_vport *vport,
937 struct lpfc_nodelist *ndlp, void *arg, uint32_t evt)
938{
939 return ndlp->nlp_state;
940}
941
942static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -0500943lpfc_device_rm_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
944 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -0500945{
James Smart2e0fef82007-06-17 19:56:36 -0500946 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -0500947
James Smart2e0fef82007-06-17 19:56:36 -0500948 if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
949 spin_lock_irq(shost->host_lock);
950 ndlp->nlp_flag |= NLP_NODEV_REMOVE;
951 spin_unlock_irq(shost->host_lock);
952 return ndlp->nlp_state;
953 } else {
954 /* software abort outstanding PLOGI */
955 lpfc_els_abort(vport->phba, ndlp);
956
957 lpfc_drop_node(vport, ndlp);
James Smarta0f9b482006-04-15 11:52:56 -0400958 return NLP_STE_FREED_NODE;
959 }
dea31012005-04-17 16:05:31 -0500960}
961
962static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -0500963lpfc_device_recov_plogi_issue(struct lpfc_vport *vport,
964 struct lpfc_nodelist *ndlp,
965 void *arg,
966 uint32_t evt)
dea31012005-04-17 16:05:31 -0500967{
James Smart2e0fef82007-06-17 19:56:36 -0500968 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
969 struct lpfc_hba *phba = vport->phba;
970
James Smart92d7f7b2007-06-17 19:56:38 -0500971 /* Don't do anything that will mess up processing of the
972 * previous RSCN.
973 */
974 if (vport->fc_flag & FC_RSCN_DEFERRED)
975 return ndlp->nlp_state;
976
dea31012005-04-17 16:05:31 -0500977 /* software abort outstanding PLOGI */
James Smart07951072007-04-25 09:51:38 -0400978 lpfc_els_abort(phba, ndlp);
dea31012005-04-17 16:05:31 -0500979
Jamie Wellnitz5024ab12006-02-28 19:25:28 -0500980 ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE;
James Smart2e0fef82007-06-17 19:56:36 -0500981 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
James Smart92d7f7b2007-06-17 19:56:38 -0500982 spin_lock_irq(shost->host_lock);
James Smarta0f9b482006-04-15 11:52:56 -0400983 ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
James Smart2e0fef82007-06-17 19:56:36 -0500984 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -0500985
Jamie Wellnitzc9f87352006-02-28 19:25:23 -0500986 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -0500987}
988
989static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -0500990lpfc_rcv_plogi_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
991 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -0500992{
James Smart0d2b6b82008-06-14 22:52:47 -0400993 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
James Smart2e0fef82007-06-17 19:56:36 -0500994 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -0500995 struct lpfc_iocbq *cmdiocb;
996
997 /* software abort outstanding ADISC */
James Smart07951072007-04-25 09:51:38 -0400998 lpfc_els_abort(phba, ndlp);
dea31012005-04-17 16:05:31 -0500999
1000 cmdiocb = (struct lpfc_iocbq *) arg;
1001
James Smart0d2b6b82008-06-14 22:52:47 -04001002 if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) {
1003 if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
1004 spin_lock_irq(shost->host_lock);
1005 ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
1006 spin_unlock_irq(shost->host_lock);
James Smart90160e02008-08-24 21:49:45 -04001007 if (vport->num_disc_nodes)
James Smart0d2b6b82008-06-14 22:52:47 -04001008 lpfc_more_adisc(vport);
James Smart0d2b6b82008-06-14 22:52:47 -04001009 }
1010 return ndlp->nlp_state;
1011 }
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001012 ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
James Smart2e0fef82007-06-17 19:56:36 -05001013 lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
1014 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
dea31012005-04-17 16:05:31 -05001015
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001016 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001017}
1018
1019static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001020lpfc_rcv_prli_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1021 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001022{
James Smart2e0fef82007-06-17 19:56:36 -05001023 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
dea31012005-04-17 16:05:31 -05001024
James Smart2e0fef82007-06-17 19:56:36 -05001025 lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001026 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001027}
1028
1029static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001030lpfc_rcv_logo_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1031 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001032{
James Smart2e0fef82007-06-17 19:56:36 -05001033 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001034 struct lpfc_iocbq *cmdiocb;
1035
1036 cmdiocb = (struct lpfc_iocbq *) arg;
1037
1038 /* software abort outstanding ADISC */
James Smart07951072007-04-25 09:51:38 -04001039 lpfc_els_abort(phba, ndlp);
dea31012005-04-17 16:05:31 -05001040
James Smart2e0fef82007-06-17 19:56:36 -05001041 lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001042 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001043}
1044
1045static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001046lpfc_rcv_padisc_adisc_issue(struct lpfc_vport *vport,
1047 struct lpfc_nodelist *ndlp,
1048 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001049{
1050 struct lpfc_iocbq *cmdiocb;
1051
1052 cmdiocb = (struct lpfc_iocbq *) arg;
1053
James Smart2e0fef82007-06-17 19:56:36 -05001054 lpfc_rcv_padisc(vport, ndlp, cmdiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001055 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001056}
1057
1058static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001059lpfc_rcv_prlo_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1060 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001061{
1062 struct lpfc_iocbq *cmdiocb;
1063
1064 cmdiocb = (struct lpfc_iocbq *) arg;
1065
1066 /* Treat like rcv logo */
James Smart2e0fef82007-06-17 19:56:36 -05001067 lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_PRLO);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001068 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001069}
1070
1071static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001072lpfc_cmpl_adisc_adisc_issue(struct lpfc_vport *vport,
1073 struct lpfc_nodelist *ndlp,
1074 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001075{
James Smart2e0fef82007-06-17 19:56:36 -05001076 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1077 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001078 struct lpfc_iocbq *cmdiocb, *rspiocb;
1079 IOCB_t *irsp;
1080 ADISC *ap;
James Smart6fb120a2009-05-22 14:52:59 -04001081 int rc;
dea31012005-04-17 16:05:31 -05001082
1083 cmdiocb = (struct lpfc_iocbq *) arg;
1084 rspiocb = cmdiocb->context_un.rsp_iocb;
1085
1086 ap = (ADISC *)lpfc_check_elscmpl_iocb(phba, cmdiocb, rspiocb);
1087 irsp = &rspiocb->iocb;
1088
1089 if ((irsp->ulpStatus) ||
James Smart92d7f7b2007-06-17 19:56:38 -05001090 (!lpfc_check_adisc(vport, ndlp, &ap->nodeName, &ap->portName))) {
dea31012005-04-17 16:05:31 -05001091 /* 1 sec timeout */
1092 mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
James Smart2e0fef82007-06-17 19:56:36 -05001093 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001094 ndlp->nlp_flag |= NLP_DELAY_TMO;
James Smart2e0fef82007-06-17 19:56:36 -05001095 spin_unlock_irq(shost->host_lock);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001096 ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
dea31012005-04-17 16:05:31 -05001097
James Smart2e0fef82007-06-17 19:56:36 -05001098 memset(&ndlp->nlp_nodename, 0, sizeof(struct lpfc_name));
1099 memset(&ndlp->nlp_portname, 0, sizeof(struct lpfc_name));
dea31012005-04-17 16:05:31 -05001100
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001101 ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
James Smart2e0fef82007-06-17 19:56:36 -05001102 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
1103 lpfc_unreg_rpi(vport, ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001104 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001105 }
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001106
James Smart6fb120a2009-05-22 14:52:59 -04001107 if (phba->sli_rev == LPFC_SLI_REV4) {
1108 rc = lpfc_sli4_resume_rpi(ndlp);
1109 if (rc) {
1110 /* Stay in state and retry. */
1111 ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
1112 return ndlp->nlp_state;
1113 }
1114 }
1115
James.Smart@Emulex.Com25013222005-06-25 10:34:33 -04001116 if (ndlp->nlp_type & NLP_FCP_TARGET) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001117 ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
James Smart2e0fef82007-06-17 19:56:36 -05001118 lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE);
James.Smart@Emulex.Com25013222005-06-25 10:34:33 -04001119 } else {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001120 ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
James Smart2e0fef82007-06-17 19:56:36 -05001121 lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
James.Smart@Emulex.Com25013222005-06-25 10:34:33 -04001122 }
James Smart6fb120a2009-05-22 14:52:59 -04001123
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001124 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001125}
1126
1127static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001128lpfc_device_rm_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1129 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001130{
James Smart2e0fef82007-06-17 19:56:36 -05001131 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05001132
James Smart2e0fef82007-06-17 19:56:36 -05001133 if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
1134 spin_lock_irq(shost->host_lock);
1135 ndlp->nlp_flag |= NLP_NODEV_REMOVE;
1136 spin_unlock_irq(shost->host_lock);
1137 return ndlp->nlp_state;
1138 } else {
1139 /* software abort outstanding ADISC */
1140 lpfc_els_abort(vport->phba, ndlp);
1141
1142 lpfc_drop_node(vport, ndlp);
James Smarta0f9b482006-04-15 11:52:56 -04001143 return NLP_STE_FREED_NODE;
1144 }
dea31012005-04-17 16:05:31 -05001145}
1146
1147static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001148lpfc_device_recov_adisc_issue(struct lpfc_vport *vport,
1149 struct lpfc_nodelist *ndlp,
1150 void *arg,
1151 uint32_t evt)
dea31012005-04-17 16:05:31 -05001152{
James Smart2e0fef82007-06-17 19:56:36 -05001153 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1154 struct lpfc_hba *phba = vport->phba;
1155
James Smart92d7f7b2007-06-17 19:56:38 -05001156 /* Don't do anything that will mess up processing of the
1157 * previous RSCN.
1158 */
1159 if (vport->fc_flag & FC_RSCN_DEFERRED)
1160 return ndlp->nlp_state;
1161
dea31012005-04-17 16:05:31 -05001162 /* software abort outstanding ADISC */
James Smart07951072007-04-25 09:51:38 -04001163 lpfc_els_abort(phba, ndlp);
dea31012005-04-17 16:05:31 -05001164
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001165 ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
James Smart2e0fef82007-06-17 19:56:36 -05001166 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
1167 spin_lock_irq(shost->host_lock);
James Smarta0f9b482006-04-15 11:52:56 -04001168 ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
James Smart2e0fef82007-06-17 19:56:36 -05001169 spin_unlock_irq(shost->host_lock);
James Smart92d7f7b2007-06-17 19:56:38 -05001170 lpfc_disc_set_adisc(vport, ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001171 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001172}
1173
1174static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001175lpfc_rcv_plogi_reglogin_issue(struct lpfc_vport *vport,
1176 struct lpfc_nodelist *ndlp,
1177 void *arg,
dea31012005-04-17 16:05:31 -05001178 uint32_t evt)
1179{
James Smart2e0fef82007-06-17 19:56:36 -05001180 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
dea31012005-04-17 16:05:31 -05001181
James Smart2e0fef82007-06-17 19:56:36 -05001182 lpfc_rcv_plogi(vport, ndlp, cmdiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001183 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001184}
1185
1186static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001187lpfc_rcv_prli_reglogin_issue(struct lpfc_vport *vport,
1188 struct lpfc_nodelist *ndlp,
1189 void *arg,
dea31012005-04-17 16:05:31 -05001190 uint32_t evt)
1191{
James Smart2e0fef82007-06-17 19:56:36 -05001192 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
dea31012005-04-17 16:05:31 -05001193
James Smart2e0fef82007-06-17 19:56:36 -05001194 lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001195 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001196}
1197
1198static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001199lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport,
1200 struct lpfc_nodelist *ndlp,
1201 void *arg,
dea31012005-04-17 16:05:31 -05001202 uint32_t evt)
1203{
James Smart2e0fef82007-06-17 19:56:36 -05001204 struct lpfc_hba *phba = vport->phba;
1205 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
James Smart7054a602007-04-25 09:52:34 -04001206 LPFC_MBOXQ_t *mb;
1207 LPFC_MBOXQ_t *nextmb;
1208 struct lpfc_dmabuf *mp;
dea31012005-04-17 16:05:31 -05001209
1210 cmdiocb = (struct lpfc_iocbq *) arg;
1211
James Smart7054a602007-04-25 09:52:34 -04001212 /* cleanup any ndlp on mbox q waiting for reglogin cmpl */
1213 if ((mb = phba->sli.mbox_active)) {
James Smart04c68492009-05-22 14:52:52 -04001214 if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) &&
James Smart7054a602007-04-25 09:52:34 -04001215 (ndlp == (struct lpfc_nodelist *) mb->context2)) {
James Smart92d7f7b2007-06-17 19:56:38 -05001216 lpfc_nlp_put(ndlp);
James Smart7054a602007-04-25 09:52:34 -04001217 mb->context2 = NULL;
1218 mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
1219 }
1220 }
1221
James Smart2e0fef82007-06-17 19:56:36 -05001222 spin_lock_irq(&phba->hbalock);
James Smart7054a602007-04-25 09:52:34 -04001223 list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
James Smart04c68492009-05-22 14:52:52 -04001224 if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) &&
James Smart7054a602007-04-25 09:52:34 -04001225 (ndlp == (struct lpfc_nodelist *) mb->context2)) {
James Smart5ffc2662009-11-18 15:39:44 -05001226 if (phba->sli_rev == LPFC_SLI_REV4) {
1227 spin_unlock_irq(&phba->hbalock);
1228 lpfc_sli4_free_rpi(phba,
1229 mb->u.mb.un.varRegLogin.rpi);
1230 spin_lock_irq(&phba->hbalock);
1231 }
James Smart7054a602007-04-25 09:52:34 -04001232 mp = (struct lpfc_dmabuf *) (mb->context1);
1233 if (mp) {
James Smart98c9ea52007-10-27 13:37:33 -04001234 __lpfc_mbuf_free(phba, mp->virt, mp->phys);
James Smart7054a602007-04-25 09:52:34 -04001235 kfree(mp);
1236 }
James Smart92d7f7b2007-06-17 19:56:38 -05001237 lpfc_nlp_put(ndlp);
James Smart7054a602007-04-25 09:52:34 -04001238 list_del(&mb->list);
James Smart5ffc2662009-11-18 15:39:44 -05001239 phba->sli.mboxq_cnt--;
James Smart7054a602007-04-25 09:52:34 -04001240 mempool_free(mb, phba->mbox_mem_pool);
1241 }
1242 }
James Smart2e0fef82007-06-17 19:56:36 -05001243 spin_unlock_irq(&phba->hbalock);
James Smart7054a602007-04-25 09:52:34 -04001244
James Smart2e0fef82007-06-17 19:56:36 -05001245 lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001246 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001247}
1248
1249static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001250lpfc_rcv_padisc_reglogin_issue(struct lpfc_vport *vport,
1251 struct lpfc_nodelist *ndlp,
1252 void *arg,
dea31012005-04-17 16:05:31 -05001253 uint32_t evt)
1254{
James Smart2e0fef82007-06-17 19:56:36 -05001255 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
dea31012005-04-17 16:05:31 -05001256
James Smart2e0fef82007-06-17 19:56:36 -05001257 lpfc_rcv_padisc(vport, ndlp, cmdiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001258 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001259}
1260
1261static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001262lpfc_rcv_prlo_reglogin_issue(struct lpfc_vport *vport,
1263 struct lpfc_nodelist *ndlp,
1264 void *arg,
dea31012005-04-17 16:05:31 -05001265 uint32_t evt)
1266{
1267 struct lpfc_iocbq *cmdiocb;
1268
1269 cmdiocb = (struct lpfc_iocbq *) arg;
James Smart51ef4c22007-08-02 11:10:31 -04001270 lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001271 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001272}
1273
1274static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001275lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport,
1276 struct lpfc_nodelist *ndlp,
1277 void *arg,
1278 uint32_t evt)
dea31012005-04-17 16:05:31 -05001279{
James Smart2e0fef82007-06-17 19:56:36 -05001280 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
James Smart2e0fef82007-06-17 19:56:36 -05001281 LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
James Smart04c68492009-05-22 14:52:52 -04001282 MAILBOX_t *mb = &pmb->u.mb;
James Smart2e0fef82007-06-17 19:56:36 -05001283 uint32_t did = mb->un.varWords[1];
dea31012005-04-17 16:05:31 -05001284
dea31012005-04-17 16:05:31 -05001285 if (mb->mbxStatus) {
1286 /* RegLogin failed */
James Smarte8b62012007-08-02 11:10:09 -04001287 lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
1288 "0246 RegLogin failed Data: x%x x%x x%x\n",
James Smart2e0fef82007-06-17 19:56:36 -05001289 did, mb->mbxStatus, vport->port_state);
James Smartd0e56da2006-07-06 15:49:42 -04001290 /*
1291 * If RegLogin failed due to lack of HBA resources do not
1292 * retry discovery.
1293 */
1294 if (mb->mbxStatus == MBXERR_RPI_FULL) {
James Smart87af33f2007-10-27 13:37:43 -04001295 ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
1296 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
James Smartd0e56da2006-07-06 15:49:42 -04001297 return ndlp->nlp_state;
1298 }
1299
James Smart2e0fef82007-06-17 19:56:36 -05001300 /* Put ndlp in npr state set plogi timer for 1 sec */
dea31012005-04-17 16:05:31 -05001301 mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
James Smart2e0fef82007-06-17 19:56:36 -05001302 spin_lock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001303 ndlp->nlp_flag |= NLP_DELAY_TMO;
James Smart2e0fef82007-06-17 19:56:36 -05001304 spin_unlock_irq(shost->host_lock);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001305 ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
dea31012005-04-17 16:05:31 -05001306
James Smart2e0fef82007-06-17 19:56:36 -05001307 lpfc_issue_els_logo(vport, ndlp, 0);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001308 ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
James Smart2e0fef82007-06-17 19:56:36 -05001309 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001310 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001311 }
1312
dea31012005-04-17 16:05:31 -05001313 ndlp->nlp_rpi = mb->un.varWords[0];
James Smart6fb120a2009-05-22 14:52:59 -04001314 ndlp->nlp_flag |= NLP_RPI_VALID;
dea31012005-04-17 16:05:31 -05001315
1316 /* Only if we are not a fabric nport do we issue PRLI */
1317 if (!(ndlp->nlp_type & NLP_FABRIC)) {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001318 ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
James Smart2e0fef82007-06-17 19:56:36 -05001319 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
1320 lpfc_issue_els_prli(vport, ndlp, 0);
dea31012005-04-17 16:05:31 -05001321 } else {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001322 ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
James Smart2e0fef82007-06-17 19:56:36 -05001323 lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
dea31012005-04-17 16:05:31 -05001324 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001325 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001326}
1327
1328static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001329lpfc_device_rm_reglogin_issue(struct lpfc_vport *vport,
1330 struct lpfc_nodelist *ndlp,
1331 void *arg,
dea31012005-04-17 16:05:31 -05001332 uint32_t evt)
1333{
James Smart2e0fef82007-06-17 19:56:36 -05001334 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1335
1336 if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
1337 spin_lock_irq(shost->host_lock);
James Smarta0f9b482006-04-15 11:52:56 -04001338 ndlp->nlp_flag |= NLP_NODEV_REMOVE;
James Smart2e0fef82007-06-17 19:56:36 -05001339 spin_unlock_irq(shost->host_lock);
James Smarta0f9b482006-04-15 11:52:56 -04001340 return ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001341 } else {
1342 lpfc_drop_node(vport, ndlp);
James Smarta0f9b482006-04-15 11:52:56 -04001343 return NLP_STE_FREED_NODE;
1344 }
dea31012005-04-17 16:05:31 -05001345}
1346
1347static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001348lpfc_device_recov_reglogin_issue(struct lpfc_vport *vport,
1349 struct lpfc_nodelist *ndlp,
1350 void *arg,
1351 uint32_t evt)
dea31012005-04-17 16:05:31 -05001352{
James Smart2e0fef82007-06-17 19:56:36 -05001353 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1354
James Smart92d7f7b2007-06-17 19:56:38 -05001355 /* Don't do anything that will mess up processing of the
1356 * previous RSCN.
1357 */
1358 if (vport->fc_flag & FC_RSCN_DEFERRED)
1359 return ndlp->nlp_state;
1360
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001361 ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
James Smart2e0fef82007-06-17 19:56:36 -05001362 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
1363 spin_lock_irq(shost->host_lock);
James Smarta0f9b482006-04-15 11:52:56 -04001364 ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
James Smart2e0fef82007-06-17 19:56:36 -05001365 spin_unlock_irq(shost->host_lock);
James Smart92d7f7b2007-06-17 19:56:38 -05001366 lpfc_disc_set_adisc(vport, ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001367 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001368}
1369
1370static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001371lpfc_rcv_plogi_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1372 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001373{
1374 struct lpfc_iocbq *cmdiocb;
1375
1376 cmdiocb = (struct lpfc_iocbq *) arg;
1377
James Smart2e0fef82007-06-17 19:56:36 -05001378 lpfc_rcv_plogi(vport, ndlp, cmdiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001379 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001380}
1381
1382static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001383lpfc_rcv_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1384 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001385{
James Smart2e0fef82007-06-17 19:56:36 -05001386 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
dea31012005-04-17 16:05:31 -05001387
James Smart2e0fef82007-06-17 19:56:36 -05001388 lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001389 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001390}
1391
1392static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001393lpfc_rcv_logo_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1394 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001395{
James Smart2e0fef82007-06-17 19:56:36 -05001396 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
dea31012005-04-17 16:05:31 -05001397
1398 /* Software abort outstanding PRLI before sending acc */
James Smart2e0fef82007-06-17 19:56:36 -05001399 lpfc_els_abort(vport->phba, ndlp);
dea31012005-04-17 16:05:31 -05001400
James Smart2e0fef82007-06-17 19:56:36 -05001401 lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001402 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001403}
1404
1405static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001406lpfc_rcv_padisc_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1407 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001408{
James Smart2e0fef82007-06-17 19:56:36 -05001409 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
dea31012005-04-17 16:05:31 -05001410
James Smart2e0fef82007-06-17 19:56:36 -05001411 lpfc_rcv_padisc(vport, ndlp, cmdiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001412 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001413}
1414
1415/* This routine is envoked when we rcv a PRLO request from a nport
1416 * we are logged into. We should send back a PRLO rsp setting the
1417 * appropriate bits.
1418 * NEXT STATE = PRLI_ISSUE
1419 */
1420static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001421lpfc_rcv_prlo_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1422 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001423{
James Smart2e0fef82007-06-17 19:56:36 -05001424 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
dea31012005-04-17 16:05:31 -05001425
James Smart51ef4c22007-08-02 11:10:31 -04001426 lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001427 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001428}
1429
1430static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001431lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1432 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001433{
James Smart92d7f7b2007-06-17 19:56:38 -05001434 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05001435 struct lpfc_iocbq *cmdiocb, *rspiocb;
James Smart2e0fef82007-06-17 19:56:36 -05001436 struct lpfc_hba *phba = vport->phba;
dea31012005-04-17 16:05:31 -05001437 IOCB_t *irsp;
1438 PRLI *npr;
1439
1440 cmdiocb = (struct lpfc_iocbq *) arg;
1441 rspiocb = cmdiocb->context_un.rsp_iocb;
1442 npr = (PRLI *)lpfc_check_elscmpl_iocb(phba, cmdiocb, rspiocb);
1443
1444 irsp = &rspiocb->iocb;
1445 if (irsp->ulpStatus) {
James Smart858c9f62007-06-17 19:56:39 -05001446 if ((vport->port_type == LPFC_NPIV_PORT) &&
James Smart3de2a652007-08-02 11:09:59 -04001447 vport->cfg_restrict_login) {
James Smart858c9f62007-06-17 19:56:39 -05001448 goto out;
1449 }
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001450 ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
James Smart2e0fef82007-06-17 19:56:36 -05001451 lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001452 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001453 }
1454
1455 /* Check out PRLI rsp */
1456 ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
1457 ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
1458 if ((npr->acceptRspCode == PRLI_REQ_EXECUTED) &&
1459 (npr->prliType == PRLI_FCP_TYPE)) {
1460 if (npr->initiatorFunc)
1461 ndlp->nlp_type |= NLP_FCP_INITIATOR;
1462 if (npr->targetFunc)
1463 ndlp->nlp_type |= NLP_FCP_TARGET;
1464 if (npr->Retry)
1465 ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE;
1466 }
James Smart92d7f7b2007-06-17 19:56:38 -05001467 if (!(ndlp->nlp_type & NLP_FCP_TARGET) &&
1468 (vport->port_type == LPFC_NPIV_PORT) &&
James Smart3de2a652007-08-02 11:09:59 -04001469 vport->cfg_restrict_login) {
James Smart858c9f62007-06-17 19:56:39 -05001470out:
James Smart92d7f7b2007-06-17 19:56:38 -05001471 spin_lock_irq(shost->host_lock);
1472 ndlp->nlp_flag |= NLP_TARGET_REMOVE;
1473 spin_unlock_irq(shost->host_lock);
1474 lpfc_issue_els_logo(vport, ndlp, 0);
1475
1476 ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
James Smart87af33f2007-10-27 13:37:43 -04001477 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
James Smart92d7f7b2007-06-17 19:56:38 -05001478 return ndlp->nlp_state;
1479 }
dea31012005-04-17 16:05:31 -05001480
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001481 ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
James Smart92d7f7b2007-06-17 19:56:38 -05001482 if (ndlp->nlp_type & NLP_FCP_TARGET)
1483 lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE);
1484 else
1485 lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001486 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001487}
1488
1489/*! lpfc_device_rm_prli_issue
James Smart92d7f7b2007-06-17 19:56:38 -05001490 *
1491 * \pre
1492 * \post
1493 * \param phba
1494 * \param ndlp
1495 * \param arg
1496 * \param evt
1497 * \return uint32_t
1498 *
1499 * \b Description:
1500 * This routine is envoked when we a request to remove a nport we are in the
1501 * process of PRLIing. We should software abort outstanding prli, unreg
1502 * login, send a logout. We will change node state to UNUSED_NODE, put it
1503 * on plogi list so it can be freed when LOGO completes.
1504 *
1505 */
1506
dea31012005-04-17 16:05:31 -05001507static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001508lpfc_device_rm_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1509 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001510{
James Smart2e0fef82007-06-17 19:56:36 -05001511 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
dea31012005-04-17 16:05:31 -05001512
James Smart2e0fef82007-06-17 19:56:36 -05001513 if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
1514 spin_lock_irq(shost->host_lock);
1515 ndlp->nlp_flag |= NLP_NODEV_REMOVE;
1516 spin_unlock_irq(shost->host_lock);
1517 return ndlp->nlp_state;
1518 } else {
1519 /* software abort outstanding PLOGI */
1520 lpfc_els_abort(vport->phba, ndlp);
1521
1522 lpfc_drop_node(vport, ndlp);
James Smarta0f9b482006-04-15 11:52:56 -04001523 return NLP_STE_FREED_NODE;
1524 }
dea31012005-04-17 16:05:31 -05001525}
1526
1527
1528/*! lpfc_device_recov_prli_issue
James Smart92d7f7b2007-06-17 19:56:38 -05001529 *
1530 * \pre
1531 * \post
1532 * \param phba
1533 * \param ndlp
1534 * \param arg
1535 * \param evt
1536 * \return uint32_t
1537 *
1538 * \b Description:
1539 * The routine is envoked when the state of a device is unknown, like
1540 * during a link down. We should remove the nodelist entry from the
1541 * unmapped list, issue a UNREG_LOGIN, do a software abort of the
1542 * outstanding PRLI command, then free the node entry.
1543 */
dea31012005-04-17 16:05:31 -05001544static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001545lpfc_device_recov_prli_issue(struct lpfc_vport *vport,
1546 struct lpfc_nodelist *ndlp,
1547 void *arg,
1548 uint32_t evt)
dea31012005-04-17 16:05:31 -05001549{
James Smart2e0fef82007-06-17 19:56:36 -05001550 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1551 struct lpfc_hba *phba = vport->phba;
1552
James Smart92d7f7b2007-06-17 19:56:38 -05001553 /* Don't do anything that will mess up processing of the
1554 * previous RSCN.
1555 */
1556 if (vport->fc_flag & FC_RSCN_DEFERRED)
1557 return ndlp->nlp_state;
1558
dea31012005-04-17 16:05:31 -05001559 /* software abort outstanding PRLI */
James Smart07951072007-04-25 09:51:38 -04001560 lpfc_els_abort(phba, ndlp);
dea31012005-04-17 16:05:31 -05001561
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001562 ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
James Smart2e0fef82007-06-17 19:56:36 -05001563 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
1564 spin_lock_irq(shost->host_lock);
James Smarta0f9b482006-04-15 11:52:56 -04001565 ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
James Smart2e0fef82007-06-17 19:56:36 -05001566 spin_unlock_irq(shost->host_lock);
James Smart92d7f7b2007-06-17 19:56:38 -05001567 lpfc_disc_set_adisc(vport, ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001568 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001569}
1570
1571static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001572lpfc_rcv_plogi_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1573 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001574{
James Smart2e0fef82007-06-17 19:56:36 -05001575 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
dea31012005-04-17 16:05:31 -05001576
James Smart2e0fef82007-06-17 19:56:36 -05001577 lpfc_rcv_plogi(vport, ndlp, cmdiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001578 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001579}
1580
1581static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001582lpfc_rcv_prli_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1583 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001584{
James Smart2e0fef82007-06-17 19:56:36 -05001585 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
dea31012005-04-17 16:05:31 -05001586
James Smart2e0fef82007-06-17 19:56:36 -05001587 lpfc_rcv_prli(vport, ndlp, cmdiocb);
1588 lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001589 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001590}
1591
1592static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001593lpfc_rcv_logo_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1594 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001595{
James Smart2e0fef82007-06-17 19:56:36 -05001596 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
dea31012005-04-17 16:05:31 -05001597
James Smart2e0fef82007-06-17 19:56:36 -05001598 lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001599 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001600}
1601
1602static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001603lpfc_rcv_padisc_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1604 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001605{
James Smart2e0fef82007-06-17 19:56:36 -05001606 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
dea31012005-04-17 16:05:31 -05001607
James Smart2e0fef82007-06-17 19:56:36 -05001608 lpfc_rcv_padisc(vport, ndlp, cmdiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001609 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001610}
1611
1612static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001613lpfc_rcv_prlo_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1614 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001615{
James Smart2e0fef82007-06-17 19:56:36 -05001616 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
dea31012005-04-17 16:05:31 -05001617
James Smart51ef4c22007-08-02 11:10:31 -04001618 lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001619 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001620}
1621
1622static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001623lpfc_device_recov_unmap_node(struct lpfc_vport *vport,
1624 struct lpfc_nodelist *ndlp,
1625 void *arg,
1626 uint32_t evt)
dea31012005-04-17 16:05:31 -05001627{
James Smart2e0fef82007-06-17 19:56:36 -05001628 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1629
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001630 ndlp->nlp_prev_state = NLP_STE_UNMAPPED_NODE;
James Smart2e0fef82007-06-17 19:56:36 -05001631 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
1632 spin_lock_irq(shost->host_lock);
James Smarta0f9b482006-04-15 11:52:56 -04001633 ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
James Smart2e0fef82007-06-17 19:56:36 -05001634 spin_unlock_irq(shost->host_lock);
1635 lpfc_disc_set_adisc(vport, ndlp);
dea31012005-04-17 16:05:31 -05001636
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001637 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001638}
1639
1640static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001641lpfc_rcv_plogi_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1642 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001643{
James Smart2e0fef82007-06-17 19:56:36 -05001644 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
dea31012005-04-17 16:05:31 -05001645
James Smart2e0fef82007-06-17 19:56:36 -05001646 lpfc_rcv_plogi(vport, ndlp, cmdiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001647 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001648}
1649
1650static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001651lpfc_rcv_prli_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1652 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001653{
James Smart2e0fef82007-06-17 19:56:36 -05001654 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
dea31012005-04-17 16:05:31 -05001655
James Smart2e0fef82007-06-17 19:56:36 -05001656 lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001657 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001658}
1659
1660static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001661lpfc_rcv_logo_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1662 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001663{
James Smart2e0fef82007-06-17 19:56:36 -05001664 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
dea31012005-04-17 16:05:31 -05001665
James Smart2e0fef82007-06-17 19:56:36 -05001666 lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001667 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001668}
1669
1670static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001671lpfc_rcv_padisc_mapped_node(struct lpfc_vport *vport,
1672 struct lpfc_nodelist *ndlp,
1673 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001674{
James Smart2e0fef82007-06-17 19:56:36 -05001675 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
dea31012005-04-17 16:05:31 -05001676
James Smart2e0fef82007-06-17 19:56:36 -05001677 lpfc_rcv_padisc(vport, ndlp, cmdiocb);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001678 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001679}
1680
1681static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001682lpfc_rcv_prlo_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1683 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001684{
James Smart2e0fef82007-06-17 19:56:36 -05001685 struct lpfc_hba *phba = vport->phba;
1686 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
dea31012005-04-17 16:05:31 -05001687
1688 /* flush the target */
James Smart51ef4c22007-08-02 11:10:31 -04001689 lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring],
1690 ndlp->nlp_sid, 0, LPFC_CTX_TGT);
dea31012005-04-17 16:05:31 -05001691
1692 /* Treat like rcv logo */
James Smart2e0fef82007-06-17 19:56:36 -05001693 lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_PRLO);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001694 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001695}
1696
1697static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001698lpfc_device_recov_mapped_node(struct lpfc_vport *vport,
1699 struct lpfc_nodelist *ndlp,
1700 void *arg,
1701 uint32_t evt)
dea31012005-04-17 16:05:31 -05001702{
James Smart2e0fef82007-06-17 19:56:36 -05001703 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1704
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001705 ndlp->nlp_prev_state = NLP_STE_MAPPED_NODE;
James Smart2e0fef82007-06-17 19:56:36 -05001706 lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
1707 spin_lock_irq(shost->host_lock);
James Smarta0f9b482006-04-15 11:52:56 -04001708 ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
James Smart2e0fef82007-06-17 19:56:36 -05001709 spin_unlock_irq(shost->host_lock);
1710 lpfc_disc_set_adisc(vport, ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001711 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001712}
1713
1714static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001715lpfc_rcv_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1716 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001717{
James Smart2e0fef82007-06-17 19:56:36 -05001718 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1719 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
dea31012005-04-17 16:05:31 -05001720
1721 /* Ignore PLOGI if we have an outstanding LOGO */
James Smart0d2b6b82008-06-14 22:52:47 -04001722 if (ndlp->nlp_flag & (NLP_LOGO_SND | NLP_LOGO_ACC))
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001723 return ndlp->nlp_state;
James Smart2e0fef82007-06-17 19:56:36 -05001724 if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) {
James Smart0d2b6b82008-06-14 22:52:47 -04001725 lpfc_cancel_retry_delay_tmo(vport, ndlp);
James Smart2e0fef82007-06-17 19:56:36 -05001726 spin_lock_irq(shost->host_lock);
James Smart0d2b6b82008-06-14 22:52:47 -04001727 ndlp->nlp_flag &= ~(NLP_NPR_ADISC | NLP_NPR_2B_DISC);
James Smart2e0fef82007-06-17 19:56:36 -05001728 spin_unlock_irq(shost->host_lock);
James Smart0d2b6b82008-06-14 22:52:47 -04001729 } else if (!(ndlp->nlp_flag & NLP_NPR_2B_DISC)) {
1730 /* send PLOGI immediately, move to PLOGI issue state */
1731 if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
1732 ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
1733 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
1734 lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
1735 }
dea31012005-04-17 16:05:31 -05001736 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001737 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001738}
1739
1740static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001741lpfc_rcv_prli_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1742 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001743{
James Smart2e0fef82007-06-17 19:56:36 -05001744 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1745 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
1746 struct ls_rjt stat;
dea31012005-04-17 16:05:31 -05001747
1748 memset(&stat, 0, sizeof (struct ls_rjt));
1749 stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
1750 stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
James Smart858c9f62007-06-17 19:56:39 -05001751 lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
dea31012005-04-17 16:05:31 -05001752
1753 if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
1754 if (ndlp->nlp_flag & NLP_NPR_ADISC) {
James Smart2e0fef82007-06-17 19:56:36 -05001755 spin_lock_irq(shost->host_lock);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001756 ndlp->nlp_flag &= ~NLP_NPR_ADISC;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001757 ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
James Smart2e0fef82007-06-17 19:56:36 -05001758 spin_unlock_irq(shost->host_lock);
1759 lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
1760 lpfc_issue_els_adisc(vport, ndlp, 0);
dea31012005-04-17 16:05:31 -05001761 } else {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001762 ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
James Smart2e0fef82007-06-17 19:56:36 -05001763 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
1764 lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
dea31012005-04-17 16:05:31 -05001765 }
1766 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001767 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001768}
1769
1770static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001771lpfc_rcv_logo_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1772 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001773{
James Smart2e0fef82007-06-17 19:56:36 -05001774 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
dea31012005-04-17 16:05:31 -05001775
James Smart2e0fef82007-06-17 19:56:36 -05001776 lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001777 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001778}
1779
1780static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001781lpfc_rcv_padisc_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1782 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001783{
James Smart2e0fef82007-06-17 19:56:36 -05001784 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
dea31012005-04-17 16:05:31 -05001785
James Smart2e0fef82007-06-17 19:56:36 -05001786 lpfc_rcv_padisc(vport, ndlp, cmdiocb);
James Smart33ccf8d2006-08-17 11:57:58 -04001787 /*
1788 * Do not start discovery if discovery is about to start
1789 * or discovery in progress for this node. Starting discovery
1790 * here will affect the counting of discovery threads.
1791 */
James Smart2fb9bd82006-12-02 13:33:57 -05001792 if (!(ndlp->nlp_flag & NLP_DELAY_TMO) &&
James Smart92d7f7b2007-06-17 19:56:38 -05001793 !(ndlp->nlp_flag & NLP_NPR_2B_DISC)) {
dea31012005-04-17 16:05:31 -05001794 if (ndlp->nlp_flag & NLP_NPR_ADISC) {
James Smart92d7f7b2007-06-17 19:56:38 -05001795 ndlp->nlp_flag &= ~NLP_NPR_ADISC;
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001796 ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
James Smart2e0fef82007-06-17 19:56:36 -05001797 lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
1798 lpfc_issue_els_adisc(vport, ndlp, 0);
dea31012005-04-17 16:05:31 -05001799 } else {
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001800 ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
James Smart2e0fef82007-06-17 19:56:36 -05001801 lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
1802 lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
dea31012005-04-17 16:05:31 -05001803 }
1804 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001805 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001806}
1807
1808static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001809lpfc_rcv_prlo_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1810 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001811{
James Smart2e0fef82007-06-17 19:56:36 -05001812 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1813 struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
dea31012005-04-17 16:05:31 -05001814
James Smart2e0fef82007-06-17 19:56:36 -05001815 spin_lock_irq(shost->host_lock);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001816 ndlp->nlp_flag |= NLP_LOGO_ACC;
James Smart2e0fef82007-06-17 19:56:36 -05001817 spin_unlock_irq(shost->host_lock);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001818
James Smart51ef4c22007-08-02 11:10:31 -04001819 lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
dea31012005-04-17 16:05:31 -05001820
James Smart2e0fef82007-06-17 19:56:36 -05001821 if ((ndlp->nlp_flag & NLP_DELAY_TMO) == 0) {
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001822 mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
James Smart2e0fef82007-06-17 19:56:36 -05001823 spin_lock_irq(shost->host_lock);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001824 ndlp->nlp_flag |= NLP_DELAY_TMO;
1825 ndlp->nlp_flag &= ~NLP_NPR_ADISC;
James Smart2e0fef82007-06-17 19:56:36 -05001826 spin_unlock_irq(shost->host_lock);
Jamie Wellnitz5024ab12006-02-28 19:25:28 -05001827 ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001828 } else {
James Smart2e0fef82007-06-17 19:56:36 -05001829 spin_lock_irq(shost->host_lock);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001830 ndlp->nlp_flag &= ~NLP_NPR_ADISC;
James Smart2e0fef82007-06-17 19:56:36 -05001831 spin_unlock_irq(shost->host_lock);
dea31012005-04-17 16:05:31 -05001832 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001833 return ndlp->nlp_state;
1834}
dea31012005-04-17 16:05:31 -05001835
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001836static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001837lpfc_cmpl_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1838 void *arg, uint32_t evt)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001839{
1840 struct lpfc_iocbq *cmdiocb, *rspiocb;
James Smarta0f9b482006-04-15 11:52:56 -04001841 IOCB_t *irsp;
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001842
1843 cmdiocb = (struct lpfc_iocbq *) arg;
1844 rspiocb = cmdiocb->context_un.rsp_iocb;
James Smarta0f9b482006-04-15 11:52:56 -04001845
1846 irsp = &rspiocb->iocb;
1847 if (irsp->ulpStatus) {
James Smarta8adb832007-10-27 13:37:53 -04001848 ndlp->nlp_flag |= NLP_DEFER_RM;
James Smarta0f9b482006-04-15 11:52:56 -04001849 return NLP_STE_FREED_NODE;
1850 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001851 return ndlp->nlp_state;
1852}
1853
1854static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001855lpfc_cmpl_prli_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1856 void *arg, uint32_t evt)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001857{
1858 struct lpfc_iocbq *cmdiocb, *rspiocb;
James Smarta0f9b482006-04-15 11:52:56 -04001859 IOCB_t *irsp;
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001860
1861 cmdiocb = (struct lpfc_iocbq *) arg;
1862 rspiocb = cmdiocb->context_un.rsp_iocb;
James Smarta0f9b482006-04-15 11:52:56 -04001863
1864 irsp = &rspiocb->iocb;
1865 if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) {
James Smart2e0fef82007-06-17 19:56:36 -05001866 lpfc_drop_node(vport, ndlp);
James Smarta0f9b482006-04-15 11:52:56 -04001867 return NLP_STE_FREED_NODE;
1868 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001869 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001870}
1871
1872static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001873lpfc_cmpl_logo_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1874 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001875{
James Smartd7c255b2008-08-24 21:50:00 -04001876 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1877 if (ndlp->nlp_DID == Fabric_DID) {
1878 spin_lock_irq(shost->host_lock);
1879 vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
1880 spin_unlock_irq(shost->host_lock);
1881 }
James Smart2e0fef82007-06-17 19:56:36 -05001882 lpfc_unreg_rpi(vport, ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001883 return ndlp->nlp_state;
1884}
1885
1886static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001887lpfc_cmpl_adisc_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1888 void *arg, uint32_t evt)
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001889{
1890 struct lpfc_iocbq *cmdiocb, *rspiocb;
James Smarta0f9b482006-04-15 11:52:56 -04001891 IOCB_t *irsp;
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001892
1893 cmdiocb = (struct lpfc_iocbq *) arg;
1894 rspiocb = cmdiocb->context_un.rsp_iocb;
James Smarta0f9b482006-04-15 11:52:56 -04001895
1896 irsp = &rspiocb->iocb;
1897 if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) {
James Smart2e0fef82007-06-17 19:56:36 -05001898 lpfc_drop_node(vport, ndlp);
James Smarta0f9b482006-04-15 11:52:56 -04001899 return NLP_STE_FREED_NODE;
1900 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001901 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001902}
1903
1904static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001905lpfc_cmpl_reglogin_npr_node(struct lpfc_vport *vport,
1906 struct lpfc_nodelist *ndlp,
1907 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001908{
James Smart2e0fef82007-06-17 19:56:36 -05001909 LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
James Smart04c68492009-05-22 14:52:52 -04001910 MAILBOX_t *mb = &pmb->u.mb;
dea31012005-04-17 16:05:31 -05001911
James Smart04c68492009-05-22 14:52:52 -04001912 if (!mb->mbxStatus) {
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001913 ndlp->nlp_rpi = mb->un.varWords[0];
James Smart04c68492009-05-22 14:52:52 -04001914 ndlp->nlp_flag |= NLP_RPI_VALID;
1915 } else {
James Smarta0f9b482006-04-15 11:52:56 -04001916 if (ndlp->nlp_flag & NLP_NODEV_REMOVE) {
James Smart2e0fef82007-06-17 19:56:36 -05001917 lpfc_drop_node(vport, ndlp);
James Smarta0f9b482006-04-15 11:52:56 -04001918 return NLP_STE_FREED_NODE;
1919 }
1920 }
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001921 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001922}
1923
1924static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001925lpfc_device_rm_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1926 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001927{
James Smart2e0fef82007-06-17 19:56:36 -05001928 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1929
James Smarta0f9b482006-04-15 11:52:56 -04001930 if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
James Smart2e0fef82007-06-17 19:56:36 -05001931 spin_lock_irq(shost->host_lock);
James Smarta0f9b482006-04-15 11:52:56 -04001932 ndlp->nlp_flag |= NLP_NODEV_REMOVE;
James Smart2e0fef82007-06-17 19:56:36 -05001933 spin_unlock_irq(shost->host_lock);
James Smarta0f9b482006-04-15 11:52:56 -04001934 return ndlp->nlp_state;
1935 }
James Smart2e0fef82007-06-17 19:56:36 -05001936 lpfc_drop_node(vport, ndlp);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001937 return NLP_STE_FREED_NODE;
dea31012005-04-17 16:05:31 -05001938}
1939
1940static uint32_t
James Smart2e0fef82007-06-17 19:56:36 -05001941lpfc_device_recov_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
1942 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05001943{
James Smart2e0fef82007-06-17 19:56:36 -05001944 struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
1945
James Smart92d7f7b2007-06-17 19:56:38 -05001946 /* Don't do anything that will mess up processing of the
1947 * previous RSCN.
1948 */
1949 if (vport->fc_flag & FC_RSCN_DEFERRED)
1950 return ndlp->nlp_state;
1951
James Smarteaf15d52008-12-04 22:39:29 -05001952 lpfc_cancel_retry_delay_tmo(vport, ndlp);
James Smart2e0fef82007-06-17 19:56:36 -05001953 spin_lock_irq(shost->host_lock);
James Smarta0f9b482006-04-15 11:52:56 -04001954 ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
James Smart2e0fef82007-06-17 19:56:36 -05001955 spin_unlock_irq(shost->host_lock);
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05001956 return ndlp->nlp_state;
dea31012005-04-17 16:05:31 -05001957}
1958
1959
1960/* This next section defines the NPort Discovery State Machine */
1961
1962/* There are 4 different double linked lists nodelist entries can reside on.
1963 * The plogi list and adisc list are used when Link Up discovery or RSCN
1964 * processing is needed. Each list holds the nodes that we will send PLOGI
1965 * or ADISC on. These lists will keep track of what nodes will be effected
1966 * by an RSCN, or a Link Up (Typically, all nodes are effected on Link Up).
1967 * The unmapped_list will contain all nodes that we have successfully logged
1968 * into at the Fibre Channel level. The mapped_list will contain all nodes
1969 * that are mapped FCP targets.
1970 */
1971/*
1972 * The bind list is a list of undiscovered (potentially non-existent) nodes
1973 * that we have saved binding information on. This information is used when
1974 * nodes transition from the unmapped to the mapped list.
1975 */
1976/* For UNUSED_NODE state, the node has just been allocated .
1977 * For PLOGI_ISSUE and REG_LOGIN_ISSUE, the node is on
1978 * the PLOGI list. For REG_LOGIN_COMPL, the node is taken off the PLOGI list
1979 * and put on the unmapped list. For ADISC processing, the node is taken off
1980 * the ADISC list and placed on either the mapped or unmapped list (depending
1981 * on its previous state). Once on the unmapped list, a PRLI is issued and the
1982 * state changed to PRLI_ISSUE. When the PRLI completion occurs, the state is
1983 * changed to UNMAPPED_NODE. If the completion indicates a mapped
1984 * node, the node is taken off the unmapped list. The binding list is checked
1985 * for a valid binding, or a binding is automatically assigned. If binding
1986 * assignment is unsuccessful, the node is left on the unmapped list. If
1987 * binding assignment is successful, the associated binding list entry (if
1988 * any) is removed, and the node is placed on the mapped list.
1989 */
1990/*
1991 * For a Link Down, all nodes on the ADISC, PLOGI, unmapped or mapped
James Smartc01f3202006-08-18 17:47:08 -04001992 * lists will receive a DEVICE_RECOVERY event. If the linkdown or devloss timers
dea31012005-04-17 16:05:31 -05001993 * expire, all effected nodes will receive a DEVICE_RM event.
1994 */
1995/*
1996 * For a Link Up or RSCN, all nodes will move from the mapped / unmapped lists
1997 * to either the ADISC or PLOGI list. After a Nameserver query or ALPA loopmap
1998 * check, additional nodes may be added or removed (via DEVICE_RM) to / from
1999 * the PLOGI or ADISC lists. Once the PLOGI and ADISC lists are populated,
2000 * we will first process the ADISC list. 32 entries are processed initially and
2001 * ADISC is initited for each one. Completions / Events for each node are
2002 * funnelled thru the state machine. As each node finishes ADISC processing, it
2003 * starts ADISC for any nodes waiting for ADISC processing. If no nodes are
2004 * waiting, and the ADISC list count is identically 0, then we are done. For
2005 * Link Up discovery, since all nodes on the PLOGI list are UNREG_LOGIN'ed, we
2006 * can issue a CLEAR_LA and reenable Link Events. Next we will process the PLOGI
2007 * list. 32 entries are processed initially and PLOGI is initited for each one.
2008 * Completions / Events for each node are funnelled thru the state machine. As
2009 * each node finishes PLOGI processing, it starts PLOGI for any nodes waiting
2010 * for PLOGI processing. If no nodes are waiting, and the PLOGI list count is
2011 * indentically 0, then we are done. We have now completed discovery / RSCN
2012 * handling. Upon completion, ALL nodes should be on either the mapped or
2013 * unmapped lists.
2014 */
2015
2016static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
James Smart2e0fef82007-06-17 19:56:36 -05002017 (struct lpfc_vport *, struct lpfc_nodelist *, void *, uint32_t) = {
dea31012005-04-17 16:05:31 -05002018 /* Action routine Event Current State */
2019 lpfc_rcv_plogi_unused_node, /* RCV_PLOGI UNUSED_NODE */
2020 lpfc_rcv_els_unused_node, /* RCV_PRLI */
2021 lpfc_rcv_logo_unused_node, /* RCV_LOGO */
2022 lpfc_rcv_els_unused_node, /* RCV_ADISC */
2023 lpfc_rcv_els_unused_node, /* RCV_PDISC */
2024 lpfc_rcv_els_unused_node, /* RCV_PRLO */
2025 lpfc_disc_illegal, /* CMPL_PLOGI */
2026 lpfc_disc_illegal, /* CMPL_PRLI */
2027 lpfc_cmpl_logo_unused_node, /* CMPL_LOGO */
2028 lpfc_disc_illegal, /* CMPL_ADISC */
2029 lpfc_disc_illegal, /* CMPL_REG_LOGIN */
2030 lpfc_device_rm_unused_node, /* DEVICE_RM */
2031 lpfc_disc_illegal, /* DEVICE_RECOVERY */
2032
2033 lpfc_rcv_plogi_plogi_issue, /* RCV_PLOGI PLOGI_ISSUE */
James Smart92d7f7b2007-06-17 19:56:38 -05002034 lpfc_rcv_prli_plogi_issue, /* RCV_PRLI */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002035 lpfc_rcv_logo_plogi_issue, /* RCV_LOGO */
dea31012005-04-17 16:05:31 -05002036 lpfc_rcv_els_plogi_issue, /* RCV_ADISC */
2037 lpfc_rcv_els_plogi_issue, /* RCV_PDISC */
2038 lpfc_rcv_els_plogi_issue, /* RCV_PRLO */
2039 lpfc_cmpl_plogi_plogi_issue, /* CMPL_PLOGI */
2040 lpfc_disc_illegal, /* CMPL_PRLI */
James Smart0ff10d42008-01-11 01:52:36 -05002041 lpfc_cmpl_logo_plogi_issue, /* CMPL_LOGO */
dea31012005-04-17 16:05:31 -05002042 lpfc_disc_illegal, /* CMPL_ADISC */
James Smart0ff10d42008-01-11 01:52:36 -05002043 lpfc_cmpl_reglogin_plogi_issue,/* CMPL_REG_LOGIN */
dea31012005-04-17 16:05:31 -05002044 lpfc_device_rm_plogi_issue, /* DEVICE_RM */
2045 lpfc_device_recov_plogi_issue, /* DEVICE_RECOVERY */
2046
2047 lpfc_rcv_plogi_adisc_issue, /* RCV_PLOGI ADISC_ISSUE */
2048 lpfc_rcv_prli_adisc_issue, /* RCV_PRLI */
2049 lpfc_rcv_logo_adisc_issue, /* RCV_LOGO */
2050 lpfc_rcv_padisc_adisc_issue, /* RCV_ADISC */
2051 lpfc_rcv_padisc_adisc_issue, /* RCV_PDISC */
2052 lpfc_rcv_prlo_adisc_issue, /* RCV_PRLO */
2053 lpfc_disc_illegal, /* CMPL_PLOGI */
2054 lpfc_disc_illegal, /* CMPL_PRLI */
2055 lpfc_disc_illegal, /* CMPL_LOGO */
2056 lpfc_cmpl_adisc_adisc_issue, /* CMPL_ADISC */
2057 lpfc_disc_illegal, /* CMPL_REG_LOGIN */
2058 lpfc_device_rm_adisc_issue, /* DEVICE_RM */
2059 lpfc_device_recov_adisc_issue, /* DEVICE_RECOVERY */
2060
2061 lpfc_rcv_plogi_reglogin_issue, /* RCV_PLOGI REG_LOGIN_ISSUE */
2062 lpfc_rcv_prli_reglogin_issue, /* RCV_PLOGI */
2063 lpfc_rcv_logo_reglogin_issue, /* RCV_LOGO */
2064 lpfc_rcv_padisc_reglogin_issue, /* RCV_ADISC */
2065 lpfc_rcv_padisc_reglogin_issue, /* RCV_PDISC */
2066 lpfc_rcv_prlo_reglogin_issue, /* RCV_PRLO */
James Smart87af33f2007-10-27 13:37:43 -04002067 lpfc_cmpl_plogi_illegal, /* CMPL_PLOGI */
dea31012005-04-17 16:05:31 -05002068 lpfc_disc_illegal, /* CMPL_PRLI */
2069 lpfc_disc_illegal, /* CMPL_LOGO */
2070 lpfc_disc_illegal, /* CMPL_ADISC */
2071 lpfc_cmpl_reglogin_reglogin_issue,/* CMPL_REG_LOGIN */
2072 lpfc_device_rm_reglogin_issue, /* DEVICE_RM */
2073 lpfc_device_recov_reglogin_issue,/* DEVICE_RECOVERY */
2074
2075 lpfc_rcv_plogi_prli_issue, /* RCV_PLOGI PRLI_ISSUE */
2076 lpfc_rcv_prli_prli_issue, /* RCV_PRLI */
2077 lpfc_rcv_logo_prli_issue, /* RCV_LOGO */
2078 lpfc_rcv_padisc_prli_issue, /* RCV_ADISC */
2079 lpfc_rcv_padisc_prli_issue, /* RCV_PDISC */
2080 lpfc_rcv_prlo_prli_issue, /* RCV_PRLO */
James Smart87af33f2007-10-27 13:37:43 -04002081 lpfc_cmpl_plogi_illegal, /* CMPL_PLOGI */
dea31012005-04-17 16:05:31 -05002082 lpfc_cmpl_prli_prli_issue, /* CMPL_PRLI */
2083 lpfc_disc_illegal, /* CMPL_LOGO */
2084 lpfc_disc_illegal, /* CMPL_ADISC */
2085 lpfc_disc_illegal, /* CMPL_REG_LOGIN */
2086 lpfc_device_rm_prli_issue, /* DEVICE_RM */
2087 lpfc_device_recov_prli_issue, /* DEVICE_RECOVERY */
2088
2089 lpfc_rcv_plogi_unmap_node, /* RCV_PLOGI UNMAPPED_NODE */
2090 lpfc_rcv_prli_unmap_node, /* RCV_PRLI */
2091 lpfc_rcv_logo_unmap_node, /* RCV_LOGO */
2092 lpfc_rcv_padisc_unmap_node, /* RCV_ADISC */
2093 lpfc_rcv_padisc_unmap_node, /* RCV_PDISC */
2094 lpfc_rcv_prlo_unmap_node, /* RCV_PRLO */
2095 lpfc_disc_illegal, /* CMPL_PLOGI */
2096 lpfc_disc_illegal, /* CMPL_PRLI */
2097 lpfc_disc_illegal, /* CMPL_LOGO */
2098 lpfc_disc_illegal, /* CMPL_ADISC */
2099 lpfc_disc_illegal, /* CMPL_REG_LOGIN */
2100 lpfc_disc_illegal, /* DEVICE_RM */
2101 lpfc_device_recov_unmap_node, /* DEVICE_RECOVERY */
2102
2103 lpfc_rcv_plogi_mapped_node, /* RCV_PLOGI MAPPED_NODE */
2104 lpfc_rcv_prli_mapped_node, /* RCV_PRLI */
2105 lpfc_rcv_logo_mapped_node, /* RCV_LOGO */
2106 lpfc_rcv_padisc_mapped_node, /* RCV_ADISC */
2107 lpfc_rcv_padisc_mapped_node, /* RCV_PDISC */
2108 lpfc_rcv_prlo_mapped_node, /* RCV_PRLO */
2109 lpfc_disc_illegal, /* CMPL_PLOGI */
2110 lpfc_disc_illegal, /* CMPL_PRLI */
2111 lpfc_disc_illegal, /* CMPL_LOGO */
2112 lpfc_disc_illegal, /* CMPL_ADISC */
2113 lpfc_disc_illegal, /* CMPL_REG_LOGIN */
2114 lpfc_disc_illegal, /* DEVICE_RM */
2115 lpfc_device_recov_mapped_node, /* DEVICE_RECOVERY */
2116
2117 lpfc_rcv_plogi_npr_node, /* RCV_PLOGI NPR_NODE */
2118 lpfc_rcv_prli_npr_node, /* RCV_PRLI */
2119 lpfc_rcv_logo_npr_node, /* RCV_LOGO */
2120 lpfc_rcv_padisc_npr_node, /* RCV_ADISC */
2121 lpfc_rcv_padisc_npr_node, /* RCV_PDISC */
2122 lpfc_rcv_prlo_npr_node, /* RCV_PRLO */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002123 lpfc_cmpl_plogi_npr_node, /* CMPL_PLOGI */
2124 lpfc_cmpl_prli_npr_node, /* CMPL_PRLI */
dea31012005-04-17 16:05:31 -05002125 lpfc_cmpl_logo_npr_node, /* CMPL_LOGO */
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002126 lpfc_cmpl_adisc_npr_node, /* CMPL_ADISC */
dea31012005-04-17 16:05:31 -05002127 lpfc_cmpl_reglogin_npr_node, /* CMPL_REG_LOGIN */
2128 lpfc_device_rm_npr_node, /* DEVICE_RM */
2129 lpfc_device_recov_npr_node, /* DEVICE_RECOVERY */
2130};
2131
2132int
James Smart2e0fef82007-06-17 19:56:36 -05002133lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
2134 void *arg, uint32_t evt)
dea31012005-04-17 16:05:31 -05002135{
2136 uint32_t cur_state, rc;
James Smart2e0fef82007-06-17 19:56:36 -05002137 uint32_t(*func) (struct lpfc_vport *, struct lpfc_nodelist *, void *,
dea31012005-04-17 16:05:31 -05002138 uint32_t);
James Smarte47c9092008-02-08 18:49:26 -05002139 uint32_t got_ndlp = 0;
dea31012005-04-17 16:05:31 -05002140
James Smarte47c9092008-02-08 18:49:26 -05002141 if (lpfc_nlp_get(ndlp))
2142 got_ndlp = 1;
2143
dea31012005-04-17 16:05:31 -05002144 cur_state = ndlp->nlp_state;
2145
2146 /* DSM in event <evt> on NPort <nlp_DID> in state <cur_state> */
James Smarte8b62012007-08-02 11:10:09 -04002147 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
2148 "0211 DSM in event x%x on NPort x%x in "
2149 "state %d Data: x%x\n",
2150 evt, ndlp->nlp_DID, cur_state, ndlp->nlp_flag);
dea31012005-04-17 16:05:31 -05002151
James Smart858c9f62007-06-17 19:56:39 -05002152 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM,
2153 "DSM in: evt:%d ste:%d did:x%x",
2154 evt, cur_state, ndlp->nlp_DID);
2155
dea31012005-04-17 16:05:31 -05002156 func = lpfc_disc_action[(cur_state * NLP_EVT_MAX_EVENT) + evt];
James Smart2e0fef82007-06-17 19:56:36 -05002157 rc = (func) (vport, ndlp, arg, evt);
dea31012005-04-17 16:05:31 -05002158
2159 /* DSM out state <rc> on NPort <nlp_DID> */
James Smarte47c9092008-02-08 18:49:26 -05002160 if (got_ndlp) {
2161 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
James Smarte8b62012007-08-02 11:10:09 -04002162 "0212 DSM out state %d on NPort x%x Data: x%x\n",
2163 rc, ndlp->nlp_DID, ndlp->nlp_flag);
dea31012005-04-17 16:05:31 -05002164
James Smarte47c9092008-02-08 18:49:26 -05002165 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM,
2166 "DSM out: ste:%d did:x%x flg:x%x",
2167 rc, ndlp->nlp_DID, ndlp->nlp_flag);
2168 /* Decrement the ndlp reference count held for this function */
2169 lpfc_nlp_put(ndlp);
2170 } else {
2171 lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
James Smartd7c255b2008-08-24 21:50:00 -04002172 "0213 DSM out state %d on NPort free\n", rc);
James Smart858c9f62007-06-17 19:56:39 -05002173
James Smarte47c9092008-02-08 18:49:26 -05002174 lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM,
2175 "DSM out: ste:%d did:x%x flg:x%x",
2176 rc, 0, 0);
2177 }
dea31012005-04-17 16:05:31 -05002178
Jamie Wellnitzc9f87352006-02-28 19:25:23 -05002179 return rc;
dea31012005-04-17 16:05:31 -05002180}