lpfc_nportdisc.c 75.3 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-2012 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 54
	/* First, we MUST have a RPI registered */
	if (!(ndlp->nlp_flag & NLP_RPI_REGISTERED))
		return 0;

已提交
55 56 57
	/* Compare the ADISC rsp WWNN / WWPN matches our internal node
	 * table entry for that node.
	 */
J
James Smart 已提交
58
	if (memcmp(nn, &ndlp->nlp_nodename, sizeof (struct lpfc_name)))
59
		return 0;
已提交
60

J
James Smart 已提交
61
	if (memcmp(pn, &ndlp->nlp_portname, sizeof (struct lpfc_name)))
62
		return 0;
已提交
63 64

	/* we match, return success */
65
	return 1;
已提交
66 67 68
}

int
J
James Smart 已提交
69
lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
70
		 struct serv_parm *sp, uint32_t class, int flogi)
已提交
71
{
J
James Smart 已提交
72
	volatile struct serv_parm *hsp = &vport->fc_sparam;
73 74 75 76 77 78 79 80 81
	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.
	 */
已提交
82
	if (sp->cls1.classValid) {
83 84 85 86 87 88 89 90 91 92 93 94 95
		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;
			}
96
		}
97
	} else if (class == CLASS1)
98
		goto bad_service_param;
已提交
99
	if (sp->cls2.classValid) {
100 101 102 103 104 105 106 107 108 109 110 111 112
		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;
			}
113
		}
114
	} else if (class == CLASS2)
115
		goto bad_service_param;
已提交
116
	if (sp->cls3.classValid) {
117 118 119 120 121 122 123 124 125 126 127 128 129
		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;
			}
130
		}
131
	} else if (class == CLASS3)
132
		goto bad_service_param;
已提交
133

134 135 136 137 138 139 140 141
	/*
	 * 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) {
已提交
142
		sp->cmn.bbRcvSizeLsb = hsp->cmn.bbRcvSizeLsb;
143 144 145
		sp->cmn.bbRcvSizeMsb = (sp->cmn.bbRcvSizeMsb & 0xF0) |
				       (hsp->cmn.bbRcvSizeMsb & 0x0F);
	}
已提交
146 147 148

	memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof (struct lpfc_name));
	memcpy(&ndlp->nlp_portname, &sp->portName, sizeof (struct lpfc_name));
149
	return 1;
150
bad_service_param:
151 152 153 154 155 156 157 158 159
	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]);
160
	return 0;
已提交
161 162 163
}

static void *
J
James Smart 已提交
164
lpfc_check_elscmpl_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
165
			struct lpfc_iocbq *rspiocb)
已提交
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
{
	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));
		}
185
	} else {
已提交
186 187 188 189 190 191 192
		/* 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;
	}
193
	return ptr;
已提交
194 195 196
}


197

已提交
198 199 200 201 202 203
/*
 * 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 已提交
204
lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
已提交
205
{
206
	LIST_HEAD(completions);
207 208
	LIST_HEAD(txcmplq_completions);
	LIST_HEAD(abort_list);
J
James Smart 已提交
209 210
	struct lpfc_sli  *psli = &phba->sli;
	struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
已提交
211 212 213
	struct lpfc_iocbq *iocb, *next_iocb;

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

	lpfc_fabric_abort_nport(ndlp);
已提交
221 222

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

	/* Next check the txcmplq */
233 234 235 236
	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 已提交
237
		/* Check to see if iocb matches the nport we are looking for */
238 239
		if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))
			list_add_tail(&iocb->dlist, &abort_list);
240
	}
241 242
	spin_lock_irq(&phba->hbalock);
	list_splice(&txcmplq_completions, &pring->txcmplq);
J
James Smart 已提交
243
	spin_unlock_irq(&phba->hbalock);
已提交
244

245 246 247 248 249 250 251
	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);
	}

252 253 254
	/* Cancel all the IOCBs from the completions list */
	lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
			      IOERR_SLI_ABORTED);
255

256
	lpfc_cancel_retry_delay_tmo(phba->pport, ndlp);
257
	return 0;
已提交
258 259 260
}

static int
J
James Smart 已提交
261
lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
262
	       struct lpfc_iocbq *cmdiocb)
已提交
263
{
J
James Smart 已提交
264 265
	struct Scsi_Host   *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba    *phba = vport->phba;
已提交
266 267 268 269 270 271 272 273 274
	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));
275
	if (vport->port_state <= LPFC_FDISC) {
已提交
276 277 278 279
		/* 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 已提交
280
		if (vport->fc_flag & FC_PT2PT) {
281
			 lpfc_els_abort_flogi(phba);
J
James Smart 已提交
282
		        if (!(vport->fc_flag & FC_PT2PT_PLOGI)) {
已提交
283 284 285 286 287 288 289 290
				/* 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 已提交
291
				lpfc_disc_start(vport);
292
			} else
J
James Smart 已提交
293
				lpfc_initial_flogi(vport);
294
		} else {
已提交
295 296
			stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY;
			stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
J
James Smart 已提交
297
			lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
J
James Smart 已提交
298
					    ndlp, NULL);
已提交
299 300 301 302 303 304
			return 0;
		}
	}
	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
	lp = (uint32_t *) pcmd->virt;
	sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
	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;
	}
323
	if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 0) == 0)) {
已提交
324 325 326
		/* Reject this request because invalid parameters */
		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
		stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
J
James Smart 已提交
327 328
		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
			NULL);
329
		return 0;
已提交
330 331 332 333
	}
	icmd = &cmdiocb->iocb;

	/* PLOGI chkparm OK */
334 335 336 337
	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);
已提交
338

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

已提交
344 345 346 347 348 349 350 351 352 353 354 355
	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;

356
	/* no need to reg_login if we are already in one of these states */
357
	switch (ndlp->nlp_state) {
已提交
358 359 360 361 362 363 364
	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:
365 366
		lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL);
		return 1;
已提交
367 368
	}

369
	/* Check for Nport to NPort pt2pt protocol */
370 371
	if ((vport->fc_flag & FC_PT2PT) &&
	    !(vport->fc_flag & FC_PT2PT_PLOGI)) {
372

已提交
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
			goto out;
		}
386 387 388 389 390 391 392
		/*
		 * For SLI4, the VFI/VPI are registered AFTER the
		 * Nport with the higher WWPN sends us a PLOGI with
		 * our assigned NPortId.
		 */
		if (phba->sli_rev == LPFC_SLI_REV4)
			lpfc_issue_reg_vfi(vport);
已提交
393

J
James Smart 已提交
394
		lpfc_can_disctmo(vport);
已提交
395 396
	}
	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
J
James Smart 已提交
397
	if (!mbox)
已提交
398 399
		goto out;

400 401 402 403
	/* Registering an existing RPI behaves differently for SLI3 vs SLI4 */
	if (phba->sli_rev == LPFC_SLI_REV4)
		lpfc_unreg_rpi(vport, ndlp);

404
	rc = lpfc_reg_rpi(phba, vport->vpi, icmd->un.rcvels.remoteID,
405
			    (uint8_t *) sp, mbox, ndlp->nlp_rpi);
J
James Smart 已提交
406 407
	if (rc) {
		mempool_free(mbox, phba->mbox_mem_pool);
已提交
408 409 410 411 412 413 414
		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;
415 416 417 418
	/*
	 * mbox->context2 = lpfc_nlp_get(ndlp) deferred until mailbox
	 * command issued in lpfc_cmpl_els_acc().
	 */
J
James Smart 已提交
419 420
	mbox->vport = vport;
	spin_lock_irq(shost->host_lock);
421
	ndlp->nlp_flag |= (NLP_ACC_REGLOGIN | NLP_RCV_PLOGI);
J
James Smart 已提交
422
	spin_unlock_irq(shost->host_lock);
已提交
423

J
James Smart 已提交
424 425 426 427 428 429 430 431 432 433 434
	/*
	 * 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 */
435
		lpfc_els_abort(phba, ndlp);
J
James Smart 已提交
436 437
	}

J
James Smart 已提交
438
	if ((vport->port_type == LPFC_NPIV_PORT &&
439
	     vport->cfg_restrict_login)) {
J
James Smart 已提交
440 441 442 443 444 445 446 447 448 449 450

		/* 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;
451
		rc = lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
J
James Smart 已提交
452
			ndlp, mbox);
453 454
		if (rc)
			mempool_free(mbox, phba->mbox_mem_pool);
J
James Smart 已提交
455 456
		return 1;
	}
457 458 459
	rc = lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox);
	if (rc)
		mempool_free(mbox, phba->mbox_mem_pool);
460
	return 1;
已提交
461 462 463
out:
	stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
	stat.un.b.lsRjtRsnCodeExp = LSEXP_OUT_OF_RESOURCE;
J
James Smart 已提交
464
	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
465
	return 0;
已提交
466 467
}

468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
/**
 * lpfc_mbx_cmpl_resume_rpi - Resume RPI completion routine
 * @phba: pointer to lpfc hba data structure.
 * @mboxq: pointer to mailbox object
 *
 * This routine is invoked to issue a completion to a rcv'ed
 * ADISC or PDISC after the paused RPI has been resumed.
 **/
static void
lpfc_mbx_cmpl_resume_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
{
	struct lpfc_vport *vport;
	struct lpfc_iocbq *elsiocb;
	struct lpfc_nodelist *ndlp;
	uint32_t cmd;

	elsiocb = (struct lpfc_iocbq *)mboxq->context1;
	ndlp = (struct lpfc_nodelist *) mboxq->context2;
	vport = mboxq->vport;
	cmd = elsiocb->drvrTimeout;

	if (cmd == ELS_CMD_ADISC) {
		lpfc_els_rsp_adisc_acc(vport, elsiocb, ndlp);
	} else {
		lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, elsiocb,
			ndlp, NULL);
	}
	kfree(elsiocb);
496
	mempool_free(mboxq, phba->mbox_mem_pool);
497 498
}

已提交
499
static int
J
James Smart 已提交
500
lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
已提交
501 502
		struct lpfc_iocbq *cmdiocb)
{
J
James Smart 已提交
503
	struct Scsi_Host   *shost = lpfc_shost_from_vport(vport);
504
	struct lpfc_iocbq  *elsiocb;
已提交
505
	struct lpfc_dmabuf *pcmd;
J
James Smart 已提交
506 507
	struct serv_parm   *sp;
	struct lpfc_name   *pnn, *ppn;
已提交
508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
	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 已提交
529
	if (icmd->ulpStatus == 0 && lpfc_check_adisc(vport, ndlp, pnn, ppn)) {
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553

		/*
		 * As soon as  we send ACC, the remote NPort can
		 * start sending us data. Thus, for SLI4 we must
		 * resume the RPI before the ACC goes out.
		 */
		if (vport->phba->sli_rev == LPFC_SLI_REV4) {
			elsiocb = kmalloc(sizeof(struct lpfc_iocbq),
				GFP_KERNEL);
			if (elsiocb) {

				/* Save info from cmd IOCB used in rsp */
				memcpy((uint8_t *)elsiocb, (uint8_t *)cmdiocb,
					sizeof(struct lpfc_iocbq));

				/* Save the ELS cmd */
				elsiocb->drvrTimeout = cmd;

				lpfc_sli4_resume_rpi(ndlp,
					lpfc_mbx_cmpl_resume_rpi, elsiocb);
				goto out;
			}
		}

已提交
554
		if (cmd == ELS_CMD_ADISC) {
J
James Smart 已提交
555
			lpfc_els_rsp_adisc_acc(vport, cmdiocb, ndlp);
556
		} else {
557 558
			lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb,
				ndlp, NULL);
已提交
559
		}
560 561 562 563 564 565 566
out:
		/* If we are authenticated, move to the proper state */
		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);

567
		return 1;
已提交
568 569 570 571 572 573
	}
	/* 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 已提交
574
	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
已提交
575 576 577 578

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

J
James Smart 已提交
579
	spin_lock_irq(shost->host_lock);
已提交
580
	ndlp->nlp_flag |= NLP_DELAY_TMO;
J
James Smart 已提交
581
	spin_unlock_irq(shost->host_lock);
582 583
	ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
	ndlp->nlp_prev_state = ndlp->nlp_state;
J
James Smart 已提交
584
	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
585
	return 0;
已提交
586 587 588
}

static int
J
James Smart 已提交
589 590
lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
	      struct lpfc_iocbq *cmdiocb, uint32_t els_cmd)
已提交
591
{
J
James Smart 已提交
592
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
J
James Smart 已提交
593 594 595
	struct lpfc_hba    *phba = vport->phba;
	struct lpfc_vport **vports;
	int i, active_vlink_present = 0 ;
J
James Smart 已提交
596 597

	/* Put ndlp in NPR state with 1 sec timeout for plogi, ACC logo */
已提交
598 599 600
	/* Only call LOGO ACC for first LOGO, this avoids sending unnecessary
	 * PLOGIs during LOGO storms from a device.
	 */
J
James Smart 已提交
601
	spin_lock_irq(shost->host_lock);
已提交
602
	ndlp->nlp_flag |= NLP_LOGO_ACC;
J
James Smart 已提交
603
	spin_unlock_irq(shost->host_lock);
604
	if (els_cmd == ELS_CMD_PRLO)
605
		lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
606
	else
607
		lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
J
James Smart 已提交
608 609 610
	if (ndlp->nlp_DID == Fabric_DID) {
		if (vport->port_state <= LPFC_FDISC)
			goto out;
611 612
		lpfc_linkdown_port(vport);
		spin_lock_irq(shost->host_lock);
J
James Smart 已提交
613
		vport->fc_flag |= FC_VPORT_LOGO_RCVD;
614
		spin_unlock_irq(shost->host_lock);
J
James Smart 已提交
615 616 617 618 619 620 621 622 623 624 625 626 627
		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);
		}
已提交
628

J
James Smart 已提交
629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
		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);
		}
646 647 648 649
	} 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)) {
已提交
650 651
		/* Only try to re-login if this is NOT a Fabric Node */
		mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
J
James Smart 已提交
652
		spin_lock_irq(shost->host_lock);
已提交
653
		ndlp->nlp_flag |= NLP_DELAY_TMO;
J
James Smart 已提交
654
		spin_unlock_irq(shost->host_lock);
已提交
655

656
		ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
657
	}
J
James Smart 已提交
658
out:
659 660
	ndlp->nlp_prev_state = ndlp->nlp_state;
	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
已提交
661

J
James Smart 已提交
662
	spin_lock_irq(shost->host_lock);
已提交
663
	ndlp->nlp_flag &= ~NLP_NPR_ADISC;
J
James Smart 已提交
664
	spin_unlock_irq(shost->host_lock);
已提交
665 666 667 668 669
	/* 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.
	 */
670
	return 0;
已提交
671 672 673
}

static void
J
James Smart 已提交
674 675
lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
	      struct lpfc_iocbq *cmdiocb)
已提交
676 677 678 679 680 681 682 683 684 685 686 687 688
{
	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;
689
	if (npr->prliType == PRLI_FCP_TYPE) {
已提交
690 691 692 693 694 695 696 697 698 699 700 701 702 703
		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 已提交
704 705 706 707 708

		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);

已提交
709 710 711 712 713
		fc_remote_port_rolechg(rport, roles);
	}
}

static uint32_t
J
James Smart 已提交
714
lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
已提交
715
{
J
James Smart 已提交
716 717
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

718
	if (!(ndlp->nlp_flag & NLP_RPI_REGISTERED)) {
719 720 721 722
		ndlp->nlp_flag &= ~NLP_NPR_ADISC;
		return 0;
	}

723 724 725
	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)) ||
726 727
		    ((ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) &&
		     (ndlp->nlp_type & NLP_FCP_TARGET))) {
728 729 730 731 732
			spin_lock_irq(shost->host_lock);
			ndlp->nlp_flag |= NLP_NPR_ADISC;
			spin_unlock_irq(shost->host_lock);
			return 1;
		}
733 734 735 736
	}
	ndlp->nlp_flag &= ~NLP_NPR_ADISC;
	lpfc_unreg_rpi(vport, ndlp);
	return 0;
已提交
737
}
738

739
/**
L
Lucas De Marchi 已提交
740
 * lpfc_release_rpi - Release a RPI by issuing unreg_login mailbox cmd.
741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768
 * @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);
	}
}
已提交
769 770

static uint32_t
J
James Smart 已提交
771 772
lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
		  void *arg, uint32_t evt)
已提交
773
{
774 775 776 777 778 779 780 781 782 783 784 785 786 787
	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);
	}
788
	lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
789
			 "0271 Illegal State Transition: node x%x "
790 791 792
			 "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);
793
	return ndlp->nlp_state;
已提交
794 795
}

796 797 798 799 800 801 802 803 804 805 806
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,
807
			 "0272 Illegal State Transition: node x%x "
808 809 810 811 812 813 814
			 "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;
}

已提交
815 816 817
/* Start of Discovery State Machine routines */

static uint32_t
J
James Smart 已提交
818 819
lpfc_rcv_plogi_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			   void *arg, uint32_t evt)
已提交
820 821 822 823 824
{
	struct lpfc_iocbq *cmdiocb;

	cmdiocb = (struct lpfc_iocbq *) arg;

J
James Smart 已提交
825
	if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) {
826
		return ndlp->nlp_state;
已提交
827
	}
828
	return NLP_STE_FREED_NODE;
已提交
829 830 831
}

static uint32_t
J
James Smart 已提交
832 833
lpfc_rcv_els_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			 void *arg, uint32_t evt)
已提交
834
{
J
James Smart 已提交
835
	lpfc_issue_els_logo(vport, ndlp, 0);
836
	return ndlp->nlp_state;
已提交
837 838 839
}

static uint32_t
J
James Smart 已提交
840 841
lpfc_rcv_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
已提交
842
{
J
James Smart 已提交
843 844
	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
845

J
James Smart 已提交
846
	spin_lock_irq(shost->host_lock);
已提交
847
	ndlp->nlp_flag |= NLP_LOGO_ACC;
J
James Smart 已提交
848
	spin_unlock_irq(shost->host_lock);
849
	lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
已提交
850

851
	return ndlp->nlp_state;
已提交
852 853 854
}

static uint32_t
J
James Smart 已提交
855 856
lpfc_cmpl_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			   void *arg, uint32_t evt)
已提交
857
{
858
	return NLP_STE_FREED_NODE;
已提交
859 860 861
}

static uint32_t
J
James Smart 已提交
862 863
lpfc_device_rm_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			   void *arg, uint32_t evt)
已提交
864
{
865
	return NLP_STE_FREED_NODE;
已提交
866 867
}

868 869 870 871 872 873 874 875
static uint32_t
lpfc_device_recov_unused_node(struct lpfc_vport *vport,
			struct lpfc_nodelist *ndlp,
			   void *arg, uint32_t evt)
{
	return ndlp->nlp_state;
}

已提交
876
static uint32_t
J
James Smart 已提交
877
lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
已提交
878 879
			   void *arg, uint32_t evt)
{
880
	struct Scsi_Host   *shost = lpfc_shost_from_vport(vport);
J
James Smart 已提交
881
	struct lpfc_hba   *phba = vport->phba;
已提交
882
	struct lpfc_iocbq *cmdiocb = arg;
J
James Smart 已提交
883 884 885
	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);
已提交
886 887 888 889 890 891 892 893 894
	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 已提交
895
	port_cmp = memcmp(&vport->fc_portname, &sp->portName,
896
			  sizeof(struct lpfc_name));
已提交
897 898 899 900 901 902

	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 已提交
903 904
		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
			NULL);
905
	} else {
906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
		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 已提交
922
	} /* If our portname was less */
已提交
923

924 925 926
	return ndlp->nlp_state;
}

927 928 929 930 931 932 933 934 935 936
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 已提交
937
	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
938 939 940
	return ndlp->nlp_state;
}

941
static uint32_t
J
James Smart 已提交
942 943
lpfc_rcv_logo_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
944
{
J
James Smart 已提交
945
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
946

947
				/* software abort outstanding PLOGI */
J
James Smart 已提交
948
	lpfc_els_abort(vport->phba, ndlp);
949

J
James Smart 已提交
950
	lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
951
	return ndlp->nlp_state;
已提交
952 953 954
}

static uint32_t
J
James Smart 已提交
955 956
lpfc_rcv_els_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			 void *arg, uint32_t evt)
已提交
957
{
J
James Smart 已提交
958 959 960
	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba   *phba = vport->phba;
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
961 962

	/* software abort outstanding PLOGI */
963
	lpfc_els_abort(phba, ndlp);
已提交
964 965

	if (evt == NLP_EVT_RCV_LOGO) {
966
		lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
967
	} else {
J
James Smart 已提交
968
		lpfc_issue_els_logo(vport, ndlp, 0);
已提交
969 970
	}

J
James Smart 已提交
971
	/* Put ndlp in npr state set plogi timer for 1 sec */
972
	mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
J
James Smart 已提交
973
	spin_lock_irq(shost->host_lock);
974
	ndlp->nlp_flag |= NLP_DELAY_TMO;
J
James Smart 已提交
975
	spin_unlock_irq(shost->host_lock);
976 977
	ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
	ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE;
J
James Smart 已提交
978
	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
已提交
979

980
	return ndlp->nlp_state;
已提交
981 982 983
}

static uint32_t
J
James Smart 已提交
984 985 986
lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
			    struct lpfc_nodelist *ndlp,
			    void *arg,
已提交
987 988
			    uint32_t evt)
{
J
James Smart 已提交
989
	struct lpfc_hba    *phba = vport->phba;
990
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
J
James Smart 已提交
991
	struct lpfc_iocbq  *cmdiocb, *rspiocb;
992
	struct lpfc_dmabuf *pcmd, *prsp, *mp;
已提交
993 994 995 996 997 998 999 1000 1001
	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) {
1002
		/* Recovery from PLOGI collision logic */
1003
		return ndlp->nlp_state;
已提交
1004 1005 1006 1007 1008 1009 1010 1011 1012
	}

	irsp = &rspiocb->iocb;

	if (irsp->ulpStatus)
		goto out;

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

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

J
James Smart 已提交
1015
	lp = (uint32_t *) prsp->virt;
已提交
1016
	sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
1017 1018 1019 1020 1021

	/* 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)) {
1022 1023 1024 1025
		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
				 "0142 PLOGI RSP: Invalid WWN.\n");
		goto out;
	}
1026
	if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3, 0))
已提交
1027 1028
		goto out;
	/* PLOGI chkparm OK */
1029 1030 1031 1032
	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);
1033
	if (vport->cfg_fcp_class == 2 && (sp->cls2.classValid))
已提交
1034
		ndlp->nlp_fcp_info |= CLASS2;
J
James Smart 已提交
1035
	else
已提交
1036
		ndlp->nlp_fcp_info |= CLASS3;
J
James Smart 已提交
1037

已提交
1038 1039 1040 1041 1042 1043 1044 1045 1046 1047
	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 已提交
1048
		((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb;
已提交
1049

J
James Smart 已提交
1050
	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
1051
	if (!mbox) {
1052 1053
		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
			"0133 PLOGI: no memory for reg_login "
1054 1055 1056
			"Data: x%x x%x x%x x%x\n",
			ndlp->nlp_DID, ndlp->nlp_state,
			ndlp->nlp_flag, ndlp->nlp_rpi);
已提交
1057
		goto out;
1058
	}
已提交
1059

J
James Smart 已提交
1060 1061
	lpfc_unreg_rpi(vport, ndlp);

1062
	if (lpfc_reg_rpi(phba, vport->vpi, irsp->un.elsreq64.remoteID,
1063
			 (uint8_t *) sp, mbox, ndlp->nlp_rpi) == 0) {
1064
		switch (ndlp->nlp_DID) {
已提交
1065
		case NameServer_DID:
1066
			mbox->mbox_cmpl = lpfc_mbx_cmpl_ns_reg_login;
已提交
1067 1068
			break;
		case FDMI_DID:
1069
			mbox->mbox_cmpl = lpfc_mbx_cmpl_fdmi_reg_login;
已提交
1070 1071
			break;
		default:
1072
			ndlp->nlp_flag |= NLP_REG_LOGIN_SEND;
1073
			mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
已提交
1074
		}
1075
		mbox->context2 = lpfc_nlp_get(ndlp);
J
James Smart 已提交
1076
		mbox->vport = vport;
1077
		if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT)
已提交
1078
		    != MBX_NOT_FINISHED) {
J
James Smart 已提交
1079 1080
			lpfc_nlp_set_state(vport, ndlp,
					   NLP_STE_REG_LOGIN_ISSUE);
1081
			return ndlp->nlp_state;
已提交
1082
		}
1083 1084
		if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND)
			ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
1085 1086 1087
		/* decrement node reference count to the failed mbox
		 * command
		 */
1088
		lpfc_nlp_put(ndlp);
1089
		mp = (struct lpfc_dmabuf *) mbox->context1;
1090 1091
		lpfc_mbuf_free(phba, mp->virt, mp->phys);
		kfree(mp);
已提交
1092
		mempool_free(mbox, phba->mbox_mem_pool);
1093

1094 1095 1096 1097 1098
		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);
已提交
1099 1100
	} else {
		mempool_free(mbox, phba->mbox_mem_pool);
1101

1102 1103 1104 1105 1106
		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);
已提交
1107 1108 1109
	}


1110 1111 1112
out:
	if (ndlp->nlp_DID == NameServer_DID) {
		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
1113 1114
		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
				 "0261 Cannot Register NameServer login\n");
1115 1116
	}

1117 1118 1119 1120 1121 1122 1123
	/*
	** In case the node reference counter does not go to zero, ensure that
	** the stale state for the node is not processed.
	*/

	ndlp->nlp_prev_state = ndlp->nlp_state;
	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
1124
	spin_lock_irq(shost->host_lock);
1125
	ndlp->nlp_flag |= NLP_DEFER_RM;
1126
	spin_unlock_irq(shost->host_lock);
1127
	return NLP_STE_FREED_NODE;
已提交
1128 1129
}

1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140
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)
{
1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
	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);
	}
1153 1154 1155
	return ndlp->nlp_state;
}

已提交
1156
static uint32_t
J
James Smart 已提交
1157 1158
lpfc_device_rm_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			   void *arg, uint32_t evt)
已提交
1159
{
J
James Smart 已提交
1160 1161 1162 1163
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

	if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
		spin_lock_irq(shost->host_lock);
1164
		ndlp->nlp_flag |= NLP_NODEV_REMOVE;
J
James Smart 已提交
1165
		spin_unlock_irq(shost->host_lock);
1166
		return ndlp->nlp_state;
J
James Smart 已提交
1167
	} else {
1168
		/* software abort outstanding PLOGI */
J
James Smart 已提交
1169
		lpfc_els_abort(vport->phba, ndlp);
已提交
1170

J
James Smart 已提交
1171
		lpfc_drop_node(vport, ndlp);
1172 1173
		return NLP_STE_FREED_NODE;
	}
已提交
1174 1175 1176
}

static uint32_t
J
James Smart 已提交
1177 1178 1179 1180
lpfc_device_recov_plogi_issue(struct lpfc_vport *vport,
			      struct lpfc_nodelist *ndlp,
			      void *arg,
			      uint32_t evt)
已提交
1181
{
J
James Smart 已提交
1182 1183 1184
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba  *phba = vport->phba;

1185 1186 1187 1188 1189 1190
	/* Don't do anything that will mess up processing of the
	 * previous RSCN.
	 */
	if (vport->fc_flag & FC_RSCN_DEFERRED)
		return ndlp->nlp_state;

已提交
1191
	/* software abort outstanding PLOGI */
1192
	lpfc_els_abort(phba, ndlp);
已提交
1193

1194
	ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE;
J
James Smart 已提交
1195
	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
1196
	spin_lock_irq(shost->host_lock);
1197
	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
J
James Smart 已提交
1198
	spin_unlock_irq(shost->host_lock);
已提交
1199

1200
	return ndlp->nlp_state;
已提交
1201 1202 1203
}

static uint32_t
J
James Smart 已提交
1204 1205
lpfc_rcv_plogi_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			   void *arg, uint32_t evt)
已提交
1206
{
1207
	struct Scsi_Host   *shost = lpfc_shost_from_vport(vport);
J
James Smart 已提交
1208
	struct lpfc_hba   *phba = vport->phba;
已提交
1209 1210 1211
	struct lpfc_iocbq *cmdiocb;

	/* software abort outstanding ADISC */
1212
	lpfc_els_abort(phba, ndlp);
已提交
1213 1214 1215

	cmdiocb = (struct lpfc_iocbq *) arg;

1216 1217 1218 1219 1220
	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);
1221
			if (vport->num_disc_nodes)
1222 1223 1224 1225
				lpfc_more_adisc(vport);
		}
		return ndlp->nlp_state;
	}
1226
	ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
J
James Smart 已提交
1227 1228
	lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
	lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
已提交
1229

1230
	return ndlp->nlp_state;
已提交
1231 1232 1233
}

static uint32_t
J
James Smart 已提交
1234 1235
lpfc_rcv_prli_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
已提交
1236
{
J
James Smart 已提交
1237
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1238

J
James Smart 已提交
1239
	lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
1240
	return ndlp->nlp_state;
已提交
1241 1242 1243
}

static uint32_t
J
James Smart 已提交
1244 1245
lpfc_rcv_logo_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
已提交
1246
{
J
James Smart 已提交
1247
	struct lpfc_hba *phba = vport->phba;
已提交
1248 1249 1250 1251 1252
	struct lpfc_iocbq *cmdiocb;

	cmdiocb = (struct lpfc_iocbq *) arg;

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

J
James Smart 已提交
1255
	lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
1256
	return ndlp->nlp_state;
已提交
1257 1258 1259
}

static uint32_t
J
James Smart 已提交
1260 1261 1262
lpfc_rcv_padisc_adisc_issue(struct lpfc_vport *vport,
			    struct lpfc_nodelist *ndlp,
			    void *arg, uint32_t evt)
已提交
1263 1264 1265 1266 1267
{
	struct lpfc_iocbq *cmdiocb;

	cmdiocb = (struct lpfc_iocbq *) arg;

J
James Smart 已提交
1268
	lpfc_rcv_padisc(vport, ndlp, cmdiocb);
1269
	return ndlp->nlp_state;
已提交
1270 1271 1272
}

static uint32_t
J
James Smart 已提交
1273 1274
lpfc_rcv_prlo_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
已提交
1275 1276 1277 1278 1279 1280
{
	struct lpfc_iocbq *cmdiocb;

	cmdiocb = (struct lpfc_iocbq *) arg;

	/* Treat like rcv logo */
J
James Smart 已提交
1281
	lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_PRLO);
1282
	return ndlp->nlp_state;
已提交
1283 1284 1285
}

static uint32_t
J
James Smart 已提交
1286 1287 1288
lpfc_cmpl_adisc_adisc_issue(struct lpfc_vport *vport,
			    struct lpfc_nodelist *ndlp,
			    void *arg, uint32_t evt)
已提交
1289
{
J
James Smart 已提交
1290 1291
	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba   *phba = vport->phba;
已提交
1292 1293 1294
	struct lpfc_iocbq *cmdiocb, *rspiocb;
	IOCB_t *irsp;
	ADISC *ap;
1295
	int rc;
已提交
1296 1297 1298 1299 1300 1301 1302 1303

	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) ||
1304
	    (!lpfc_check_adisc(vport, ndlp, &ap->nodeName, &ap->portName))) {
已提交
1305 1306
		/* 1 sec timeout */
		mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
J
James Smart 已提交
1307
		spin_lock_irq(shost->host_lock);
已提交
1308
		ndlp->nlp_flag |= NLP_DELAY_TMO;
J
James Smart 已提交
1309
		spin_unlock_irq(shost->host_lock);
1310
		ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
已提交
1311

J
James Smart 已提交
1312 1313
		memset(&ndlp->nlp_nodename, 0, sizeof(struct lpfc_name));
		memset(&ndlp->nlp_portname, 0, sizeof(struct lpfc_name));
已提交
1314

1315
		ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
J
James Smart 已提交
1316 1317
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
		lpfc_unreg_rpi(vport, ndlp);
1318
		return ndlp->nlp_state;
已提交
1319
	}
1320

1321
	if (phba->sli_rev == LPFC_SLI_REV4) {
1322
		rc = lpfc_sli4_resume_rpi(ndlp, NULL, NULL);
1323 1324 1325 1326 1327 1328 1329
		if (rc) {
			/* Stay in state and retry. */
			ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
			return ndlp->nlp_state;
		}
	}

1330
	if (ndlp->nlp_type & NLP_FCP_TARGET) {
1331
		ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
J
James Smart 已提交
1332
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE);
1333
	} else {
1334
		ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
J
James Smart 已提交
1335
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
1336
	}
1337

1338
	return ndlp->nlp_state;
已提交
1339 1340 1341
}

static uint32_t
J
James Smart 已提交
1342 1343
lpfc_device_rm_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			   void *arg, uint32_t evt)
已提交
1344
{
J
James Smart 已提交
1345 1346 1347 1348
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

	if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
		spin_lock_irq(shost->host_lock);
1349
		ndlp->nlp_flag |= NLP_NODEV_REMOVE;
J
James Smart 已提交
1350
		spin_unlock_irq(shost->host_lock);
1351
		return ndlp->nlp_state;
J
James Smart 已提交
1352
	} else {
1353
		/* software abort outstanding ADISC */
J
James Smart 已提交
1354
		lpfc_els_abort(vport->phba, ndlp);
已提交
1355

J
James Smart 已提交
1356
		lpfc_drop_node(vport, ndlp);
1357 1358
		return NLP_STE_FREED_NODE;
	}
已提交
1359 1360 1361
}

static uint32_t
J
James Smart 已提交
1362 1363 1364 1365
lpfc_device_recov_adisc_issue(struct lpfc_vport *vport,
			      struct lpfc_nodelist *ndlp,
			      void *arg,
			      uint32_t evt)
已提交
1366
{
J
James Smart 已提交
1367 1368 1369
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba  *phba = vport->phba;

1370 1371 1372 1373 1374 1375
	/* Don't do anything that will mess up processing of the
	 * previous RSCN.
	 */
	if (vport->fc_flag & FC_RSCN_DEFERRED)
		return ndlp->nlp_state;

已提交
1376
	/* software abort outstanding ADISC */
1377
	lpfc_els_abort(phba, ndlp);
已提交
1378

1379
	ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
J
James Smart 已提交
1380 1381
	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
	spin_lock_irq(shost->host_lock);
1382
	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
J
James Smart 已提交
1383
	spin_unlock_irq(shost->host_lock);
1384
	lpfc_disc_set_adisc(vport, ndlp);
1385
	return ndlp->nlp_state;
已提交
1386 1387 1388
}

static uint32_t
J
James Smart 已提交
1389 1390 1391
lpfc_rcv_plogi_reglogin_issue(struct lpfc_vport *vport,
			      struct lpfc_nodelist *ndlp,
			      void *arg,
已提交
1392 1393
			      uint32_t evt)
{
J
James Smart 已提交
1394
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1395

J
James Smart 已提交
1396
	lpfc_rcv_plogi(vport, ndlp, cmdiocb);
1397
	return ndlp->nlp_state;
已提交
1398 1399 1400
}

static uint32_t
J
James Smart 已提交
1401 1402 1403
lpfc_rcv_prli_reglogin_issue(struct lpfc_vport *vport,
			     struct lpfc_nodelist *ndlp,
			     void *arg,
已提交
1404 1405
			     uint32_t evt)
{
J
James Smart 已提交
1406
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1407

J
James Smart 已提交
1408
	lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
1409
	return ndlp->nlp_state;
已提交
1410 1411 1412
}

static uint32_t
J
James Smart 已提交
1413 1414 1415
lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport,
			     struct lpfc_nodelist *ndlp,
			     void *arg,
已提交
1416 1417
			     uint32_t evt)
{
J
James Smart 已提交
1418 1419
	struct lpfc_hba   *phba = vport->phba;
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
1420 1421 1422
	LPFC_MBOXQ_t	  *mb;
	LPFC_MBOXQ_t	  *nextmb;
	struct lpfc_dmabuf *mp;
已提交
1423 1424 1425

	cmdiocb = (struct lpfc_iocbq *) arg;

1426 1427
	/* cleanup any ndlp on mbox q waiting for reglogin cmpl */
	if ((mb = phba->sli.mbox_active)) {
1428
		if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) &&
1429
		   (ndlp == (struct lpfc_nodelist *) mb->context2)) {
1430
			lpfc_nlp_put(ndlp);
1431 1432 1433 1434 1435
			mb->context2 = NULL;
			mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
		}
	}

J
James Smart 已提交
1436
	spin_lock_irq(&phba->hbalock);
1437
	list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
1438
		if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) &&
1439 1440 1441
		   (ndlp == (struct lpfc_nodelist *) mb->context2)) {
			mp = (struct lpfc_dmabuf *) (mb->context1);
			if (mp) {
1442
				__lpfc_mbuf_free(phba, mp->virt, mp->phys);
1443 1444
				kfree(mp);
			}
1445
			lpfc_nlp_put(ndlp);
1446
			list_del(&mb->list);
1447
			phba->sli.mboxq_cnt--;
1448 1449 1450
			mempool_free(mb, phba->mbox_mem_pool);
		}
	}
J
James Smart 已提交
1451
	spin_unlock_irq(&phba->hbalock);
1452

J
James Smart 已提交
1453
	lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
1454
	return ndlp->nlp_state;
已提交
1455 1456 1457
}

static uint32_t
J
James Smart 已提交
1458 1459 1460
lpfc_rcv_padisc_reglogin_issue(struct lpfc_vport *vport,
			       struct lpfc_nodelist *ndlp,
			       void *arg,
已提交
1461 1462
			       uint32_t evt)
{
J
James Smart 已提交
1463
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1464

J
James Smart 已提交
1465
	lpfc_rcv_padisc(vport, ndlp, cmdiocb);
1466
	return ndlp->nlp_state;
已提交
1467 1468 1469
}

static uint32_t
J
James Smart 已提交
1470 1471 1472
lpfc_rcv_prlo_reglogin_issue(struct lpfc_vport *vport,
			     struct lpfc_nodelist *ndlp,
			     void *arg,
已提交
1473 1474 1475 1476 1477
			     uint32_t evt)
{
	struct lpfc_iocbq *cmdiocb;

	cmdiocb = (struct lpfc_iocbq *) arg;
1478
	lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
1479
	return ndlp->nlp_state;
已提交
1480 1481 1482
}

static uint32_t
J
James Smart 已提交
1483 1484 1485 1486
lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport,
				  struct lpfc_nodelist *ndlp,
				  void *arg,
				  uint32_t evt)
已提交
1487
{
J
James Smart 已提交
1488 1489
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
1490
	MAILBOX_t *mb = &pmb->u.mb;
J
James Smart 已提交
1491
	uint32_t did  = mb->un.varWords[1];
已提交
1492 1493 1494

	if (mb->mbxStatus) {
		/* RegLogin failed */
1495
		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
1496 1497 1498 1499 1500
				"0246 RegLogin failed Data: x%x x%x x%x x%x "
				 "x%x\n",
				 did, mb->mbxStatus, vport->port_state,
				 mb->un.varRegLogin.vpi,
				 mb->un.varRegLogin.rpi);
1501 1502 1503 1504 1505
		/*
		 * If RegLogin failed due to lack of HBA resources do not
		 * retry discovery.
		 */
		if (mb->mbxStatus == MBXERR_RPI_FULL) {
1506 1507
			ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
			lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
1508 1509 1510
			return ndlp->nlp_state;
		}

J
James Smart 已提交
1511
		/* Put ndlp in npr state set plogi timer for 1 sec */
已提交
1512
		mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
J
James Smart 已提交
1513
		spin_lock_irq(shost->host_lock);
已提交
1514
		ndlp->nlp_flag |= NLP_DELAY_TMO;
J
James Smart 已提交
1515
		spin_unlock_irq(shost->host_lock);
1516
		ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
已提交
1517

J
James Smart 已提交
1518
		lpfc_issue_els_logo(vport, ndlp, 0);
1519
		ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
J
James Smart 已提交
1520
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
1521
		return ndlp->nlp_state;
已提交
1522 1523
	}

1524 1525 1526 1527
	/* SLI4 ports have preallocated logical rpis. */
	if (vport->phba->sli_rev < LPFC_SLI_REV4)
		ndlp->nlp_rpi = mb->un.varWords[0];

1528
	ndlp->nlp_flag |= NLP_RPI_REGISTERED;
已提交
1529 1530 1531

	/* Only if we are not a fabric nport do we issue PRLI */
	if (!(ndlp->nlp_type & NLP_FABRIC)) {
1532
		ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
J
James Smart 已提交
1533 1534
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
		lpfc_issue_els_prli(vport, ndlp, 0);
已提交
1535
	} else {
1536
		ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
J
James Smart 已提交
1537
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
已提交
1538
	}
1539
	return ndlp->nlp_state;
已提交
1540 1541 1542
}

static uint32_t
J
James Smart 已提交
1543 1544 1545
lpfc_device_rm_reglogin_issue(struct lpfc_vport *vport,
			      struct lpfc_nodelist *ndlp,
			      void *arg,
已提交
1546 1547
			      uint32_t evt)
{
J
James Smart 已提交
1548 1549 1550 1551
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

	if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
		spin_lock_irq(shost->host_lock);
1552
		ndlp->nlp_flag |= NLP_NODEV_REMOVE;
J
James Smart 已提交
1553
		spin_unlock_irq(shost->host_lock);
1554
		return ndlp->nlp_state;
J
James Smart 已提交
1555 1556
	} else {
		lpfc_drop_node(vport, ndlp);
1557 1558
		return NLP_STE_FREED_NODE;
	}
已提交
1559 1560 1561
}

static uint32_t
J
James Smart 已提交
1562 1563 1564 1565
lpfc_device_recov_reglogin_issue(struct lpfc_vport *vport,
				 struct lpfc_nodelist *ndlp,
				 void *arg,
				 uint32_t evt)
已提交
1566
{
J
James Smart 已提交
1567 1568
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

1569 1570 1571 1572 1573 1574
	/* Don't do anything that will mess up processing of the
	 * previous RSCN.
	 */
	if (vport->fc_flag & FC_RSCN_DEFERRED)
		return ndlp->nlp_state;

1575
	ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
J
James Smart 已提交
1576 1577
	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
	spin_lock_irq(shost->host_lock);
1578
	ndlp->nlp_flag |= NLP_IGNR_REG_CMPL;
1579
	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
J
James Smart 已提交
1580
	spin_unlock_irq(shost->host_lock);
1581
	lpfc_disc_set_adisc(vport, ndlp);
1582
	return ndlp->nlp_state;
已提交
1583 1584 1585
}

static uint32_t
J
James Smart 已提交
1586 1587
lpfc_rcv_plogi_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
已提交
1588 1589 1590 1591 1592
{
	struct lpfc_iocbq *cmdiocb;

	cmdiocb = (struct lpfc_iocbq *) arg;

J
James Smart 已提交
1593
	lpfc_rcv_plogi(vport, ndlp, cmdiocb);
1594
	return ndlp->nlp_state;
已提交
1595 1596 1597
}

static uint32_t
J
James Smart 已提交
1598 1599
lpfc_rcv_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			 void *arg, uint32_t evt)
已提交
1600
{
J
James Smart 已提交
1601
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1602

J
James Smart 已提交
1603
	lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
1604
	return ndlp->nlp_state;
已提交
1605 1606 1607
}

static uint32_t
J
James Smart 已提交
1608 1609
lpfc_rcv_logo_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			 void *arg, uint32_t evt)
已提交
1610
{
J
James Smart 已提交
1611
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1612 1613

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

J
James Smart 已提交
1616
	lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
1617
	return ndlp->nlp_state;
已提交
1618 1619 1620
}

static uint32_t
J
James Smart 已提交
1621 1622
lpfc_rcv_padisc_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			   void *arg, uint32_t evt)
已提交
1623
{
J
James Smart 已提交
1624
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1625

J
James Smart 已提交
1626
	lpfc_rcv_padisc(vport, ndlp, cmdiocb);
1627
	return ndlp->nlp_state;
已提交
1628 1629 1630 1631 1632 1633 1634 1635
}

/* 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 已提交
1636 1637
lpfc_rcv_prlo_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			 void *arg, uint32_t evt)
已提交
1638
{
J
James Smart 已提交
1639
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1640

1641
	lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
1642
	return ndlp->nlp_state;
已提交
1643 1644 1645
}

static uint32_t
J
James Smart 已提交
1646 1647
lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
已提交
1648
{
1649
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
已提交
1650
	struct lpfc_iocbq *cmdiocb, *rspiocb;
J
James Smart 已提交
1651
	struct lpfc_hba   *phba = vport->phba;
已提交
1652 1653 1654 1655 1656 1657 1658 1659 1660
	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 已提交
1661
		if ((vport->port_type == LPFC_NPIV_PORT) &&
1662
		    vport->cfg_restrict_login) {
J
James Smart 已提交
1663 1664
			goto out;
		}
1665
		ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
J
James Smart 已提交
1666
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
1667
		return ndlp->nlp_state;
已提交
1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681
	}

	/* 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;
	}
1682 1683
	if (!(ndlp->nlp_type & NLP_FCP_TARGET) &&
	    (vport->port_type == LPFC_NPIV_PORT) &&
1684
	     vport->cfg_restrict_login) {
J
James Smart 已提交
1685
out:
1686 1687 1688 1689 1690 1691
		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;
1692
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
1693 1694
		return ndlp->nlp_state;
	}
已提交
1695

1696
	ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
1697 1698 1699 1700
	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);
1701
	return ndlp->nlp_state;
已提交
1702 1703 1704
}

/*! lpfc_device_rm_prli_issue
1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721
 *
 * \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.
 *
 */

已提交
1722
static uint32_t
J
James Smart 已提交
1723 1724
lpfc_device_rm_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
已提交
1725
{
J
James Smart 已提交
1726 1727 1728 1729
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

	if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
		spin_lock_irq(shost->host_lock);
1730
		ndlp->nlp_flag |= NLP_NODEV_REMOVE;
J
James Smart 已提交
1731
		spin_unlock_irq(shost->host_lock);
1732
		return ndlp->nlp_state;
J
James Smart 已提交
1733
	} else {
1734
		/* software abort outstanding PLOGI */
J
James Smart 已提交
1735
		lpfc_els_abort(vport->phba, ndlp);
已提交
1736

J
James Smart 已提交
1737
		lpfc_drop_node(vport, ndlp);
1738 1739
		return NLP_STE_FREED_NODE;
	}
已提交
1740 1741 1742 1743
}


/*! lpfc_device_recov_prli_issue
1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758
 *
 * \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.
 */
已提交
1759
static uint32_t
J
James Smart 已提交
1760 1761 1762 1763
lpfc_device_recov_prli_issue(struct lpfc_vport *vport,
			     struct lpfc_nodelist *ndlp,
			     void *arg,
			     uint32_t evt)
已提交
1764
{
J
James Smart 已提交
1765 1766 1767
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba  *phba = vport->phba;

1768 1769 1770 1771 1772 1773
	/* Don't do anything that will mess up processing of the
	 * previous RSCN.
	 */
	if (vport->fc_flag & FC_RSCN_DEFERRED)
		return ndlp->nlp_state;

已提交
1774
	/* software abort outstanding PRLI */
1775
	lpfc_els_abort(phba, ndlp);
已提交
1776

1777
	ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
J
James Smart 已提交
1778 1779
	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
	spin_lock_irq(shost->host_lock);
1780
	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
J
James Smart 已提交
1781
	spin_unlock_irq(shost->host_lock);
1782
	lpfc_disc_set_adisc(vport, ndlp);
1783
	return ndlp->nlp_state;
已提交
1784 1785
}

1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896
static uint32_t
lpfc_rcv_plogi_logo_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_UNABLE_TPC;
	stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
	return ndlp->nlp_state;
}

static uint32_t
lpfc_rcv_prli_logo_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_UNABLE_TPC;
	stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
	return ndlp->nlp_state;
}

static uint32_t
lpfc_rcv_logo_logo_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			 void *arg, uint32_t evt)
{
	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *)arg;

	spin_lock_irq(shost->host_lock);
	ndlp->nlp_flag &= NLP_LOGO_ACC;
	spin_unlock_irq(shost->host_lock);
	lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
	return ndlp->nlp_state;
}

static uint32_t
lpfc_rcv_padisc_logo_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_UNABLE_TPC;
	stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
	return ndlp->nlp_state;
}

static uint32_t
lpfc_rcv_prlo_logo_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_UNABLE_TPC;
	stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
	return ndlp->nlp_state;
}

static uint32_t
lpfc_cmpl_logo_logo_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
{
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

	ndlp->nlp_prev_state = NLP_STE_LOGO_ISSUE;
	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
	spin_lock_irq(shost->host_lock);
	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
	spin_unlock_irq(shost->host_lock);
	lpfc_disc_set_adisc(vport, ndlp);
	return ndlp->nlp_state;
}

static uint32_t
lpfc_device_rm_logo_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
{
	/*
	 * Take no action.  If a LOGO is outstanding, then possibly DevLoss has
	 * timed out and is calling for Device Remove.  In this case, the LOGO
	 * must be allowed to complete in state LOGO_ISSUE so that the rpi
	 * and other NLP flags are correctly cleaned up.
	 */
	return ndlp->nlp_state;
}

static uint32_t
lpfc_device_recov_logo_issue(struct lpfc_vport *vport,
			     struct lpfc_nodelist *ndlp,
			     void *arg, uint32_t evt)
{
	/*
	 * Device Recovery events have no meaning for a node with a LOGO
	 * outstanding.  The LOGO has to complete first and handle the
	 * node from that point.
	 */
	return ndlp->nlp_state;
}

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

J
James Smart 已提交
1903
	lpfc_rcv_plogi(vport, ndlp, cmdiocb);
1904
	return ndlp->nlp_state;
已提交
1905 1906 1907
}

static uint32_t
J
James Smart 已提交
1908 1909
lpfc_rcv_prli_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			 void *arg, uint32_t evt)
已提交
1910
{
J
James Smart 已提交
1911
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1912

J
James Smart 已提交
1913 1914
	lpfc_rcv_prli(vport, ndlp, cmdiocb);
	lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
1915
	return ndlp->nlp_state;
已提交
1916 1917 1918
}

static uint32_t
J
James Smart 已提交
1919 1920
lpfc_rcv_logo_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			 void *arg, uint32_t evt)
已提交
1921
{
J
James Smart 已提交
1922
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1923

J
James Smart 已提交
1924
	lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
1925
	return ndlp->nlp_state;
已提交
1926 1927 1928
}

static uint32_t
J
James Smart 已提交
1929 1930
lpfc_rcv_padisc_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			   void *arg, uint32_t evt)
已提交
1931
{
J
James Smart 已提交
1932
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1933

J
James Smart 已提交
1934
	lpfc_rcv_padisc(vport, ndlp, cmdiocb);
1935
	return ndlp->nlp_state;
已提交
1936 1937 1938
}

static uint32_t
J
James Smart 已提交
1939 1940
lpfc_rcv_prlo_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			 void *arg, uint32_t evt)
已提交
1941
{
J
James Smart 已提交
1942
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1943

1944
	lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
1945
	return ndlp->nlp_state;
已提交
1946 1947 1948
}

static uint32_t
J
James Smart 已提交
1949 1950 1951 1952
lpfc_device_recov_unmap_node(struct lpfc_vport *vport,
			     struct lpfc_nodelist *ndlp,
			     void *arg,
			     uint32_t evt)
已提交
1953
{
J
James Smart 已提交
1954 1955
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

1956
	ndlp->nlp_prev_state = NLP_STE_UNMAPPED_NODE;
J
James Smart 已提交
1957 1958
	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
	spin_lock_irq(shost->host_lock);
1959
	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
J
James Smart 已提交
1960 1961
	spin_unlock_irq(shost->host_lock);
	lpfc_disc_set_adisc(vport, ndlp);
已提交
1962

1963
	return ndlp->nlp_state;
已提交
1964 1965 1966
}

static uint32_t
J
James Smart 已提交
1967 1968
lpfc_rcv_plogi_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			   void *arg, uint32_t evt)
已提交
1969
{
J
James Smart 已提交
1970
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1971

J
James Smart 已提交
1972
	lpfc_rcv_plogi(vport, ndlp, cmdiocb);
1973
	return ndlp->nlp_state;
已提交
1974 1975 1976
}

static uint32_t
J
James Smart 已提交
1977 1978
lpfc_rcv_prli_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
已提交
1979
{
J
James Smart 已提交
1980
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1981

J
James Smart 已提交
1982
	lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
1983
	return ndlp->nlp_state;
已提交
1984 1985 1986
}

static uint32_t
J
James Smart 已提交
1987 1988
lpfc_rcv_logo_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
已提交
1989
{
J
James Smart 已提交
1990
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
1991

J
James Smart 已提交
1992
	lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
1993
	return ndlp->nlp_state;
已提交
1994 1995 1996
}

static uint32_t
J
James Smart 已提交
1997 1998 1999
lpfc_rcv_padisc_mapped_node(struct lpfc_vport *vport,
			    struct lpfc_nodelist *ndlp,
			    void *arg, uint32_t evt)
已提交
2000
{
J
James Smart 已提交
2001
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
2002

J
James Smart 已提交
2003
	lpfc_rcv_padisc(vport, ndlp, cmdiocb);
2004
	return ndlp->nlp_state;
已提交
2005 2006 2007
}

static uint32_t
J
James Smart 已提交
2008 2009
lpfc_rcv_prlo_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  void *arg, uint32_t evt)
已提交
2010
{
J
James Smart 已提交
2011 2012
	struct lpfc_hba  *phba = vport->phba;
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
2013 2014

	/* flush the target */
2015 2016
	lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring],
			    ndlp->nlp_sid, 0, LPFC_CTX_TGT);
已提交
2017 2018

	/* Treat like rcv logo */
J
James Smart 已提交
2019
	lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_PRLO);
2020
	return ndlp->nlp_state;
已提交
2021 2022 2023
}

static uint32_t
J
James Smart 已提交
2024 2025 2026 2027
lpfc_device_recov_mapped_node(struct lpfc_vport *vport,
			      struct lpfc_nodelist *ndlp,
			      void *arg,
			      uint32_t evt)
已提交
2028
{
J
James Smart 已提交
2029 2030
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

2031
	ndlp->nlp_prev_state = NLP_STE_MAPPED_NODE;
J
James Smart 已提交
2032 2033
	lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
	spin_lock_irq(shost->host_lock);
2034
	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
J
James Smart 已提交
2035 2036
	spin_unlock_irq(shost->host_lock);
	lpfc_disc_set_adisc(vport, ndlp);
2037
	return ndlp->nlp_state;
已提交
2038 2039 2040
}

static uint32_t
J
James Smart 已提交
2041 2042
lpfc_rcv_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			void *arg, uint32_t evt)
已提交
2043
{
J
James Smart 已提交
2044 2045
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	struct lpfc_iocbq *cmdiocb  = (struct lpfc_iocbq *) arg;
已提交
2046 2047

	/* Ignore PLOGI if we have an outstanding LOGO */
2048
	if (ndlp->nlp_flag & (NLP_LOGO_SND | NLP_LOGO_ACC))
2049
		return ndlp->nlp_state;
J
James Smart 已提交
2050
	if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) {
2051
		lpfc_cancel_retry_delay_tmo(vport, ndlp);
J
James Smart 已提交
2052
		spin_lock_irq(shost->host_lock);
2053
		ndlp->nlp_flag &= ~(NLP_NPR_ADISC | NLP_NPR_2B_DISC);
J
James Smart 已提交
2054
		spin_unlock_irq(shost->host_lock);
2055 2056 2057 2058 2059 2060 2061
	} 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);
		}
已提交
2062
	}
2063
	return ndlp->nlp_state;
已提交
2064 2065 2066
}

static uint32_t
J
James Smart 已提交
2067 2068
lpfc_rcv_prli_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
		       void *arg, uint32_t evt)
已提交
2069
{
J
James Smart 已提交
2070 2071 2072
	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
	struct ls_rjt     stat;
已提交
2073 2074 2075 2076

	memset(&stat, 0, sizeof (struct ls_rjt));
	stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
	stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
J
James Smart 已提交
2077
	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
已提交
2078 2079 2080

	if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
		if (ndlp->nlp_flag & NLP_NPR_ADISC) {
J
James Smart 已提交
2081
			spin_lock_irq(shost->host_lock);
2082
			ndlp->nlp_flag &= ~NLP_NPR_ADISC;
2083
			ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
J
James Smart 已提交
2084 2085 2086
			spin_unlock_irq(shost->host_lock);
			lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
			lpfc_issue_els_adisc(vport, ndlp, 0);
已提交
2087
		} else {
2088
			ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
J
James Smart 已提交
2089 2090
			lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
			lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
已提交
2091 2092
		}
	}
2093
	return ndlp->nlp_state;
已提交
2094 2095 2096
}

static uint32_t
J
James Smart 已提交
2097 2098
lpfc_rcv_logo_npr_node(struct lpfc_vport *vport,  struct lpfc_nodelist *ndlp,
		       void *arg, uint32_t evt)
已提交
2099
{
J
James Smart 已提交
2100
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
2101

J
James Smart 已提交
2102
	lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
2103
	return ndlp->nlp_state;
已提交
2104 2105 2106
}

static uint32_t
J
James Smart 已提交
2107 2108
lpfc_rcv_padisc_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			 void *arg, uint32_t evt)
已提交
2109
{
J
James Smart 已提交
2110
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
2111

J
James Smart 已提交
2112
	lpfc_rcv_padisc(vport, ndlp, cmdiocb);
J
James Smart 已提交
2113 2114 2115 2116 2117
	/*
	 * 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 已提交
2118
	if (!(ndlp->nlp_flag & NLP_DELAY_TMO) &&
2119
	    !(ndlp->nlp_flag & NLP_NPR_2B_DISC)) {
已提交
2120
		if (ndlp->nlp_flag & NLP_NPR_ADISC) {
2121
			ndlp->nlp_flag &= ~NLP_NPR_ADISC;
2122
			ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
J
James Smart 已提交
2123 2124
			lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
			lpfc_issue_els_adisc(vport, ndlp, 0);
已提交
2125
		} else {
2126
			ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
J
James Smart 已提交
2127 2128
			lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
			lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
已提交
2129 2130
		}
	}
2131
	return ndlp->nlp_state;
已提交
2132 2133 2134
}

static uint32_t
J
James Smart 已提交
2135 2136
lpfc_rcv_prlo_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
		       void *arg, uint32_t evt)
已提交
2137
{
J
James Smart 已提交
2138 2139
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
已提交
2140

J
James Smart 已提交
2141
	spin_lock_irq(shost->host_lock);
2142
	ndlp->nlp_flag |= NLP_LOGO_ACC;
J
James Smart 已提交
2143
	spin_unlock_irq(shost->host_lock);
2144

2145
	lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
已提交
2146

J
James Smart 已提交
2147
	if ((ndlp->nlp_flag & NLP_DELAY_TMO) == 0) {
2148
		mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
J
James Smart 已提交
2149
		spin_lock_irq(shost->host_lock);
2150 2151
		ndlp->nlp_flag |= NLP_DELAY_TMO;
		ndlp->nlp_flag &= ~NLP_NPR_ADISC;
J
James Smart 已提交
2152
		spin_unlock_irq(shost->host_lock);
2153
		ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
2154
	} else {
J
James Smart 已提交
2155
		spin_lock_irq(shost->host_lock);
2156
		ndlp->nlp_flag &= ~NLP_NPR_ADISC;
J
James Smart 已提交
2157
		spin_unlock_irq(shost->host_lock);
已提交
2158
	}
2159 2160
	return ndlp->nlp_state;
}
已提交
2161

2162
static uint32_t
J
James Smart 已提交
2163 2164
lpfc_cmpl_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			 void *arg, uint32_t evt)
2165 2166
{
	struct lpfc_iocbq *cmdiocb, *rspiocb;
2167
	IOCB_t *irsp;
2168
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
2169 2170 2171

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

	irsp = &rspiocb->iocb;
	if (irsp->ulpStatus) {
2175
		spin_lock_irq(shost->host_lock);
2176
		ndlp->nlp_flag |= NLP_DEFER_RM;
2177
		spin_unlock_irq(shost->host_lock);
2178 2179
		return NLP_STE_FREED_NODE;
	}
2180 2181 2182 2183
	return ndlp->nlp_state;
}

static uint32_t
J
James Smart 已提交
2184 2185
lpfc_cmpl_prli_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			void *arg, uint32_t evt)
2186 2187
{
	struct lpfc_iocbq *cmdiocb, *rspiocb;
2188
	IOCB_t *irsp;
2189 2190 2191

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

	irsp = &rspiocb->iocb;
	if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) {
J
James Smart 已提交
2195
		lpfc_drop_node(vport, ndlp);
2196 2197
		return NLP_STE_FREED_NODE;
	}
2198
	return ndlp->nlp_state;
已提交
2199 2200 2201
}

static uint32_t
J
James Smart 已提交
2202 2203
lpfc_cmpl_logo_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			void *arg, uint32_t evt)
已提交
2204
{
2205
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
2206 2207

	/* For the fabric port just clear the fc flags. */
2208 2209 2210 2211 2212
	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 已提交
2213
	lpfc_unreg_rpi(vport, ndlp);
2214 2215 2216 2217
	return ndlp->nlp_state;
}

static uint32_t
J
James Smart 已提交
2218 2219
lpfc_cmpl_adisc_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			 void *arg, uint32_t evt)
2220 2221
{
	struct lpfc_iocbq *cmdiocb, *rspiocb;
2222
	IOCB_t *irsp;
2223 2224 2225

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

	irsp = &rspiocb->iocb;
	if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) {
J
James Smart 已提交
2229
		lpfc_drop_node(vport, ndlp);
2230 2231
		return NLP_STE_FREED_NODE;
	}
2232
	return ndlp->nlp_state;
已提交
2233 2234 2235
}

static uint32_t
J
James Smart 已提交
2236 2237 2238
lpfc_cmpl_reglogin_npr_node(struct lpfc_vport *vport,
			    struct lpfc_nodelist *ndlp,
			    void *arg, uint32_t evt)
已提交
2239
{
J
James Smart 已提交
2240
	LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
2241
	MAILBOX_t    *mb = &pmb->u.mb;
已提交
2242

2243
	if (!mb->mbxStatus) {
2244 2245 2246
		/* SLI4 ports have preallocated logical rpis. */
		if (vport->phba->sli_rev < LPFC_SLI_REV4)
			ndlp->nlp_rpi = mb->un.varWords[0];
2247
		ndlp->nlp_flag |= NLP_RPI_REGISTERED;
2248
	} else {
2249
		if (ndlp->nlp_flag & NLP_NODEV_REMOVE) {
J
James Smart 已提交
2250
			lpfc_drop_node(vport, ndlp);
2251 2252 2253
			return NLP_STE_FREED_NODE;
		}
	}
2254
	return ndlp->nlp_state;
已提交
2255 2256 2257
}

static uint32_t
J
James Smart 已提交
2258 2259
lpfc_device_rm_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			void *arg, uint32_t evt)
已提交
2260
{
J
James Smart 已提交
2261 2262
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

2263
	if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
J
James Smart 已提交
2264
		spin_lock_irq(shost->host_lock);
2265
		ndlp->nlp_flag |= NLP_NODEV_REMOVE;
J
James Smart 已提交
2266
		spin_unlock_irq(shost->host_lock);
2267 2268
		return ndlp->nlp_state;
	}
J
James Smart 已提交
2269
	lpfc_drop_node(vport, ndlp);
2270
	return NLP_STE_FREED_NODE;
已提交
2271 2272 2273
}

static uint32_t
J
James Smart 已提交
2274 2275
lpfc_device_recov_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			   void *arg, uint32_t evt)
已提交
2276
{
J
James Smart 已提交
2277 2278
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

2279 2280 2281 2282 2283 2284
	/* Don't do anything that will mess up processing of the
	 * previous RSCN.
	 */
	if (vport->fc_flag & FC_RSCN_DEFERRED)
		return ndlp->nlp_state;

2285
	lpfc_cancel_retry_delay_tmo(vport, ndlp);
J
James Smart 已提交
2286
	spin_lock_irq(shost->host_lock);
2287
	ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
J
James Smart 已提交
2288
	spin_unlock_irq(shost->host_lock);
2289
	return ndlp->nlp_state;
已提交
2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324
}


/* 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
2325
 * lists will receive a DEVICE_RECOVERY event. If the linkdown or devloss timers
已提交
2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349
 * 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 已提交
2350
     (struct lpfc_vport *, struct lpfc_nodelist *, void *, uint32_t) = {
已提交
2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363
	/* 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       */
2364
	lpfc_device_recov_unused_node,	/* DEVICE_RECOVERY */
已提交
2365 2366

	lpfc_rcv_plogi_plogi_issue,	/* RCV_PLOGI   PLOGI_ISSUE    */
2367
	lpfc_rcv_prli_plogi_issue,	/* RCV_PRLI        */
2368
	lpfc_rcv_logo_plogi_issue,	/* RCV_LOGO        */
已提交
2369 2370 2371 2372 2373
	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       */
2374
	lpfc_cmpl_logo_plogi_issue,	/* CMPL_LOGO       */
已提交
2375
	lpfc_disc_illegal,		/* CMPL_ADISC      */
2376
	lpfc_cmpl_reglogin_plogi_issue,/* CMPL_REG_LOGIN  */
已提交
2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399
	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        */
2400
	lpfc_cmpl_plogi_illegal,	/* CMPL_PLOGI      */
已提交
2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413
	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        */
2414
	lpfc_cmpl_plogi_illegal,	/* CMPL_PLOGI      */
已提交
2415 2416 2417 2418 2419 2420 2421
	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 */

2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435
	lpfc_rcv_plogi_logo_issue,	/* RCV_PLOGI   LOGO_ISSUE     */
	lpfc_rcv_prli_logo_issue,	/* RCV_PRLI        */
	lpfc_rcv_logo_logo_issue,	/* RCV_LOGO        */
	lpfc_rcv_padisc_logo_issue,	/* RCV_ADISC       */
	lpfc_rcv_padisc_logo_issue,	/* RCV_PDISC       */
	lpfc_rcv_prlo_logo_issue,	/* RCV_PRLO        */
	lpfc_cmpl_plogi_illegal,	/* CMPL_PLOGI      */
	lpfc_disc_illegal,		/* CMPL_PRLI       */
	lpfc_cmpl_logo_logo_issue,	/* CMPL_LOGO       */
	lpfc_disc_illegal,		/* CMPL_ADISC      */
	lpfc_disc_illegal,		/* CMPL_REG_LOGIN  */
	lpfc_device_rm_logo_issue,	/* DEVICE_RM       */
	lpfc_device_recov_logo_issue,	/* DEVICE_RECOVERY */

已提交
2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469
	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        */
2470 2471
	lpfc_cmpl_plogi_npr_node,	/* CMPL_PLOGI      */
	lpfc_cmpl_prli_npr_node,	/* CMPL_PRLI       */
已提交
2472
	lpfc_cmpl_logo_npr_node,        /* CMPL_LOGO       */
2473
	lpfc_cmpl_adisc_npr_node,       /* CMPL_ADISC      */
已提交
2474 2475 2476 2477 2478 2479
	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 已提交
2480 2481
lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			void *arg, uint32_t evt)
已提交
2482 2483
{
	uint32_t cur_state, rc;
J
James Smart 已提交
2484
	uint32_t(*func) (struct lpfc_vport *, struct lpfc_nodelist *, void *,
已提交
2485
			 uint32_t);
2486 2487 2488 2489
	uint32_t got_ndlp = 0;

	if (lpfc_nlp_get(ndlp))
		got_ndlp = 1;
已提交
2490 2491 2492 2493

	cur_state = ndlp->nlp_state;

	/* DSM in event <evt> on NPort <nlp_DID> in state <cur_state> */
2494 2495 2496 2497
	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);
已提交
2498

J
James Smart 已提交
2499 2500 2501 2502
	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM,
		 "DSM in:          evt:%d ste:%d did:x%x",
		evt, cur_state, ndlp->nlp_DID);

已提交
2503
	func = lpfc_disc_action[(cur_state * NLP_EVT_MAX_EVENT) + evt];
J
James Smart 已提交
2504
	rc = (func) (vport, ndlp, arg, evt);
已提交
2505 2506

	/* DSM out state <rc> on NPort <nlp_DID> */
2507 2508
	if (got_ndlp) {
		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
2509 2510
			 "0212 DSM out state %d on NPort x%x Data: x%x\n",
			 rc, ndlp->nlp_DID, ndlp->nlp_flag);
已提交
2511

2512 2513 2514 2515 2516 2517 2518
		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,
2519
			"0213 DSM out state %d on NPort free\n", rc);
J
James Smart 已提交
2520

2521 2522 2523 2524
		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM,
			"DSM out:         ste:%d did:x%x flg:x%x",
			rc, 0, 0);
	}
已提交
2525

2526
	return rc;
已提交
2527
}