lpfc_els.c 94.9 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-2007 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 24 25
 *******************************************************************/

#include <linux/blkdev.h>
#include <linux/pci.h>
#include <linux/interrupt.h>

26
#include <scsi/scsi.h>
已提交
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport_fc.h>

#include "lpfc_hw.h"
#include "lpfc_sli.h"
#include "lpfc_disc.h"
#include "lpfc_scsi.h"
#include "lpfc.h"
#include "lpfc_logmsg.h"
#include "lpfc_crtn.h"

static int lpfc_els_retry(struct lpfc_hba *, struct lpfc_iocbq *,
			  struct lpfc_iocbq *);
static int lpfc_max_els_tries = 3;

static int
J
James Smart 已提交
44
lpfc_els_chk_latt(struct lpfc_vport *vport)
已提交
45
{
J
James Smart 已提交
46 47
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba  *phba = vport->phba;
已提交
48 49
	uint32_t ha_copy;

J
James Smart 已提交
50 51
	if (vport->port_state >= LPFC_VPORT_READY ||
	    phba->link_state == LPFC_LINK_DOWN)
已提交
52 53 54 55 56 57 58 59 60 61 62 63
		return 0;

	/* Read the HBA Host Attention Register */
	ha_copy = readl(phba->HAregaddr);

	if (!(ha_copy & HA_LATT))
		return 0;

	/* Pending Link Event during Discovery */
	lpfc_printf_log(phba, KERN_WARNING, LOG_DISCOVERY,
			"%d:0237 Pending Link Event during "
			"Discovery: State x%x\n",
J
James Smart 已提交
64
			phba->brd_no, phba->pport->port_state);
已提交
65 66 67 68 69 70 71

	/* CLEAR_LA should re-enable link attention events and
	 * we should then imediately take a LATT event. The
	 * LATT processing should call lpfc_linkdown() which
	 * will cleanup any left over in-progress discovery
	 * events.
	 */
J
James Smart 已提交
72 73 74
	spin_lock_irq(shost->host_lock);
	vport->fc_flag |= FC_ABORT_DISCOVERY;
	spin_unlock_irq(shost->host_lock);
已提交
75

J
James Smart 已提交
76
	if (phba->link_state != LPFC_CLEAR_LA) {
77
		lpfc_issue_clear_la(phba, vport);
已提交
78 79
	}

80
	return 1;
已提交
81 82 83 84

}

static struct lpfc_iocbq *
J
James Smart 已提交
85 86 87 88
lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
		   uint16_t cmdSize, uint8_t retry,
		   struct lpfc_nodelist *ndlp, uint32_t did,
		   uint32_t elscmd)
已提交
89
{
J
James Smart 已提交
90
	struct lpfc_hba  *phba = vport->phba;
91
	struct lpfc_iocbq *elsiocb;
已提交
92 93 94 95 96
	struct lpfc_dmabuf *pcmd, *prsp, *pbuflist;
	struct ulp_bde64 *bpl;
	IOCB_t *icmd;


J
James Smart 已提交
97 98
	if (!lpfc_is_link_up(phba))
		return NULL;
已提交
99 100

	/* Allocate buffer for  command iocb */
101
	elsiocb = lpfc_sli_get_iocbq(phba);
已提交
102 103 104 105 106 107 108 109 110 111

	if (elsiocb == NULL)
		return NULL;
	icmd = &elsiocb->iocb;

	/* fill in BDEs for command */
	/* Allocate buffer for command payload */
	if (((pcmd = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == 0) ||
	    ((pcmd->virt = lpfc_mbuf_alloc(phba,
					   MEM_PRI, &(pcmd->phys))) == 0)) {
J
Jesper Juhl 已提交
112
		kfree(pcmd);
已提交
113

114
		lpfc_sli_release_iocbq(phba, elsiocb);
已提交
115 116 117 118 119 120 121 122 123 124 125 126
		return NULL;
	}

	INIT_LIST_HEAD(&pcmd->list);

	/* Allocate buffer for response payload */
	if (expectRsp) {
		prsp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
		if (prsp)
			prsp->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
						     &prsp->phys);
		if (prsp == 0 || prsp->virt == 0) {
J
Jesper Juhl 已提交
127
			kfree(prsp);
已提交
128 129
			lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
			kfree(pcmd);
130
			lpfc_sli_release_iocbq(phba, elsiocb);
已提交
131 132 133 134 135 136 137 138 139 140
			return NULL;
		}
		INIT_LIST_HEAD(&prsp->list);
	} else {
		prsp = NULL;
	}

	/* Allocate buffer for Buffer ptr list */
	pbuflist = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
	if (pbuflist)
141 142
		pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
						 &pbuflist->phys);
已提交
143
	if (pbuflist == 0 || pbuflist->virt == 0) {
144
		lpfc_sli_release_iocbq(phba, elsiocb);
已提交
145 146 147 148
		lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
		lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
		kfree(pcmd);
		kfree(prsp);
J
Jesper Juhl 已提交
149
		kfree(pbuflist);
已提交
150 151 152 153 154 155 156 157
		return NULL;
	}

	INIT_LIST_HEAD(&pbuflist->list);

	icmd->un.elsreq64.bdl.addrHigh = putPaddrHigh(pbuflist->phys);
	icmd->un.elsreq64.bdl.addrLow = putPaddrLow(pbuflist->phys);
	icmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BDL;
J
James Smart 已提交
158
	icmd->un.elsreq64.remoteID = did;	/* DID */
已提交
159 160 161
	if (expectRsp) {
		icmd->un.elsreq64.bdl.bdeSize = (2 * sizeof (struct ulp_bde64));
		icmd->ulpCommand = CMD_ELS_REQUEST64_CR;
162
		icmd->ulpTimeout = phba->fc_ratov * 2;
已提交
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
	} else {
		icmd->un.elsreq64.bdl.bdeSize = sizeof (struct ulp_bde64);
		icmd->ulpCommand = CMD_XMIT_ELS_RSP64_CX;
	}

	icmd->ulpBdeCount = 1;
	icmd->ulpLe = 1;
	icmd->ulpClass = CLASS3;

	bpl = (struct ulp_bde64 *) pbuflist->virt;
	bpl->addrLow = le32_to_cpu(putPaddrLow(pcmd->phys));
	bpl->addrHigh = le32_to_cpu(putPaddrHigh(pcmd->phys));
	bpl->tus.f.bdeSize = cmdSize;
	bpl->tus.f.bdeFlags = 0;
	bpl->tus.w = le32_to_cpu(bpl->tus.w);

	if (expectRsp) {
		bpl++;
		bpl->addrLow = le32_to_cpu(putPaddrLow(prsp->phys));
		bpl->addrHigh = le32_to_cpu(putPaddrHigh(prsp->phys));
		bpl->tus.f.bdeSize = FCELSSIZE;
		bpl->tus.f.bdeFlags = BUFF_USE_RCV;
		bpl->tus.w = le32_to_cpu(bpl->tus.w);
	}

	/* Save for completion so we can release these resources */
189 190 191
	elsiocb->context1 = lpfc_nlp_get(ndlp);
	elsiocb->context2 = pcmd;
	elsiocb->context3 = pbuflist;
已提交
192
	elsiocb->retry = retry;
J
James Smart 已提交
193
	elsiocb->vport = vport;
已提交
194 195 196 197 198 199 200 201 202 203
	elsiocb->drvrTimeout = (phba->fc_ratov << 1) + LPFC_DRVR_TIMEOUT;

	if (prsp) {
		list_add(&prsp->list, &pcmd->list);
	}

	if (expectRsp) {
		/* Xmit ELS command <elsCmd> to remote NPORT <did> */
		lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
				"%d:0116 Xmit ELS command x%x to remote "
J
James Smart 已提交
204 205 206
				"NPORT x%x I/O tag: x%x, port state: x%x\n",
				phba->brd_no, elscmd, did,
				elsiocb->iotag, vport->port_state);
已提交
207 208 209 210
	} else {
		/* Xmit ELS response <elsCmd> to remote NPORT <did> */
		lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
				"%d:0117 Xmit ELS response x%x to remote "
211
				"NPORT x%x I/O tag: x%x, size: x%x\n",
已提交
212
				phba->brd_no, elscmd,
213
				ndlp->nlp_DID, elsiocb->iotag, cmdSize);
已提交
214 215
	}

216
	return elsiocb;
已提交
217 218 219 220
}


static int
J
James Smart 已提交
221 222
lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			   struct serv_parm *sp, IOCB_t *irsp)
已提交
223
{
J
James Smart 已提交
224 225
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba  *phba = vport->phba;
已提交
226
	LPFC_MBOXQ_t *mbox;
227
	struct lpfc_dmabuf *mp;
已提交
228 229
	int rc;

J
James Smart 已提交
230 231 232
	spin_lock_irq(shost->host_lock);
	vport->fc_flag |= FC_FABRIC;
	spin_unlock_irq(shost->host_lock);
已提交
233 234 235 236 237 238 239 240

	phba->fc_edtov = be32_to_cpu(sp->cmn.e_d_tov);
	if (sp->cmn.edtovResolution)	/* E_D_TOV ticks are in nanoseconds */
		phba->fc_edtov = (phba->fc_edtov + 999999) / 1000000;

	phba->fc_ratov = (be32_to_cpu(sp->cmn.w2.r_a_tov) + 999) / 1000;

	if (phba->fc_topology == TOPOLOGY_LOOP) {
J
James Smart 已提交
241 242 243
		spin_lock_irq(shost->host_lock);
		vport->fc_flag |= FC_PUBLIC_LOOP;
		spin_unlock_irq(shost->host_lock);
已提交
244 245 246 247 248
	} else {
		/*
		 * If we are a N-port connected to a Fabric, fixup sparam's so
		 * logins to devices on remote loops work.
		 */
J
James Smart 已提交
249
		vport->fc_sparam.cmn.altBbCredit = 1;
已提交
250 251
	}

J
James Smart 已提交
252
	vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID;
已提交
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
	memcpy(&ndlp->nlp_portname, &sp->portName, sizeof(struct lpfc_name));
	memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof (struct lpfc_name));
	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;
	memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));

J
James Smart 已提交
268 269
	ndlp->nlp_sid = irsp->un.ulpWord[4] & Mask_DID;

已提交
270 271 272 273
	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
	if (!mbox)
		goto fail;

J
James Smart 已提交
274
	vport->port_state = LPFC_FABRIC_CFG_LINK;
已提交
275 276
	lpfc_config_link(phba, mbox);
	mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
277
	mbox->vport = vport;
已提交
278 279 280 281 282 283 284 285

	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
	if (rc == MBX_NOT_FINISHED)
		goto fail_free_mbox;

	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
	if (!mbox)
		goto fail;
J
James Smart 已提交
286 287
	rc = lpfc_reg_login(phba, Fabric_DID, (uint8_t *) sp, mbox, 0);
	if (rc)
已提交
288 289 290
		goto fail_free_mbox;

	mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login;
J
James Smart 已提交
291
	mbox->vport = vport;
292
	mbox->context2 = lpfc_nlp_get(ndlp);
已提交
293 294 295

	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
	if (rc == MBX_NOT_FINISHED)
296
		goto fail_issue_reg_login;
已提交
297 298 299

	return 0;

300
 fail_issue_reg_login:
301
	lpfc_nlp_put(ndlp);
302 303 304
	mp = (struct lpfc_dmabuf *) mbox->context1;
	lpfc_mbuf_free(phba, mp->virt, mp->phys);
	kfree(mp);
已提交
305 306 307 308 309 310 311 312 313 314
 fail_free_mbox:
	mempool_free(mbox, phba->mbox_mem_pool);
 fail:
	return -ENXIO;
}

/*
 * We FLOGIed into an NPort, initiate pt2pt protocol
 */
static int
J
James Smart 已提交
315 316
lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
			  struct serv_parm *sp)
已提交
317
{
J
James Smart 已提交
318 319
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba  *phba = vport->phba;
已提交
320 321 322
	LPFC_MBOXQ_t *mbox;
	int rc;

J
James Smart 已提交
323 324 325
	spin_lock_irq(shost->host_lock);
	vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
	spin_unlock_irq(shost->host_lock);
已提交
326 327 328

	phba->fc_edtov = FF_DEF_EDTOV;
	phba->fc_ratov = FF_DEF_RATOV;
J
James Smart 已提交
329
	rc = memcmp(&vport->fc_portname, &sp->portName,
已提交
330 331 332
			sizeof(struct lpfc_name));
	if (rc >= 0) {
		/* This side will initiate the PLOGI */
J
James Smart 已提交
333 334 335
		spin_lock_irq(shost->host_lock);
		vport->fc_flag |= FC_PT2PT_PLOGI;
		spin_unlock_irq(shost->host_lock);
已提交
336 337 338 339 340 341 342 343

		/*
		 * N_Port ID cannot be 0, set our to LocalID the other
		 * side will be RemoteID.
		 */

		/* not equal */
		if (rc)
J
James Smart 已提交
344
			vport->fc_myDID = PT2PT_LocalID;
已提交
345 346 347 348 349 350 351 352

		mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
		if (!mbox)
			goto fail;

		lpfc_config_link(phba, mbox);

		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
353
		mbox->vport = vport;
已提交
354 355 356 357 358 359
		rc = lpfc_sli_issue_mbox(phba, mbox,
				MBX_NOWAIT | MBX_STOP_IOCB);
		if (rc == MBX_NOT_FINISHED) {
			mempool_free(mbox, phba->mbox_mem_pool);
			goto fail;
		}
360
		lpfc_nlp_put(ndlp);
已提交
361

J
James Smart 已提交
362
		ndlp = lpfc_findnode_did(vport, PT2PT_RemoteID);
已提交
363 364 365 366 367 368 369 370 371
		if (!ndlp) {
			/*
			 * Cannot find existing Fabric ndlp, so allocate a
			 * new one
			 */
			ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
			if (!ndlp)
				goto fail;

J
James Smart 已提交
372
			lpfc_nlp_init(vport, ndlp, PT2PT_RemoteID);
已提交
373 374 375
		}

		memcpy(&ndlp->nlp_portname, &sp->portName,
J
James Smart 已提交
376
		       sizeof(struct lpfc_name));
已提交
377
		memcpy(&ndlp->nlp_nodename, &sp->nodeName,
J
James Smart 已提交
378 379 380
		       sizeof(struct lpfc_name));
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
		spin_lock_irq(shost->host_lock);
已提交
381
		ndlp->nlp_flag |= NLP_NPR_2B_DISC;
J
James Smart 已提交
382
		spin_unlock_irq(shost->host_lock);
已提交
383 384
	} else {
		/* This side will wait for the PLOGI */
385
		lpfc_nlp_put(ndlp);
已提交
386 387
	}

J
James Smart 已提交
388 389 390
	spin_lock_irq(shost->host_lock);
	vport->fc_flag |= FC_PT2PT;
	spin_unlock_irq(shost->host_lock);
已提交
391 392

	/* Start discovery - this should just do CLEAR_LA */
J
James Smart 已提交
393
	lpfc_disc_start(vport);
已提交
394 395 396 397 398 399
	return 0;
 fail:
	return -ENXIO;
}

static void
400 401
lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
		    struct lpfc_iocbq *rspiocb)
已提交
402
{
J
James Smart 已提交
403 404
	struct lpfc_vport *vport = cmdiocb->vport;
	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
已提交
405 406 407 408 409 410 411
	IOCB_t *irsp = &rspiocb->iocb;
	struct lpfc_nodelist *ndlp = cmdiocb->context1;
	struct lpfc_dmabuf *pcmd = cmdiocb->context2, *prsp;
	struct serv_parm *sp;
	int rc;

	/* Check to see if link went down during discovery */
J
James Smart 已提交
412
	if (lpfc_els_chk_latt(vport)) {
413
		lpfc_nlp_put(ndlp);
已提交
414 415 416 417 418
		goto out;
	}

	if (irsp->ulpStatus) {
		/* Check for retry */
J
James Smart 已提交
419
		if (lpfc_els_retry(phba, cmdiocb, rspiocb))
已提交
420
			goto out;
J
James Smart 已提交
421

已提交
422
		/* FLOGI failed, so there is no fabric */
J
James Smart 已提交
423 424 425
		spin_lock_irq(shost->host_lock);
		vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
		spin_unlock_irq(shost->host_lock);
已提交
426

427
		/* If private loop, then allow max outstanding els to be
已提交
428 429 430 431
		 * LPFC_MAX_DISC_THREADS (32). Scanning in the case of no
		 * alpa map would take too long otherwise.
		 */
		if (phba->alpa_map[0] == 0) {
432
			phba->cfg_discovery_threads = LPFC_MAX_DISC_THREADS;
已提交
433 434 435 436 437 438
		}

		/* FLOGI failure */
		lpfc_printf_log(phba,
				KERN_INFO,
				LOG_ELS,
439
				"%d:0100 FLOGI failure Data: x%x x%x x%x\n",
已提交
440
				phba->brd_no,
441 442
				irsp->ulpStatus, irsp->un.ulpWord[4],
				irsp->ulpTimeout);
已提交
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461
		goto flogifail;
	}

	/*
	 * The FLogI succeeded.  Sync the data for the CPU before
	 * accessing it.
	 */
	prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list);

	sp = prsp->virt + sizeof(uint32_t);

	/* FLOGI completes successfully */
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
			"%d:0101 FLOGI completes sucessfully "
			"Data: x%x x%x x%x x%x\n",
			phba->brd_no,
			irsp->un.ulpWord[4], sp->cmn.e_d_tov,
			sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution);

J
James Smart 已提交
462
	if (vport->port_state == LPFC_FLOGI) {
已提交
463 464 465 466 467
		/*
		 * If Common Service Parameters indicate Nport
		 * we are point to point, if Fport we are Fabric.
		 */
		if (sp->cmn.fPort)
J
James Smart 已提交
468
			rc = lpfc_cmpl_els_flogi_fabric(vport, ndlp, sp, irsp);
已提交
469
		else
J
James Smart 已提交
470
			rc = lpfc_cmpl_els_flogi_nport(vport, ndlp, sp);
已提交
471 472 473 474 475 476

		if (!rc)
			goto out;
	}

flogifail:
477
	lpfc_nlp_put(ndlp);
已提交
478 479 480 481 482

	if (irsp->ulpStatus != IOSTAT_LOCAL_REJECT ||
	    (irsp->un.ulpWord[4] != IOERR_SLI_ABORTED &&
	     irsp->un.ulpWord[4] != IOERR_SLI_DOWN)) {
		/* FLOGI failed, so just use loop map to make discovery list */
J
James Smart 已提交
483
		lpfc_disc_list_loopmap(vport);
已提交
484 485

		/* Start discovery */
J
James Smart 已提交
486
		lpfc_disc_start(vport);
已提交
487 488 489 490 491 492 493
	}

out:
	lpfc_els_free_iocb(phba, cmdiocb);
}

static int
J
James Smart 已提交
494
lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
已提交
495 496
		     uint8_t retry)
{
J
James Smart 已提交
497
	struct lpfc_hba  *phba = vport->phba;
已提交
498 499 500 501 502 503 504 505 506 507 508 509
	struct serv_parm *sp;
	IOCB_t *icmd;
	struct lpfc_iocbq *elsiocb;
	struct lpfc_sli_ring *pring;
	uint8_t *pcmd;
	uint16_t cmdsize;
	uint32_t tmo;
	int rc;

	pring = &phba->sli.ring[LPFC_ELS_RING];

	cmdsize = (sizeof (uint32_t) + sizeof (struct serv_parm));
J
James Smart 已提交
510 511
	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
				     ndlp->nlp_DID, ELS_CMD_FLOGI);
512
	if (!elsiocb)
513
		return 1;
已提交
514 515 516 517 518 519 520

	icmd = &elsiocb->iocb;
	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);

	/* For FLOGI request, remainder of payload is service parameters */
	*((uint32_t *) (pcmd)) = ELS_CMD_FLOGI;
	pcmd += sizeof (uint32_t);
J
James Smart 已提交
521
	memcpy(pcmd, &vport->fc_sparam, sizeof (struct serv_parm));
已提交
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536
	sp = (struct serv_parm *) pcmd;

	/* Setup CSPs accordingly for Fabric */
	sp->cmn.e_d_tov = 0;
	sp->cmn.w2.r_a_tov = 0;
	sp->cls1.classValid = 0;
	sp->cls2.seqDelivery = 1;
	sp->cls3.seqDelivery = 1;
	if (sp->cmn.fcphLow < FC_PH3)
		sp->cmn.fcphLow = FC_PH3;
	if (sp->cmn.fcphHigh < FC_PH3)
		sp->cmn.fcphHigh = FC_PH3;

	tmo = phba->fc_ratov;
	phba->fc_ratov = LPFC_DISC_FLOGI_TMO;
J
James Smart 已提交
537
	lpfc_set_disctmo(vport);
已提交
538 539 540 541 542 543 544
	phba->fc_ratov = tmo;

	phba->fc_stat.elsXmitFLOGI++;
	elsiocb->iocb_cmpl = lpfc_cmpl_els_flogi;
	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
545
		return 1;
已提交
546
	}
547
	return 0;
已提交
548 549 550
}

int
J
James Smart 已提交
551
lpfc_els_abort_flogi(struct lpfc_hba *phba)
已提交
552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
{
	struct lpfc_sli_ring *pring;
	struct lpfc_iocbq *iocb, *next_iocb;
	struct lpfc_nodelist *ndlp;
	IOCB_t *icmd;

	/* Abort outstanding I/O on NPort <nlp_DID> */
	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
			"%d:0201 Abort outstanding I/O on NPort x%x\n",
			phba->brd_no, Fabric_DID);

	pring = &phba->sli.ring[LPFC_ELS_RING];

	/*
	 * Check the txcmplq for an iocb that matches the nport the driver is
	 * searching for.
	 */
J
James Smart 已提交
569
	spin_lock_irq(&phba->hbalock);
已提交
570 571
	list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
		icmd = &iocb->iocb;
J
James Smart 已提交
572 573
		if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR &&
		    icmd->un.elsreq64.bdl.ulpIoTag32) {
已提交
574
			ndlp = (struct lpfc_nodelist *)(iocb->context1);
575 576
			if (ndlp && (ndlp->nlp_DID == Fabric_DID))
				lpfc_sli_issue_abort_iotag(phba, pring, iocb);
已提交
577 578
		}
	}
J
James Smart 已提交
579
	spin_unlock_irq(&phba->hbalock);
已提交
580 581 582 583 584

	return 0;
}

int
J
James Smart 已提交
585
lpfc_initial_flogi(struct lpfc_vport *vport)
已提交
586
{
J
James Smart 已提交
587
	struct lpfc_hba *phba = vport->phba;
已提交
588 589
	struct lpfc_nodelist *ndlp;

590
	/* First look for the Fabric ndlp */
J
James Smart 已提交
591
	ndlp = lpfc_findnode_did(vport, Fabric_DID);
592
	if (!ndlp) {
已提交
593
		/* Cannot find existing Fabric ndlp, so allocate a new one */
594 595 596
		ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
		if (!ndlp)
			return 0;
J
James Smart 已提交
597
		lpfc_nlp_init(vport, ndlp, Fabric_DID);
598
	} else {
J
James Smart 已提交
599
		lpfc_dequeue_node(vport, ndlp);
已提交
600
	}
J
James Smart 已提交
601
	if (lpfc_issue_els_flogi(vport, ndlp, 0)) {
602
		lpfc_nlp_put(ndlp);
已提交
603
	}
604
	return 1;
已提交
605 606 607
}

static void
J
James Smart 已提交
608
lpfc_more_plogi(struct lpfc_vport *vport)
已提交
609 610
{
	int sentplogi;
J
James Smart 已提交
611
	struct lpfc_hba *phba = vport->phba;
已提交
612

J
James Smart 已提交
613 614
	if (vport->num_disc_nodes)
		vport->num_disc_nodes--;
已提交
615 616 617 618 619

	/* Continue discovery with <num_disc_nodes> PLOGIs to go */
	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
			"%d:0232 Continue discovery with %d PLOGIs to go "
			"Data: x%x x%x x%x\n",
J
James Smart 已提交
620 621
			phba->brd_no, vport->num_disc_nodes,
			vport->fc_plogi_cnt, vport->fc_flag, vport->port_state);
已提交
622 623

	/* Check to see if there are more PLOGIs to be sent */
J
James Smart 已提交
624 625 626 627
	if (vport->fc_flag & FC_NLP_MORE)
		/* go thru NPR nodes and issue any remaining ELS PLOGIs */
		sentplogi = lpfc_els_disc_plogi(vport);

已提交
628 629 630
	return;
}

631
static struct lpfc_nodelist *
632
lpfc_plogi_confirm_nport(struct lpfc_hba *phba, struct lpfc_dmabuf *prsp,
633 634
			 struct lpfc_nodelist *ndlp)
{
J
James Smart 已提交
635
	struct lpfc_vport    *vport = ndlp->vport;
636 637 638 639 640 641
	struct lpfc_nodelist *new_ndlp;
	uint32_t *lp;
	struct serv_parm *sp;
	uint8_t name[sizeof (struct lpfc_name)];
	uint32_t rc;

J
James Smart 已提交
642 643 644 645 646 647
	/* Fabric nodes can have the same WWPN so we don't bother searching
	 * by WWPN.  Just return the ndlp that was given to us.
	 */
	if (ndlp->nlp_type & NLP_FABRIC)
		return ndlp;

648 649
	lp = (uint32_t *) prsp->virt;
	sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
650
	memset(name, 0, sizeof(struct lpfc_name));
651

652
	/* Now we find out if the NPort we are logging into, matches the WWPN
653 654
	 * we have for that ndlp. If not, we have some work to do.
	 */
J
James Smart 已提交
655
	new_ndlp = lpfc_findnode_wwpn(vport, &sp->portName);
656

657
	if (new_ndlp == ndlp)
658 659 660
		return ndlp;

	if (!new_ndlp) {
J
James Smart 已提交
661 662
		rc = memcmp(&ndlp->nlp_portname, name,
			    sizeof(struct lpfc_name));
663 664
		if (!rc)
			return ndlp;
665 666 667 668
		new_ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC);
		if (!new_ndlp)
			return ndlp;

J
James Smart 已提交
669
		lpfc_nlp_init(vport, new_ndlp, ndlp->nlp_DID);
670 671
	}

J
James Smart 已提交
672
	lpfc_unreg_rpi(vport, new_ndlp);
673
	new_ndlp->nlp_DID = ndlp->nlp_DID;
674
	new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
J
James Smart 已提交
675
	lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state);
676

J
James Smart 已提交
677
	/* Move this back to NPR state */
678
	if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0)
J
James Smart 已提交
679
		lpfc_drop_node(vport, ndlp);
680
	else {
J
James Smart 已提交
681
		lpfc_unreg_rpi(vport, ndlp);
682
		ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
J
James Smart 已提交
683
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
684
	}
685 686 687
	return new_ndlp;
}

已提交
688
static void
J
James Smart 已提交
689 690
lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
		    struct lpfc_iocbq *rspiocb)
已提交
691
{
J
James Smart 已提交
692 693
	struct lpfc_vport *vport = cmdiocb->vport;
	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
已提交
694 695
	IOCB_t *irsp;
	struct lpfc_nodelist *ndlp;
696
	struct lpfc_dmabuf *prsp;
已提交
697 698 699 700 701 702
	int disc, rc, did, type;

	/* we pass cmdiocb to state machine which needs rspiocb as well */
	cmdiocb->context_un.rsp_iocb = rspiocb;

	irsp = &rspiocb->iocb;
J
James Smart 已提交
703
	ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID);
704 705

	if (!ndlp) {
706
		goto out;
707
	}
已提交
708 709 710 711

	/* Since ndlp can be freed in the disc state machine, note if this node
	 * is being used during discovery.
	 */
J
James Smart 已提交
712
	spin_lock_irq(shost->host_lock);
已提交
713
	disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
714
	ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
J
James Smart 已提交
715
	spin_unlock_irq(shost->host_lock);
已提交
716 717 718 719 720
	rc   = 0;

	/* PLOGI completes to NPort <nlp_DID> */
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
			"%d:0102 PLOGI completes to NPort x%x "
721
			"Data: x%x x%x x%x x%x x%x\n",
已提交
722
			phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus,
723
			irsp->un.ulpWord[4], irsp->ulpTimeout, disc,
J
James Smart 已提交
724
			vport->num_disc_nodes);
已提交
725 726

	/* Check to see if link went down during discovery */
J
James Smart 已提交
727 728
	if (lpfc_els_chk_latt(vport)) {
		spin_lock_irq(shost->host_lock);
已提交
729
		ndlp->nlp_flag |= NLP_NPR_2B_DISC;
J
James Smart 已提交
730
		spin_unlock_irq(shost->host_lock);
已提交
731 732 733 734 735 736 737 738 739 740 741 742
		goto out;
	}

	/* ndlp could be freed in DSM, save these values now */
	type = ndlp->nlp_type;
	did = ndlp->nlp_DID;

	if (irsp->ulpStatus) {
		/* Check for retry */
		if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
			/* ELS command is being retried */
			if (disc) {
J
James Smart 已提交
743
				spin_lock_irq(shost->host_lock);
已提交
744
				ndlp->nlp_flag |= NLP_NPR_2B_DISC;
J
James Smart 已提交
745
				spin_unlock_irq(shost->host_lock);
已提交
746 747 748 749 750 751 752 753
			}
			goto out;
		}

		/* PLOGI failed */
		/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
		if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
		   ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
754
		   (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
已提交
755
		   (irsp->un.ulpWord[4] == IOERR_SLI_DOWN))) {
756
			rc = NLP_STE_FREED_NODE;
757
		} else {
J
James Smart 已提交
758
			rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb,
已提交
759 760 761 762
					NLP_EVT_CMPL_PLOGI);
		}
	} else {
		/* Good status, call state machine */
763 764 765 766
		prsp = list_entry(((struct lpfc_dmabuf *)
			cmdiocb->context2)->list.next,
			struct lpfc_dmabuf, list);
		ndlp = lpfc_plogi_confirm_nport(phba, prsp, ndlp);
J
James Smart 已提交
767
		rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb,
已提交
768 769 770
					NLP_EVT_CMPL_PLOGI);
	}

J
James Smart 已提交
771
	if (disc && vport->num_disc_nodes) {
已提交
772
		/* Check to see if there are more PLOGIs to be sent */
J
James Smart 已提交
773
		lpfc_more_plogi(vport);
已提交
774

J
James Smart 已提交
775 776 777 778
		if (vport->num_disc_nodes == 0) {
			spin_lock_irq(shost->host_lock);
			vport->fc_flag &= ~FC_NDISC_ACTIVE;
			spin_unlock_irq(shost->host_lock);
已提交
779

J
James Smart 已提交
780 781
			lpfc_can_disctmo(vport);
			if (vport->fc_flag & FC_RSCN_MODE) {
782 783 784 785
				/*
				 * Check to see if more RSCNs came in while
				 * we were processing this one.
				 */
J
James Smart 已提交
786 787 788 789 790
				if ((vport->fc_rscn_id_cnt == 0) &&
				    (!(vport->fc_flag & FC_RSCN_DISCOVERY))) {
					spin_lock_irq(shost->host_lock);
					vport->fc_flag &= ~FC_RSCN_MODE;
					spin_unlock_irq(shost->host_lock);
791
				} else {
J
James Smart 已提交
792
					lpfc_els_handle_rscn(vport);
793
				}
已提交
794 795 796 797 798 799 800 801 802 803
			}
		}
	}

out:
	lpfc_els_free_iocb(phba, cmdiocb);
	return;
}

int
J
James Smart 已提交
804
lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
已提交
805
{
J
James Smart 已提交
806
	struct lpfc_hba  *phba = vport->phba;
已提交
807 808 809 810 811 812 813 814 815 816 817 818
	struct serv_parm *sp;
	IOCB_t *icmd;
	struct lpfc_iocbq *elsiocb;
	struct lpfc_sli_ring *pring;
	struct lpfc_sli *psli;
	uint8_t *pcmd;
	uint16_t cmdsize;

	psli = &phba->sli;
	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */

	cmdsize = (sizeof (uint32_t) + sizeof (struct serv_parm));
J
James Smart 已提交
819 820
	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, NULL, did,
				     ELS_CMD_PLOGI);
821 822
	if (!elsiocb)
		return 1;
已提交
823 824 825 826 827 828 829

	icmd = &elsiocb->iocb;
	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);

	/* For PLOGI request, remainder of payload is service parameters */
	*((uint32_t *) (pcmd)) = ELS_CMD_PLOGI;
	pcmd += sizeof (uint32_t);
J
James Smart 已提交
830
	memcpy(pcmd, &vport->fc_sparam, sizeof (struct serv_parm));
已提交
831 832 833 834 835 836 837 838 839 840 841 842
	sp = (struct serv_parm *) pcmd;

	if (sp->cmn.fcphLow < FC_PH_4_3)
		sp->cmn.fcphLow = FC_PH_4_3;

	if (sp->cmn.fcphHigh < FC_PH3)
		sp->cmn.fcphHigh = FC_PH3;

	phba->fc_stat.elsXmitPLOGI++;
	elsiocb->iocb_cmpl = lpfc_cmpl_els_plogi;
	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
843
		return 1;
已提交
844
	}
845
	return 0;
已提交
846 847 848
}

static void
J
James Smart 已提交
849 850
lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
		   struct lpfc_iocbq *rspiocb)
已提交
851
{
J
James Smart 已提交
852 853
	struct lpfc_vport *vport = cmdiocb->vport;
	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
已提交
854 855 856 857 858 859 860 861 862 863
	IOCB_t *irsp;
	struct lpfc_sli *psli;
	struct lpfc_nodelist *ndlp;

	psli = &phba->sli;
	/* we pass cmdiocb to state machine which needs rspiocb as well */
	cmdiocb->context_un.rsp_iocb = rspiocb;

	irsp = &(rspiocb->iocb);
	ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
J
James Smart 已提交
864
	spin_lock_irq(shost->host_lock);
已提交
865
	ndlp->nlp_flag &= ~NLP_PRLI_SND;
J
James Smart 已提交
866
	spin_unlock_irq(shost->host_lock);
已提交
867 868 869 870

	/* PRLI completes to NPort <nlp_DID> */
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
			"%d:0103 PRLI completes to NPort x%x "
871
			"Data: x%x x%x x%x x%x\n",
已提交
872
			phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus,
873
			irsp->un.ulpWord[4], irsp->ulpTimeout,
J
James Smart 已提交
874
			vport->num_disc_nodes);
已提交
875

J
James Smart 已提交
876
	vport->fc_prli_sent--;
已提交
877
	/* Check to see if link went down during discovery */
J
James Smart 已提交
878
	if (lpfc_els_chk_latt(vport))
已提交
879 880 881 882 883 884 885 886 887 888 889 890
		goto out;

	if (irsp->ulpStatus) {
		/* Check for retry */
		if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
			/* ELS command is being retried */
			goto out;
		}
		/* PRLI failed */
		/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
		if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
		   ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
891
		   (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
已提交
892 893
		   (irsp->un.ulpWord[4] == IOERR_SLI_DOWN))) {
			goto out;
894
		} else {
J
James Smart 已提交
895
			lpfc_disc_state_machine(vport, ndlp, cmdiocb,
已提交
896 897 898 899
					NLP_EVT_CMPL_PRLI);
		}
	} else {
		/* Good status, call state machine */
J
James Smart 已提交
900 901
		lpfc_disc_state_machine(vport, ndlp, cmdiocb,
							NLP_EVT_CMPL_PRLI);
已提交
902 903 904 905 906 907 908 909
	}

out:
	lpfc_els_free_iocb(phba, cmdiocb);
	return;
}

int
J
James Smart 已提交
910
lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
已提交
911 912
		    uint8_t retry)
{
J
James Smart 已提交
913 914
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba *phba = vport->phba;
已提交
915 916 917 918 919 920 921 922 923 924 925 926
	PRLI *npr;
	IOCB_t *icmd;
	struct lpfc_iocbq *elsiocb;
	struct lpfc_sli_ring *pring;
	struct lpfc_sli *psli;
	uint8_t *pcmd;
	uint16_t cmdsize;

	psli = &phba->sli;
	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */

	cmdsize = (sizeof (uint32_t) + sizeof (PRLI));
J
James Smart 已提交
927 928
	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
				     ndlp->nlp_DID, ELS_CMD_PRLI);
929
	if (!elsiocb)
930
		return 1;
已提交
931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959

	icmd = &elsiocb->iocb;
	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);

	/* For PRLI request, remainder of payload is service parameters */
	memset(pcmd, 0, (sizeof (PRLI) + sizeof (uint32_t)));
	*((uint32_t *) (pcmd)) = ELS_CMD_PRLI;
	pcmd += sizeof (uint32_t);

	/* For PRLI, remainder of payload is PRLI parameter page */
	npr = (PRLI *) pcmd;
	/*
	 * If our firmware version is 3.20 or later,
	 * set the following bits for FC-TAPE support.
	 */
	if (phba->vpd.rev.feaLevelHigh >= 0x02) {
		npr->ConfmComplAllowed = 1;
		npr->Retry = 1;
		npr->TaskRetryIdReq = 1;
	}
	npr->estabImagePair = 1;
	npr->readXferRdyDis = 1;

	/* For FCP support */
	npr->prliType = PRLI_FCP_TYPE;
	npr->initiatorFunc = 1;

	phba->fc_stat.elsXmitPRLI++;
	elsiocb->iocb_cmpl = lpfc_cmpl_els_prli;
J
James Smart 已提交
960
	spin_lock_irq(shost->host_lock);
已提交
961
	ndlp->nlp_flag |= NLP_PRLI_SND;
J
James Smart 已提交
962
	spin_unlock_irq(shost->host_lock);
已提交
963
	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
J
James Smart 已提交
964
		spin_lock_irq(shost->host_lock);
已提交
965
		ndlp->nlp_flag &= ~NLP_PRLI_SND;
J
James Smart 已提交
966
		spin_unlock_irq(shost->host_lock);
已提交
967
		lpfc_els_free_iocb(phba, elsiocb);
968
		return 1;
已提交
969
	}
J
James Smart 已提交
970
	vport->fc_prli_sent++;
971
	return 0;
已提交
972 973 974
}

static void
J
James Smart 已提交
975
lpfc_more_adisc(struct lpfc_vport *vport)
已提交
976 977
{
	int sentadisc;
J
James Smart 已提交
978
	struct lpfc_hba *phba = vport->phba;
已提交
979

J
James Smart 已提交
980 981
	if (vport->num_disc_nodes)
		vport->num_disc_nodes--;
已提交
982 983 984 985 986

	/* Continue discovery with <num_disc_nodes> ADISCs to go */
	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
			"%d:0210 Continue discovery with %d ADISCs to go "
			"Data: x%x x%x x%x\n",
J
James Smart 已提交
987 988
			phba->brd_no, vport->num_disc_nodes,
			vport->fc_adisc_cnt, vport->fc_flag, vport->port_state);
已提交
989 990

	/* Check to see if there are more ADISCs to be sent */
J
James Smart 已提交
991 992 993 994
	if (vport->fc_flag & FC_NLP_MORE) {
		lpfc_set_disctmo(vport);
		/* go thru NPR nodes and issue any remaining ELS ADISCs */
		sentadisc = lpfc_els_disc_adisc(vport);
已提交
995 996 997 998 999
	}
	return;
}

static void
J
James Smart 已提交
1000
lpfc_rscn_disc(struct lpfc_vport *vport)
已提交
1001
{
J
James Smart 已提交
1002 1003
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

已提交
1004
	/* RSCN discovery */
J
James Smart 已提交
1005 1006 1007
	/* go thru NPR nodes and issue ELS PLOGIs */
	if (vport->fc_npr_cnt)
		if (lpfc_els_disc_plogi(vport))
已提交
1008
			return;
J
James Smart 已提交
1009 1010

	if (vport->fc_flag & FC_RSCN_MODE) {
已提交
1011 1012 1013
		/* Check to see if more RSCNs came in while we were
		 * processing this one.
		 */
J
James Smart 已提交
1014 1015 1016 1017 1018
		if ((vport->fc_rscn_id_cnt == 0) &&
		    (!(vport->fc_flag & FC_RSCN_DISCOVERY))) {
			spin_lock_irq(shost->host_lock);
			vport->fc_flag &= ~FC_RSCN_MODE;
			spin_unlock_irq(shost->host_lock);
已提交
1019
		} else {
J
James Smart 已提交
1020
			lpfc_els_handle_rscn(vport);
已提交
1021 1022 1023 1024 1025
		}
	}
}

static void
J
James Smart 已提交
1026 1027
lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
		    struct lpfc_iocbq *rspiocb)
已提交
1028
{
J
James Smart 已提交
1029 1030
	struct lpfc_vport *vport = cmdiocb->vport;
	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
已提交
1031 1032
	IOCB_t *irsp;
	struct lpfc_nodelist *ndlp;
J
James Smart 已提交
1033
	int  disc;
已提交
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043

	/* we pass cmdiocb to state machine which needs rspiocb as well */
	cmdiocb->context_un.rsp_iocb = rspiocb;

	irsp = &(rspiocb->iocb);
	ndlp = (struct lpfc_nodelist *) cmdiocb->context1;

	/* Since ndlp can be freed in the disc state machine, note if this node
	 * is being used during discovery.
	 */
J
James Smart 已提交
1044
	spin_lock_irq(shost->host_lock);
已提交
1045
	disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
1046
	ndlp->nlp_flag &= ~(NLP_ADISC_SND | NLP_NPR_2B_DISC);
J
James Smart 已提交
1047
	spin_unlock_irq(shost->host_lock);
已提交
1048 1049 1050 1051

	/* ADISC completes to NPort <nlp_DID> */
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
			"%d:0104 ADISC completes to NPort x%x "
1052
			"Data: x%x x%x x%x x%x x%x\n",
已提交
1053
			phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus,
1054
			irsp->un.ulpWord[4], irsp->ulpTimeout, disc,
J
James Smart 已提交
1055
			vport->num_disc_nodes);
已提交
1056 1057

	/* Check to see if link went down during discovery */
J
James Smart 已提交
1058 1059
	if (lpfc_els_chk_latt(vport)) {
		spin_lock_irq(shost->host_lock);
已提交
1060
		ndlp->nlp_flag |= NLP_NPR_2B_DISC;
J
James Smart 已提交
1061
		spin_unlock_irq(shost->host_lock);
已提交
1062 1063 1064 1065 1066 1067 1068 1069
		goto out;
	}

	if (irsp->ulpStatus) {
		/* Check for retry */
		if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
			/* ELS command is being retried */
			if (disc) {
J
James Smart 已提交
1070
				spin_lock_irq(shost->host_lock);
已提交
1071
				ndlp->nlp_flag |= NLP_NPR_2B_DISC;
J
James Smart 已提交
1072 1073
				spin_unlock_irq(shost->host_lock);
				lpfc_set_disctmo(vport);
已提交
1074 1075 1076 1077 1078
			}
			goto out;
		}
		/* ADISC failed */
		/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
1079 1080 1081 1082
		if ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
		   ((irsp->un.ulpWord[4] != IOERR_SLI_ABORTED) &&
		   (irsp->un.ulpWord[4] != IOERR_LINK_DOWN) &&
		   (irsp->un.ulpWord[4] != IOERR_SLI_DOWN))) {
J
James Smart 已提交
1083
			lpfc_disc_state_machine(vport, ndlp, cmdiocb,
已提交
1084 1085 1086 1087
					NLP_EVT_CMPL_ADISC);
		}
	} else {
		/* Good status, call state machine */
J
James Smart 已提交
1088
		lpfc_disc_state_machine(vport, ndlp, cmdiocb,
已提交
1089 1090 1091
					NLP_EVT_CMPL_ADISC);
	}

J
James Smart 已提交
1092
	if (disc && vport->num_disc_nodes) {
已提交
1093
		/* Check to see if there are more ADISCs to be sent */
J
James Smart 已提交
1094
		lpfc_more_adisc(vport);
已提交
1095 1096

		/* Check to see if we are done with ADISC authentication */
J
James Smart 已提交
1097 1098
		if (vport->num_disc_nodes == 0) {
			lpfc_can_disctmo(vport);
已提交
1099
			/* If we get here, there is nothing left to wait for */
J
James Smart 已提交
1100 1101
			if (vport->port_state < LPFC_VPORT_READY &&
			    phba->link_state != LPFC_CLEAR_LA) {
1102
				if (vport->port_type == LPFC_PHYSICAL_PORT)
J
James Smart 已提交
1103
					lpfc_issue_clear_la(phba, vport);
已提交
1104
			} else {
J
James Smart 已提交
1105
				lpfc_rscn_disc(vport);
已提交
1106 1107 1108 1109 1110 1111 1112 1113 1114
			}
		}
	}
out:
	lpfc_els_free_iocb(phba, cmdiocb);
	return;
}

int
J
James Smart 已提交
1115
lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
已提交
1116 1117
		     uint8_t retry)
{
J
James Smart 已提交
1118 1119
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba  *phba = vport->phba;
已提交
1120 1121 1122
	ADISC *ap;
	IOCB_t *icmd;
	struct lpfc_iocbq *elsiocb;
J
James Smart 已提交
1123 1124
	struct lpfc_sli *psli = &phba->sli;
	struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
已提交
1125 1126 1127 1128
	uint8_t *pcmd;
	uint16_t cmdsize;

	cmdsize = (sizeof (uint32_t) + sizeof (ADISC));
J
James Smart 已提交
1129 1130
	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
				     ndlp->nlp_DID, ELS_CMD_ADISC);
1131
	if (!elsiocb)
1132
		return 1;
已提交
1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143

	icmd = &elsiocb->iocb;
	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);

	/* For ADISC request, remainder of payload is service parameters */
	*((uint32_t *) (pcmd)) = ELS_CMD_ADISC;
	pcmd += sizeof (uint32_t);

	/* Fill in ADISC payload */
	ap = (ADISC *) pcmd;
	ap->hardAL_PA = phba->fc_pref_ALPA;
J
James Smart 已提交
1144 1145 1146
	memcpy(&ap->portName, &vport->fc_portname, sizeof (struct lpfc_name));
	memcpy(&ap->nodeName, &vport->fc_nodename, sizeof (struct lpfc_name));
	ap->DID = be32_to_cpu(vport->fc_myDID);
已提交
1147 1148 1149

	phba->fc_stat.elsXmitADISC++;
	elsiocb->iocb_cmpl = lpfc_cmpl_els_adisc;
J
James Smart 已提交
1150
	spin_lock_irq(shost->host_lock);
已提交
1151
	ndlp->nlp_flag |= NLP_ADISC_SND;
J
James Smart 已提交
1152
	spin_unlock_irq(shost->host_lock);
已提交
1153
	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
J
James Smart 已提交
1154
		spin_lock_irq(shost->host_lock);
已提交
1155
		ndlp->nlp_flag &= ~NLP_ADISC_SND;
J
James Smart 已提交
1156
		spin_unlock_irq(shost->host_lock);
已提交
1157
		lpfc_els_free_iocb(phba, elsiocb);
1158
		return 1;
已提交
1159
	}
1160
	return 0;
已提交
1161 1162 1163
}

static void
J
James Smart 已提交
1164 1165
lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
		   struct lpfc_iocbq *rspiocb)
已提交
1166
{
J
James Smart 已提交
1167 1168 1169
	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
	struct lpfc_vport *vport = ndlp->vport;
	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
已提交
1170 1171 1172 1173 1174 1175 1176 1177
	IOCB_t *irsp;
	struct lpfc_sli *psli;

	psli = &phba->sli;
	/* we pass cmdiocb to state machine which needs rspiocb as well */
	cmdiocb->context_un.rsp_iocb = rspiocb;

	irsp = &(rspiocb->iocb);
J
James Smart 已提交
1178
	spin_lock_irq(shost->host_lock);
已提交
1179
	ndlp->nlp_flag &= ~NLP_LOGO_SND;
J
James Smart 已提交
1180
	spin_unlock_irq(shost->host_lock);
已提交
1181 1182 1183 1184

	/* LOGO completes to NPort <nlp_DID> */
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
			"%d:0105 LOGO completes to NPort x%x "
1185
			"Data: x%x x%x x%x x%x\n",
已提交
1186
			phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus,
1187
			irsp->un.ulpWord[4], irsp->ulpTimeout,
J
James Smart 已提交
1188
			vport->num_disc_nodes);
已提交
1189 1190

	/* Check to see if link went down during discovery */
J
James Smart 已提交
1191
	if (lpfc_els_chk_latt(vport))
已提交
1192 1193 1194 1195
		goto out;

	if (irsp->ulpStatus) {
		/* Check for retry */
J
James Smart 已提交
1196
		if (lpfc_els_retry(phba, cmdiocb, rspiocb))
已提交
1197 1198 1199 1200 1201 1202
			/* ELS command is being retried */
			goto out;
		/* LOGO failed */
		/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
		if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
		   ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
1203
		   (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
已提交
1204 1205
		   (irsp->un.ulpWord[4] == IOERR_SLI_DOWN))) {
			goto out;
1206
		} else {
J
James Smart 已提交
1207
			lpfc_disc_state_machine(vport, ndlp, cmdiocb,
已提交
1208 1209 1210
					NLP_EVT_CMPL_LOGO);
		}
	} else {
1211 1212 1213
		/* Good status, call state machine.
		 * This will unregister the rpi if needed.
		 */
J
James Smart 已提交
1214 1215
		lpfc_disc_state_machine(vport, ndlp, cmdiocb,
							NLP_EVT_CMPL_LOGO);
已提交
1216 1217 1218 1219 1220 1221 1222 1223
	}

out:
	lpfc_els_free_iocb(phba, cmdiocb);
	return;
}

int
J
James Smart 已提交
1224
lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
已提交
1225 1226
		    uint8_t retry)
{
J
James Smart 已提交
1227 1228
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba  *phba = vport->phba;
已提交
1229 1230 1231 1232 1233 1234 1235 1236 1237 1238
	IOCB_t *icmd;
	struct lpfc_iocbq *elsiocb;
	struct lpfc_sli_ring *pring;
	struct lpfc_sli *psli;
	uint8_t *pcmd;
	uint16_t cmdsize;

	psli = &phba->sli;
	pring = &psli->ring[LPFC_ELS_RING];

1239
	cmdsize = (2 * sizeof (uint32_t)) + sizeof (struct lpfc_name);
J
James Smart 已提交
1240 1241
	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
				     ndlp->nlp_DID, ELS_CMD_LOGO);
1242
	if (!elsiocb)
1243
		return 1;
已提交
1244 1245 1246 1247 1248 1249 1250

	icmd = &elsiocb->iocb;
	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
	*((uint32_t *) (pcmd)) = ELS_CMD_LOGO;
	pcmd += sizeof (uint32_t);

	/* Fill in LOGO payload */
J
James Smart 已提交
1251
	*((uint32_t *) (pcmd)) = be32_to_cpu(vport->fc_myDID);
已提交
1252
	pcmd += sizeof (uint32_t);
J
James Smart 已提交
1253
	memcpy(pcmd, &vport->fc_portname, sizeof (struct lpfc_name));
已提交
1254 1255 1256

	phba->fc_stat.elsXmitLOGO++;
	elsiocb->iocb_cmpl = lpfc_cmpl_els_logo;
J
James Smart 已提交
1257
	spin_lock_irq(shost->host_lock);
已提交
1258
	ndlp->nlp_flag |= NLP_LOGO_SND;
J
James Smart 已提交
1259
	spin_unlock_irq(shost->host_lock);
已提交
1260
	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
J
James Smart 已提交
1261
		spin_lock_irq(shost->host_lock);
已提交
1262
		ndlp->nlp_flag &= ~NLP_LOGO_SND;
J
James Smart 已提交
1263
		spin_unlock_irq(shost->host_lock);
已提交
1264
		lpfc_els_free_iocb(phba, elsiocb);
1265
		return 1;
已提交
1266
	}
1267
	return 0;
已提交
1268 1269 1270
}

static void
J
James Smart 已提交
1271 1272
lpfc_cmpl_els_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
		  struct lpfc_iocbq *rspiocb)
已提交
1273
{
J
James Smart 已提交
1274
	struct lpfc_vport *vport = cmdiocb->vport;
已提交
1275 1276 1277 1278 1279 1280 1281 1282
	IOCB_t *irsp;

	irsp = &rspiocb->iocb;

	/* ELS cmd tag <ulpIoTag> completes */
	lpfc_printf_log(phba,
			KERN_INFO,
			LOG_ELS,
1283
			"%d:0106 ELS cmd tag x%x completes Data: x%x x%x x%x\n",
已提交
1284
			phba->brd_no,
1285 1286
			irsp->ulpIoTag, irsp->ulpStatus,
			irsp->un.ulpWord[4], irsp->ulpTimeout);
已提交
1287 1288

	/* Check to see if link went down during discovery */
J
James Smart 已提交
1289
	lpfc_els_chk_latt(vport);
已提交
1290 1291 1292 1293 1294
	lpfc_els_free_iocb(phba, cmdiocb);
	return;
}

int
J
James Smart 已提交
1295
lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
已提交
1296
{
J
James Smart 已提交
1297
	struct lpfc_hba  *phba = vport->phba;
已提交
1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308
	IOCB_t *icmd;
	struct lpfc_iocbq *elsiocb;
	struct lpfc_sli_ring *pring;
	struct lpfc_sli *psli;
	uint8_t *pcmd;
	uint16_t cmdsize;
	struct lpfc_nodelist *ndlp;

	psli = &phba->sli;
	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */
	cmdsize = (sizeof (uint32_t) + sizeof (SCR));
1309 1310 1311
	ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
	if (!ndlp)
		return 1;
已提交
1312

J
James Smart 已提交
1313 1314 1315 1316
	lpfc_nlp_init(vport, ndlp, nportid);

	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
				     ndlp->nlp_DID, ELS_CMD_SCR);
已提交
1317

1318
	if (!elsiocb) {
1319
		lpfc_nlp_put(ndlp);
1320
		return 1;
已提交
1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335
	}

	icmd = &elsiocb->iocb;
	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);

	*((uint32_t *) (pcmd)) = ELS_CMD_SCR;
	pcmd += sizeof (uint32_t);

	/* For SCR, remainder of payload is SCR parameter page */
	memset(pcmd, 0, sizeof (SCR));
	((SCR *) pcmd)->Function = SCR_FUNC_FULL;

	phba->fc_stat.elsXmitSCR++;
	elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
1336
		lpfc_nlp_put(ndlp);
已提交
1337
		lpfc_els_free_iocb(phba, elsiocb);
1338
		return 1;
已提交
1339
	}
1340
	lpfc_nlp_put(ndlp);
1341
	return 0;
已提交
1342 1343 1344
}

static int
J
James Smart 已提交
1345
lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
已提交
1346
{
J
James Smart 已提交
1347
	struct lpfc_hba  *phba = vport->phba;
已提交
1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361
	IOCB_t *icmd;
	struct lpfc_iocbq *elsiocb;
	struct lpfc_sli_ring *pring;
	struct lpfc_sli *psli;
	FARP *fp;
	uint8_t *pcmd;
	uint32_t *lp;
	uint16_t cmdsize;
	struct lpfc_nodelist *ondlp;
	struct lpfc_nodelist *ndlp;

	psli = &phba->sli;
	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */
	cmdsize = (sizeof (uint32_t) + sizeof (FARP));
1362 1363 1364
	ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
	if (!ndlp)
		return 1;
已提交
1365

J
James Smart 已提交
1366 1367 1368 1369
	lpfc_nlp_init(vport, ndlp, nportid);

	elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
				     ndlp->nlp_DID, ELS_CMD_RNID);
1370
	if (!elsiocb) {
1371
		lpfc_nlp_put(ndlp);
1372
		return 1;
已提交
1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385
	}

	icmd = &elsiocb->iocb;
	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);

	*((uint32_t *) (pcmd)) = ELS_CMD_FARPR;
	pcmd += sizeof (uint32_t);

	/* Fill in FARPR payload */
	fp = (FARP *) (pcmd);
	memset(fp, 0, sizeof (FARP));
	lp = (uint32_t *) pcmd;
	*lp++ = be32_to_cpu(nportid);
J
James Smart 已提交
1386
	*lp++ = be32_to_cpu(vport->fc_myDID);
已提交
1387 1388 1389
	fp->Rflags = 0;
	fp->Mflags = (FARP_MATCH_PORT | FARP_MATCH_NODE);

J
James Smart 已提交
1390 1391 1392 1393
	memcpy(&fp->RportName, &vport->fc_portname, sizeof (struct lpfc_name));
	memcpy(&fp->RnodeName, &vport->fc_nodename, sizeof (struct lpfc_name));
	ondlp = lpfc_findnode_did(vport, nportid);
	if (ondlp) {
已提交
1394 1395 1396 1397 1398 1399 1400 1401 1402
		memcpy(&fp->OportName, &ondlp->nlp_portname,
		       sizeof (struct lpfc_name));
		memcpy(&fp->OnodeName, &ondlp->nlp_nodename,
		       sizeof (struct lpfc_name));
	}

	phba->fc_stat.elsXmitFARPR++;
	elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
1403
		lpfc_nlp_put(ndlp);
已提交
1404
		lpfc_els_free_iocb(phba, elsiocb);
1405
		return 1;
已提交
1406
	}
1407
	lpfc_nlp_put(ndlp);
1408
	return 0;
已提交
1409 1410
}

1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431
static void
lpfc_end_rscn(struct lpfc_vport *vport)
{
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

	if (vport->fc_flag & FC_RSCN_MODE) {
		/*
		 * Check to see if more RSCNs came in while we were
		 * processing this one.
		 */
		if (vport->fc_rscn_id_cnt ||
		    (vport->fc_flag & FC_RSCN_DISCOVERY) != 0)
			lpfc_els_handle_rscn(vport);
		else {
			spin_lock_irq(shost->host_lock);
			vport->fc_flag &= ~FC_RSCN_MODE;
			spin_unlock_irq(shost->host_lock);
		}
	}
}

1432
void
J
James Smart 已提交
1433
lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp)
1434
{
J
James Smart 已提交
1435 1436 1437
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);

	spin_lock_irq(shost->host_lock);
1438
	nlp->nlp_flag &= ~NLP_DELAY_TMO;
J
James Smart 已提交
1439
	spin_unlock_irq(shost->host_lock);
1440 1441 1442 1443 1444 1445 1446
	del_timer_sync(&nlp->nlp_delayfunc);
	nlp->nlp_last_elscmd = 0;

	if (!list_empty(&nlp->els_retry_evt.evt_listp))
		list_del_init(&nlp->els_retry_evt.evt_listp);

	if (nlp->nlp_flag & NLP_NPR_2B_DISC) {
J
James Smart 已提交
1447
		spin_lock_irq(shost->host_lock);
1448
		nlp->nlp_flag &= ~NLP_NPR_2B_DISC;
J
James Smart 已提交
1449 1450
		spin_unlock_irq(shost->host_lock);
		if (vport->num_disc_nodes) {
1451 1452 1453
			/* Check to see if there are more
			 * PLOGIs to be sent
			 */
J
James Smart 已提交
1454 1455 1456 1457 1458 1459 1460
			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);
1461
				lpfc_end_rscn(vport);
1462 1463 1464 1465 1466 1467
			}
		}
	}
	return;
}

已提交
1468 1469 1470
void
lpfc_els_retry_delay(unsigned long ptr)
{
J
James Smart 已提交
1471 1472 1473 1474
	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) ptr;
	struct lpfc_vport *vport = ndlp->vport;
	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba   *phba = vport->phba;
已提交
1475
	unsigned long iflag;
J
James Smart 已提交
1476
	struct lpfc_work_evt  *evtp = &ndlp->els_retry_evt;
已提交
1477

J
James Smart 已提交
1478 1479
	ndlp = (struct lpfc_nodelist *) ptr;
	phba = ndlp->vport->phba;
已提交
1480 1481
	evtp = &ndlp->els_retry_evt;

J
James Smart 已提交
1482
	spin_lock_irqsave(shost->host_lock, iflag);
已提交
1483
	if (!list_empty(&evtp->evt_listp)) {
J
James Smart 已提交
1484
		spin_unlock_irqrestore(shost->host_lock, iflag);
已提交
1485 1486 1487 1488 1489 1490 1491 1492 1493
		return;
	}

	evtp->evt_arg1  = ndlp;
	evtp->evt       = LPFC_EVT_ELS_RETRY;
	list_add_tail(&evtp->evt_listp, &phba->work_list);
	if (phba->work_wait)
		wake_up(phba->work_wait);

J
James Smart 已提交
1494
	spin_unlock_irqrestore(shost->host_lock, iflag);
已提交
1495 1496 1497 1498 1499 1500
	return;
}

void
lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp)
{
J
James Smart 已提交
1501 1502 1503
	struct lpfc_vport *vport = ndlp->vport;
	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
	uint32_t cmd, did, retry;
已提交
1504

J
James Smart 已提交
1505
	spin_lock_irq(shost->host_lock);
1506 1507 1508
	did = ndlp->nlp_DID;
	cmd = ndlp->nlp_last_elscmd;
	ndlp->nlp_last_elscmd = 0;
已提交
1509 1510

	if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
J
James Smart 已提交
1511
		spin_unlock_irq(shost->host_lock);
已提交
1512 1513 1514 1515
		return;
	}

	ndlp->nlp_flag &= ~NLP_DELAY_TMO;
J
James Smart 已提交
1516
	spin_unlock_irq(shost->host_lock);
1517 1518 1519 1520 1521 1522
	/*
	 * If a discovery event readded nlp_delayfunc after timer
	 * firing and before processing the timer, cancel the
	 * nlp_delayfunc.
	 */
	del_timer_sync(&ndlp->nlp_delayfunc);
已提交
1523 1524 1525 1526
	retry = ndlp->nlp_retry;

	switch (cmd) {
	case ELS_CMD_FLOGI:
J
James Smart 已提交
1527
		lpfc_issue_els_flogi(vport, ndlp, retry);
已提交
1528 1529
		break;
	case ELS_CMD_PLOGI:
J
James Smart 已提交
1530
		if (!lpfc_issue_els_plogi(vport, ndlp->nlp_DID, retry)) {
1531
			ndlp->nlp_prev_state = ndlp->nlp_state;
J
James Smart 已提交
1532
			lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
1533
		}
已提交
1534 1535
		break;
	case ELS_CMD_ADISC:
J
James Smart 已提交
1536
		if (!lpfc_issue_els_adisc(vport, ndlp, retry)) {
1537
			ndlp->nlp_prev_state = ndlp->nlp_state;
J
James Smart 已提交
1538
			lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
1539
		}
已提交
1540 1541
		break;
	case ELS_CMD_PRLI:
J
James Smart 已提交
1542
		if (!lpfc_issue_els_prli(vport, ndlp, retry)) {
1543
			ndlp->nlp_prev_state = ndlp->nlp_state;
J
James Smart 已提交
1544
			lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
1545
		}
已提交
1546 1547
		break;
	case ELS_CMD_LOGO:
J
James Smart 已提交
1548
		if (!lpfc_issue_els_logo(vport, ndlp, retry)) {
1549
			ndlp->nlp_prev_state = ndlp->nlp_state;
J
James Smart 已提交
1550
			lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
1551
		}
已提交
1552 1553 1554 1555 1556 1557
		break;
	}
	return;
}

static int
J
James Smart 已提交
1558 1559
lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
	       struct lpfc_iocbq *rspiocb)
已提交
1560
{
J
James Smart 已提交
1561 1562 1563 1564 1565
	struct lpfc_vport *vport = cmdiocb->vport;
	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
	IOCB_t *irsp = &rspiocb->iocb;
	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
	struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
已提交
1566 1567
	uint32_t *elscmd;
	struct ls_rjt stat;
J
James Smart 已提交
1568 1569
	int retry = 0, maxretry = lpfc_max_els_tries, delay = 0;
	uint32_t cmd = 0;
1570
	uint32_t did;
已提交
1571

1572

已提交
1573 1574 1575 1576 1577 1578 1579 1580 1581
	/* Note: context2 may be 0 for internal driver abort
	 * of delays ELS command.
	 */

	if (pcmd && pcmd->virt) {
		elscmd = (uint32_t *) (pcmd->virt);
		cmd = *elscmd++;
	}

1582
	if (ndlp)
1583 1584 1585 1586
		did = ndlp->nlp_DID;
	else {
		/* We should only hit this case for retrying PLOGI */
		did = irsp->un.elsreq64.remoteID;
J
James Smart 已提交
1587
		ndlp = lpfc_findnode_did(vport, did);
1588 1589 1590 1591
		if (!ndlp && (cmd != ELS_CMD_PLOGI))
			return 1;
	}

已提交
1592 1593 1594 1595 1596 1597 1598 1599
	switch (irsp->ulpStatus) {
	case IOSTAT_FCP_RSP_ERROR:
	case IOSTAT_REMOTE_STOP:
		break;

	case IOSTAT_LOCAL_REJECT:
		switch ((irsp->un.ulpWord[4] & 0xff)) {
		case IOERR_LOOP_OPEN_FAILURE:
J
James Smart 已提交
1600
			if (cmd == ELS_CMD_PLOGI && cmdiocb->retry == 0)
已提交
1601 1602 1603 1604 1605 1606 1607 1608 1609
					delay = 1;
			retry = 1;
			break;

		case IOERR_SEQUENCE_TIMEOUT:
			retry = 1;
			break;

		case IOERR_NO_RESOURCES:
J
James Smart 已提交
1610
			if (cmd == ELS_CMD_PLOGI)
已提交
1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675
				delay = 1;
			retry = 1;
			break;

		case IOERR_INVALID_RPI:
			retry = 1;
			break;
		}
		break;

	case IOSTAT_NPORT_RJT:
	case IOSTAT_FABRIC_RJT:
		if (irsp->un.ulpWord[4] & RJT_UNAVAIL_TEMP) {
			retry = 1;
			break;
		}
		break;

	case IOSTAT_NPORT_BSY:
	case IOSTAT_FABRIC_BSY:
		retry = 1;
		break;

	case IOSTAT_LS_RJT:
		stat.un.lsRjtError = be32_to_cpu(irsp->un.ulpWord[4]);
		/* Added for Vendor specifc support
		 * Just keep retrying for these Rsn / Exp codes
		 */
		switch (stat.un.b.lsRjtRsnCode) {
		case LSRJT_UNABLE_TPC:
			if (stat.un.b.lsRjtRsnCodeExp ==
			    LSEXP_CMD_IN_PROGRESS) {
				if (cmd == ELS_CMD_PLOGI) {
					delay = 1;
					maxretry = 48;
				}
				retry = 1;
				break;
			}
			if (cmd == ELS_CMD_PLOGI) {
				delay = 1;
				maxretry = lpfc_max_els_tries + 1;
				retry = 1;
				break;
			}
			break;

		case LSRJT_LOGICAL_BSY:
			if (cmd == ELS_CMD_PLOGI) {
				delay = 1;
				maxretry = 48;
			}
			retry = 1;
			break;
		}
		break;

	case IOSTAT_INTERMED_RSP:
	case IOSTAT_BA_RJT:
		break;

	default:
		break;
	}

1676
	if (did == FDMI_DID)
已提交
1677 1678 1679 1680 1681 1682 1683
		retry = 1;

	if ((++cmdiocb->retry) >= maxretry) {
		phba->fc_stat.elsRetryExceeded++;
		retry = 0;
	}

1684 1685 1686
	if ((vport->load_flag & FC_UNLOADING) != 0)
		retry = 0;

已提交
1687 1688 1689 1690 1691 1692 1693
	if (retry) {

		/* Retry ELS command <elsCmd> to remote NPORT <did> */
		lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
				"%d:0107 Retry ELS command x%x to remote "
				"NPORT x%x Data: x%x x%x\n",
				phba->brd_no,
1694
				cmd, did, cmdiocb->retry, delay);
已提交
1695 1696 1697

		if ((cmd == ELS_CMD_PLOGI) || (cmd == ELS_CMD_ADISC)) {
			/* If discovery / RSCN timer is running, reset it */
J
James Smart 已提交
1698 1699 1700
			if (timer_pending(&vport->fc_disctmo) ||
			      (vport->fc_flag & FC_RSCN_MODE))
				lpfc_set_disctmo(vport);
已提交
1701 1702 1703
		}

		phba->fc_stat.elsXmitRetry++;
1704
		if (ndlp && delay) {
已提交
1705 1706 1707 1708
			phba->fc_stat.elsDelayRetry++;
			ndlp->nlp_retry = cmdiocb->retry;

			mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
J
James Smart 已提交
1709
			spin_lock_irq(shost->host_lock);
已提交
1710
			ndlp->nlp_flag |= NLP_DELAY_TMO;
J
James Smart 已提交
1711
			spin_unlock_irq(shost->host_lock);
已提交
1712

1713
			ndlp->nlp_prev_state = ndlp->nlp_state;
J
James Smart 已提交
1714
			lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
已提交
1715 1716
			ndlp->nlp_last_elscmd = cmd;

1717
			return 1;
已提交
1718 1719 1720
		}
		switch (cmd) {
		case ELS_CMD_FLOGI:
J
James Smart 已提交
1721
			lpfc_issue_els_flogi(vport, ndlp, cmdiocb->retry);
1722
			return 1;
已提交
1723
		case ELS_CMD_PLOGI:
1724 1725
			if (ndlp) {
				ndlp->nlp_prev_state = ndlp->nlp_state;
J
James Smart 已提交
1726
				lpfc_nlp_set_state(vport, ndlp,
1727
						   NLP_STE_PLOGI_ISSUE);
1728
			}
J
James Smart 已提交
1729
			lpfc_issue_els_plogi(vport, did, cmdiocb->retry);
1730
			return 1;
已提交
1731
		case ELS_CMD_ADISC:
1732
			ndlp->nlp_prev_state = ndlp->nlp_state;
J
James Smart 已提交
1733 1734
			lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
			lpfc_issue_els_adisc(vport, ndlp, cmdiocb->retry);
1735
			return 1;
已提交
1736
		case ELS_CMD_PRLI:
1737
			ndlp->nlp_prev_state = ndlp->nlp_state;
J
James Smart 已提交
1738 1739
			lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
			lpfc_issue_els_prli(vport, ndlp, cmdiocb->retry);
1740
			return 1;
已提交
1741
		case ELS_CMD_LOGO:
1742
			ndlp->nlp_prev_state = ndlp->nlp_state;
J
James Smart 已提交
1743 1744
			lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
			lpfc_issue_els_logo(vport, ndlp, cmdiocb->retry);
1745
			return 1;
已提交
1746 1747 1748 1749 1750 1751
		}
	}

	/* No retry ELS command <elsCmd> to remote NPORT <did> */
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
			"%d:0108 No retry ELS command x%x to remote NPORT x%x "
1752
			"Data: x%x\n",
已提交
1753
			phba->brd_no,
1754
			cmd, did, cmdiocb->retry);
已提交
1755

1756
	return 0;
已提交
1757 1758 1759
}

int
1760
lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
已提交
1761 1762 1763
{
	struct lpfc_dmabuf *buf_ptr, *buf_ptr1;

1764 1765 1766 1767
	if (elsiocb->context1) {
		lpfc_nlp_put(elsiocb->context1);
		elsiocb->context1 = NULL;
	}
已提交
1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787
	/* context2  = cmd,  context2->next = rsp, context3 = bpl */
	if (elsiocb->context2) {
		buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
		/* Free the response before processing the command.  */
		if (!list_empty(&buf_ptr1->list)) {
			list_remove_head(&buf_ptr1->list, buf_ptr,
					 struct lpfc_dmabuf,
					 list);
			lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
			kfree(buf_ptr);
		}
		lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys);
		kfree(buf_ptr1);
	}

	if (elsiocb->context3) {
		buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3;
		lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
		kfree(buf_ptr);
	}
1788
	lpfc_sli_release_iocbq(phba, elsiocb);
已提交
1789 1790 1791 1792
	return 0;
}

static void
J
James Smart 已提交
1793 1794
lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
		       struct lpfc_iocbq *rspiocb)
已提交
1795
{
J
James Smart 已提交
1796 1797
	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
	struct lpfc_vport *vport = cmdiocb->vport;
已提交
1798 1799 1800 1801 1802 1803 1804 1805 1806 1807

	/* ACC to LOGO completes to NPort <nlp_DID> */
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
			"%d:0109 ACC to LOGO completes to NPort x%x "
			"Data: x%x x%x x%x\n",
			phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag,
			ndlp->nlp_state, ndlp->nlp_rpi);

	switch (ndlp->nlp_state) {
	case NLP_STE_UNUSED_NODE:	/* node is just allocated */
J
James Smart 已提交
1808
		lpfc_drop_node(vport, ndlp);
已提交
1809 1810
		break;
	case NLP_STE_NPR_NODE:		/* NPort Recovery mode */
J
James Smart 已提交
1811
		lpfc_unreg_rpi(vport, ndlp);
已提交
1812 1813 1814 1815 1816 1817 1818 1819 1820
		break;
	default:
		break;
	}
	lpfc_els_free_iocb(phba, cmdiocb);
	return;
}

static void
1821 1822
lpfc_cmpl_els_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
		  struct lpfc_iocbq *rspiocb)
已提交
1823
{
J
James Smart 已提交
1824 1825 1826
	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
	struct lpfc_vport *vport = ndlp ? ndlp->vport : NULL;
	struct Scsi_Host  *shost = vport ? lpfc_shost_from_vport(vport) : NULL;
J
James Smart 已提交
1827
	IOCB_t *irsp;
已提交
1828
	LPFC_MBOXQ_t *mbox = NULL;
J
James Smart 已提交
1829
	struct lpfc_dmabuf *mp = NULL;
已提交
1830

J
James Smart 已提交
1831 1832
	irsp = &rspiocb->iocb;

已提交
1833 1834 1835 1836
	if (cmdiocb->context_un.mbox)
		mbox = cmdiocb->context_un.mbox;

	/* Check to see if link went down during discovery */
J
James Smart 已提交
1837
	if (!ndlp || lpfc_els_chk_latt(vport)) {
已提交
1838
		if (mbox) {
1839 1840 1841 1842 1843
			mp = (struct lpfc_dmabuf *) mbox->context1;
			if (mp) {
				lpfc_mbuf_free(phba, mp->virt, mp->phys);
				kfree(mp);
			}
1844
			mempool_free(mbox, phba->mbox_mem_pool);
已提交
1845 1846 1847 1848 1849 1850 1851
		}
		goto out;
	}

	/* ELS response tag <ulpIoTag> completes */
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
			"%d:0110 ELS response tag x%x completes "
1852
			"Data: x%x x%x x%x x%x x%x x%x x%x\n",
已提交
1853 1854
			phba->brd_no,
			cmdiocb->iocb.ulpIoTag, rspiocb->iocb.ulpStatus,
1855
			rspiocb->iocb.un.ulpWord[4], rspiocb->iocb.ulpTimeout,
J
James Smart 已提交
1856
			ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
1857
			ndlp->nlp_rpi);
已提交
1858 1859 1860 1861

	if (mbox) {
		if ((rspiocb->iocb.ulpStatus == 0)
		    && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) {
J
James Smart 已提交
1862
			lpfc_unreg_rpi(vport, ndlp);
已提交
1863
			mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
1864
			mbox->context2 = lpfc_nlp_get(ndlp);
J
James Smart 已提交
1865
			mbox->vport = vport;
1866
			ndlp->nlp_prev_state = ndlp->nlp_state;
J
James Smart 已提交
1867 1868
			lpfc_nlp_set_state(vport, ndlp,
					   NLP_STE_REG_LOGIN_ISSUE);
已提交
1869 1870 1871 1872 1873
			if (lpfc_sli_issue_mbox(phba, mbox,
						(MBX_NOWAIT | MBX_STOP_IOCB))
			    != MBX_NOT_FINISHED) {
				goto out;
			}
1874
			lpfc_nlp_put(ndlp);
已提交
1875 1876 1877
			/* NOTE: we should have messages for unsuccessful
			   reglogin */
		} else {
J
James Smart 已提交
1878 1879 1880 1881 1882 1883
			/* Do not call NO_LIST for lpfc_els_abort'ed ELS cmds */
			if (!((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
			      ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
			       (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
			       (irsp->un.ulpWord[4] == IOERR_SLI_DOWN)))) {
				if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
J
James Smart 已提交
1884
					lpfc_drop_node(vport, ndlp);
J
James Smart 已提交
1885 1886
					ndlp = NULL;
				}
已提交
1887 1888
			}
		}
1889 1890 1891 1892 1893 1894
		mp = (struct lpfc_dmabuf *) mbox->context1;
		if (mp) {
			lpfc_mbuf_free(phba, mp->virt, mp->phys);
			kfree(mp);
		}
		mempool_free(mbox, phba->mbox_mem_pool);
已提交
1895 1896 1897
	}
out:
	if (ndlp) {
J
James Smart 已提交
1898
		spin_lock_irq(shost->host_lock);
已提交
1899
		ndlp->nlp_flag &= ~NLP_ACC_REGLOGIN;
J
James Smart 已提交
1900
		spin_unlock_irq(shost->host_lock);
已提交
1901 1902 1903 1904 1905 1906
	}
	lpfc_els_free_iocb(phba, cmdiocb);
	return;
}

int
J
James Smart 已提交
1907 1908 1909
lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
		 struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp,
		 LPFC_MBOXQ_t *mbox, uint8_t newnode)
已提交
1910
{
J
James Smart 已提交
1911 1912
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba  *phba = vport->phba;
已提交
1913 1914 1915 1916 1917 1918 1919 1920
	IOCB_t *icmd;
	IOCB_t *oldcmd;
	struct lpfc_iocbq *elsiocb;
	struct lpfc_sli_ring *pring;
	struct lpfc_sli *psli;
	uint8_t *pcmd;
	uint16_t cmdsize;
	int rc;
1921
	ELS_PKT *els_pkt_ptr;
已提交
1922 1923 1924 1925 1926 1927 1928 1929

	psli = &phba->sli;
	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */
	oldcmd = &oldiocb->iocb;

	switch (flag) {
	case ELS_CMD_ACC:
		cmdsize = sizeof (uint32_t);
J
James Smart 已提交
1930 1931
		elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
					     ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
1932
		if (!elsiocb) {
J
James Smart 已提交
1933
			spin_lock_irq(shost->host_lock);
1934
			ndlp->nlp_flag &= ~NLP_LOGO_ACC;
J
James Smart 已提交
1935
			spin_unlock_irq(shost->host_lock);
1936
			return 1;
已提交
1937
		}
J
James Smart 已提交
1938

已提交
1939 1940 1941 1942 1943 1944 1945 1946
		icmd = &elsiocb->iocb;
		icmd->ulpContext = oldcmd->ulpContext;	/* Xri */
		pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
		*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
		pcmd += sizeof (uint32_t);
		break;
	case ELS_CMD_PLOGI:
		cmdsize = (sizeof (struct serv_parm) + sizeof (uint32_t));
J
James Smart 已提交
1947 1948
		elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
					     ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
1949
		if (!elsiocb)
1950
			return 1;
1951

已提交
1952 1953 1954 1955 1956 1957 1958 1959 1960
		icmd = &elsiocb->iocb;
		icmd->ulpContext = oldcmd->ulpContext;	/* Xri */
		pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);

		if (mbox)
			elsiocb->context_un.mbox = mbox;

		*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
		pcmd += sizeof (uint32_t);
J
James Smart 已提交
1961
		memcpy(pcmd, &vport->fc_sparam, sizeof (struct serv_parm));
已提交
1962
		break;
1963 1964
	case ELS_CMD_PRLO:
		cmdsize = sizeof (uint32_t) + sizeof (PRLO);
J
James Smart 已提交
1965
		elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979
					     ndlp, ndlp->nlp_DID, ELS_CMD_PRLO);
		if (!elsiocb)
			return 1;

		icmd = &elsiocb->iocb;
		icmd->ulpContext = oldcmd->ulpContext; /* Xri */
		pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);

		memcpy(pcmd, ((struct lpfc_dmabuf *) oldiocb->context2)->virt,
		       sizeof (uint32_t) + sizeof (PRLO));
		*((uint32_t *) (pcmd)) = ELS_CMD_PRLO_ACC;
		els_pkt_ptr = (ELS_PKT *) pcmd;
		els_pkt_ptr->un.prlo.acceptRspCode = PRLO_REQ_EXECUTED;
		break;
已提交
1980
	default:
1981
		return 1;
已提交
1982 1983
	}

1984 1985
	if (newnode) {
		lpfc_nlp_put(ndlp);
已提交
1986
		elsiocb->context1 = NULL;
1987
	}
已提交
1988 1989 1990

	/* Xmit ELS ACC response tag <ulpIoTag> */
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
1991 1992 1993
			"%d:0128 Xmit ELS ACC response tag x%x, XRI: x%x, "
			"DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x\n",
			phba->brd_no, elsiocb->iotag,
已提交
1994 1995 1996 1997
			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);

	if (ndlp->nlp_flag & NLP_LOGO_ACC) {
J
James Smart 已提交
1998
		spin_lock_irq(shost->host_lock);
1999
		ndlp->nlp_flag &= ~NLP_LOGO_ACC;
J
James Smart 已提交
2000
		spin_unlock_irq(shost->host_lock);
已提交
2001 2002 2003 2004 2005 2006 2007 2008 2009
		elsiocb->iocb_cmpl = lpfc_cmpl_els_logo_acc;
	} else {
		elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
	}

	phba->fc_stat.elsXmitACC++;
	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
2010
		return 1;
已提交
2011
	}
2012
	return 0;
已提交
2013 2014 2015
}

int
J
James Smart 已提交
2016 2017
lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
		    struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
已提交
2018
{
J
James Smart 已提交
2019
	struct lpfc_hba  *phba = vport->phba;
已提交
2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032
	IOCB_t *icmd;
	IOCB_t *oldcmd;
	struct lpfc_iocbq *elsiocb;
	struct lpfc_sli_ring *pring;
	struct lpfc_sli *psli;
	uint8_t *pcmd;
	uint16_t cmdsize;
	int rc;

	psli = &phba->sli;
	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */

	cmdsize = 2 * sizeof (uint32_t);
J
James Smart 已提交
2033 2034
	elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
				     ndlp->nlp_DID, ELS_CMD_LS_RJT);
2035
	if (!elsiocb)
2036
		return 1;
已提交
2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048

	icmd = &elsiocb->iocb;
	oldcmd = &oldiocb->iocb;
	icmd->ulpContext = oldcmd->ulpContext;	/* Xri */
	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);

	*((uint32_t *) (pcmd)) = ELS_CMD_LS_RJT;
	pcmd += sizeof (uint32_t);
	*((uint32_t *) (pcmd)) = rejectError;

	/* Xmit ELS RJT <err> response tag <ulpIoTag> */
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
2049 2050 2051
			"%d:0129 Xmit ELS RJT x%x response tag x%x xri x%x, "
			"did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
			phba->brd_no, rejectError, elsiocb->iotag,
已提交
2052 2053 2054 2055 2056 2057 2058 2059
			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);

	phba->fc_stat.elsXmitLSRJT++;
	elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
2060
		return 1;
已提交
2061
	}
2062
	return 0;
已提交
2063 2064 2065
}

int
J
James Smart 已提交
2066 2067
lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
		       struct lpfc_nodelist *ndlp)
已提交
2068
{
J
James Smart 已提交
2069 2070 2071
	struct lpfc_hba  *phba = vport->phba;
	struct lpfc_sli  *psli = &phba->sli;
	struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
已提交
2072
	ADISC *ap;
J
James Smart 已提交
2073
	IOCB_t *icmd, *oldcmd;
已提交
2074 2075 2076 2077 2078 2079
	struct lpfc_iocbq *elsiocb;
	uint8_t *pcmd;
	uint16_t cmdsize;
	int rc;

	cmdsize = sizeof (uint32_t) + sizeof (ADISC);
J
James Smart 已提交
2080 2081
	elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
				     ndlp->nlp_DID, ELS_CMD_ACC);
2082
	if (!elsiocb)
2083
		return 1;
已提交
2084

2085 2086 2087 2088
	icmd = &elsiocb->iocb;
	oldcmd = &oldiocb->iocb;
	icmd->ulpContext = oldcmd->ulpContext;	/* Xri */

已提交
2089 2090
	/* Xmit ADISC ACC response tag <ulpIoTag> */
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
2091 2092 2093
			"%d:0130 Xmit ADISC ACC response iotag x%x xri: "
			"x%x, did x%x, nlp_flag x%x, nlp_state x%x rpi x%x\n",
			phba->brd_no, elsiocb->iotag,
已提交
2094 2095 2096 2097 2098 2099 2100 2101 2102 2103
			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);

	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);

	*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
	pcmd += sizeof (uint32_t);

	ap = (ADISC *) (pcmd);
	ap->hardAL_PA = phba->fc_pref_ALPA;
J
James Smart 已提交
2104 2105 2106
	memcpy(&ap->portName, &vport->fc_portname, sizeof (struct lpfc_name));
	memcpy(&ap->nodeName, &vport->fc_nodename, sizeof (struct lpfc_name));
	ap->DID = be32_to_cpu(vport->fc_myDID);
已提交
2107 2108 2109 2110 2111 2112

	phba->fc_stat.elsXmitACC++;
	elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
2113
		return 1;
已提交
2114
	}
2115
	return 0;
已提交
2116 2117 2118
}

int
J
James Smart 已提交
2119
lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
2120
		      struct lpfc_nodelist *ndlp)
已提交
2121
{
J
James Smart 已提交
2122
	struct lpfc_hba  *phba = vport->phba;
已提交
2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137
	PRLI *npr;
	lpfc_vpd_t *vpd;
	IOCB_t *icmd;
	IOCB_t *oldcmd;
	struct lpfc_iocbq *elsiocb;
	struct lpfc_sli_ring *pring;
	struct lpfc_sli *psli;
	uint8_t *pcmd;
	uint16_t cmdsize;
	int rc;

	psli = &phba->sli;
	pring = &psli->ring[LPFC_ELS_RING];	/* ELS ring */

	cmdsize = sizeof (uint32_t) + sizeof (PRLI);
J
James Smart 已提交
2138
	elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
2139
	     ndlp->nlp_DID, (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK)));
2140 2141
	if (!elsiocb)
		return 1;
已提交
2142

2143 2144 2145 2146
	icmd = &elsiocb->iocb;
	oldcmd = &oldiocb->iocb;
	icmd->ulpContext = oldcmd->ulpContext;	/* Xri */

已提交
2147 2148
	/* Xmit PRLI ACC response tag <ulpIoTag> */
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
2149 2150 2151
			"%d:0131 Xmit PRLI ACC response tag x%x xri x%x, "
			"did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
			phba->brd_no, elsiocb->iotag,
已提交
2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188
			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);

	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);

	*((uint32_t *) (pcmd)) = (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK));
	pcmd += sizeof (uint32_t);

	/* For PRLI, remainder of payload is PRLI parameter page */
	memset(pcmd, 0, sizeof (PRLI));

	npr = (PRLI *) pcmd;
	vpd = &phba->vpd;
	/*
	 * If our firmware version is 3.20 or later,
	 * set the following bits for FC-TAPE support.
	 */
	if (vpd->rev.feaLevelHigh >= 0x02) {
		npr->ConfmComplAllowed = 1;
		npr->Retry = 1;
		npr->TaskRetryIdReq = 1;
	}

	npr->acceptRspCode = PRLI_REQ_EXECUTED;
	npr->estabImagePair = 1;
	npr->readXferRdyDis = 1;
	npr->ConfmComplAllowed = 1;

	npr->prliType = PRLI_FCP_TYPE;
	npr->initiatorFunc = 1;

	phba->fc_stat.elsXmitACC++;
	elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;

	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
2189
		return 1;
已提交
2190
	}
2191
	return 0;
已提交
2192 2193 2194
}

static int
J
James Smart 已提交
2195
lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format,
2196
		      struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
已提交
2197
{
J
James Smart 已提交
2198
	struct lpfc_hba  *phba = vport->phba;
已提交
2199
	RNID *rn;
J
James Smart 已提交
2200
	IOCB_t *icmd, *oldcmd;
已提交
2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215
	struct lpfc_iocbq *elsiocb;
	struct lpfc_sli_ring *pring;
	struct lpfc_sli *psli;
	uint8_t *pcmd;
	uint16_t cmdsize;
	int rc;

	psli = &phba->sli;
	pring = &psli->ring[LPFC_ELS_RING];

	cmdsize = sizeof (uint32_t) + sizeof (uint32_t)
		+ (2 * sizeof (struct lpfc_name));
	if (format)
		cmdsize += sizeof (RNID_TOP_DISC);

J
James Smart 已提交
2216 2217
	elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
				     ndlp->nlp_DID, ELS_CMD_ACC);
2218
	if (!elsiocb)
2219
		return 1;
已提交
2220

2221 2222 2223 2224
	icmd = &elsiocb->iocb;
	oldcmd = &oldiocb->iocb;
	icmd->ulpContext = oldcmd->ulpContext;	/* Xri */

已提交
2225 2226 2227
	/* Xmit RNID ACC response tag <ulpIoTag> */
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
			"%d:0132 Xmit RNID ACC response tag x%x "
2228 2229
			"xri x%x\n",
			phba->brd_no, elsiocb->iotag,
已提交
2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240
			elsiocb->iocb.ulpContext);

	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);

	*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
	pcmd += sizeof (uint32_t);

	memset(pcmd, 0, sizeof (RNID));
	rn = (RNID *) (pcmd);
	rn->Format = format;
	rn->CommonLen = (2 * sizeof (struct lpfc_name));
J
James Smart 已提交
2241 2242
	memcpy(&rn->portName, &vport->fc_portname, sizeof (struct lpfc_name));
	memcpy(&rn->nodeName, &vport->fc_nodename, sizeof (struct lpfc_name));
已提交
2243 2244 2245 2246 2247 2248 2249
	switch (format) {
	case 0:
		rn->SpecificLen = 0;
		break;
	case RNID_TOPOLOGY_DISC:
		rn->SpecificLen = sizeof (RNID_TOP_DISC);
		memcpy(&rn->un.topologyDisc.portName,
J
James Smart 已提交
2250
		       &vport->fc_portname, sizeof (struct lpfc_name));
已提交
2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262
		rn->un.topologyDisc.unitType = RNID_HBA;
		rn->un.topologyDisc.physPort = 0;
		rn->un.topologyDisc.attachedNodes = 0;
		break;
	default:
		rn->CommonLen = 0;
		rn->SpecificLen = 0;
		break;
	}

	phba->fc_stat.elsXmitACC++;
	elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
2263
	lpfc_nlp_put(ndlp);
已提交
2264 2265 2266 2267 2268 2269
	elsiocb->context1 = NULL;  /* Don't need ndlp for cmpl,
				    * it could be freed */

	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
	if (rc == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
2270
		return 1;
已提交
2271
	}
2272
	return 0;
已提交
2273 2274 2275
}

int
J
James Smart 已提交
2276
lpfc_els_disc_adisc(struct lpfc_vport *vport)
已提交
2277
{
J
James Smart 已提交
2278
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
已提交
2279
	struct lpfc_nodelist *ndlp, *next_ndlp;
J
James Smart 已提交
2280
	int sentadisc = 0;
已提交
2281

2282
	/* go thru NPR nodes and issue any remaining ELS ADISCs */
J
James Smart 已提交
2283
	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
2284 2285 2286
		if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
		    (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
		    (ndlp->nlp_flag & NLP_NPR_ADISC) != 0) {
J
James Smart 已提交
2287
			spin_lock_irq(shost->host_lock);
2288
			ndlp->nlp_flag &= ~NLP_NPR_ADISC;
J
James Smart 已提交
2289
			spin_unlock_irq(shost->host_lock);
2290
			ndlp->nlp_prev_state = ndlp->nlp_state;
J
James Smart 已提交
2291 2292
			lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
			lpfc_issue_els_adisc(vport, ndlp, 0);
2293
			sentadisc++;
J
James Smart 已提交
2294 2295 2296 2297 2298 2299
			vport->num_disc_nodes++;
			if (vport->num_disc_nodes >=
			    vport->phba->cfg_discovery_threads) {
				spin_lock_irq(shost->host_lock);
				vport->fc_flag |= FC_NLP_MORE;
				spin_unlock_irq(shost->host_lock);
2300
				break;
已提交
2301 2302 2303 2304
			}
		}
	}
	if (sentadisc == 0) {
J
James Smart 已提交
2305 2306 2307
		spin_lock_irq(shost->host_lock);
		vport->fc_flag &= ~FC_NLP_MORE;
		spin_unlock_irq(shost->host_lock);
已提交
2308
	}
2309
	return sentadisc;
已提交
2310 2311 2312
}

int
J
James Smart 已提交
2313
lpfc_els_disc_plogi(struct lpfc_vport *vport)
已提交
2314
{
J
James Smart 已提交
2315
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
已提交
2316
	struct lpfc_nodelist *ndlp, *next_ndlp;
J
James Smart 已提交
2317
	int sentplogi = 0;
已提交
2318

J
James Smart 已提交
2319 2320
	/* go thru NPR nodes and issue any remaining ELS PLOGIs */
	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
2321 2322 2323 2324 2325
		if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
		    (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
		    (ndlp->nlp_flag & NLP_DELAY_TMO) == 0 &&
		    (ndlp->nlp_flag & NLP_NPR_ADISC) == 0) {
			ndlp->nlp_prev_state = ndlp->nlp_state;
J
James Smart 已提交
2326 2327
			lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
			lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
2328
			sentplogi++;
J
James Smart 已提交
2329 2330 2331 2332 2333 2334
			vport->num_disc_nodes++;
			if (vport->num_disc_nodes >=
			    vport->phba->cfg_discovery_threads) {
				spin_lock_irq(shost->host_lock);
				vport->fc_flag |= FC_NLP_MORE;
				spin_unlock_irq(shost->host_lock);
2335
				break;
已提交
2336 2337 2338 2339
			}
		}
	}
	if (sentplogi == 0) {
J
James Smart 已提交
2340 2341 2342
		spin_lock_irq(shost->host_lock);
		vport->fc_flag &= ~FC_NLP_MORE;
		spin_unlock_irq(shost->host_lock);
已提交
2343
	}
2344
	return sentplogi;
已提交
2345 2346 2347
}

int
J
James Smart 已提交
2348
lpfc_els_flush_rscn(struct lpfc_vport *vport)
已提交
2349
{
J
James Smart 已提交
2350 2351
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba  *phba = vport->phba;
已提交
2352 2353 2354
	struct lpfc_dmabuf *mp;
	int i;

J
James Smart 已提交
2355 2356
	for (i = 0; i < vport->fc_rscn_id_cnt; i++) {
		mp = vport->fc_rscn_id_list[i];
2357 2358 2359 2360 2361 2362
		if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
			lpfc_sli_hbqbuf_free(phba, mp->virt, mp->phys);
		else {
			lpfc_mbuf_free(phba, mp->virt, mp->phys);
			kfree(mp);
		}
J
James Smart 已提交
2363
		vport->fc_rscn_id_list[i] = NULL;
已提交
2364
	}
J
James Smart 已提交
2365 2366 2367 2368 2369
	spin_lock_irq(shost->host_lock);
	vport->fc_rscn_id_cnt = 0;
	vport->fc_flag &= ~(FC_RSCN_MODE | FC_RSCN_DISCOVERY);
	spin_unlock_irq(shost->host_lock);
	lpfc_can_disctmo(vport);
2370
	return 0;
已提交
2371 2372 2373
}

int
J
James Smart 已提交
2374
lpfc_rscn_payload_check(struct lpfc_vport *vport, uint32_t did)
已提交
2375 2376 2377 2378 2379 2380
{
	D_ID ns_did;
	D_ID rscn_did;
	struct lpfc_dmabuf *mp;
	uint32_t *lp;
	uint32_t payload_len, cmd, i, match;
J
James Smart 已提交
2381
	struct lpfc_hba *phba = vport->phba;
已提交
2382 2383 2384 2385 2386 2387

	ns_did.un.word = did;
	match = 0;

	/* Never match fabric nodes for RSCNs */
	if ((did & Fabric_DID_MASK) == Fabric_DID_MASK)
J
James Smart 已提交
2388
		return 0;
已提交
2389 2390

	/* If we are doing a FULL RSCN rediscovery, match everything */
J
James Smart 已提交
2391
	if (vport->fc_flag & FC_RSCN_DISCOVERY)
2392
		return did;
已提交
2393

J
James Smart 已提交
2394 2395
	for (i = 0; i < vport->fc_rscn_id_cnt; i++) {
		mp = vport->fc_rscn_id_list[i];
已提交
2396 2397 2398 2399 2400 2401 2402 2403 2404 2405
		lp = (uint32_t *) mp->virt;
		cmd = *lp++;
		payload_len = be32_to_cpu(cmd) & 0xffff; /* payload length */
		payload_len -= sizeof (uint32_t);	/* take off word 0 */
		while (payload_len) {
			rscn_did.un.word = *lp++;
			rscn_did.un.word = be32_to_cpu(rscn_did.un.word);
			payload_len -= sizeof (uint32_t);
			switch (rscn_did.un.b.resv) {
			case 0:	/* Single N_Port ID effected */
J
James Smart 已提交
2406
				if (ns_did.un.word == rscn_did.un.word)
已提交
2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421
					match = did;
				break;
			case 1:	/* Whole N_Port Area effected */
				if ((ns_did.un.b.domain == rscn_did.un.b.domain)
				    && (ns_did.un.b.area == rscn_did.un.b.area))
						match = did;
				break;
			case 2:	/* Whole N_Port Domain effected */
				if (ns_did.un.b.domain == rscn_did.un.b.domain)
						match = did;
				break;
			case 3:	/* Whole Fabric effected */
				match = did;
				break;
			default:
J
James Smart 已提交
2422
				/* Unknown Identifier in RSCN node */
已提交
2423 2424 2425 2426 2427 2428
				lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
						"%d:0217 Unknown Identifier in "
						"RSCN payload Data: x%x\n",
						phba->brd_no, rscn_did.un.word);
				break;
			}
J
James Smart 已提交
2429
			if (match)
已提交
2430 2431 2432
				break;
			}
		}
2433
	return match;
已提交
2434 2435 2436
}

static int
J
James Smart 已提交
2437
lpfc_rscn_recovery_check(struct lpfc_vport *vport)
已提交
2438
{
2439
	struct lpfc_nodelist *ndlp = NULL;
已提交
2440 2441

	/* Look at all nodes effected by pending RSCNs and move
2442
	 * them to NPR state.
已提交
2443 2444
	 */

J
James Smart 已提交
2445
	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
2446
		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE ||
J
James Smart 已提交
2447
		    lpfc_rscn_payload_check(vport, ndlp->nlp_DID) == 0)
2448
			continue;
已提交
2449

J
James Smart 已提交
2450
		lpfc_disc_state_machine(vport, ndlp, NULL,
已提交
2451
					NLP_EVT_DEVICE_RECOVERY);
2452

2453 2454 2455 2456 2457
		/*
		 * Make sure NLP_DELAY_TMO is NOT running after a device
		 * recovery event.
		 */
		if (ndlp->nlp_flag & NLP_DELAY_TMO)
J
James Smart 已提交
2458
			lpfc_cancel_retry_delay_tmo(vport, ndlp);
已提交
2459
	}
2460

2461
	return 0;
已提交
2462 2463 2464
}

static int
J
James Smart 已提交
2465 2466
lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
		  struct lpfc_nodelist *ndlp, uint8_t newnode)
已提交
2467
{
J
James Smart 已提交
2468 2469
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba  *phba = vport->phba;
已提交
2470 2471 2472 2473
	struct lpfc_dmabuf *pcmd;
	uint32_t *lp;
	IOCB_t *icmd;
	uint32_t payload_len, cmd;
2474
	int i;
已提交
2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485

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

	cmd = *lp++;
	payload_len = be32_to_cpu(cmd) & 0xffff;	/* payload length */
	payload_len -= sizeof (uint32_t);	/* take off word 0 */
	cmd &= ELS_CMD_MASK;

	/* RSCN received */
2486
	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
已提交
2487
			"%d:0214 RSCN received Data: x%x x%x x%x x%x\n",
J
James Smart 已提交
2488 2489
			phba->brd_no, vport->fc_flag, payload_len, *lp,
			vport->fc_rscn_id_cnt);
已提交
2490

2491
	for (i = 0; i < payload_len/sizeof(uint32_t); i++)
J
James Smart 已提交
2492
		fc_host_post_event(shost, fc_get_event_number(),
2493 2494
			FCH_EVT_RSCN, lp[i]);

已提交
2495 2496 2497
	/* If we are about to begin discovery, just ACC the RSCN.
	 * Discovery processing will satisfy it.
	 */
J
James Smart 已提交
2498 2499
	if (vport->port_state <= LPFC_NS_QRY) {
		lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL,
已提交
2500
								newnode);
2501
		return 0;
已提交
2502 2503 2504 2505 2506
	}

	/* If we are already processing an RSCN, save the received
	 * RSCN payload buffer, cmdiocb->context2 to process later.
	 */
J
James Smart 已提交
2507 2508 2509 2510 2511 2512 2513
	if (vport->fc_flag & (FC_RSCN_MODE | FC_NDISC_ACTIVE)) {
		if ((vport->fc_rscn_id_cnt < FC_MAX_HOLD_RSCN) &&
		    !(vport->fc_flag & FC_RSCN_DISCOVERY)) {
			spin_lock_irq(shost->host_lock);
			vport->fc_flag |= FC_RSCN_MODE;
			spin_unlock_irq(shost->host_lock);
			vport->fc_rscn_id_list[vport->fc_rscn_id_cnt++] = pcmd;
已提交
2514 2515 2516 2517 2518 2519 2520 2521 2522 2523

			/* If we zero, cmdiocb->context2, the calling
			 * routine will not try to free it.
			 */
			cmdiocb->context2 = NULL;

			/* Deferred RSCN */
			lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
					"%d:0235 Deferred RSCN "
					"Data: x%x x%x x%x\n",
J
James Smart 已提交
2524 2525 2526
					phba->brd_no, vport->fc_rscn_id_cnt,
					vport->fc_flag,
					vport->port_state);
已提交
2527
		} else {
J
James Smart 已提交
2528 2529 2530
			spin_lock_irq(shost->host_lock);
			vport->fc_flag |= FC_RSCN_DISCOVERY;
			spin_unlock_irq(shost->host_lock);
已提交
2531 2532 2533 2534
			/* ReDiscovery RSCN */
			lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
					"%d:0234 ReDiscovery RSCN "
					"Data: x%x x%x x%x\n",
J
James Smart 已提交
2535 2536 2537
					phba->brd_no, vport->fc_rscn_id_cnt,
					vport->fc_flag,
					vport->port_state);
已提交
2538 2539
		}
		/* Send back ACC */
J
James Smart 已提交
2540
		lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL,
已提交
2541 2542 2543
								newnode);

		/* send RECOVERY event for ALL nodes that match RSCN payload */
J
James Smart 已提交
2544
		lpfc_rscn_recovery_check(vport);
2545
		return 0;
已提交
2546 2547
	}

J
James Smart 已提交
2548 2549 2550 2551
	spin_lock_irq(shost->host_lock);
	vport->fc_flag |= FC_RSCN_MODE;
	spin_unlock_irq(shost->host_lock);
	vport->fc_rscn_id_list[vport->fc_rscn_id_cnt++] = pcmd;
已提交
2552 2553 2554 2555 2556 2557
	/*
	 * If we zero, cmdiocb->context2, the calling routine will
	 * not try to free it.
	 */
	cmdiocb->context2 = NULL;

J
James Smart 已提交
2558
	lpfc_set_disctmo(vport);
已提交
2559 2560

	/* Send back ACC */
J
James Smart 已提交
2561
	lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, newnode);
已提交
2562 2563

	/* send RECOVERY event for ALL nodes that match RSCN payload */
J
James Smart 已提交
2564
	lpfc_rscn_recovery_check(vport);
已提交
2565

J
James Smart 已提交
2566
	return lpfc_els_handle_rscn(vport);
已提交
2567 2568 2569
}

int
J
James Smart 已提交
2570
lpfc_els_handle_rscn(struct lpfc_vport *vport)
已提交
2571 2572
{
	struct lpfc_nodelist *ndlp;
J
James Smart 已提交
2573
	struct lpfc_hba *phba = vport->phba;
已提交
2574 2575

	/* Start timer for RSCN processing */
J
James Smart 已提交
2576
	lpfc_set_disctmo(vport);
已提交
2577 2578

	/* RSCN processed */
2579
	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
已提交
2580 2581
			"%d:0215 RSCN processed Data: x%x x%x x%x x%x\n",
			phba->brd_no,
J
James Smart 已提交
2582 2583
			vport->fc_flag, 0, vport->fc_rscn_id_cnt,
			vport->port_state);
已提交
2584 2585

	/* To process RSCN, first compare RSCN data with NameServer */
J
James Smart 已提交
2586 2587
	vport->fc_ns_retry = 0;
	ndlp = lpfc_findnode_did(vport, NameServer_DID);
2588
	if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
已提交
2589
		/* Good ndlp, issue CT Request to NameServer */
J
James Smart 已提交
2590
		if (lpfc_ns_cmd(vport, ndlp, SLI_CTNS_GID_FT) == 0)
已提交
2591 2592
			/* Wait for NameServer query cmpl before we can
			   continue */
2593
			return 1;
已提交
2594 2595 2596
	} else {
		/* If login to NameServer does not exist, issue one */
		/* Good status, issue PLOGI to NameServer */
J
James Smart 已提交
2597 2598
		ndlp = lpfc_findnode_did(vport, NameServer_DID);
		if (ndlp)
已提交
2599 2600
			/* Wait for NameServer login cmpl before we can
			   continue */
2601
			return 1;
J
James Smart 已提交
2602

2603 2604
		ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
		if (!ndlp) {
J
James Smart 已提交
2605
			lpfc_els_flush_rscn(vport);
2606
			return 0;
已提交
2607
		} else {
J
James Smart 已提交
2608
			lpfc_nlp_init(vport, ndlp, NameServer_DID);
已提交
2609
			ndlp->nlp_type |= NLP_FABRIC;
2610
			ndlp->nlp_prev_state = ndlp->nlp_state;
J
James Smart 已提交
2611 2612
			lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
			lpfc_issue_els_plogi(vport, NameServer_DID, 0);
已提交
2613 2614
			/* Wait for NameServer login cmpl before we can
			   continue */
2615
			return 1;
已提交
2616 2617 2618
		}
	}

J
James Smart 已提交
2619
	lpfc_els_flush_rscn(vport);
2620
	return 0;
已提交
2621 2622 2623
}

static int
J
James Smart 已提交
2624 2625
lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
		   struct lpfc_nodelist *ndlp, uint8_t newnode)
已提交
2626
{
J
James Smart 已提交
2627 2628
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba  *phba = vport->phba;
已提交
2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642
	struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
	uint32_t *lp = (uint32_t *) pcmd->virt;
	IOCB_t *icmd = &cmdiocb->iocb;
	struct serv_parm *sp;
	LPFC_MBOXQ_t *mbox;
	struct ls_rjt stat;
	uint32_t cmd, did;
	int rc;

	cmd = *lp++;
	sp = (struct serv_parm *) lp;

	/* FLOGI received */

J
James Smart 已提交
2643
	lpfc_set_disctmo(vport);
已提交
2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654

	if (phba->fc_topology == TOPOLOGY_LOOP) {
		/* We should never receive a FLOGI in loop mode, ignore it */
		did = icmd->un.elsreq64.remoteID;

		/* An FLOGI ELS command <elsCmd> was received from DID <did> in
		   Loop Mode */
		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
				"%d:0113 An FLOGI ELS command x%x was received "
				"from DID x%x in Loop Mode\n",
				phba->brd_no, cmd, did);
2655
		return 1;
已提交
2656 2657 2658 2659
	}

	did = Fabric_DID;

J
James Smart 已提交
2660
	if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3))) {
已提交
2661 2662 2663 2664
		/* For a FLOGI we accept, then if our portname is greater
		 * then the remote portname we initiate Nport login.
		 */

J
James Smart 已提交
2665
		rc = memcmp(&vport->fc_portname, &sp->portName,
已提交
2666 2667 2668
			    sizeof (struct lpfc_name));

		if (!rc) {
J
James Smart 已提交
2669 2670
			mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
			if (!mbox)
2671
				return 1;
J
James Smart 已提交
2672

已提交
2673 2674 2675 2676 2677 2678
			lpfc_linkdown(phba);
			lpfc_init_link(phba, mbox,
				       phba->cfg_topology,
				       phba->cfg_link_speed);
			mbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
			mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
2679
			mbox->vport = vport;
已提交
2680 2681
			rc = lpfc_sli_issue_mbox
				(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
2682
			lpfc_set_loopback_flag(phba);
已提交
2683
			if (rc == MBX_NOT_FINISHED) {
2684
				mempool_free(mbox, phba->mbox_mem_pool);
已提交
2685
			}
2686
			return 1;
2687
		} else if (rc > 0) {	/* greater than */
J
James Smart 已提交
2688 2689 2690
			spin_lock_irq(shost->host_lock);
			vport->fc_flag |= FC_PT2PT_PLOGI;
			spin_unlock_irq(shost->host_lock);
已提交
2691
		}
J
James Smart 已提交
2692 2693 2694 2695
		spin_lock_irq(shost->host_lock);
		vport->fc_flag |= FC_PT2PT;
		vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
		spin_unlock_irq(shost->host_lock);
已提交
2696 2697 2698 2699 2700 2701
	} else {
		/* 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 已提交
2702
		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp);
2703
		return 1;
已提交
2704 2705 2706
	}

	/* Send back ACC */
J
James Smart 已提交
2707
	lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL, newnode);
已提交
2708

2709
	return 0;
已提交
2710 2711 2712
}

static int
J
James Smart 已提交
2713 2714
lpfc_els_rcv_rnid(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
		  struct lpfc_nodelist *ndlp)
已提交
2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736
{
	struct lpfc_dmabuf *pcmd;
	uint32_t *lp;
	IOCB_t *icmd;
	RNID *rn;
	struct ls_rjt stat;
	uint32_t cmd, did;

	icmd = &cmdiocb->iocb;
	did = icmd->un.elsreq64.remoteID;
	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
	lp = (uint32_t *) pcmd->virt;

	cmd = *lp++;
	rn = (RNID *) lp;

	/* RNID received */

	switch (rn->Format) {
	case 0:
	case RNID_TOPOLOGY_DISC:
		/* Send back ACC */
J
James Smart 已提交
2737
		lpfc_els_rsp_rnid_acc(vport, rn->Format, cmdiocb, ndlp);
已提交
2738 2739 2740 2741 2742 2743 2744
		break;
	default:
		/* Reject this request because format not supported */
		stat.un.b.lsRjtRsvd0 = 0;
		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
		stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
		stat.un.b.vendorUnique = 0;
J
James Smart 已提交
2745
		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp);
已提交
2746
	}
2747
	return 0;
已提交
2748 2749 2750
}

static int
J
James Smart 已提交
2751 2752
lpfc_els_rcv_lirr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
		  struct lpfc_nodelist *ndlp)
2753 2754 2755 2756 2757 2758 2759 2760
{
	struct ls_rjt stat;

	/* For now, unconditionally reject this command */
	stat.un.b.lsRjtRsvd0 = 0;
	stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
	stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
	stat.un.b.vendorUnique = 0;
J
James Smart 已提交
2761
	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp);
2762 2763 2764
	return 0;
}

2765
static void
2766
lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
2767
{
J
James Smart 已提交
2768 2769
	struct lpfc_sli *psli = &phba->sli;
	struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782
	MAILBOX_t *mb;
	IOCB_t *icmd;
	RPS_RSP *rps_rsp;
	uint8_t *pcmd;
	struct lpfc_iocbq *elsiocb;
	struct lpfc_nodelist *ndlp;
	uint16_t xri, status;
	uint32_t cmdsize;

	mb = &pmb->mb;

	ndlp = (struct lpfc_nodelist *) pmb->context2;
	xri = (uint16_t) ((unsigned long)(pmb->context1));
R
Randy Dunlap 已提交
2783 2784
	pmb->context1 = NULL;
	pmb->context2 = NULL;
2785 2786

	if (mb->mbxStatus) {
2787
		mempool_free(pmb, phba->mbox_mem_pool);
2788 2789 2790 2791
		return;
	}

	cmdsize = sizeof(RPS_RSP) + sizeof(uint32_t);
2792
	mempool_free(pmb, phba->mbox_mem_pool);
J
James Smart 已提交
2793 2794 2795
	elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize,
				     lpfc_max_els_tries, ndlp,
				     ndlp->nlp_DID, ELS_CMD_ACC);
2796
	lpfc_nlp_put(ndlp);
2797
	if (!elsiocb)
2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811
		return;

	icmd = &elsiocb->iocb;
	icmd->ulpContext = xri;

	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
	*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
	pcmd += sizeof (uint32_t); /* Skip past command */
	rps_rsp = (RPS_RSP *)pcmd;

	if (phba->fc_topology != TOPOLOGY_LOOP)
		status = 0x10;
	else
		status = 0x8;
J
James Smart 已提交
2812
	if (phba->pport->fc_flag & FC_FABRIC)
2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825
		status |= 0x4;

	rps_rsp->rsvd1 = 0;
	rps_rsp->portStatus = be16_to_cpu(status);
	rps_rsp->linkFailureCnt = be32_to_cpu(mb->un.varRdLnk.linkFailureCnt);
	rps_rsp->lossSyncCnt = be32_to_cpu(mb->un.varRdLnk.lossSyncCnt);
	rps_rsp->lossSignalCnt = be32_to_cpu(mb->un.varRdLnk.lossSignalCnt);
	rps_rsp->primSeqErrCnt = be32_to_cpu(mb->un.varRdLnk.primSeqErrCnt);
	rps_rsp->invalidXmitWord = be32_to_cpu(mb->un.varRdLnk.invalidXmitWord);
	rps_rsp->crcCnt = be32_to_cpu(mb->un.varRdLnk.crcCnt);

	/* Xmit ELS RPS ACC response tag <ulpIoTag> */
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
2826 2827 2828
			"%d:0118 Xmit ELS RPS ACC response tag x%x xri x%x, "
			"did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
			phba->brd_no, elsiocb->iotag,
2829 2830 2831 2832 2833
			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);

	elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
	phba->fc_stat.elsXmitACC++;
2834
	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR)
2835 2836 2837 2838 2839
		lpfc_els_free_iocb(phba, elsiocb);
	return;
}

static int
J
James Smart 已提交
2840 2841
lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
		 struct lpfc_nodelist *ndlp)
已提交
2842
{
J
James Smart 已提交
2843
	struct lpfc_hba *phba = vport->phba;
已提交
2844
	uint32_t *lp;
2845 2846 2847 2848 2849 2850
	uint8_t flag;
	LPFC_MBOXQ_t *mbox;
	struct lpfc_dmabuf *pcmd;
	RPS *rps;
	struct ls_rjt stat;

2851 2852
	if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
	    (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) {
2853 2854 2855 2856
		stat.un.b.lsRjtRsvd0 = 0;
		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
		stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
		stat.un.b.vendorUnique = 0;
J
James Smart 已提交
2857
		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp);
2858 2859 2860 2861 2862 2863 2864 2865 2866
	}

	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
	lp = (uint32_t *) pcmd->virt;
	flag = (be32_to_cpu(*lp++) & 0xf);
	rps = (RPS *) lp;

	if ((flag == 0) ||
	    ((flag == 1) && (be32_to_cpu(rps->un.portNum) == 0)) ||
J
James Smart 已提交
2867
	    ((flag == 2) && (memcmp(&rps->un.portName, &vport->fc_portname,
2868
			   sizeof (struct lpfc_name)) == 0))) {
J
James Smart 已提交
2869 2870 2871

		mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC);
		if (mbox) {
2872 2873 2874
			lpfc_read_lnk_stat(phba, mbox);
			mbox->context1 =
			    (void *)((unsigned long)cmdiocb->iocb.ulpContext);
2875
			mbox->context2 = lpfc_nlp_get(ndlp);
2876 2877
			mbox->mbox_cmpl = lpfc_els_rsp_rps_acc;
			if (lpfc_sli_issue_mbox (phba, mbox,
J
James Smart 已提交
2878
			    (MBX_NOWAIT | MBX_STOP_IOCB)) != MBX_NOT_FINISHED)
2879 2880
				/* Mbox completion will send ELS Response */
				return 0;
J
James Smart 已提交
2881

2882
			lpfc_nlp_put(ndlp);
2883 2884 2885 2886 2887 2888 2889
			mempool_free(mbox, phba->mbox_mem_pool);
		}
	}
	stat.un.b.lsRjtRsvd0 = 0;
	stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
	stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
	stat.un.b.vendorUnique = 0;
J
James Smart 已提交
2890
	lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp);
2891 2892 2893
	return 0;
}

2894
static int
J
James Smart 已提交
2895 2896
lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize,
		     struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
2897
{
J
James Smart 已提交
2898 2899
	struct lpfc_hba *phba = vport->phba;
	IOCB_t *icmd, *oldcmd;
2900 2901
	RPL_RSP rpl_rsp;
	struct lpfc_iocbq *elsiocb;
J
James Smart 已提交
2902 2903
	struct lpfc_sli *psli = &phba->sli;
	struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
2904
	uint8_t *pcmd;
已提交
2905

J
James Smart 已提交
2906 2907
	elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
				     ndlp->nlp_DID, ELS_CMD_ACC);
2908

2909
	if (!elsiocb)
2910
		return 1;
2911

2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925
	icmd = &elsiocb->iocb;
	oldcmd = &oldiocb->iocb;
	icmd->ulpContext = oldcmd->ulpContext;	/* Xri */

	pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
	*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
	pcmd += sizeof (uint16_t);
	*((uint16_t *)(pcmd)) = be16_to_cpu(cmdsize);
	pcmd += sizeof(uint16_t);

	/* Setup the RPL ACC payload */
	rpl_rsp.listLen = be32_to_cpu(1);
	rpl_rsp.index = 0;
	rpl_rsp.port_num_blk.portNum = 0;
J
James Smart 已提交
2926 2927
	rpl_rsp.port_num_blk.portID = be32_to_cpu(vport->fc_myDID);
	memcpy(&rpl_rsp.port_num_blk.portName, &vport->fc_portname,
2928 2929 2930 2931 2932 2933 2934
	    sizeof(struct lpfc_name));

	memcpy(pcmd, &rpl_rsp, cmdsize - sizeof(uint32_t));


	/* Xmit ELS RPL ACC response tag <ulpIoTag> */
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
2935 2936 2937
			"%d:0120 Xmit ELS RPL ACC response tag x%x xri x%x, "
			"did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
			phba->brd_no, elsiocb->iotag,
2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951
			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);

	elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;

	phba->fc_stat.elsXmitACC++;
	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
		lpfc_els_free_iocb(phba, elsiocb);
		return 1;
	}
	return 0;
}

static int
J
James Smart 已提交
2952 2953
lpfc_els_rcv_rpl(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
		 struct lpfc_nodelist *ndlp)
2954 2955 2956 2957 2958 2959 2960 2961
{
	struct lpfc_dmabuf *pcmd;
	uint32_t *lp;
	uint32_t maxsize;
	uint16_t cmdsize;
	RPL *rpl;
	struct ls_rjt stat;

2962 2963
	if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
	    (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) {
2964 2965 2966 2967
		stat.un.b.lsRjtRsvd0 = 0;
		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
		stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
		stat.un.b.vendorUnique = 0;
J
James Smart 已提交
2968
		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp);
2969 2970
	}

已提交
2971 2972
	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
	lp = (uint32_t *) pcmd->virt;
2973
	rpl = (RPL *) (lp + 1);
已提交
2974

2975
	maxsize = be32_to_cpu(rpl->maxsize);
已提交
2976

2977 2978 2979 2980 2981
	/* We support only one port */
	if ((rpl->index == 0) &&
	    ((maxsize == 0) ||
	     ((maxsize * sizeof(uint32_t)) >= sizeof(RPL_RSP)))) {
		cmdsize = sizeof(uint32_t) + sizeof(RPL_RSP);
2982
	} else {
2983 2984
		cmdsize = sizeof(uint32_t) + maxsize * sizeof(uint32_t);
	}
J
James Smart 已提交
2985
	lpfc_els_rsp_rpl_acc(vport, cmdsize, cmdiocb, ndlp);
已提交
2986 2987 2988 2989 2990

	return 0;
}

static int
J
James Smart 已提交
2991 2992
lpfc_els_rcv_farp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
		  struct lpfc_nodelist *ndlp)
已提交
2993
{
J
James Smart 已提交
2994
	struct lpfc_hba *phba = vport->phba;
已提交
2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009
	struct lpfc_dmabuf *pcmd;
	uint32_t *lp;
	IOCB_t *icmd;
	FARP *fp;
	uint32_t cmd, cnt, did;

	icmd = &cmdiocb->iocb;
	did = icmd->un.elsreq64.remoteID;
	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
	lp = (uint32_t *) pcmd->virt;

	cmd = *lp++;
	fp = (FARP *) lp;

	/* FARP-REQ received from DID <did> */
3010
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
已提交
3011 3012 3013 3014 3015
			 "%d:0601 FARP-REQ received from DID x%x\n",
			 phba->brd_no, did);

	/* We will only support match on WWPN or WWNN */
	if (fp->Mflags & ~(FARP_MATCH_NODE | FARP_MATCH_PORT)) {
3016
		return 0;
已提交
3017 3018 3019 3020 3021
	}

	cnt = 0;
	/* If this FARP command is searching for my portname */
	if (fp->Mflags & FARP_MATCH_PORT) {
J
James Smart 已提交
3022
		if (memcmp(&fp->RportName, &vport->fc_portname,
已提交
3023 3024 3025 3026 3027 3028
			   sizeof (struct lpfc_name)) == 0)
			cnt = 1;
	}

	/* If this FARP command is searching for my nodename */
	if (fp->Mflags & FARP_MATCH_NODE) {
J
James Smart 已提交
3029
		if (memcmp(&fp->RnodeName, &vport->fc_nodename,
已提交
3030 3031 3032 3033 3034 3035 3036 3037 3038
			   sizeof (struct lpfc_name)) == 0)
			cnt = 1;
	}

	if (cnt) {
		if ((ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) ||
		   (ndlp->nlp_state == NLP_STE_MAPPED_NODE)) {
			/* Log back into the node before sending the FARP. */
			if (fp->Rflags & FARP_REQUEST_PLOGI) {
3039
				ndlp->nlp_prev_state = ndlp->nlp_state;
J
James Smart 已提交
3040
				lpfc_nlp_set_state(vport, ndlp,
3041
						   NLP_STE_PLOGI_ISSUE);
J
James Smart 已提交
3042
				lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
已提交
3043 3044 3045
			}

			/* Send a FARP response to that node */
J
James Smart 已提交
3046 3047
			if (fp->Rflags & FARP_REQUEST_FARPR)
				lpfc_issue_els_farpr(vport, did, 0);
已提交
3048 3049
		}
	}
3050
	return 0;
已提交
3051 3052 3053
}

static int
J
James Smart 已提交
3054 3055
lpfc_els_rcv_farpr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
		   struct lpfc_nodelist  *ndlp)
已提交
3056 3057 3058 3059 3060
{
	struct lpfc_dmabuf *pcmd;
	uint32_t *lp;
	IOCB_t *icmd;
	uint32_t cmd, did;
J
James Smart 已提交
3061
	struct lpfc_hba *phba = vport->phba;
已提交
3062 3063 3064 3065 3066 3067 3068 3069

	icmd = &cmdiocb->iocb;
	did = icmd->un.elsreq64.remoteID;
	pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
	lp = (uint32_t *) pcmd->virt;

	cmd = *lp++;
	/* FARP-RSP received from DID <did> */
3070
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
已提交
3071 3072 3073
			 "%d:0600 FARP-RSP received from DID x%x\n",
			 phba->brd_no, did);
	/* ACCEPT the Farp resp request */
J
James Smart 已提交
3074
	lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
已提交
3075 3076 3077 3078 3079

	return 0;
}

static int
J
James Smart 已提交
3080 3081
lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
		 struct lpfc_nodelist *fan_ndlp)
已提交
3082 3083 3084 3085 3086
{
	struct lpfc_dmabuf *pcmd;
	uint32_t *lp;
	IOCB_t *icmd;
	uint32_t cmd, did;
3087 3088
	FAN *fp;
	struct lpfc_nodelist *ndlp, *next_ndlp;
J
James Smart 已提交
3089
	struct lpfc_hba *phba = vport->phba;
3090 3091

	/* FAN received */
3092 3093 3094
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
			"%d:0265 FAN received\n",
			phba->brd_no);
已提交
3095 3096 3097

	icmd = &cmdiocb->iocb;
	did = icmd->un.elsreq64.remoteID;
3098 3099
	pcmd = (struct lpfc_dmabuf *)cmdiocb->context2;
	lp = (uint32_t *)pcmd->virt;
已提交
3100 3101

	cmd = *lp++;
3102
	fp = (FAN *)lp;
已提交
3103

3104
	/* FAN received; Fan does not have a reply sequence */
已提交
3105

J
James Smart 已提交
3106
	if (phba->pport->port_state == LPFC_LOCAL_CFG_LINK) {
3107 3108 3109 3110 3111 3112 3113
		if ((memcmp(&phba->fc_fabparam.nodeName, &fp->FnodeName,
			sizeof(struct lpfc_name)) != 0) ||
		    (memcmp(&phba->fc_fabparam.portName, &fp->FportName,
			sizeof(struct lpfc_name)) != 0)) {
			/*
			 * This node has switched fabrics.  FLOGI is required
			 * Clean up the old rpi's
已提交
3114
			 */
3115 3116

			list_for_each_entry_safe(ndlp, next_ndlp,
J
James Smart 已提交
3117
						 &vport->fc_nodes, nlp_listp) {
3118 3119
				if (ndlp->nlp_state != NLP_STE_NPR_NODE)
					continue;
3120 3121 3122 3123 3124
				if (ndlp->nlp_type & NLP_FABRIC) {
					/*
					 * Clean up old Fabric, Nameserver and
					 * other NLP_FABRIC logins
					 */
J
James Smart 已提交
3125
					lpfc_drop_node(vport, ndlp);
3126
				} else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
3127 3128 3129
					/* Fail outstanding I/O now since this
					 * device is marked for PLOGI
					 */
J
James Smart 已提交
3130
					lpfc_unreg_rpi(vport, ndlp);
3131 3132 3133
				}
			}

J
James Smart 已提交
3134 3135 3136
			vport->port_state = LPFC_FLOGI;
			lpfc_set_disctmo(vport);
			lpfc_initial_flogi(vport);
3137
			return 0;
已提交
3138
		}
3139 3140 3141
		/* Discovery not needed,
		 * move the nodes to their original state.
		 */
J
James Smart 已提交
3142
		list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
3143 3144 3145
					 nlp_listp) {
			if (ndlp->nlp_state != NLP_STE_NPR_NODE)
				continue;
已提交
3146

3147 3148 3149
			switch (ndlp->nlp_prev_state) {
			case NLP_STE_UNMAPPED_NODE:
				ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
J
James Smart 已提交
3150
				lpfc_nlp_set_state(vport, ndlp,
3151
						   NLP_STE_UNMAPPED_NODE);
3152 3153 3154 3155
				break;

			case NLP_STE_MAPPED_NODE:
				ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
J
James Smart 已提交
3156
				lpfc_nlp_set_state(vport, ndlp,
3157
						   NLP_STE_MAPPED_NODE);
3158 3159 3160 3161 3162 3163 3164 3165
				break;

			default:
				break;
			}
		}

		/* Start discovery - this should just do CLEAR_LA */
J
James Smart 已提交
3166
		lpfc_disc_start(vport);
已提交
3167
	}
3168
	return 0;
已提交
3169 3170 3171 3172 3173
}

void
lpfc_els_timeout(unsigned long ptr)
{
J
James Smart 已提交
3174 3175
	struct lpfc_vport *vport = (struct lpfc_vport *) ptr;
	struct lpfc_hba   *phba = vport->phba;
已提交
3176 3177
	unsigned long iflag;

J
James Smart 已提交
3178 3179 3180
	spin_lock_irqsave(&vport->work_port_lock, iflag);
	if ((vport->work_port_events & WORKER_ELS_TMO) == 0) {
		vport->work_port_events |= WORKER_ELS_TMO;
已提交
3181 3182 3183
		if (phba->work_wait)
			wake_up(phba->work_wait);
	}
J
James Smart 已提交
3184
	spin_unlock_irqrestore(&vport->work_port_lock, iflag);
已提交
3185 3186 3187 3188
	return;
}

void
J
James Smart 已提交
3189
lpfc_els_timeout_handler(struct lpfc_vport *vport)
已提交
3190
{
J
James Smart 已提交
3191
	struct lpfc_hba  *phba = vport->phba;
已提交
3192 3193 3194 3195
	struct lpfc_sli_ring *pring;
	struct lpfc_iocbq *tmp_iocb, *piocb;
	IOCB_t *cmd = NULL;
	struct lpfc_dmabuf *pcmd;
J
James Smart 已提交
3196
	uint32_t els_command = 0;
已提交
3197
	uint32_t timeout;
J
James Smart 已提交
3198
	uint32_t remote_ID = 0xffffffff;
已提交
3199 3200

	/* If the timer is already canceled do nothing */
J
James Smart 已提交
3201
	if ((vport->work_port_events & WORKER_ELS_TMO) == 0) {
已提交
3202 3203
		return;
	}
J
James Smart 已提交
3204
	spin_lock_irq(&phba->hbalock);
已提交
3205 3206 3207 3208 3209 3210 3211
	timeout = (uint32_t)(phba->fc_ratov << 1);

	pring = &phba->sli.ring[LPFC_ELS_RING];

	list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
		cmd = &piocb->iocb;

J
James Smart 已提交
3212 3213 3214
		if ((piocb->iocb_flag & LPFC_IO_LIBDFC) != 0 ||
		    piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN ||
		    piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)
已提交
3215
			continue;
J
James Smart 已提交
3216 3217 3218 3219

		if (piocb->vport != vport)
			continue;

已提交
3220
		pcmd = (struct lpfc_dmabuf *) piocb->context2;
J
James Smart 已提交
3221 3222
		if (pcmd)
			els_command = *(uint32_t *) (pcmd->virt);
已提交
3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237

		if ((els_command == ELS_CMD_FARP)
		    || (els_command == ELS_CMD_FARPR)) {
			continue;
		}

		if (piocb->drvrTimeout > 0) {
			if (piocb->drvrTimeout >= timeout) {
				piocb->drvrTimeout -= timeout;
			} else {
				piocb->drvrTimeout = 0;
			}
			continue;
		}

J
James Smart 已提交
3238 3239
		remote_ID = 0xffffffff;
		if (cmd->ulpCommand != CMD_GEN_REQUEST64_CR)
已提交
3240
			remote_ID = cmd->un.elsreq64.remoteID;
J
James Smart 已提交
3241 3242 3243 3244 3245
		else {
			struct lpfc_nodelist *ndlp;
			ndlp = __lpfc_findnode_rpi(vport, cmd->ulpContext);
			if (ndlp)
				remote_ID = ndlp->nlp_DID;
已提交
3246 3247 3248 3249 3250 3251 3252 3253 3254
		}

		lpfc_printf_log(phba,
				KERN_ERR,
				LOG_ELS,
				"%d:0127 ELS timeout Data: x%x x%x x%x x%x\n",
				phba->brd_no, els_command,
				remote_ID, cmd->ulpCommand, cmd->ulpIoTag);

3255
		lpfc_sli_issue_abort_iotag(phba, pring, piocb);
已提交
3256
	}
J
James Smart 已提交
3257
	spin_unlock_irq(&phba->hbalock);
3258

J
James Smart 已提交
3259 3260
	if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt)
		mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout);
已提交
3261 3262 3263
}

void
J
James Smart 已提交
3264
lpfc_els_flush_cmd(struct lpfc_vport *vport)
已提交
3265
{
3266
	LIST_HEAD(completions);
J
James Smart 已提交
3267
	struct lpfc_hba  *phba = vport->phba;
3268
	struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
已提交
3269 3270 3271
	struct lpfc_iocbq *tmp_iocb, *piocb;
	IOCB_t *cmd = NULL;

J
James Smart 已提交
3272
	spin_lock_irq(&phba->hbalock);
已提交
3273 3274 3275 3276 3277 3278 3279 3280
	list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
		cmd = &piocb->iocb;

		if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
			continue;
		}

		/* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */
3281 3282 3283 3284
		if (cmd->ulpCommand == CMD_QUE_RING_BUF_CN ||
		    cmd->ulpCommand == CMD_QUE_RING_BUF64_CN ||
		    cmd->ulpCommand == CMD_CLOSE_XRI_CN ||
		    cmd->ulpCommand == CMD_ABORT_XRI_CN)
已提交
3285 3286
			continue;

J
James Smart 已提交
3287 3288 3289
		if (piocb->vport != vport)
			continue;

3290
		list_move_tail(&piocb->list, &completions);
3291
		pring->txq_cnt--;
已提交
3292 3293 3294 3295 3296 3297 3298
	}

	list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
		if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
			continue;
		}

J
James Smart 已提交
3299 3300 3301
		if (piocb->vport != vport)
			continue;

3302
		lpfc_sli_issue_abort_iotag(phba, pring, piocb);
已提交
3303
	}
J
James Smart 已提交
3304
	spin_unlock_irq(&phba->hbalock);
3305

J
James Smart 已提交
3306
	while (!list_empty(&completions)) {
3307 3308 3309 3310
		piocb = list_get_first(&completions, struct lpfc_iocbq, list);
		cmd = &piocb->iocb;
		list_del(&piocb->list);

J
James Smart 已提交
3311 3312 3313
		if (!piocb->iocb_cmpl)
			lpfc_sli_release_iocbq(phba, piocb);
		else {
3314 3315 3316
			cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
			cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
			(piocb->iocb_cmpl) (phba, piocb, piocb);
J
James Smart 已提交
3317
		}
3318 3319
	}

已提交
3320 3321 3322
	return;
}

3323 3324 3325 3326
static void
lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
		      struct lpfc_vport *vport, struct lpfc_dmabuf *mp,
		      struct lpfc_iocbq *elsiocb)
已提交
3327 3328 3329
{
	struct lpfc_nodelist *ndlp;
	struct ls_rjt stat;
3330
	uint32_t *lp;
J
James Smart 已提交
3331
	uint32_t cmd, did, newnode, rjt_err = 0;
3332
	IOCB_t *icmd = &elsiocb->iocb;
已提交
3333

3334
	if (!vport || !mp)
已提交
3335
		goto dropit;
J
James Smart 已提交
3336

已提交
3337 3338 3339
	newnode = 0;
	lp = (uint32_t *) mp->virt;
	cmd = *lp++;
3340 3341
	if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) == 0)
		lpfc_post_buffer(phba, pring, 1, 1);
已提交
3342

3343
	if (icmd->ulpStatus)
已提交
3344 3345 3346
		goto dropit;

	/* Check to see if link went down during discovery */
3347
	if (lpfc_els_chk_latt(vport))
已提交
3348 3349 3350
		goto dropit;

	did = icmd->un.rcvels.remoteID;
J
James Smart 已提交
3351
	ndlp = lpfc_findnode_did(vport, did);
3352
	if (!ndlp) {
已提交
3353
		/* Cannot find existing Fabric ndlp, so allocate a new one */
3354
		ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
3355
		if (!ndlp)
已提交
3356 3357
			goto dropit;

J
James Smart 已提交
3358
		lpfc_nlp_init(vport, ndlp, did);
已提交
3359 3360 3361 3362
		newnode = 1;
		if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) {
			ndlp->nlp_type |= NLP_FABRIC;
		}
J
James Smart 已提交
3363
		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
已提交
3364 3365 3366
	}

	phba->fc_stat.elsRcvFrame++;
3367 3368 3369
	if (elsiocb->context1)
		lpfc_nlp_put(elsiocb->context1);
	elsiocb->context1 = lpfc_nlp_get(ndlp);
已提交
3370
	elsiocb->context2 = mp;
J
James Smart 已提交
3371
	elsiocb->vport = vport;
已提交
3372 3373 3374 3375 3376 3377 3378

	if ((cmd & ELS_CMD_MASK) == ELS_CMD_RSCN) {
		cmd &= ELS_CMD_MASK;
	}
	/* ELS command <elsCmd> received from NPORT <did> */
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
			"%d:0112 ELS command x%x received from NPORT x%x "
J
James Smart 已提交
3379
			"Data: x%x\n", phba->brd_no, cmd, did,
3380
			vport->port_state);
已提交
3381 3382 3383 3384

	switch (cmd) {
	case ELS_CMD_PLOGI:
		phba->fc_stat.elsRcvPLOGI++;
J
James Smart 已提交
3385
		if (vport->port_state < LPFC_DISC_AUTH) {
3386
			rjt_err = 1;
已提交
3387 3388
			break;
		}
3389
		ndlp = lpfc_plogi_confirm_nport(phba, mp, ndlp);
J
James Smart 已提交
3390 3391
		lpfc_disc_state_machine(vport, ndlp, elsiocb,
					NLP_EVT_RCV_PLOGI);
已提交
3392 3393 3394
		break;
	case ELS_CMD_FLOGI:
		phba->fc_stat.elsRcvFLOGI++;
J
James Smart 已提交
3395
		lpfc_els_rcv_flogi(vport, elsiocb, ndlp, newnode);
3396
		if (newnode)
J
James Smart 已提交
3397
			lpfc_drop_node(vport, ndlp);
已提交
3398 3399 3400
		break;
	case ELS_CMD_LOGO:
		phba->fc_stat.elsRcvLOGO++;
J
James Smart 已提交
3401
		if (vport->port_state < LPFC_DISC_AUTH) {
3402
			rjt_err = 1;
已提交
3403 3404
			break;
		}
J
James Smart 已提交
3405
		lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_LOGO);
已提交
3406 3407 3408
		break;
	case ELS_CMD_PRLO:
		phba->fc_stat.elsRcvPRLO++;
J
James Smart 已提交
3409
		if (vport->port_state < LPFC_DISC_AUTH) {
3410
			rjt_err = 1;
已提交
3411 3412
			break;
		}
J
James Smart 已提交
3413
		lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PRLO);
已提交
3414 3415 3416
		break;
	case ELS_CMD_RSCN:
		phba->fc_stat.elsRcvRSCN++;
J
James Smart 已提交
3417
		lpfc_els_rcv_rscn(vport, elsiocb, ndlp, newnode);
3418
		if (newnode)
J
James Smart 已提交
3419
			lpfc_drop_node(vport, ndlp);
已提交
3420 3421 3422
		break;
	case ELS_CMD_ADISC:
		phba->fc_stat.elsRcvADISC++;
J
James Smart 已提交
3423
		if (vport->port_state < LPFC_DISC_AUTH) {
3424
			rjt_err = 1;
已提交
3425 3426
			break;
		}
J
James Smart 已提交
3427 3428
		lpfc_disc_state_machine(vport, ndlp, elsiocb,
					NLP_EVT_RCV_ADISC);
已提交
3429 3430 3431
		break;
	case ELS_CMD_PDISC:
		phba->fc_stat.elsRcvPDISC++;
J
James Smart 已提交
3432
		if (vport->port_state < LPFC_DISC_AUTH) {
3433
			rjt_err = 1;
已提交
3434 3435
			break;
		}
J
James Smart 已提交
3436 3437
		lpfc_disc_state_machine(vport, ndlp, elsiocb,
					NLP_EVT_RCV_PDISC);
已提交
3438 3439 3440
		break;
	case ELS_CMD_FARPR:
		phba->fc_stat.elsRcvFARPR++;
J
James Smart 已提交
3441
		lpfc_els_rcv_farpr(vport, elsiocb, ndlp);
已提交
3442 3443 3444
		break;
	case ELS_CMD_FARP:
		phba->fc_stat.elsRcvFARP++;
J
James Smart 已提交
3445
		lpfc_els_rcv_farp(vport, elsiocb, ndlp);
已提交
3446 3447 3448
		break;
	case ELS_CMD_FAN:
		phba->fc_stat.elsRcvFAN++;
J
James Smart 已提交
3449
		lpfc_els_rcv_fan(vport, elsiocb, ndlp);
已提交
3450 3451 3452
		break;
	case ELS_CMD_PRLI:
		phba->fc_stat.elsRcvPRLI++;
J
James Smart 已提交
3453
		if (vport->port_state < LPFC_DISC_AUTH) {
3454
			rjt_err = 1;
已提交
3455 3456
			break;
		}
J
James Smart 已提交
3457
		lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PRLI);
已提交
3458
		break;
3459 3460
	case ELS_CMD_LIRR:
		phba->fc_stat.elsRcvLIRR++;
J
James Smart 已提交
3461
		lpfc_els_rcv_lirr(vport, elsiocb, ndlp);
3462
		if (newnode)
J
James Smart 已提交
3463
			lpfc_drop_node(vport, ndlp);
3464 3465 3466
		break;
	case ELS_CMD_RPS:
		phba->fc_stat.elsRcvRPS++;
J
James Smart 已提交
3467
		lpfc_els_rcv_rps(vport, elsiocb, ndlp);
3468
		if (newnode)
J
James Smart 已提交
3469
			lpfc_drop_node(vport, ndlp);
3470 3471 3472
		break;
	case ELS_CMD_RPL:
		phba->fc_stat.elsRcvRPL++;
J
James Smart 已提交
3473
		lpfc_els_rcv_rpl(vport, elsiocb, ndlp);
3474
		if (newnode)
J
James Smart 已提交
3475
			lpfc_drop_node(vport, ndlp);
3476
		break;
已提交
3477 3478
	case ELS_CMD_RNID:
		phba->fc_stat.elsRcvRNID++;
J
James Smart 已提交
3479
		lpfc_els_rcv_rnid(vport, elsiocb, ndlp);
3480
		if (newnode)
J
James Smart 已提交
3481
			lpfc_drop_node(vport, ndlp);
已提交
3482 3483 3484
		break;
	default:
		/* Unsupported ELS command, reject */
3485
		rjt_err = 1;
已提交
3486 3487 3488

		/* Unknown ELS command <elsCmd> received from NPORT <did> */
		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
3489 3490 3491
				"%d:0115 Unknown ELS command x%x "
				"received from NPORT x%x\n",
				phba->brd_no, cmd, did);
3492
		if (newnode)
J
James Smart 已提交
3493
			lpfc_drop_node(vport, ndlp);
已提交
3494 3495 3496 3497 3498 3499 3500
		break;
	}

	/* check if need to LS_RJT received ELS cmd */
	if (rjt_err) {
		stat.un.b.lsRjtRsvd0 = 0;
		stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
3501
		stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
已提交
3502
		stat.un.b.vendorUnique = 0;
J
James Smart 已提交
3503
		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, elsiocb, ndlp);
已提交
3504 3505
	}

3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561
	return;

dropit:
	lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
			"%d:0111 Dropping received ELS cmd "
			"Data: x%x x%x x%x\n",
			phba->brd_no,
			icmd->ulpStatus, icmd->un.ulpWord[4],
			icmd->ulpTimeout);
	phba->fc_stat.elsRcvDrop++;
}


void
lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
		     struct lpfc_iocbq *elsiocb)
{
	struct lpfc_vport *vport = phba->pport;
	struct lpfc_dmabuf *mp = NULL;
	IOCB_t *icmd = &elsiocb->iocb;
	struct hbq_dmabuf *sp = NULL;
	dma_addr_t paddr;

	if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) &&
	    ((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) {
		phba->fc_stat.NoRcvBuf++;
		/* Not enough posted buffers; Try posting more buffers */
		if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
			lpfc_sli_hbqbuf_fill_hbq(phba);
		else
			lpfc_post_buffer(phba, pring, 0, 1);
		return;
	}

	/* If there are no BDEs associated with this IOCB,
	 * there is nothing to do.
	 */
	if (icmd->ulpBdeCount == 0)
		return;

	/* type of ELS cmd is first 32bit word in packet */
	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
		paddr = getPaddr(icmd->un.cont64[0].addrHigh,
				 icmd->un.cont64[0].addrLow);
		sp = lpfc_sli_hbqbuf_find(phba, icmd->un.ulpWord[3]);
		if (sp)
			phba->hbq_buff_count--;
		mp = sp ? &sp->dbuf : NULL;
	} else {
		paddr = getPaddr(icmd->un.cont64[0].addrHigh,
				 icmd->un.cont64[0].addrLow);
		mp = lpfc_sli_ringpostbuf_get(phba, pring, paddr);
	}

	lpfc_els_unsol_buffer(phba, pring, vport, mp, elsiocb);

3562 3563
	lpfc_nlp_put(elsiocb->context1);
	elsiocb->context1 = NULL;
已提交
3564
	if (elsiocb->context2) {
3565 3566 3567 3568 3569 3570
		if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
			lpfc_sli_free_hbq(phba, sp);
		else {
			lpfc_mbuf_free(phba, mp->virt, mp->phys);
			kfree(mp);
		}
已提交
3571
	}
3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589

	/* RCV_ELS64_CX provide for 2 BDEs - process 2nd if included */
	if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) != 0 &&
	    icmd->ulpBdeCount == 2) {
		sp = lpfc_sli_hbqbuf_find(phba, icmd->un.ulpWord[15]);
		if (sp)
			phba->hbq_buff_count--;
		mp = sp ? &sp->dbuf : NULL;
		lpfc_els_unsol_buffer(phba, pring, vport, mp, elsiocb);
		/* free mp if we are done with it */
		if (elsiocb->context2) {
			if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
				lpfc_sli_free_hbq(phba, sp);
			else {
				lpfc_mbuf_free(phba, mp->virt, mp->phys);
				kfree(mp);
			}
		}
已提交
3590 3591
	}
}