lpfc_nportdisc.c 68.4 KB
Newer Older
1
 /*******************************************************************
已提交
2
 * This file is part of the Emulex Linux Device Driver for         *
3
 * Fibre Channel Host Bus Adapters.                                *
4
 * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
5
 * EMULEX and SLI are trademarks of Emulex.                        *
已提交
6
 * www.emulex.com                                                  *
7
 * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
已提交
8 9
 *                                                                 *
 * This program is free software; you can redistribute it and/or   *
10 11 12 13 14 15 16 17 18 19
 * modify it under the terms of version 2 of the GNU General       *
 * Public License as published by the Free Software Foundation.    *
 * This program is distributed in the hope that it will be useful. *
 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
 * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
 * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
 * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
 * more details, a copy of which can be found in the file COPYING  *
 * included with this package.                                     *
已提交
20 21 22 23
 *******************************************************************/

#include <linux/blkdev.h>
#include <linux/pci.h>
24
#include <linux/slab.h>
已提交
25 26
#include <linux/interrupt.h>

27
#include <scsi/scsi.h>
已提交
28 29 30 31
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport_fc.h>

32
#include "lpfc_hw4.h"
已提交
33 34
#include "lpfc_hw.h"
#include "lpfc_sli.h"
35
#include "lpfc_sli4.h"
36
#include "lpfc_nl.h"
已提交
37 38 39 40 41
#include "lpfc_disc.h"
#include "lpfc_scsi.h"
#include "lpfc.h"
#include "lpfc_logmsg.h"
#include "lpfc_crtn.h"
42
#include "lpfc_vport.h"
J
James Smart 已提交
43
#include "lpfc_debugfs.h"
已提交
44 45 46 47


/* Called to verify a rcv'ed ADISC was intended for us. */
static int
J
James Smart 已提交
48 49
lpfc_check_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
		 struct lpfc_name *nn, struct lpfc_name *pn)
已提交
50 51 52 53
{
	/* Compare the ADISC rsp WWNN / WWPN matches our internal node
	 * table entry for that node.
	 */
J
James Smart 已提交
54
	if (memcmp(nn, &ndlp->nlp_nodename, sizeof (struct lpfc_name)))
55
		return 0;
已提交
56

J
James Smart 已提交
57
	if (memcmp(pn, &ndlp->nlp_portname, sizeof (struct lpfc_name)))
58
		return 0;
已提交
59 60

	/* we match, return success */
61
	return 1;
已提交
62 63 64
}

int
J
James Smart 已提交
65
lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
66
		 struct serv_parm *sp, uint32_t class, int flogi)
已提交
67
{
J
James Smart 已提交
68
	volatile struct serv_parm *hsp = &vport->fc_sparam;
69 70 71 72 73 74 75 76 77
	uint16_t hsp_value, ssp_value = 0;

	/*
	 * The receive data field size and buffer-to-buffer receive data field
	 * size entries are 16 bits but are represented as two 8-bit fields in
	 * the driver data structure to account for rsvd bits and other control
	 * bits.  Reconstruct and compare the fields as a 16-bit values before
	 * correcting the byte values.
	 */
已提交
78
	if (sp->cls1.classValid) {
79 80 81 82 83 84 85 86 87 88 89 90 91
		if (!flogi) {
			hsp_value = ((hsp->cls1.rcvDataSizeMsb << 8) |
				     hsp->cls1.rcvDataSizeLsb);
			ssp_value = ((sp->cls1.rcvDataSizeMsb << 8) |
				     sp->cls1.rcvDataSizeLsb);
			if (!ssp_value)
				goto bad_service_param;
			if (ssp_value > hsp_value) {
				sp->cls1.rcvDataSizeLsb =
					hsp->cls1.rcvDataSizeLsb;
				sp->cls1.rcvDataSizeMsb =
					hsp->cls1.rcvDataSizeMsb;
			}
92
		}
93
	} else if (class == CLASS1)
94
		goto bad_service_param;
已提交
95
	if (sp->cls2.classValid) {
96 97 98 99 100 101 102 103 104 105 106 107 108
		if (!flogi) {
			hsp_value = ((hsp->cls2.rcvDataSizeMsb << 8) |
				     hsp->cls2.rcvDataSizeLsb);
			ssp_value = ((sp->cls2.rcvDataSizeMsb << 8) |
				     sp->cls2.rcvDataSizeLsb);
			if (!ssp_value)
				goto bad_service_param;
			if (ssp_value > hsp_value) {
				sp->cls2.rcvDataSizeLsb =
					hsp->cls2.rcvDataSizeLsb;
				sp->cls2.rcvDataSizeMsb =
					hsp->cls2.rcvDataSizeMsb;
			}
109
		}
110
	} else if (class == CLASS2)
111
		goto bad_service_param;
已提交
112
	if (sp->cls3.classValid) {
113 114 115 116 117 118 119 120 121 122 123 124 125
		if (!flogi) {
			hsp_value = ((hsp->cls3.rcvDataSizeMsb << 8) |
				     hsp->cls3.rcvDataSizeLsb);
			ssp_value = ((sp->cls3.rcvDataSizeMsb << 8) |
				     sp->cls3.rcvDataSizeLsb);
			if (!ssp_value)
				goto bad_service_param;
			if (ssp_value > hsp_value) {
				sp->cls3.rcvDataSizeLsb =
					hsp->cls3.rcvDataSizeLsb;
				sp->cls3.rcvDataSizeMsb =
					hsp->cls3.rcvDataSizeMsb;
			}
126
		}
127
	} else if (class == CLASS3)
128
		goto bad_service_param;
已提交
129

130 131 132 133 134 135 136 137
	/*
	 * Preserve the upper four bits of the MSB from the PLOGI response.
	 * These bits contain the Buffer-to-Buffer State Change Number
	 * from the target and need to be passed to the FW.
	 */
	hsp_value = (hsp->cmn.bbRcvSizeMsb << 8) | hsp->cmn.bbRcvSizeLsb;
	ssp_value = (sp->cmn.bbRcvSizeMsb << 8) | sp->cmn.bbRcvSizeLsb;
	if (ssp_value > hsp_value) {
已提交
138
		sp->cmn.bbRcvSizeLsb = hsp->cmn.bbRcvSizeLsb;
139 140 141
		sp->cmn.bbRcvSizeMsb = (sp->cmn.bbRcvSizeMsb & 0xF0) |
				       (hsp->cmn.bbRcvSizeMsb & 0x0F);
	}
已提交
142 143 144

	memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof (struct lpfc_name));
	memcpy(&ndlp->nlp_portname, &sp->portName, sizeof (struct lpfc_name));
145
	return 1;
146
bad_service_param:
147 148 149 150 151 152 153 154 155
	lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
			 "0207 Device %x "
			 "(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x) sent "
			 "invalid service parameters.  Ignoring device.\n",
			 ndlp->nlp_DID,
			 sp->nodeName.u.wwn[0], sp->nodeName.u.wwn[1],
			 sp->nodeName.u.wwn[2], sp->nodeName.u.wwn[3],
			 sp->nodeName.u.wwn[4], sp->nodeName.u.wwn[5],
			 sp->nodeName.u.wwn[6], sp->nodeName.u.wwn[7]);
156
	return 0;
已提交
157 158 159
}

static void *
J
James Smart 已提交
160
lpfc_check_elscmpl_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
161
			struct lpfc_iocbq *rspiocb)
已提交
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
{
	struct lpfc_dmabuf *pcmd, *prsp;
	uint32_t *lp;
	void     *ptr = NULL;
	IOCB_t   *irsp;

	irsp = &rspiocb->iocb;
	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;

	/* For lpfc_els_abort, context2 could be zero'ed to delay
	 * freeing associated memory till after ABTS completes.
	 */
	if (pcmd) {
		prsp =  list_get_first(&pcmd->list, struct lpfc_dmabuf,
				       list);
		if (prsp) {
			lp = (uint32_t *) prsp->virt;
			ptr = (void *)((uint8_t *)lp + sizeof(uint32_t));
		}
181
	} else {
已提交
182 183 184 185 186 187 188
		/* Force ulpStatus error since we are returning NULL ptr */
		if (!(irsp->ulpStatus)) {
			irsp->ulpStatus = IOSTAT_LOCAL_REJECT;
			irsp->un.ulpWord[4] = IOERR_SLI_ABORTED;
		}
		ptr = NULL;
	}
189
	return ptr;
已提交
190 191 192
}


193

已提交
194 195 196 197 198 199
/*
 * Free resources / clean up outstanding I/Os
 * associated with a LPFC_NODELIST entry. This
 * routine effectively results in a "software abort".
 */
int
J
James Smart 已提交
200
lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
已提交
201
{
202
	LIST_HEAD(completions);
203 204
	LIST_HEAD(txcmplq_completions);
	LIST_HEAD(abort_list);
J
James Smart 已提交
205 206
	struct lpfc_sli  *psli = &phba->sli;
	struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
已提交
207 208 209
	struct lpfc_iocbq *iocb, *next_iocb;

	/* Abort outstanding I/O on NPort <nlp_DID> */
210
	lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_DISCOVERY,
211
			 "2819 Abort outstanding I/O on NPort x%x "
212 213 214
			 "Data: x%x x%x x%x\n",
			 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
			 ndlp->nlp_rpi);
215 216

	lpfc_fabric_abort_nport(ndlp);
已提交
217 218

	/* First check the txq */
J
James Smart 已提交
219
	spin_lock_irq(&phba->hbalock);
220
	list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
J
James Smart 已提交
221
		/* Check to see if iocb matches the nport we are looking for */
222
		if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
J
James Smart 已提交
223
			/* It matches, so deque and call compl with anp error */
224 225
			list_move_tail(&iocb->list, &completions);
			pring->txq_cnt--;
已提交
226
		}
227
	}
已提交
228 229

	/* Next check the txcmplq */
230 231 232 233
	list_splice_init(&pring->txcmplq, &txcmplq_completions);
	spin_unlock_irq(&phba->hbalock);

	list_for_each_entry_safe(iocb, next_iocb, &txcmplq_completions, list) {
J
James Smart 已提交
234
		/* Check to see if iocb matches the nport we are looking for */
235 236
		if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))
			list_add_tail(&iocb->dlist, &abort_list);
237
	}
238 239
	spin_lock_irq(&phba->hbalock);
	list_splice(&txcmplq_completions, &pring->txcmplq);
J
James Smart 已提交
240
	spin_unlock_irq(&phba->hbalock);
已提交
241

242 243 244 245 246 247 248
	list_for_each_entry_safe(iocb, next_iocb, &abort_list, dlist) {
			spin_lock_irq(&phba->hbalock);
			list_del_init(&iocb->dlist);
			lpfc_sli_issue_abort_iotag(phba, pring, iocb);
			spin_unlock_irq(&phba->hbalock);
	}

249 250 251
	/* Cancel all the IOCBs from the completions list */
	lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
			      IOERR_SLI_ABORTED);
252

253
	lpfc_cancel_retry_delay_tmo(phba->pport, ndlp);
254
	return 0;
已提交
255 256 257
}

static int
J
James Smart 已提交
258
lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
259
	       struct lpfc_iocbq *cmdiocb)
已提交
260
{
J
James Smart 已提交
261 262
	struct Scsi_Host   *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba    *phba = vport->phba;
已提交
263 264 265 266 267 268 269 270 271
	struct lpfc_dmabuf *pcmd;
	uint32_t *lp;
	IOCB_t *icmd;
	struct serv_parm *sp;
	LPFC_MBOXQ_t *mbox;
	struct ls_rjt stat;
	int rc;

	memset(&stat, 0, sizeof (struct ls_rjt));
272
	if (vport->port_state <= LPFC_FDISC) {
已提交
273 274 275 276
		/* Before responding to PLOGI, check for pt2pt mode.
		 * If we are pt2pt, with an outstanding FLOGI, abort
		 * the FLOGI and resend it first.
		 */
J
James Smart 已提交
277
		if (vport->fc_flag & FC_PT2PT) {
278
			 lpfc_els_abort_flogi(phba);
J
James Smart 已提交
279
		        if (!(vport->fc_flag & FC_PT2PT_PLOGI)) {
已提交
280 281 282 283 284 285 286 287
				/* If the other side is supposed to initiate
				 * the PLOGI anyway, just ACC it now and
				 * move on with discovery.
				 */
				phba->fc_edtov = FF_DEF_EDTOV;
				phba->fc_ratov = FF_DEF_RATOV;
				/* Start discovery - this should just do
				   CLEAR_LA */
J
James Smart 已提交
288
				lpfc_disc_start(vport);
289
			} else
J
James Smart 已提交
290
				lpfc_initial_flogi(vport);
291
		} else {
已提交
292 293
			stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY;
			stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
J
James Smart 已提交
294
			lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
J
James Smart 已提交
295
					    ndlp, NULL);
已提交
296 297 298 299 300 301
			return 0;
		}
	}
	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
	lp = (uint32_t *) pcmd->virt;
	sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
	if (wwn_to_u64(sp->portName.u.wwn) == 0) {
		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
				 "0140 PLOGI Reject: invalid nname\n");
		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
		stat.un.b.lsRjtRsnCodeExp = LSEXP_INVALID_PNAME;
		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
			NULL);
		return 0;
	}
	if (wwn_to_u64(sp->nodeName.u.wwn) == 0) {
		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
				 "0141 PLOGI Reject: invalid pname\n");
		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
		stat.un.b.lsRjtRsnCodeExp = LSEXP_INVALID_NNAME;
		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
			NULL);
		return 0;
	}
320
	if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 0) == 0)) {
已提交
321 322 323
		/* Reject this request because invalid parameters */
		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
		stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
J
James Smart 已提交
324 325
		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
			NULL);
326
		return 0;
已提交
327 328 329 330
	}
	icmd = &cmdiocb->iocb;

	/* PLOGI chkparm OK */
331 332 333 334
	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
			 "0114 PLOGI chkparm OK Data: x%x x%x x%x x%x\n",
			 ndlp->nlp_DID, ndlp->nlp_state, ndlp->nlp_flag,
			 ndlp->nlp_rpi);
已提交
335

336
	if (vport->cfg_fcp_class == 2 && sp->cls2.classValid)
已提交
337
		ndlp->nlp_fcp_info |= CLASS2;
338
	else
已提交
339
		ndlp->nlp_fcp_info |= CLASS3;
J
James Smart 已提交
340

已提交
341 342 343 344 345 346 347 348 349 350 351 352
	ndlp->nlp_class_sup = 0;
	if (sp->cls1.classValid)
		ndlp->nlp_class_sup |= FC_COS_CLASS1;
	if (sp->cls2.classValid)
		ndlp->nlp_class_sup |= FC_COS_CLASS2;
	if (sp->cls3.classValid)
		ndlp->nlp_class_sup |= FC_COS_CLASS3;
	if (sp->cls4.classValid)
		ndlp->nlp_class_sup |= FC_COS_CLASS4;
	ndlp->nlp_maxframe =
		((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb;

353 354 355 356 357
	/*
	 * Need to unreg_login if we are already in one of these states and
	 * change to NPR state. This will block the port until after the ACC
	 * completes and the reg_login is issued and completed.
	 */
358
	switch (ndlp->nlp_state) {
已提交
359 360 361 362 363 364 365
	case  NLP_STE_NPR_NODE:
		if (!(ndlp->nlp_flag & NLP_NPR_ADISC))
			break;
	case  NLP_STE_REG_LOGIN_ISSUE:
	case  NLP_STE_PRLI_ISSUE:
	case  NLP_STE_UNMAPPED_NODE:
	case  NLP_STE_MAPPED_NODE:
366 367 368
		lpfc_unreg_rpi(vport, ndlp);
		ndlp->nlp_prev_state = ndlp->nlp_state;
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
已提交
369 370
	}

371 372
	if ((vport->fc_flag & FC_PT2PT) &&
	    !(vport->fc_flag & FC_PT2PT_PLOGI)) {
已提交
373
		/* rcv'ed PLOGI decides what our NPortId will be */
J
James Smart 已提交
374
		vport->fc_myDID = icmd->un.rcvels.parmRo;
已提交
375 376 377 378 379
		mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
		if (mbox == NULL)
			goto out;
		lpfc_config_link(phba, mbox);
		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
380
		mbox->vport = vport;
381
		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
已提交
382
		if (rc == MBX_NOT_FINISHED) {
383
			mempool_free(mbox, phba->mbox_mem_pool);
已提交
384 385 386
			goto out;
		}

J
James Smart 已提交
387
		lpfc_can_disctmo(vport);
已提交
388 389
	}
	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
J
James Smart 已提交
390
	if (!mbox)
已提交
391 392
		goto out;

393
	rc = lpfc_reg_rpi(phba, vport->vpi, icmd->un.rcvels.remoteID,
394
			    (uint8_t *) sp, mbox, ndlp->nlp_rpi);
J
James Smart 已提交
395 396
	if (rc) {
		mempool_free(mbox, phba->mbox_mem_pool);
已提交
397 398 399 400 401 402 403
		goto out;
	}

	/* ACC PLOGI rsp command needs to execute first,
	 * queue this mbox command to be processed later.
	 */
	mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
404 405 406 407
	/*
	 * mbox->context2 = lpfc_nlp_get(ndlp) deferred until mailbox
	 * command issued in lpfc_cmpl_els_acc().
	 */
J
James Smart 已提交
408 409
	mbox->vport = vport;
	spin_lock_irq(shost->host_lock);
410
	ndlp->nlp_flag |= (NLP_ACC_REGLOGIN | NLP_RCV_PLOGI);
J
James Smart 已提交
411
	spin_unlock_irq(shost->host_lock);
已提交
412

J
James Smart 已提交
413 414 415 416 417 418 419 420 421 422 423
	/*
	 * If there is an outstanding PLOGI issued, abort it before
	 * sending ACC rsp for received PLOGI. If pending plogi
	 * is not canceled here, the plogi will be rejected by
	 * remote port and will be retried. On a configuration with
	 * single discovery thread, this will cause a huge delay in
	 * discovery. Also this will cause multiple state machines
	 * running in parallel for this node.
	 */
	if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) {
		/* software abort outstanding PLOGI */
424
		lpfc_els_abort(phba, ndlp);
J
James Smart 已提交
425 426
	}

J
James Smart 已提交
427
	if ((vport->port_type == LPFC_NPIV_PORT &&
428
	     vport->cfg_restrict_login)) {
J
James Smart 已提交
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443

		/* In order to preserve RPIs, we want to cleanup
		 * the default RPI the firmware created to rcv
		 * this ELS request. The only way to do this is
		 * to register, then unregister the RPI.
		 */
		spin_lock_irq(shost->host_lock);
		ndlp->nlp_flag |= NLP_RM_DFLT_RPI;
		spin_unlock_irq(shost->host_lock);
		stat.un.b.lsRjtRsnCode = LSRJT_INVALID_CMD;
		stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
			ndlp, mbox);
		return 1;
	}
444
	lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox);
445
	return 1;
已提交
446 447 448
out:
	stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
	stat.un.b.lsRjtRsnCodeExp = LSEXP_OUT_OF_RESOURCE;
J
James Smart 已提交
449
	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
450
	return 0;
已提交
451 452 453
}

static int
J
James Smart 已提交
454
lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
已提交
455 456
		struct lpfc_iocbq *cmdiocb)
{
J
James Smart 已提交
457
	struct Scsi_Host   *shost = lpfc_shost_from_vport(vport);
已提交
458
	struct lpfc_dmabuf *pcmd;
J
James Smart 已提交
459 460
	struct serv_parm   *sp;
	struct lpfc_name   *pnn, *ppn;
已提交
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481
	struct ls_rjt stat;
	ADISC *ap;
	IOCB_t *icmd;
	uint32_t *lp;
	uint32_t cmd;

	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
	lp = (uint32_t *) pcmd->virt;

	cmd = *lp++;
	if (cmd == ELS_CMD_ADISC) {
		ap = (ADISC *) lp;
		pnn = (struct lpfc_name *) & ap->nodeName;
		ppn = (struct lpfc_name *) & ap->portName;
	} else {
		sp = (struct serv_parm *) lp;
		pnn = (struct lpfc_name *) & sp->nodeName;
		ppn = (struct lpfc_name *) & sp->portName;
	}

	icmd = &cmdiocb->iocb;
J
James Smart 已提交
482
	if (icmd->ulpStatus == 0 && lpfc_check_adisc(vport, ndlp, pnn, ppn)) {
已提交
483
		if (cmd == ELS_CMD_ADISC) {
J
James Smart 已提交
484
			lpfc_els_rsp_adisc_acc(vport, cmdiocb, ndlp);
485
		} else {
J
James Smart 已提交
486
			lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp,
487
					 NULL);
已提交
488
		}
489
		return 1;
已提交
490 491 492 493 494 495
	}
	/* Reject this request because invalid parameters */
	stat.un.b.lsRjtRsvd0 = 0;
	stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
	stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
	stat.un.b.vendorUnique = 0;
J
James Smart 已提交
496
	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
已提交
497 498 499 500

	/* 1 sec timeout */
	mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);

J
James Smart 已提交
501
	spin_lock_irq(shost->host_lock);
已提交
502
	ndlp->nlp_flag |= NLP_DELAY_TMO;
J
James Smart 已提交
503
	spin_unlock_irq(shost->host_lock);
504 505
	ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
	ndlp->nlp_prev_state = ndlp->nlp_state;
J
James Smart 已提交
506
	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
507
	return 0;
已提交
508 509 510
}

static int
J
James Smart 已提交
511 512
lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
	      struct lpfc_iocbq *cmdiocb, uint32_t els_cmd)
已提交
513
{
J
James Smart 已提交
514
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
J
James Smart 已提交
515 516 517
	struct lpfc_hba    *phba = vport->phba;
	struct lpfc_vport **vports;
	int i, active_vlink_present = 0 ;
J
James Smart 已提交
518 519

	/* Put ndlp in NPR state with 1 sec timeout for plogi, ACC logo */
已提交
520 521 522
	/* Only call LOGO ACC for first LOGO, this avoids sending unnecessary
	 * PLOGIs during LOGO storms from a device.
	 */
J
James Smart 已提交
523
	spin_lock_irq(shost->host_lock);
已提交
524
	ndlp->nlp_flag |= NLP_LOGO_ACC;
J
James Smart 已提交
525
	spin_unlock_irq(shost->host_lock);
526
	if (els_cmd == ELS_CMD_PRLO)
527
		lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
528
	else
529
		lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
J
James Smart 已提交
530 531 532
	if (ndlp->nlp_DID == Fabric_DID) {
		if (vport->port_state <= LPFC_FDISC)
			goto out;
533 534
		lpfc_linkdown_port(vport);
		spin_lock_irq(shost->host_lock);
J
James Smart 已提交
535
		vport->fc_flag |= FC_VPORT_LOGO_RCVD;
536
		spin_unlock_irq(shost->host_lock);
J
James Smart 已提交
537 538 539 540 541 542 543 544 545 546 547 548 549
		vports = lpfc_create_vport_work_array(phba);
		if (vports) {
			for (i = 0; i <= phba->max_vports && vports[i] != NULL;
					i++) {
				if ((!(vports[i]->fc_flag &
					FC_VPORT_LOGO_RCVD)) &&
					(vports[i]->port_state > LPFC_FDISC)) {
					active_vlink_present = 1;
					break;
				}
			}
			lpfc_destroy_vport_work_array(phba, vports);
		}
已提交
550

J
James Smart 已提交
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567
		if (active_vlink_present) {
			/*
			 * If there are other active VLinks present,
			 * re-instantiate the Vlink using FDISC.
			 */
			mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
			spin_lock_irq(shost->host_lock);
			ndlp->nlp_flag |= NLP_DELAY_TMO;
			spin_unlock_irq(shost->host_lock);
			ndlp->nlp_last_elscmd = ELS_CMD_FDISC;
			vport->port_state = LPFC_FDISC;
		} else {
			spin_lock_irq(shost->host_lock);
			phba->pport->fc_flag &= ~FC_LOGO_RCVD_DID_CHNG;
			spin_unlock_irq(shost->host_lock);
			lpfc_retry_pport_discovery(phba);
		}
568 569 570 571
	} else if ((!(ndlp->nlp_type & NLP_FABRIC) &&
		((ndlp->nlp_type & NLP_FCP_TARGET) ||
		!(ndlp->nlp_type & NLP_FCP_INITIATOR))) ||
		(ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) {
已提交
572 573
		/* Only try to re-login if this is NOT a Fabric Node */
		mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
J
James Smart 已提交
574
		spin_lock_irq(shost->host_lock);
已提交
575
		ndlp->nlp_flag |= NLP_DELAY_TMO;
J
James Smart 已提交
576
		spin_unlock_irq(shost->host_lock);
已提交
577

578
		ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
579
	}
J
James Smart 已提交
580
out:
581 582
	ndlp->nlp_prev_state = ndlp->nlp_state;
	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
已提交
583

J
James Smart 已提交
584
	spin_lock_irq(shost->host_lock);
已提交
585
	ndlp->nlp_flag &= ~NLP_NPR_ADISC;
J
James Smart 已提交
586
	spin_unlock_irq(shost->host_lock);
已提交
587 588 589 590 591
	/* The driver has to wait until the ACC completes before it continues
	 * processing the LOGO.  The action will resume in
	 * lpfc_cmpl_els_logo_acc routine. Since part of processing includes an
	 * unreg_login, the driver waits so the ACC does not get aborted.
	 */
592
	return 0;
已提交
593 594 595
}

static void
J
James Smart 已提交
596 597
lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
	      struct lpfc_iocbq *cmdiocb)
已提交
598 599 600 601 602 603 604 605 606 607 608 609 610
{
	struct lpfc_dmabuf *pcmd;
	uint32_t *lp;
	PRLI *npr;
	struct fc_rport *rport = ndlp->rport;
	u32 roles;

	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
	lp = (uint32_t *) pcmd->virt;
	npr = (PRLI *) ((uint8_t *) lp + sizeof (uint32_t));

	ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
	ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
611
	if (npr->prliType == PRLI_FCP_TYPE) {
已提交
612 613 614 615 616 617 618 619 620 621 622 623 624 625
		if (npr->initiatorFunc)
			ndlp->nlp_type |= NLP_FCP_INITIATOR;
		if (npr->targetFunc)
			ndlp->nlp_type |= NLP_FCP_TARGET;
		if (npr->Retry)
			ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE;
	}
	if (rport) {
		/* We need to update the rport role values */
		roles = FC_RPORT_ROLE_UNKNOWN;
		if (ndlp->nlp_type & NLP_FCP_INITIATOR)
			roles |= FC_RPORT_ROLE_FCP_INITIATOR;
		if (ndlp->nlp_type & NLP_FCP_TARGET)
			roles |= FC_RPORT_ROLE_FCP_TARGET;
J
James Smart 已提交
626 627 628 629 630

		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
			"rport rolechg:   role:x%x did:x%x flg:x%x",
			roles, ndlp->nlp_DID, ndlp->nlp_flag);

已提交
631 632 633 634 635
		fc_remote_port_rolechg(rport, roles);
	}
}

static uint32_t
J
James Smart 已提交
636
lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
已提交
637
{
J
James Smart 已提交
638 639
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

640
	if (!(ndlp->nlp_flag & NLP_RPI_REGISTERED)) {
641 642 643 644
		ndlp->nlp_flag &= ~NLP_NPR_ADISC;
		return 0;
	}

645 646 647
	if (!(vport->fc_flag & FC_PT2PT)) {
		/* Check config parameter use-adisc or FCP-2 */
		if ((vport->cfg_use_adisc && (vport->fc_flag & FC_RSCN_MODE)) ||
648 649
		    ((ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) &&
		     (ndlp->nlp_type & NLP_FCP_TARGET))) {
650 651 652 653 654
			spin_lock_irq(shost->host_lock);
			ndlp->nlp_flag |= NLP_NPR_ADISC;
			spin_unlock_irq(shost->host_lock);
			return 1;
		}
655 656 657 658
	}
	ndlp->nlp_flag &= ~NLP_NPR_ADISC;
	lpfc_unreg_rpi(vport, ndlp);
	return 0;
已提交
659
}
660
/**
L
Lucas De Marchi 已提交
661
 * lpfc_release_rpi - Release a RPI by issuing unreg_login mailbox cmd.
662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689
 * @phba : Pointer to lpfc_hba structure.
 * @vport: Pointer to lpfc_vport structure.
 * @rpi  : rpi to be release.
 *
 * This function will send a unreg_login mailbox command to the firmware
 * to release a rpi.
 **/
void
lpfc_release_rpi(struct lpfc_hba *phba,
		struct lpfc_vport *vport,
		uint16_t rpi)
{
	LPFC_MBOXQ_t *pmb;
	int rc;

	pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
			GFP_KERNEL);
	if (!pmb)
		lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
			"2796 mailbox memory allocation failed \n");
	else {
		lpfc_unreg_login(phba, vport->vpi, rpi, pmb);
		pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
		rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
		if (rc == MBX_NOT_FINISHED)
			mempool_free(pmb, phba->mbox_mem_pool);
	}
}
已提交
690 691

static uint32_t
J
James Smart 已提交
692 693
lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
		  void *arg, uint32_t evt)
已提交
694
{
695 696 697 698 699 700 701 702 703 704 705 706 707 708
	struct lpfc_hba *phba;
	LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
	MAILBOX_t *mb;
	uint16_t rpi;

	phba = vport->phba;
	/* Release the RPI if reglogin completing */
	if (!(phba->pport->load_flag & FC_UNLOADING) &&
		(evt == NLP_EVT_CMPL_REG_LOGIN) &&
		(!pmb->u.mb.mbxStatus)) {
		mb = &pmb->u.mb;
		rpi = pmb->u.mb.un.varWords[0];
		lpfc_release_rpi(phba, vport, rpi);
	}
709
	lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
710
			 "0271 Illegal State Transition: node x%x "
711 712 713
			 "event x%x, state x%x Data: x%x x%x\n",
			 ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi,
			 ndlp->nlp_flag);
714
	return ndlp->nlp_state;
已提交
715 716
}

717 718 719 720 721 722 723 724 725 726 727
static uint32_t
lpfc_cmpl_plogi_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
		  void *arg, uint32_t evt)
{
	/* This transition is only legal if we previously
	 * rcv'ed a PLOGI. Since we don't want 2 discovery threads
	 * working on the same NPortID, do nothing for this thread
	 * to stop it.
	 */
	if (!(ndlp->nlp_flag & NLP_RCV_PLOGI)) {
		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
728
			 "0272 Illegal State Transition: node x%x "
729 730 731 732 733 734 735
			 "event x%x, state x%x Data: x%x x%x\n",
			 ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi,
			 ndlp->nlp_flag);
	}
	return ndlp->nlp_state;
}

已提交
736 737 738
/* Start of Discovery State Machine routines */

static uint32_t
J
James Smart 已提交
739 740
lpfc_rcv_plogi_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			   void *arg, uint32_t evt)
已提交
741 742 743 744 745
{
	struct lpfc_iocbq *cmdiocb;

	cmdiocb = (struct lpfc_iocbq *) arg;

J
James Smart 已提交
746
	if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) {
747
		return ndlp->nlp_state;
已提交
748
	}
749
	return NLP_STE_FREED_NODE;
已提交
750 751 752
}

static uint32_t
J
James Smart 已提交
753 754
lpfc_rcv_els_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			 void *arg, uint32_t evt)
已提交
755
{
J
James Smart 已提交
756
	lpfc_issue_els_logo(vport, ndlp, 0);
757
	return ndlp->nlp_state;
已提交
758 759 760
}

static uint32_t
J
James Smart 已提交
761 762
lpfc_rcv_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
已提交
763
{
J
James Smart 已提交
764 765
	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
766

J
James Smart 已提交
767
	spin_lock_irq(shost->host_lock);
已提交
768
	ndlp->nlp_flag |= NLP_LOGO_ACC;
J
James Smart 已提交
769
	spin_unlock_irq(shost->host_lock);
770
	lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
已提交
771

772
	return ndlp->nlp_state;
已提交
773 774 775
}

static uint32_t
J
James Smart 已提交
776 777
lpfc_cmpl_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			   void *arg, uint32_t evt)
已提交
778
{
779
	return NLP_STE_FREED_NODE;
已提交
780 781 782
}

static uint32_t
J
James Smart 已提交
783 784
lpfc_device_rm_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			   void *arg, uint32_t evt)
已提交
785
{
786
	return NLP_STE_FREED_NODE;
已提交
787 788 789
}

static uint32_t
J
James Smart 已提交
790
lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
已提交
791 792
			   void *arg, uint32_t evt)
{
793
	struct Scsi_Host   *shost = lpfc_shost_from_vport(vport);
J
James Smart 已提交
794
	struct lpfc_hba   *phba = vport->phba;
已提交
795
	struct lpfc_iocbq *cmdiocb = arg;
J
James Smart 已提交
796 797 798
	struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
	uint32_t *lp = (uint32_t *) pcmd->virt;
	struct serv_parm *sp = (struct serv_parm *) (lp + 1);
已提交
799 800 801 802 803 804 805 806 807
	struct ls_rjt stat;
	int port_cmp;

	memset(&stat, 0, sizeof (struct ls_rjt));

	/* For a PLOGI, we only accept if our portname is less
	 * than the remote portname.
	 */
	phba->fc_stat.elsLogiCol++;
J
James Smart 已提交
808
	port_cmp = memcmp(&vport->fc_portname, &sp->portName,
809
			  sizeof(struct lpfc_name));
已提交
810 811 812 813 814 815

	if (port_cmp >= 0) {
		/* Reject this request because the remote node will accept
		   ours */
		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
		stat.un.b.lsRjtRsnCodeExp = LSEXP_CMD_IN_PROGRESS;
J
James Smart 已提交
816 817
		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
			NULL);
818
	} else {
819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834
		if (lpfc_rcv_plogi(vport, ndlp, cmdiocb) &&
		    (ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
		    (vport->num_disc_nodes)) {
			spin_lock_irq(shost->host_lock);
			ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
			spin_unlock_irq(shost->host_lock);
			/* Check if there are more PLOGIs to be sent */
			lpfc_more_plogi(vport);
			if (vport->num_disc_nodes == 0) {
				spin_lock_irq(shost->host_lock);
				vport->fc_flag &= ~FC_NDISC_ACTIVE;
				spin_unlock_irq(shost->host_lock);
				lpfc_can_disctmo(vport);
				lpfc_end_rscn(vport);
			}
		}
J
James Smart 已提交
835
	} /* If our portname was less */
已提交
836

837 838 839
	return ndlp->nlp_state;
}

840 841 842 843 844 845 846 847 848 849
static uint32_t
lpfc_rcv_prli_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
{
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
	struct ls_rjt     stat;

	memset(&stat, 0, sizeof (struct ls_rjt));
	stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY;
	stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
J
James Smart 已提交
850
	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
851 852 853
	return ndlp->nlp_state;
}

854
static uint32_t
J
James Smart 已提交
855 856
lpfc_rcv_logo_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
857
{
J
James Smart 已提交
858
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
859

860
				/* software abort outstanding PLOGI */
J
James Smart 已提交
861
	lpfc_els_abort(vport->phba, ndlp);
862

J
James Smart 已提交
863
	lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
864
	return ndlp->nlp_state;
已提交
865 866 867
}

static uint32_t
J
James Smart 已提交
868 869
lpfc_rcv_els_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			 void *arg, uint32_t evt)
已提交
870
{
J
James Smart 已提交
871 872 873
	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba   *phba = vport->phba;
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
874 875

	/* software abort outstanding PLOGI */
876
	lpfc_els_abort(phba, ndlp);
已提交
877 878

	if (evt == NLP_EVT_RCV_LOGO) {
879
		lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
880
	} else {
J
James Smart 已提交
881
		lpfc_issue_els_logo(vport, ndlp, 0);
已提交
882 883
	}

J
James Smart 已提交
884
	/* Put ndlp in npr state set plogi timer for 1 sec */
885
	mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
J
James Smart 已提交
886
	spin_lock_irq(shost->host_lock);
887
	ndlp->nlp_flag |= NLP_DELAY_TMO;
J
James Smart 已提交
888
	spin_unlock_irq(shost->host_lock);
889 890
	ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
	ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE;
J
James Smart 已提交
891
	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
已提交
892

893
	return ndlp->nlp_state;
已提交
894 895 896
}

static uint32_t
J
James Smart 已提交
897 898 899
lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
			    struct lpfc_nodelist *ndlp,
			    void *arg,
已提交
900 901
			    uint32_t evt)
{
J
James Smart 已提交
902
	struct lpfc_hba    *phba = vport->phba;
903
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
J
James Smart 已提交
904
	struct lpfc_iocbq  *cmdiocb, *rspiocb;
905
	struct lpfc_dmabuf *pcmd, *prsp, *mp;
已提交
906 907 908 909 910 911 912 913 914
	uint32_t *lp;
	IOCB_t *irsp;
	struct serv_parm *sp;
	LPFC_MBOXQ_t *mbox;

	cmdiocb = (struct lpfc_iocbq *) arg;
	rspiocb = cmdiocb->context_un.rsp_iocb;

	if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
915
		/* Recovery from PLOGI collision logic */
916
		return ndlp->nlp_state;
已提交
917 918 919 920 921 922 923 924 925
	}

	irsp = &rspiocb->iocb;

	if (irsp->ulpStatus)
		goto out;

	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;

J
James Smart 已提交
926
	prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list);
已提交
927

J
James Smart 已提交
928
	lp = (uint32_t *) prsp->virt;
已提交
929
	sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
930 931 932 933 934

	/* Some switches have FDMI servers returning 0 for WWN */
	if ((ndlp->nlp_DID != FDMI_DID) &&
		(wwn_to_u64(sp->portName.u.wwn) == 0 ||
		wwn_to_u64(sp->nodeName.u.wwn) == 0)) {
935 936 937 938
		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
				 "0142 PLOGI RSP: Invalid WWN.\n");
		goto out;
	}
939
	if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3, 0))
已提交
940 941
		goto out;
	/* PLOGI chkparm OK */
942 943 944 945
	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
			 "0121 PLOGI chkparm OK Data: x%x x%x x%x x%x\n",
			 ndlp->nlp_DID, ndlp->nlp_state,
			 ndlp->nlp_flag, ndlp->nlp_rpi);
946
	if (vport->cfg_fcp_class == 2 && (sp->cls2.classValid))
已提交
947
		ndlp->nlp_fcp_info |= CLASS2;
J
James Smart 已提交
948
	else
已提交
949
		ndlp->nlp_fcp_info |= CLASS3;
J
James Smart 已提交
950

已提交
951 952 953 954 955 956 957 958 959 960
	ndlp->nlp_class_sup = 0;
	if (sp->cls1.classValid)
		ndlp->nlp_class_sup |= FC_COS_CLASS1;
	if (sp->cls2.classValid)
		ndlp->nlp_class_sup |= FC_COS_CLASS2;
	if (sp->cls3.classValid)
		ndlp->nlp_class_sup |= FC_COS_CLASS3;
	if (sp->cls4.classValid)
		ndlp->nlp_class_sup |= FC_COS_CLASS4;
	ndlp->nlp_maxframe =
J
James Smart 已提交
961
		((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb;
已提交
962

J
James Smart 已提交
963
	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
964
	if (!mbox) {
965 966
		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
			"0133 PLOGI: no memory for reg_login "
967 968 969
			"Data: x%x x%x x%x x%x\n",
			ndlp->nlp_DID, ndlp->nlp_state,
			ndlp->nlp_flag, ndlp->nlp_rpi);
已提交
970
		goto out;
971
	}
已提交
972

J
James Smart 已提交
973 974
	lpfc_unreg_rpi(vport, ndlp);

975
	if (lpfc_reg_rpi(phba, vport->vpi, irsp->un.elsreq64.remoteID,
976
			 (uint8_t *) sp, mbox, ndlp->nlp_rpi) == 0) {
977
		switch (ndlp->nlp_DID) {
已提交
978
		case NameServer_DID:
979
			mbox->mbox_cmpl = lpfc_mbx_cmpl_ns_reg_login;
已提交
980 981
			break;
		case FDMI_DID:
982
			mbox->mbox_cmpl = lpfc_mbx_cmpl_fdmi_reg_login;
已提交
983 984
			break;
		default:
985
			ndlp->nlp_flag |= NLP_REG_LOGIN_SEND;
986
			mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
已提交
987
		}
988
		mbox->context2 = lpfc_nlp_get(ndlp);
J
James Smart 已提交
989
		mbox->vport = vport;
990
		if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
已提交
991
		    != MBX_NOT_FINISHED) {
J
James Smart 已提交
992 993
			lpfc_nlp_set_state(vport, ndlp,
					   NLP_STE_REG_LOGIN_ISSUE);
994
			return ndlp->nlp_state;
已提交
995
		}
996 997
		if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND)
			ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
998 999 1000
		/* decrement node reference count to the failed mbox
		 * command
		 */
1001
		lpfc_nlp_put(ndlp);
1002
		mp = (struct lpfc_dmabuf *) mbox->context1;
1003 1004
		lpfc_mbuf_free(phba, mp->virt, mp->phys);
		kfree(mp);
已提交
1005
		mempool_free(mbox, phba->mbox_mem_pool);
1006

1007 1008 1009 1010 1011
		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
				 "0134 PLOGI: cannot issue reg_login "
				 "Data: x%x x%x x%x x%x\n",
				 ndlp->nlp_DID, ndlp->nlp_state,
				 ndlp->nlp_flag, ndlp->nlp_rpi);
已提交
1012 1013
	} else {
		mempool_free(mbox, phba->mbox_mem_pool);
1014

1015 1016 1017 1018 1019
		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
				 "0135 PLOGI: cannot format reg_login "
				 "Data: x%x x%x x%x x%x\n",
				 ndlp->nlp_DID, ndlp->nlp_state,
				 ndlp->nlp_flag, ndlp->nlp_rpi);
已提交
1020 1021 1022
	}


1023 1024 1025
out:
	if (ndlp->nlp_DID == NameServer_DID) {
		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
1026 1027
		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
				 "0261 Cannot Register NameServer login\n");
1028 1029
	}

1030
	spin_lock_irq(shost->host_lock);
1031
	ndlp->nlp_flag |= NLP_DEFER_RM;
1032
	spin_unlock_irq(shost->host_lock);
1033
	return NLP_STE_FREED_NODE;
已提交
1034 1035
}

1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046
static uint32_t
lpfc_cmpl_logo_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			   void *arg, uint32_t evt)
{
	return ndlp->nlp_state;
}

static uint32_t
lpfc_cmpl_reglogin_plogi_issue(struct lpfc_vport *vport,
	struct lpfc_nodelist *ndlp, void *arg, uint32_t evt)
{
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058
	struct lpfc_hba *phba;
	LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
	MAILBOX_t *mb = &pmb->u.mb;
	uint16_t rpi;

	phba = vport->phba;
	/* Release the RPI */
	if (!(phba->pport->load_flag & FC_UNLOADING) &&
		!mb->mbxStatus) {
		rpi = pmb->u.mb.un.varWords[0];
		lpfc_release_rpi(phba, vport, rpi);
	}
1059 1060 1061
	return ndlp->nlp_state;
}

已提交
1062
static uint32_t
J
James Smart 已提交
1063 1064
lpfc_device_rm_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			   void *arg, uint32_t evt)
已提交
1065
{
J
James Smart 已提交
1066 1067 1068 1069
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

	if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
		spin_lock_irq(shost->host_lock);
1070
		ndlp->nlp_flag |= NLP_NODEV_REMOVE;
J
James Smart 已提交
1071
		spin_unlock_irq(shost->host_lock);
1072
		return ndlp->nlp_state;
J
James Smart 已提交
1073
	} else {
1074
		/* software abort outstanding PLOGI */
J
James Smart 已提交
1075
		lpfc_els_abort(vport->phba, ndlp);
已提交
1076

J
James Smart 已提交
1077
		lpfc_drop_node(vport, ndlp);
1078 1079
		return NLP_STE_FREED_NODE;
	}
已提交
1080 1081 1082
}

static uint32_t
J
James Smart 已提交
1083 1084 1085 1086
lpfc_device_recov_plogi_issue(struct lpfc_vport *vport,
			      struct lpfc_nodelist *ndlp,
			      void *arg,
			      uint32_t evt)
已提交
1087
{
J
James Smart 已提交
1088 1089 1090
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba  *phba = vport->phba;

1091 1092 1093 1094 1095 1096
	/* Don't do anything that will mess up processing of the
	 * previous RSCN.
	 */
	if (vport->fc_flag & FC_RSCN_DEFERRED)
		return ndlp->nlp_state;

已提交
1097
	/* software abort outstanding PLOGI */
1098
	lpfc_els_abort(phba, ndlp);
已提交
1099

1100
	ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE;
J
James Smart 已提交
1101
	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
1102
	spin_lock_irq(shost->host_lock);
1103
	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
J
James Smart 已提交
1104
	spin_unlock_irq(shost->host_lock);
已提交
1105

1106
	return ndlp->nlp_state;
已提交
1107 1108 1109
}

static uint32_t
J
James Smart 已提交
1110 1111
lpfc_rcv_plogi_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			   void *arg, uint32_t evt)
已提交
1112
{
1113
	struct Scsi_Host   *shost = lpfc_shost_from_vport(vport);
J
James Smart 已提交
1114
	struct lpfc_hba   *phba = vport->phba;
已提交
1115 1116 1117
	struct lpfc_iocbq *cmdiocb;

	/* software abort outstanding ADISC */
1118
	lpfc_els_abort(phba, ndlp);
已提交
1119 1120 1121

	cmdiocb = (struct lpfc_iocbq *) arg;

1122 1123 1124 1125 1126
	if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) {
		if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
			spin_lock_irq(shost->host_lock);
			ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
			spin_unlock_irq(shost->host_lock);
1127
			if (vport->num_disc_nodes)
1128 1129 1130 1131
				lpfc_more_adisc(vport);
		}
		return ndlp->nlp_state;
	}
1132
	ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
J
James Smart 已提交
1133 1134
	lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
	lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
已提交
1135

1136
	return ndlp->nlp_state;
已提交
1137 1138 1139
}

static uint32_t
J
James Smart 已提交
1140 1141
lpfc_rcv_prli_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
已提交
1142
{
J
James Smart 已提交
1143
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1144

J
James Smart 已提交
1145
	lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
1146
	return ndlp->nlp_state;
已提交
1147 1148 1149
}

static uint32_t
J
James Smart 已提交
1150 1151
lpfc_rcv_logo_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
已提交
1152
{
J
James Smart 已提交
1153
	struct lpfc_hba *phba = vport->phba;
已提交
1154 1155 1156 1157 1158
	struct lpfc_iocbq *cmdiocb;

	cmdiocb = (struct lpfc_iocbq *) arg;

	/* software abort outstanding ADISC */
1159
	lpfc_els_abort(phba, ndlp);
已提交
1160

J
James Smart 已提交
1161
	lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
1162
	return ndlp->nlp_state;
已提交
1163 1164 1165
}

static uint32_t
J
James Smart 已提交
1166 1167 1168
lpfc_rcv_padisc_adisc_issue(struct lpfc_vport *vport,
			    struct lpfc_nodelist *ndlp,
			    void *arg, uint32_t evt)
已提交
1169 1170 1171 1172 1173
{
	struct lpfc_iocbq *cmdiocb;

	cmdiocb = (struct lpfc_iocbq *) arg;

J
James Smart 已提交
1174
	lpfc_rcv_padisc(vport, ndlp, cmdiocb);
1175
	return ndlp->nlp_state;
已提交
1176 1177 1178
}

static uint32_t
J
James Smart 已提交
1179 1180
lpfc_rcv_prlo_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
已提交
1181 1182 1183 1184 1185 1186
{
	struct lpfc_iocbq *cmdiocb;

	cmdiocb = (struct lpfc_iocbq *) arg;

	/* Treat like rcv logo */
J
James Smart 已提交
1187
	lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_PRLO);
1188
	return ndlp->nlp_state;
已提交
1189 1190 1191
}

static uint32_t
J
James Smart 已提交
1192 1193 1194
lpfc_cmpl_adisc_adisc_issue(struct lpfc_vport *vport,
			    struct lpfc_nodelist *ndlp,
			    void *arg, uint32_t evt)
已提交
1195
{
J
James Smart 已提交
1196 1197
	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba   *phba = vport->phba;
已提交
1198 1199 1200
	struct lpfc_iocbq *cmdiocb, *rspiocb;
	IOCB_t *irsp;
	ADISC *ap;
1201
	int rc;
已提交
1202 1203 1204 1205 1206 1207 1208 1209

	cmdiocb = (struct lpfc_iocbq *) arg;
	rspiocb = cmdiocb->context_un.rsp_iocb;

	ap = (ADISC *)lpfc_check_elscmpl_iocb(phba, cmdiocb, rspiocb);
	irsp = &rspiocb->iocb;

	if ((irsp->ulpStatus) ||
1210
	    (!lpfc_check_adisc(vport, ndlp, &ap->nodeName, &ap->portName))) {
已提交
1211 1212
		/* 1 sec timeout */
		mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
J
James Smart 已提交
1213
		spin_lock_irq(shost->host_lock);
已提交
1214
		ndlp->nlp_flag |= NLP_DELAY_TMO;
J
James Smart 已提交
1215
		spin_unlock_irq(shost->host_lock);
1216
		ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
已提交
1217

J
James Smart 已提交
1218 1219
		memset(&ndlp->nlp_nodename, 0, sizeof(struct lpfc_name));
		memset(&ndlp->nlp_portname, 0, sizeof(struct lpfc_name));
已提交
1220

1221
		ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
J
James Smart 已提交
1222 1223
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
		lpfc_unreg_rpi(vport, ndlp);
1224
		return ndlp->nlp_state;
已提交
1225
	}
1226

1227 1228 1229 1230 1231 1232 1233 1234 1235
	if (phba->sli_rev == LPFC_SLI_REV4) {
		rc = lpfc_sli4_resume_rpi(ndlp);
		if (rc) {
			/* Stay in state and retry. */
			ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
			return ndlp->nlp_state;
		}
	}

1236
	if (ndlp->nlp_type & NLP_FCP_TARGET) {
1237
		ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
J
James Smart 已提交
1238
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE);
1239
	} else {
1240
		ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
J
James Smart 已提交
1241
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
1242
	}
1243

1244
	return ndlp->nlp_state;
已提交
1245 1246 1247
}

static uint32_t
J
James Smart 已提交
1248 1249
lpfc_device_rm_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			   void *arg, uint32_t evt)
已提交
1250
{
J
James Smart 已提交
1251 1252 1253 1254
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

	if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
		spin_lock_irq(shost->host_lock);
1255
		ndlp->nlp_flag |= NLP_NODEV_REMOVE;
J
James Smart 已提交
1256
		spin_unlock_irq(shost->host_lock);
1257
		return ndlp->nlp_state;
J
James Smart 已提交
1258
	} else {
1259
		/* software abort outstanding ADISC */
J
James Smart 已提交
1260
		lpfc_els_abort(vport->phba, ndlp);
已提交
1261

J
James Smart 已提交
1262
		lpfc_drop_node(vport, ndlp);
1263 1264
		return NLP_STE_FREED_NODE;
	}
已提交
1265 1266 1267
}

static uint32_t
J
James Smart 已提交
1268 1269 1270 1271
lpfc_device_recov_adisc_issue(struct lpfc_vport *vport,
			      struct lpfc_nodelist *ndlp,
			      void *arg,
			      uint32_t evt)
已提交
1272
{
J
James Smart 已提交
1273 1274 1275
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba  *phba = vport->phba;

1276 1277 1278 1279 1280 1281
	/* Don't do anything that will mess up processing of the
	 * previous RSCN.
	 */
	if (vport->fc_flag & FC_RSCN_DEFERRED)
		return ndlp->nlp_state;

已提交
1282
	/* software abort outstanding ADISC */
1283
	lpfc_els_abort(phba, ndlp);
已提交
1284

1285
	ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
J
James Smart 已提交
1286 1287
	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
	spin_lock_irq(shost->host_lock);
1288
	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
J
James Smart 已提交
1289
	spin_unlock_irq(shost->host_lock);
1290
	lpfc_disc_set_adisc(vport, ndlp);
1291
	return ndlp->nlp_state;
已提交
1292 1293 1294
}

static uint32_t
J
James Smart 已提交
1295 1296 1297
lpfc_rcv_plogi_reglogin_issue(struct lpfc_vport *vport,
			      struct lpfc_nodelist *ndlp,
			      void *arg,
已提交
1298 1299
			      uint32_t evt)
{
J
James Smart 已提交
1300
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1301

J
James Smart 已提交
1302
	lpfc_rcv_plogi(vport, ndlp, cmdiocb);
1303
	return ndlp->nlp_state;
已提交
1304 1305 1306
}

static uint32_t
J
James Smart 已提交
1307 1308 1309
lpfc_rcv_prli_reglogin_issue(struct lpfc_vport *vport,
			     struct lpfc_nodelist *ndlp,
			     void *arg,
已提交
1310 1311
			     uint32_t evt)
{
J
James Smart 已提交
1312
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1313

J
James Smart 已提交
1314
	lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
1315
	return ndlp->nlp_state;
已提交
1316 1317 1318
}

static uint32_t
J
James Smart 已提交
1319 1320 1321
lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport,
			     struct lpfc_nodelist *ndlp,
			     void *arg,
已提交
1322 1323
			     uint32_t evt)
{
J
James Smart 已提交
1324 1325
	struct lpfc_hba   *phba = vport->phba;
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
1326 1327 1328
	LPFC_MBOXQ_t	  *mb;
	LPFC_MBOXQ_t	  *nextmb;
	struct lpfc_dmabuf *mp;
已提交
1329 1330 1331

	cmdiocb = (struct lpfc_iocbq *) arg;

1332 1333
	/* cleanup any ndlp on mbox q waiting for reglogin cmpl */
	if ((mb = phba->sli.mbox_active)) {
1334
		if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) &&
1335
		   (ndlp == (struct lpfc_nodelist *) mb->context2)) {
1336
			lpfc_nlp_put(ndlp);
1337 1338 1339 1340 1341
			mb->context2 = NULL;
			mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
		}
	}

J
James Smart 已提交
1342
	spin_lock_irq(&phba->hbalock);
1343
	list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
1344
		if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) &&
1345 1346 1347
		   (ndlp == (struct lpfc_nodelist *) mb->context2)) {
			mp = (struct lpfc_dmabuf *) (mb->context1);
			if (mp) {
1348
				__lpfc_mbuf_free(phba, mp->virt, mp->phys);
1349 1350
				kfree(mp);
			}
1351
			lpfc_nlp_put(ndlp);
1352
			list_del(&mb->list);
1353
			phba->sli.mboxq_cnt--;
1354 1355 1356
			mempool_free(mb, phba->mbox_mem_pool);
		}
	}
J
James Smart 已提交
1357
	spin_unlock_irq(&phba->hbalock);
1358

J
James Smart 已提交
1359
	lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
1360
	return ndlp->nlp_state;
已提交
1361 1362 1363
}

static uint32_t
J
James Smart 已提交
1364 1365 1366
lpfc_rcv_padisc_reglogin_issue(struct lpfc_vport *vport,
			       struct lpfc_nodelist *ndlp,
			       void *arg,
已提交
1367 1368
			       uint32_t evt)
{
J
James Smart 已提交
1369
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1370

J
James Smart 已提交
1371
	lpfc_rcv_padisc(vport, ndlp, cmdiocb);
1372
	return ndlp->nlp_state;
已提交
1373 1374 1375
}

static uint32_t
J
James Smart 已提交
1376 1377 1378
lpfc_rcv_prlo_reglogin_issue(struct lpfc_vport *vport,
			     struct lpfc_nodelist *ndlp,
			     void *arg,
已提交
1379 1380 1381 1382 1383
			     uint32_t evt)
{
	struct lpfc_iocbq *cmdiocb;

	cmdiocb = (struct lpfc_iocbq *) arg;
1384
	lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
1385
	return ndlp->nlp_state;
已提交
1386 1387 1388
}

static uint32_t
J
James Smart 已提交
1389 1390 1391 1392
lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport,
				  struct lpfc_nodelist *ndlp,
				  void *arg,
				  uint32_t evt)
已提交
1393
{
J
James Smart 已提交
1394 1395
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
1396
	MAILBOX_t *mb = &pmb->u.mb;
J
James Smart 已提交
1397
	uint32_t did  = mb->un.varWords[1];
已提交
1398 1399 1400

	if (mb->mbxStatus) {
		/* RegLogin failed */
1401 1402
		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
				"0246 RegLogin failed Data: x%x x%x x%x\n",
J
James Smart 已提交
1403
				did, mb->mbxStatus, vport->port_state);
1404 1405 1406 1407 1408
		/*
		 * If RegLogin failed due to lack of HBA resources do not
		 * retry discovery.
		 */
		if (mb->mbxStatus == MBXERR_RPI_FULL) {
1409 1410
			ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
			lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
1411 1412 1413
			return ndlp->nlp_state;
		}

J
James Smart 已提交
1414
		/* Put ndlp in npr state set plogi timer for 1 sec */
已提交
1415
		mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
J
James Smart 已提交
1416
		spin_lock_irq(shost->host_lock);
已提交
1417
		ndlp->nlp_flag |= NLP_DELAY_TMO;
J
James Smart 已提交
1418
		spin_unlock_irq(shost->host_lock);
1419
		ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
已提交
1420

J
James Smart 已提交
1421
		lpfc_issue_els_logo(vport, ndlp, 0);
1422
		ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
J
James Smart 已提交
1423
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
1424
		return ndlp->nlp_state;
已提交
1425 1426 1427
	}

	ndlp->nlp_rpi = mb->un.varWords[0];
1428
	ndlp->nlp_flag |= NLP_RPI_REGISTERED;
已提交
1429 1430 1431

	/* Only if we are not a fabric nport do we issue PRLI */
	if (!(ndlp->nlp_type & NLP_FABRIC)) {
1432
		ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
J
James Smart 已提交
1433 1434
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
		lpfc_issue_els_prli(vport, ndlp, 0);
已提交
1435
	} else {
1436
		ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
J
James Smart 已提交
1437
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
已提交
1438
	}
1439
	return ndlp->nlp_state;
已提交
1440 1441 1442
}

static uint32_t
J
James Smart 已提交
1443 1444 1445
lpfc_device_rm_reglogin_issue(struct lpfc_vport *vport,
			      struct lpfc_nodelist *ndlp,
			      void *arg,
已提交
1446 1447
			      uint32_t evt)
{
J
James Smart 已提交
1448 1449 1450 1451
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

	if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
		spin_lock_irq(shost->host_lock);
1452
		ndlp->nlp_flag |= NLP_NODEV_REMOVE;
J
James Smart 已提交
1453
		spin_unlock_irq(shost->host_lock);
1454
		return ndlp->nlp_state;
J
James Smart 已提交
1455 1456
	} else {
		lpfc_drop_node(vport, ndlp);
1457 1458
		return NLP_STE_FREED_NODE;
	}
已提交
1459 1460 1461
}

static uint32_t
J
James Smart 已提交
1462 1463 1464 1465
lpfc_device_recov_reglogin_issue(struct lpfc_vport *vport,
				 struct lpfc_nodelist *ndlp,
				 void *arg,
				 uint32_t evt)
已提交
1466
{
J
James Smart 已提交
1467 1468
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

1469 1470 1471 1472 1473 1474
	/* Don't do anything that will mess up processing of the
	 * previous RSCN.
	 */
	if (vport->fc_flag & FC_RSCN_DEFERRED)
		return ndlp->nlp_state;

1475
	ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
J
James Smart 已提交
1476 1477
	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
	spin_lock_irq(shost->host_lock);
1478
	ndlp->nlp_flag |= NLP_IGNR_REG_CMPL;
1479
	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
J
James Smart 已提交
1480
	spin_unlock_irq(shost->host_lock);
1481
	lpfc_disc_set_adisc(vport, ndlp);
1482
	return ndlp->nlp_state;
已提交
1483 1484 1485
}

static uint32_t
J
James Smart 已提交
1486 1487
lpfc_rcv_plogi_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
已提交
1488 1489 1490 1491 1492
{
	struct lpfc_iocbq *cmdiocb;

	cmdiocb = (struct lpfc_iocbq *) arg;

J
James Smart 已提交
1493
	lpfc_rcv_plogi(vport, ndlp, cmdiocb);
1494
	return ndlp->nlp_state;
已提交
1495 1496 1497
}

static uint32_t
J
James Smart 已提交
1498 1499
lpfc_rcv_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			 void *arg, uint32_t evt)
已提交
1500
{
J
James Smart 已提交
1501
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1502

J
James Smart 已提交
1503
	lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
1504
	return ndlp->nlp_state;
已提交
1505 1506 1507
}

static uint32_t
J
James Smart 已提交
1508 1509
lpfc_rcv_logo_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			 void *arg, uint32_t evt)
已提交
1510
{
J
James Smart 已提交
1511
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1512 1513

	/* Software abort outstanding PRLI before sending acc */
J
James Smart 已提交
1514
	lpfc_els_abort(vport->phba, ndlp);
已提交
1515

J
James Smart 已提交
1516
	lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
1517
	return ndlp->nlp_state;
已提交
1518 1519 1520
}

static uint32_t
J
James Smart 已提交
1521 1522
lpfc_rcv_padisc_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			   void *arg, uint32_t evt)
已提交
1523
{
J
James Smart 已提交
1524
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1525

J
James Smart 已提交
1526
	lpfc_rcv_padisc(vport, ndlp, cmdiocb);
1527
	return ndlp->nlp_state;
已提交
1528 1529 1530 1531 1532 1533 1534 1535
}

/* This routine is envoked when we rcv a PRLO request from a nport
 * we are logged into.  We should send back a PRLO rsp setting the
 * appropriate bits.
 * NEXT STATE = PRLI_ISSUE
 */
static uint32_t
J
James Smart 已提交
1536 1537
lpfc_rcv_prlo_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			 void *arg, uint32_t evt)
已提交
1538
{
J
James Smart 已提交
1539
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1540

1541
	lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
1542
	return ndlp->nlp_state;
已提交
1543 1544 1545
}

static uint32_t
J
James Smart 已提交
1546 1547
lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
已提交
1548
{
1549
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
已提交
1550
	struct lpfc_iocbq *cmdiocb, *rspiocb;
J
James Smart 已提交
1551
	struct lpfc_hba   *phba = vport->phba;
已提交
1552 1553 1554 1555 1556 1557 1558 1559 1560
	IOCB_t *irsp;
	PRLI *npr;

	cmdiocb = (struct lpfc_iocbq *) arg;
	rspiocb = cmdiocb->context_un.rsp_iocb;
	npr = (PRLI *)lpfc_check_elscmpl_iocb(phba, cmdiocb, rspiocb);

	irsp = &rspiocb->iocb;
	if (irsp->ulpStatus) {
J
James Smart 已提交
1561
		if ((vport->port_type == LPFC_NPIV_PORT) &&
1562
		    vport->cfg_restrict_login) {
J
James Smart 已提交
1563 1564
			goto out;
		}
1565
		ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
J
James Smart 已提交
1566
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
1567
		return ndlp->nlp_state;
已提交
1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581
	}

	/* Check out PRLI rsp */
	ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
	ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
	if ((npr->acceptRspCode == PRLI_REQ_EXECUTED) &&
	    (npr->prliType == PRLI_FCP_TYPE)) {
		if (npr->initiatorFunc)
			ndlp->nlp_type |= NLP_FCP_INITIATOR;
		if (npr->targetFunc)
			ndlp->nlp_type |= NLP_FCP_TARGET;
		if (npr->Retry)
			ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE;
	}
1582 1583
	if (!(ndlp->nlp_type & NLP_FCP_TARGET) &&
	    (vport->port_type == LPFC_NPIV_PORT) &&
1584
	     vport->cfg_restrict_login) {
J
James Smart 已提交
1585
out:
1586 1587 1588 1589 1590 1591
		spin_lock_irq(shost->host_lock);
		ndlp->nlp_flag |= NLP_TARGET_REMOVE;
		spin_unlock_irq(shost->host_lock);
		lpfc_issue_els_logo(vport, ndlp, 0);

		ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
1592
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
1593 1594
		return ndlp->nlp_state;
	}
已提交
1595

1596
	ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
1597 1598 1599 1600
	if (ndlp->nlp_type & NLP_FCP_TARGET)
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE);
	else
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
1601
	return ndlp->nlp_state;
已提交
1602 1603 1604
}

/*! lpfc_device_rm_prli_issue
1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621
 *
 * \pre
 * \post
 * \param   phba
 * \param   ndlp
 * \param   arg
 * \param   evt
 * \return  uint32_t
 *
 * \b Description:
 *    This routine is envoked when we a request to remove a nport we are in the
 *    process of PRLIing. We should software abort outstanding prli, unreg
 *    login, send a logout. We will change node state to UNUSED_NODE, put it
 *    on plogi list so it can be freed when LOGO completes.
 *
 */

已提交
1622
static uint32_t
J
James Smart 已提交
1623 1624
lpfc_device_rm_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
已提交
1625
{
J
James Smart 已提交
1626 1627 1628 1629
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

	if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
		spin_lock_irq(shost->host_lock);
1630
		ndlp->nlp_flag |= NLP_NODEV_REMOVE;
J
James Smart 已提交
1631
		spin_unlock_irq(shost->host_lock);
1632
		return ndlp->nlp_state;
J
James Smart 已提交
1633
	} else {
1634
		/* software abort outstanding PLOGI */
J
James Smart 已提交
1635
		lpfc_els_abort(vport->phba, ndlp);
已提交
1636

J
James Smart 已提交
1637
		lpfc_drop_node(vport, ndlp);
1638 1639
		return NLP_STE_FREED_NODE;
	}
已提交
1640 1641 1642 1643
}


/*! lpfc_device_recov_prli_issue
1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658
 *
 * \pre
 * \post
 * \param   phba
 * \param   ndlp
 * \param   arg
 * \param   evt
 * \return  uint32_t
 *
 * \b Description:
 *    The routine is envoked when the state of a device is unknown, like
 *    during a link down. We should remove the nodelist entry from the
 *    unmapped list, issue a UNREG_LOGIN, do a software abort of the
 *    outstanding PRLI command, then free the node entry.
 */
已提交
1659
static uint32_t
J
James Smart 已提交
1660 1661 1662 1663
lpfc_device_recov_prli_issue(struct lpfc_vport *vport,
			     struct lpfc_nodelist *ndlp,
			     void *arg,
			     uint32_t evt)
已提交
1664
{
J
James Smart 已提交
1665 1666 1667
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba  *phba = vport->phba;

1668 1669 1670 1671 1672 1673
	/* Don't do anything that will mess up processing of the
	 * previous RSCN.
	 */
	if (vport->fc_flag & FC_RSCN_DEFERRED)
		return ndlp->nlp_state;

已提交
1674
	/* software abort outstanding PRLI */
1675
	lpfc_els_abort(phba, ndlp);
已提交
1676

1677
	ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
J
James Smart 已提交
1678 1679
	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
	spin_lock_irq(shost->host_lock);
1680
	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
J
James Smart 已提交
1681
	spin_unlock_irq(shost->host_lock);
1682
	lpfc_disc_set_adisc(vport, ndlp);
1683
	return ndlp->nlp_state;
已提交
1684 1685 1686
}

static uint32_t
J
James Smart 已提交
1687 1688
lpfc_rcv_plogi_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
已提交
1689
{
J
James Smart 已提交
1690
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1691

J
James Smart 已提交
1692
	lpfc_rcv_plogi(vport, ndlp, cmdiocb);
1693
	return ndlp->nlp_state;
已提交
1694 1695 1696
}

static uint32_t
J
James Smart 已提交
1697 1698
lpfc_rcv_prli_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			 void *arg, uint32_t evt)
已提交
1699
{
J
James Smart 已提交
1700
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1701

J
James Smart 已提交
1702 1703
	lpfc_rcv_prli(vport, ndlp, cmdiocb);
	lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
1704
	return ndlp->nlp_state;
已提交
1705 1706 1707
}

static uint32_t
J
James Smart 已提交
1708 1709
lpfc_rcv_logo_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			 void *arg, uint32_t evt)
已提交
1710
{
J
James Smart 已提交
1711
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1712

J
James Smart 已提交
1713
	lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
1714
	return ndlp->nlp_state;
已提交
1715 1716 1717
}

static uint32_t
J
James Smart 已提交
1718 1719
lpfc_rcv_padisc_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			   void *arg, uint32_t evt)
已提交
1720
{
J
James Smart 已提交
1721
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1722

J
James Smart 已提交
1723
	lpfc_rcv_padisc(vport, ndlp, cmdiocb);
1724
	return ndlp->nlp_state;
已提交
1725 1726 1727
}

static uint32_t
J
James Smart 已提交
1728 1729
lpfc_rcv_prlo_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			 void *arg, uint32_t evt)
已提交
1730
{
J
James Smart 已提交
1731
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1732

1733
	lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
1734
	return ndlp->nlp_state;
已提交
1735 1736 1737
}

static uint32_t
J
James Smart 已提交
1738 1739 1740 1741
lpfc_device_recov_unmap_node(struct lpfc_vport *vport,
			     struct lpfc_nodelist *ndlp,
			     void *arg,
			     uint32_t evt)
已提交
1742
{
J
James Smart 已提交
1743 1744
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

1745
	ndlp->nlp_prev_state = NLP_STE_UNMAPPED_NODE;
J
James Smart 已提交
1746 1747
	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
	spin_lock_irq(shost->host_lock);
1748
	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
J
James Smart 已提交
1749 1750
	spin_unlock_irq(shost->host_lock);
	lpfc_disc_set_adisc(vport, ndlp);
已提交
1751

1752
	return ndlp->nlp_state;
已提交
1753 1754 1755
}

static uint32_t
J
James Smart 已提交
1756 1757
lpfc_rcv_plogi_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			   void *arg, uint32_t evt)
已提交
1758
{
J
James Smart 已提交
1759
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1760

J
James Smart 已提交
1761
	lpfc_rcv_plogi(vport, ndlp, cmdiocb);
1762
	return ndlp->nlp_state;
已提交
1763 1764 1765
}

static uint32_t
J
James Smart 已提交
1766 1767
lpfc_rcv_prli_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
已提交
1768
{
J
James Smart 已提交
1769
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1770

J
James Smart 已提交
1771
	lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
1772
	return ndlp->nlp_state;
已提交
1773 1774 1775
}

static uint32_t
J
James Smart 已提交
1776 1777
lpfc_rcv_logo_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
已提交
1778
{
J
James Smart 已提交
1779
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1780

J
James Smart 已提交
1781
	lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
1782
	return ndlp->nlp_state;
已提交
1783 1784 1785
}

static uint32_t
J
James Smart 已提交
1786 1787 1788
lpfc_rcv_padisc_mapped_node(struct lpfc_vport *vport,
			    struct lpfc_nodelist *ndlp,
			    void *arg, uint32_t evt)
已提交
1789
{
J
James Smart 已提交
1790
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1791

J
James Smart 已提交
1792
	lpfc_rcv_padisc(vport, ndlp, cmdiocb);
1793
	return ndlp->nlp_state;
已提交
1794 1795 1796
}

static uint32_t
J
James Smart 已提交
1797 1798
lpfc_rcv_prlo_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
已提交
1799
{
J
James Smart 已提交
1800 1801
	struct lpfc_hba  *phba = vport->phba;
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1802 1803

	/* flush the target */
1804 1805
	lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring],
			    ndlp->nlp_sid, 0, LPFC_CTX_TGT);
已提交
1806 1807

	/* Treat like rcv logo */
J
James Smart 已提交
1808
	lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_PRLO);
1809
	return ndlp->nlp_state;
已提交
1810 1811 1812
}

static uint32_t
J
James Smart 已提交
1813 1814 1815 1816
lpfc_device_recov_mapped_node(struct lpfc_vport *vport,
			      struct lpfc_nodelist *ndlp,
			      void *arg,
			      uint32_t evt)
已提交
1817
{
J
James Smart 已提交
1818 1819
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

1820
	ndlp->nlp_prev_state = NLP_STE_MAPPED_NODE;
J
James Smart 已提交
1821 1822
	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
	spin_lock_irq(shost->host_lock);
1823
	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
J
James Smart 已提交
1824 1825
	spin_unlock_irq(shost->host_lock);
	lpfc_disc_set_adisc(vport, ndlp);
1826
	return ndlp->nlp_state;
已提交
1827 1828 1829
}

static uint32_t
J
James Smart 已提交
1830 1831
lpfc_rcv_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			void *arg, uint32_t evt)
已提交
1832
{
J
James Smart 已提交
1833 1834
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	struct lpfc_iocbq *cmdiocb  = (struct lpfc_iocbq *) arg;
已提交
1835 1836

	/* Ignore PLOGI if we have an outstanding LOGO */
1837
	if (ndlp->nlp_flag & (NLP_LOGO_SND | NLP_LOGO_ACC))
1838
		return ndlp->nlp_state;
J
James Smart 已提交
1839
	if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) {
1840
		lpfc_cancel_retry_delay_tmo(vport, ndlp);
J
James Smart 已提交
1841
		spin_lock_irq(shost->host_lock);
1842
		ndlp->nlp_flag &= ~(NLP_NPR_ADISC | NLP_NPR_2B_DISC);
J
James Smart 已提交
1843
		spin_unlock_irq(shost->host_lock);
1844 1845 1846 1847 1848 1849 1850
	} else if (!(ndlp->nlp_flag & NLP_NPR_2B_DISC)) {
		/* send PLOGI immediately, move to PLOGI issue state */
		if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
			ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
			lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
			lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
		}
已提交
1851
	}
1852
	return ndlp->nlp_state;
已提交
1853 1854 1855
}

static uint32_t
J
James Smart 已提交
1856 1857
lpfc_rcv_prli_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
		       void *arg, uint32_t evt)
已提交
1858
{
J
James Smart 已提交
1859 1860 1861
	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
	struct ls_rjt     stat;
已提交
1862 1863 1864 1865

	memset(&stat, 0, sizeof (struct ls_rjt));
	stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
	stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
J
James Smart 已提交
1866
	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
已提交
1867 1868 1869

	if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
		if (ndlp->nlp_flag & NLP_NPR_ADISC) {
J
James Smart 已提交
1870
			spin_lock_irq(shost->host_lock);
1871
			ndlp->nlp_flag &= ~NLP_NPR_ADISC;
1872
			ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
J
James Smart 已提交
1873 1874 1875
			spin_unlock_irq(shost->host_lock);
			lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
			lpfc_issue_els_adisc(vport, ndlp, 0);
已提交
1876
		} else {
1877
			ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
J
James Smart 已提交
1878 1879
			lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
			lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
已提交
1880 1881
		}
	}
1882
	return ndlp->nlp_state;
已提交
1883 1884 1885
}

static uint32_t
J
James Smart 已提交
1886 1887
lpfc_rcv_logo_npr_node(struct lpfc_vport *vport,  struct lpfc_nodelist *ndlp,
		       void *arg, uint32_t evt)
已提交
1888
{
J
James Smart 已提交
1889
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1890

J
James Smart 已提交
1891
	lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
1892
	return ndlp->nlp_state;
已提交
1893 1894 1895
}

static uint32_t
J
James Smart 已提交
1896 1897
lpfc_rcv_padisc_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			 void *arg, uint32_t evt)
已提交
1898
{
J
James Smart 已提交
1899
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1900

J
James Smart 已提交
1901
	lpfc_rcv_padisc(vport, ndlp, cmdiocb);
J
James Smart 已提交
1902 1903 1904 1905 1906
	/*
	 * Do not start discovery if discovery is about to start
	 * or discovery in progress for this node. Starting discovery
	 * here will affect the counting of discovery threads.
	 */
J
James Smart 已提交
1907
	if (!(ndlp->nlp_flag & NLP_DELAY_TMO) &&
1908
	    !(ndlp->nlp_flag & NLP_NPR_2B_DISC)) {
已提交
1909
		if (ndlp->nlp_flag & NLP_NPR_ADISC) {
1910
			ndlp->nlp_flag &= ~NLP_NPR_ADISC;
1911
			ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
J
James Smart 已提交
1912 1913
			lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
			lpfc_issue_els_adisc(vport, ndlp, 0);
已提交
1914
		} else {
1915
			ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
J
James Smart 已提交
1916 1917
			lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
			lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
已提交
1918 1919
		}
	}
1920
	return ndlp->nlp_state;
已提交
1921 1922 1923
}

static uint32_t
J
James Smart 已提交
1924 1925
lpfc_rcv_prlo_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
		       void *arg, uint32_t evt)
已提交
1926
{
J
James Smart 已提交
1927 1928
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1929

J
James Smart 已提交
1930
	spin_lock_irq(shost->host_lock);
1931
	ndlp->nlp_flag |= NLP_LOGO_ACC;
J
James Smart 已提交
1932
	spin_unlock_irq(shost->host_lock);
1933

1934
	lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
已提交
1935

J
James Smart 已提交
1936
	if ((ndlp->nlp_flag & NLP_DELAY_TMO) == 0) {
1937
		mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
J
James Smart 已提交
1938
		spin_lock_irq(shost->host_lock);
1939 1940
		ndlp->nlp_flag |= NLP_DELAY_TMO;
		ndlp->nlp_flag &= ~NLP_NPR_ADISC;
J
James Smart 已提交
1941
		spin_unlock_irq(shost->host_lock);
1942
		ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
1943
	} else {
J
James Smart 已提交
1944
		spin_lock_irq(shost->host_lock);
1945
		ndlp->nlp_flag &= ~NLP_NPR_ADISC;
J
James Smart 已提交
1946
		spin_unlock_irq(shost->host_lock);
已提交
1947
	}
1948 1949
	return ndlp->nlp_state;
}
已提交
1950

1951
static uint32_t
J
James Smart 已提交
1952 1953
lpfc_cmpl_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			 void *arg, uint32_t evt)
1954 1955
{
	struct lpfc_iocbq *cmdiocb, *rspiocb;
1956
	IOCB_t *irsp;
1957 1958 1959

	cmdiocb = (struct lpfc_iocbq *) arg;
	rspiocb = cmdiocb->context_un.rsp_iocb;
1960 1961 1962

	irsp = &rspiocb->iocb;
	if (irsp->ulpStatus) {
1963
		ndlp->nlp_flag |= NLP_DEFER_RM;
1964 1965
		return NLP_STE_FREED_NODE;
	}
1966 1967 1968 1969
	return ndlp->nlp_state;
}

static uint32_t
J
James Smart 已提交
1970 1971
lpfc_cmpl_prli_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			void *arg, uint32_t evt)
1972 1973
{
	struct lpfc_iocbq *cmdiocb, *rspiocb;
1974
	IOCB_t *irsp;
1975 1976 1977

	cmdiocb = (struct lpfc_iocbq *) arg;
	rspiocb = cmdiocb->context_un.rsp_iocb;
1978 1979 1980

	irsp = &rspiocb->iocb;
	if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) {
J
James Smart 已提交
1981
		lpfc_drop_node(vport, ndlp);
1982 1983
		return NLP_STE_FREED_NODE;
	}
1984
	return ndlp->nlp_state;
已提交
1985 1986 1987
}

static uint32_t
J
James Smart 已提交
1988 1989
lpfc_cmpl_logo_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			void *arg, uint32_t evt)
已提交
1990
{
1991 1992 1993 1994 1995 1996
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	if (ndlp->nlp_DID == Fabric_DID) {
		spin_lock_irq(shost->host_lock);
		vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
		spin_unlock_irq(shost->host_lock);
	}
J
James Smart 已提交
1997
	lpfc_unreg_rpi(vport, ndlp);
1998 1999 2000 2001
	return ndlp->nlp_state;
}

static uint32_t
J
James Smart 已提交
2002 2003
lpfc_cmpl_adisc_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			 void *arg, uint32_t evt)
2004 2005
{
	struct lpfc_iocbq *cmdiocb, *rspiocb;
2006
	IOCB_t *irsp;
2007 2008 2009

	cmdiocb = (struct lpfc_iocbq *) arg;
	rspiocb = cmdiocb->context_un.rsp_iocb;
2010 2011 2012

	irsp = &rspiocb->iocb;
	if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) {
J
James Smart 已提交
2013
		lpfc_drop_node(vport, ndlp);
2014 2015
		return NLP_STE_FREED_NODE;
	}
2016
	return ndlp->nlp_state;
已提交
2017 2018 2019
}

static uint32_t
J
James Smart 已提交
2020 2021 2022
lpfc_cmpl_reglogin_npr_node(struct lpfc_vport *vport,
			    struct lpfc_nodelist *ndlp,
			    void *arg, uint32_t evt)
已提交
2023
{
J
James Smart 已提交
2024
	LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
2025
	MAILBOX_t    *mb = &pmb->u.mb;
已提交
2026

2027
	if (!mb->mbxStatus) {
2028
		ndlp->nlp_rpi = mb->un.varWords[0];
2029
		ndlp->nlp_flag |= NLP_RPI_REGISTERED;
2030
	} else {
2031
		if (ndlp->nlp_flag & NLP_NODEV_REMOVE) {
J
James Smart 已提交
2032
			lpfc_drop_node(vport, ndlp);
2033 2034 2035
			return NLP_STE_FREED_NODE;
		}
	}
2036
	return ndlp->nlp_state;
已提交
2037 2038 2039
}

static uint32_t
J
James Smart 已提交
2040 2041
lpfc_device_rm_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			void *arg, uint32_t evt)
已提交
2042
{
J
James Smart 已提交
2043 2044
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

2045
	if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
J
James Smart 已提交
2046
		spin_lock_irq(shost->host_lock);
2047
		ndlp->nlp_flag |= NLP_NODEV_REMOVE;
J
James Smart 已提交
2048
		spin_unlock_irq(shost->host_lock);
2049 2050
		return ndlp->nlp_state;
	}
J
James Smart 已提交
2051
	lpfc_drop_node(vport, ndlp);
2052
	return NLP_STE_FREED_NODE;
已提交
2053 2054 2055
}

static uint32_t
J
James Smart 已提交
2056 2057
lpfc_device_recov_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			   void *arg, uint32_t evt)
已提交
2058
{
J
James Smart 已提交
2059 2060
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

2061 2062 2063 2064 2065 2066
	/* Don't do anything that will mess up processing of the
	 * previous RSCN.
	 */
	if (vport->fc_flag & FC_RSCN_DEFERRED)
		return ndlp->nlp_state;

2067
	lpfc_cancel_retry_delay_tmo(vport, ndlp);
J
James Smart 已提交
2068
	spin_lock_irq(shost->host_lock);
2069
	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
J
James Smart 已提交
2070
	spin_unlock_irq(shost->host_lock);
2071
	return ndlp->nlp_state;
已提交
2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106
}


/* This next section defines the NPort Discovery State Machine */

/* There are 4 different double linked lists nodelist entries can reside on.
 * The plogi list and adisc list are used when Link Up discovery or RSCN
 * processing is needed. Each list holds the nodes that we will send PLOGI
 * or ADISC on. These lists will keep track of what nodes will be effected
 * by an RSCN, or a Link Up (Typically, all nodes are effected on Link Up).
 * The unmapped_list will contain all nodes that we have successfully logged
 * into at the Fibre Channel level. The mapped_list will contain all nodes
 * that are mapped FCP targets.
 */
/*
 * The bind list is a list of undiscovered (potentially non-existent) nodes
 * that we have saved binding information on. This information is used when
 * nodes transition from the unmapped to the mapped list.
 */
/* For UNUSED_NODE state, the node has just been allocated .
 * For PLOGI_ISSUE and REG_LOGIN_ISSUE, the node is on
 * the PLOGI list. For REG_LOGIN_COMPL, the node is taken off the PLOGI list
 * and put on the unmapped list. For ADISC processing, the node is taken off
 * the ADISC list and placed on either the mapped or unmapped list (depending
 * on its previous state). Once on the unmapped list, a PRLI is issued and the
 * state changed to PRLI_ISSUE. When the PRLI completion occurs, the state is
 * changed to UNMAPPED_NODE. If the completion indicates a mapped
 * node, the node is taken off the unmapped list. The binding list is checked
 * for a valid binding, or a binding is automatically assigned. If binding
 * assignment is unsuccessful, the node is left on the unmapped list. If
 * binding assignment is successful, the associated binding list entry (if
 * any) is removed, and the node is placed on the mapped list.
 */
/*
 * For a Link Down, all nodes on the ADISC, PLOGI, unmapped or mapped
2107
 * lists will receive a DEVICE_RECOVERY event. If the linkdown or devloss timers
已提交
2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131
 * expire, all effected nodes will receive a DEVICE_RM event.
 */
/*
 * For a Link Up or RSCN, all nodes will move from the mapped / unmapped lists
 * to either the ADISC or PLOGI list.  After a Nameserver query or ALPA loopmap
 * check, additional nodes may be added or removed (via DEVICE_RM) to / from
 * the PLOGI or ADISC lists. Once the PLOGI and ADISC lists are populated,
 * we will first process the ADISC list.  32 entries are processed initially and
 * ADISC is initited for each one.  Completions / Events for each node are
 * funnelled thru the state machine.  As each node finishes ADISC processing, it
 * starts ADISC for any nodes waiting for ADISC processing. If no nodes are
 * waiting, and the ADISC list count is identically 0, then we are done. For
 * Link Up discovery, since all nodes on the PLOGI list are UNREG_LOGIN'ed, we
 * can issue a CLEAR_LA and reenable Link Events. Next we will process the PLOGI
 * list.  32 entries are processed initially and PLOGI is initited for each one.
 * Completions / Events for each node are funnelled thru the state machine.  As
 * each node finishes PLOGI processing, it starts PLOGI for any nodes waiting
 * for PLOGI processing. If no nodes are waiting, and the PLOGI list count is
 * indentically 0, then we are done. We have now completed discovery / RSCN
 * handling. Upon completion, ALL nodes should be on either the mapped or
 * unmapped lists.
 */

static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
J
James Smart 已提交
2132
     (struct lpfc_vport *, struct lpfc_nodelist *, void *, uint32_t) = {
已提交
2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148
	/* Action routine                  Event       Current State  */
	lpfc_rcv_plogi_unused_node,	/* RCV_PLOGI   UNUSED_NODE    */
	lpfc_rcv_els_unused_node,	/* RCV_PRLI        */
	lpfc_rcv_logo_unused_node,	/* RCV_LOGO        */
	lpfc_rcv_els_unused_node,	/* RCV_ADISC       */
	lpfc_rcv_els_unused_node,	/* RCV_PDISC       */
	lpfc_rcv_els_unused_node,	/* RCV_PRLO        */
	lpfc_disc_illegal,		/* CMPL_PLOGI      */
	lpfc_disc_illegal,		/* CMPL_PRLI       */
	lpfc_cmpl_logo_unused_node,	/* CMPL_LOGO       */
	lpfc_disc_illegal,		/* CMPL_ADISC      */
	lpfc_disc_illegal,		/* CMPL_REG_LOGIN  */
	lpfc_device_rm_unused_node,	/* DEVICE_RM       */
	lpfc_disc_illegal,		/* DEVICE_RECOVERY */

	lpfc_rcv_plogi_plogi_issue,	/* RCV_PLOGI   PLOGI_ISSUE    */
2149
	lpfc_rcv_prli_plogi_issue,	/* RCV_PRLI        */
2150
	lpfc_rcv_logo_plogi_issue,	/* RCV_LOGO        */
已提交
2151 2152 2153 2154 2155
	lpfc_rcv_els_plogi_issue,	/* RCV_ADISC       */
	lpfc_rcv_els_plogi_issue,	/* RCV_PDISC       */
	lpfc_rcv_els_plogi_issue,	/* RCV_PRLO        */
	lpfc_cmpl_plogi_plogi_issue,	/* CMPL_PLOGI      */
	lpfc_disc_illegal,		/* CMPL_PRLI       */
2156
	lpfc_cmpl_logo_plogi_issue,	/* CMPL_LOGO       */
已提交
2157
	lpfc_disc_illegal,		/* CMPL_ADISC      */
2158
	lpfc_cmpl_reglogin_plogi_issue,/* CMPL_REG_LOGIN  */
已提交
2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181
	lpfc_device_rm_plogi_issue,	/* DEVICE_RM       */
	lpfc_device_recov_plogi_issue,	/* DEVICE_RECOVERY */

	lpfc_rcv_plogi_adisc_issue,	/* RCV_PLOGI   ADISC_ISSUE    */
	lpfc_rcv_prli_adisc_issue,	/* RCV_PRLI        */
	lpfc_rcv_logo_adisc_issue,	/* RCV_LOGO        */
	lpfc_rcv_padisc_adisc_issue,	/* RCV_ADISC       */
	lpfc_rcv_padisc_adisc_issue,	/* RCV_PDISC       */
	lpfc_rcv_prlo_adisc_issue,	/* RCV_PRLO        */
	lpfc_disc_illegal,		/* CMPL_PLOGI      */
	lpfc_disc_illegal,		/* CMPL_PRLI       */
	lpfc_disc_illegal,		/* CMPL_LOGO       */
	lpfc_cmpl_adisc_adisc_issue,	/* CMPL_ADISC      */
	lpfc_disc_illegal,		/* CMPL_REG_LOGIN  */
	lpfc_device_rm_adisc_issue,	/* DEVICE_RM       */
	lpfc_device_recov_adisc_issue,	/* DEVICE_RECOVERY */

	lpfc_rcv_plogi_reglogin_issue,	/* RCV_PLOGI  REG_LOGIN_ISSUE */
	lpfc_rcv_prli_reglogin_issue,	/* RCV_PLOGI       */
	lpfc_rcv_logo_reglogin_issue,	/* RCV_LOGO        */
	lpfc_rcv_padisc_reglogin_issue,	/* RCV_ADISC       */
	lpfc_rcv_padisc_reglogin_issue,	/* RCV_PDISC       */
	lpfc_rcv_prlo_reglogin_issue,	/* RCV_PRLO        */
2182
	lpfc_cmpl_plogi_illegal,	/* CMPL_PLOGI      */
已提交
2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195
	lpfc_disc_illegal,		/* CMPL_PRLI       */
	lpfc_disc_illegal,		/* CMPL_LOGO       */
	lpfc_disc_illegal,		/* CMPL_ADISC      */
	lpfc_cmpl_reglogin_reglogin_issue,/* CMPL_REG_LOGIN  */
	lpfc_device_rm_reglogin_issue,	/* DEVICE_RM       */
	lpfc_device_recov_reglogin_issue,/* DEVICE_RECOVERY */

	lpfc_rcv_plogi_prli_issue,	/* RCV_PLOGI   PRLI_ISSUE     */
	lpfc_rcv_prli_prli_issue,	/* RCV_PRLI        */
	lpfc_rcv_logo_prli_issue,	/* RCV_LOGO        */
	lpfc_rcv_padisc_prli_issue,	/* RCV_ADISC       */
	lpfc_rcv_padisc_prli_issue,	/* RCV_PDISC       */
	lpfc_rcv_prlo_prli_issue,	/* RCV_PRLO        */
2196
	lpfc_cmpl_plogi_illegal,	/* CMPL_PLOGI      */
已提交
2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237
	lpfc_cmpl_prli_prli_issue,	/* CMPL_PRLI       */
	lpfc_disc_illegal,		/* CMPL_LOGO       */
	lpfc_disc_illegal,		/* CMPL_ADISC      */
	lpfc_disc_illegal,		/* CMPL_REG_LOGIN  */
	lpfc_device_rm_prli_issue,	/* DEVICE_RM       */
	lpfc_device_recov_prli_issue,	/* DEVICE_RECOVERY */

	lpfc_rcv_plogi_unmap_node,	/* RCV_PLOGI   UNMAPPED_NODE  */
	lpfc_rcv_prli_unmap_node,	/* RCV_PRLI        */
	lpfc_rcv_logo_unmap_node,	/* RCV_LOGO        */
	lpfc_rcv_padisc_unmap_node,	/* RCV_ADISC       */
	lpfc_rcv_padisc_unmap_node,	/* RCV_PDISC       */
	lpfc_rcv_prlo_unmap_node,	/* RCV_PRLO        */
	lpfc_disc_illegal,		/* CMPL_PLOGI      */
	lpfc_disc_illegal,		/* CMPL_PRLI       */
	lpfc_disc_illegal,		/* CMPL_LOGO       */
	lpfc_disc_illegal,		/* CMPL_ADISC      */
	lpfc_disc_illegal,		/* CMPL_REG_LOGIN  */
	lpfc_disc_illegal,		/* DEVICE_RM       */
	lpfc_device_recov_unmap_node,	/* DEVICE_RECOVERY */

	lpfc_rcv_plogi_mapped_node,	/* RCV_PLOGI   MAPPED_NODE    */
	lpfc_rcv_prli_mapped_node,	/* RCV_PRLI        */
	lpfc_rcv_logo_mapped_node,	/* RCV_LOGO        */
	lpfc_rcv_padisc_mapped_node,	/* RCV_ADISC       */
	lpfc_rcv_padisc_mapped_node,	/* RCV_PDISC       */
	lpfc_rcv_prlo_mapped_node,	/* RCV_PRLO        */
	lpfc_disc_illegal,		/* CMPL_PLOGI      */
	lpfc_disc_illegal,		/* CMPL_PRLI       */
	lpfc_disc_illegal,		/* CMPL_LOGO       */
	lpfc_disc_illegal,		/* CMPL_ADISC      */
	lpfc_disc_illegal,		/* CMPL_REG_LOGIN  */
	lpfc_disc_illegal,		/* DEVICE_RM       */
	lpfc_device_recov_mapped_node,	/* DEVICE_RECOVERY */

	lpfc_rcv_plogi_npr_node,        /* RCV_PLOGI   NPR_NODE    */
	lpfc_rcv_prli_npr_node,         /* RCV_PRLI        */
	lpfc_rcv_logo_npr_node,         /* RCV_LOGO        */
	lpfc_rcv_padisc_npr_node,       /* RCV_ADISC       */
	lpfc_rcv_padisc_npr_node,       /* RCV_PDISC       */
	lpfc_rcv_prlo_npr_node,         /* RCV_PRLO        */
2238 2239
	lpfc_cmpl_plogi_npr_node,	/* CMPL_PLOGI      */
	lpfc_cmpl_prli_npr_node,	/* CMPL_PRLI       */
已提交
2240
	lpfc_cmpl_logo_npr_node,        /* CMPL_LOGO       */
2241
	lpfc_cmpl_adisc_npr_node,       /* CMPL_ADISC      */
已提交
2242 2243 2244 2245 2246 2247
	lpfc_cmpl_reglogin_npr_node,    /* CMPL_REG_LOGIN  */
	lpfc_device_rm_npr_node,        /* DEVICE_RM       */
	lpfc_device_recov_npr_node,     /* DEVICE_RECOVERY */
};

int
J
James Smart 已提交
2248 2249
lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			void *arg, uint32_t evt)
已提交
2250 2251
{
	uint32_t cur_state, rc;
J
James Smart 已提交
2252
	uint32_t(*func) (struct lpfc_vport *, struct lpfc_nodelist *, void *,
已提交
2253
			 uint32_t);
2254 2255 2256 2257
	uint32_t got_ndlp = 0;

	if (lpfc_nlp_get(ndlp))
		got_ndlp = 1;
已提交
2258 2259 2260 2261

	cur_state = ndlp->nlp_state;

	/* DSM in event <evt> on NPort <nlp_DID> in state <cur_state> */
2262 2263 2264 2265
	lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
			 "0211 DSM in event x%x on NPort x%x in "
			 "state %d Data: x%x\n",
			 evt, ndlp->nlp_DID, cur_state, ndlp->nlp_flag);
已提交
2266

J
James Smart 已提交
2267 2268 2269 2270
	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM,
		 "DSM in:          evt:%d ste:%d did:x%x",
		evt, cur_state, ndlp->nlp_DID);

已提交
2271
	func = lpfc_disc_action[(cur_state * NLP_EVT_MAX_EVENT) + evt];
J
James Smart 已提交
2272
	rc = (func) (vport, ndlp, arg, evt);
已提交
2273 2274

	/* DSM out state <rc> on NPort <nlp_DID> */
2275 2276
	if (got_ndlp) {
		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
2277 2278
			 "0212 DSM out state %d on NPort x%x Data: x%x\n",
			 rc, ndlp->nlp_DID, ndlp->nlp_flag);
已提交
2279

2280 2281 2282 2283 2284 2285 2286
		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM,
			"DSM out:         ste:%d did:x%x flg:x%x",
			rc, ndlp->nlp_DID, ndlp->nlp_flag);
		/* Decrement the ndlp reference count held for this function */
		lpfc_nlp_put(ndlp);
	} else {
		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
2287
			"0213 DSM out state %d on NPort free\n", rc);
J
James Smart 已提交
2288

2289 2290 2291 2292
		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM,
			"DSM out:         ste:%d did:x%x flg:x%x",
			rc, 0, 0);
	}
已提交
2293

2294
	return rc;
已提交
2295
}