lpfc_ct.c 51.8 KB
Newer Older
已提交
1 2
/*******************************************************************
 * This file is part of the Emulex Linux Device Driver for         *
3
 * Fibre Channel Host Bus Adapters.                                *
4
 * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
5
 * EMULEX and SLI are trademarks of Emulex.                        *
已提交
6 7 8
 * www.emulex.com                                                  *
 *                                                                 *
 * This program is free software; you can redistribute it and/or   *
9 10 11 12 13 14 15 16 17 18
 * 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.                                     *
已提交
19 20 21
 *******************************************************************/

/*
22
 * Fibre Channel SCSI LAN Device Driver CT support: FC Generic Services FC-GS
已提交
23 24 25 26 27 28 29
 */

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

30
#include <scsi/scsi.h>
已提交
31 32
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
33
#include <scsi/scsi_transport_fc.h>
34
#include <scsi/fc/fc_fs.h>
已提交
35

36
#include "lpfc_hw4.h"
已提交
37 38
#include "lpfc_hw.h"
#include "lpfc_sli.h"
39
#include "lpfc_sli4.h"
40
#include "lpfc_nl.h"
已提交
41 42 43 44 45 46
#include "lpfc_disc.h"
#include "lpfc_scsi.h"
#include "lpfc.h"
#include "lpfc_logmsg.h"
#include "lpfc_crtn.h"
#include "lpfc_version.h"
47
#include "lpfc_vport.h"
J
James Smart 已提交
48
#include "lpfc_debugfs.h"
已提交
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63

#define HBA_PORTSPEED_UNKNOWN               0	/* Unknown - transceiver
						 * incapable of reporting */
#define HBA_PORTSPEED_1GBIT                 1	/* 1 GBit/sec */
#define HBA_PORTSPEED_2GBIT                 2	/* 2 GBit/sec */
#define HBA_PORTSPEED_4GBIT                 8   /* 4 GBit/sec */
#define HBA_PORTSPEED_8GBIT                16   /* 8 GBit/sec */
#define HBA_PORTSPEED_10GBIT                4	/* 10 GBit/sec */
#define HBA_PORTSPEED_NOT_NEGOTIATED        5	/* Speed not established */

#define FOURBYTES	4


static char *lpfc_release_version = LPFC_DRIVER_VERSION;

64
static void
65 66
lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
			  struct lpfc_dmabuf *mp, uint32_t size)
67 68
{
	if (!mp) {
69
		lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
70
				"0146 Ignoring unsolicited CT No HBQ "
71 72
				"status = x%x\n",
				piocbq->iocb.ulpStatus);
73
	}
74 75 76 77
	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
			"0145 Ignoring unsolicted CT HBQ Size:%d "
			"status = x%x\n",
			size, piocbq->iocb.ulpStatus);
78 79 80
}

static void
81 82
lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
		     struct lpfc_dmabuf *mp, uint32_t size)
83
{
84
	lpfc_ct_ignore_hbq_buffer(phba, piocbq, mp, size);
85 86
}

已提交
87
void
J
James Smart 已提交
88 89
lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
		    struct lpfc_iocbq *piocbq)
已提交
90
{
91
	struct lpfc_dmabuf *mp = NULL;
已提交
92
	IOCB_t *icmd = &piocbq->iocb;
93 94 95 96
	int i;
	struct lpfc_iocbq *iocbq;
	dma_addr_t paddr;
	uint32_t size;
97 98
	struct list_head head;
	struct lpfc_dmabuf *bdeBuf;
已提交
99

100 101
	lpfc_bsg_ct_unsol_event(phba, pring, piocbq);

102 103 104 105
	if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) {
		lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
	} else if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) &&
		((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) {
已提交
106 107
		/* Not enough posted buffers; Try posting more buffers */
		phba->fc_stat.NoRcvBuf++;
108
		if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED))
109
			lpfc_post_buffer(phba, pring, 2);
已提交
110 111 112 113 114 115 116 117 118
		return;
	}

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

119
	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
120 121 122
		INIT_LIST_HEAD(&head);
		list_add_tail(&head, &piocbq->list);
		list_for_each_entry(iocbq, &head, list) {
123
			icmd = &iocbq->iocb;
124
			if (icmd->ulpBdeCount == 0)
125
				continue;
126 127
			bdeBuf = iocbq->context2;
			iocbq->context2 = NULL;
128
			size  = icmd->un.cont64[0].tus.f.bdeSize;
129 130
			lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, size);
			lpfc_in_buf_free(phba, bdeBuf);
131
			if (icmd->ulpBdeCount == 2) {
132 133 134 135 136 137
				bdeBuf = iocbq->context3;
				iocbq->context3 = NULL;
				size  = icmd->unsli3.rcvsli3.bde2.tus.f.bdeSize;
				lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf,
						     size);
				lpfc_in_buf_free(phba, bdeBuf);
138
			}
已提交
139
		}
140
		list_del(&head);
141
	} else {
142 143 144
		INIT_LIST_HEAD(&head);
		list_add_tail(&head, &piocbq->list);
		list_for_each_entry(iocbq, &head, list) {
145
			icmd = &iocbq->iocb;
146
			if (icmd->ulpBdeCount == 0)
147
				lpfc_ct_unsol_buffer(phba, iocbq, NULL, 0);
148 149 150 151 152 153
			for (i = 0; i < icmd->ulpBdeCount; i++) {
				paddr = getPaddr(icmd->un.cont64[i].addrHigh,
						 icmd->un.cont64[i].addrLow);
				mp = lpfc_sli_ringpostbuf_get(phba, pring,
							      paddr);
				size = icmd->un.cont64[i].tus.f.bdeSize;
154
				lpfc_ct_unsol_buffer(phba, iocbq, mp, size);
155
				lpfc_in_buf_free(phba, mp);
156
			}
157
			lpfc_post_buffer(phba, pring, i);
已提交
158
		}
159
		list_del(&head);
已提交
160 161 162
	}
}

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 189 190 191 192 193 194 195
/**
 * lpfc_sli4_ct_abort_unsol_event - Default handle for sli4 unsol abort
 * @phba: Pointer to HBA context object.
 * @pring: Pointer to the driver internal I/O ring.
 * @piocbq: Pointer to the IOCBQ.
 *
 * This function serves as the default handler for the sli4 unsolicited
 * abort event. It shall be invoked when there is no application interface
 * registered unsolicited abort handler. This handler does nothing but
 * just simply releases the dma buffer used by the unsol abort event.
 **/
void
lpfc_sli4_ct_abort_unsol_event(struct lpfc_hba *phba,
			       struct lpfc_sli_ring *pring,
			       struct lpfc_iocbq *piocbq)
{
	IOCB_t *icmd = &piocbq->iocb;
	struct lpfc_dmabuf *bdeBuf;
	uint32_t size;

	/* Forward abort event to any process registered to receive ct event */
	lpfc_bsg_ct_unsol_event(phba, pring, piocbq);

	/* If there is no BDE associated with IOCB, there is nothing to do */
	if (icmd->ulpBdeCount == 0)
		return;
	bdeBuf = piocbq->context2;
	piocbq->context2 = NULL;
	size  = icmd->un.cont64[0].tus.f.bdeSize;
	lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, size);
	lpfc_in_buf_free(phba, bdeBuf);
}

已提交
196
static void
J
James Smart 已提交
197
lpfc_free_ct_rsp(struct lpfc_hba *phba, struct lpfc_dmabuf *mlist)
已提交
198 199 200 201 202 203 204 205 206 207 208 209 210 211
{
	struct lpfc_dmabuf *mlast, *next_mlast;

	list_for_each_entry_safe(mlast, next_mlast, &mlist->list, list) {
		lpfc_mbuf_free(phba, mlast->virt, mlast->phys);
		list_del(&mlast->list);
		kfree(mlast);
	}
	lpfc_mbuf_free(phba, mlist->virt, mlist->phys);
	kfree(mlist);
	return;
}

static struct lpfc_dmabuf *
J
James Smart 已提交
212
lpfc_alloc_ct_rsp(struct lpfc_hba *phba, int cmdcode, struct ulp_bde64 *bpl,
已提交
213 214 215 216 217 218
		  uint32_t size, int *entries)
{
	struct lpfc_dmabuf *mlist = NULL;
	struct lpfc_dmabuf *mp;
	int cnt, i = 0;

219
	/* We get chunks of FCELSSIZE */
已提交
220 221 222 223 224 225 226 227 228 229 230 231 232
	cnt = size > FCELSSIZE ? FCELSSIZE: size;

	while (size) {
		/* Allocate buffer for rsp payload */
		mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
		if (!mp) {
			if (mlist)
				lpfc_free_ct_rsp(phba, mlist);
			return NULL;
		}

		INIT_LIST_HEAD(&mp->list);

233 234
		if (cmdcode == be16_to_cpu(SLI_CTNS_GID_FT) ||
		    cmdcode == be16_to_cpu(SLI_CTNS_GFF_ID))
已提交
235 236 237 238 239 240
			mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys));
		else
			mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys));

		if (!mp->virt) {
			kfree(mp);
241 242
			if (mlist)
				lpfc_free_ct_rsp(phba, mlist);
已提交
243 244 245 246 247 248 249 250 251
			return NULL;
		}

		/* Queue it to a linked list */
		if (!mlist)
			mlist = mp;
		else
			list_add_tail(&mp->list, &mlist->list);

252
		bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
已提交
253
		/* build buffer ptr list for IOCB */
254 255
		bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys) );
		bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys) );
已提交
256 257 258 259 260 261 262 263 264 265 266 267
		bpl->tus.f.bdeSize = (uint16_t) cnt;
		bpl->tus.w = le32_to_cpu(bpl->tus.w);
		bpl++;

		i++;
		size -= cnt;
	}

	*entries = i;
	return mlist;
}

J
James Smart 已提交
268 269 270 271 272
int
lpfc_ct_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocb)
{
	struct lpfc_dmabuf *buf_ptr;

273 274 275 276
	if (ctiocb->context_un.ndlp) {
		lpfc_nlp_put(ctiocb->context_un.ndlp);
		ctiocb->context_un.ndlp = NULL;
	}
J
James Smart 已提交
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
	if (ctiocb->context1) {
		buf_ptr = (struct lpfc_dmabuf *) ctiocb->context1;
		lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
		kfree(buf_ptr);
		ctiocb->context1 = NULL;
	}
	if (ctiocb->context2) {
		lpfc_free_ct_rsp(phba, (struct lpfc_dmabuf *) ctiocb->context2);
		ctiocb->context2 = NULL;
	}

	if (ctiocb->context3) {
		buf_ptr = (struct lpfc_dmabuf *) ctiocb->context3;
		lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
		kfree(buf_ptr);
		ctiocb->context1 = NULL;
	}
	lpfc_sli_release_iocbq(phba, ctiocb);
	return 0;
}

已提交
298
static int
J
James Smart 已提交
299
lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
已提交
300 301 302 303
	     struct lpfc_dmabuf *inp, struct lpfc_dmabuf *outp,
	     void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
		     struct lpfc_iocbq *),
	     struct lpfc_nodelist *ndlp, uint32_t usr_flg, uint32_t num_entry,
304
	     uint32_t tmo, uint8_t retry)
已提交
305
{
J
James Smart 已提交
306
	struct lpfc_hba  *phba = vport->phba;
已提交
307
	IOCB_t *icmd;
308
	struct lpfc_iocbq *geniocb;
309
	int rc;
已提交
310 311

	/* Allocate buffer for  command iocb */
312
	geniocb = lpfc_sli_get_iocbq(phba);
已提交
313 314 315 316 317 318 319 320

	if (geniocb == NULL)
		return 1;

	icmd = &geniocb->iocb;
	icmd->un.genreq64.bdl.ulpIoTag32 = 0;
	icmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys);
	icmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys);
321
	icmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
已提交
322 323 324 325 326 327 328 329 330 331
	icmd->un.genreq64.bdl.bdeSize = (num_entry * sizeof (struct ulp_bde64));

	if (usr_flg)
		geniocb->context3 = NULL;
	else
		geniocb->context3 = (uint8_t *) bmp;

	/* Save for completion so we can release these resources */
	geniocb->context1 = (uint8_t *) inp;
	geniocb->context2 = (uint8_t *) outp;
332
	geniocb->context_un.ndlp = lpfc_nlp_get(ndlp);
已提交
333 334 335 336 337 338 339

	/* Fill in payload, bp points to frame payload */
	icmd->ulpCommand = CMD_GEN_REQUEST64_CR;

	/* Fill in rest of iocb */
	icmd->un.genreq64.w5.hcsw.Fctl = (SI | LA);
	icmd->un.genreq64.w5.hcsw.Dfctl = 0;
340 341
	icmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL;
	icmd->un.genreq64.w5.hcsw.Type = FC_TYPE_CT;
已提交
342

343 344 345 346
	if (!tmo) {
		 /* FC spec states we need 3 * ratov for CT requests */
		tmo = (3 * phba->fc_ratov);
	}
已提交
347 348 349 350 351 352
	icmd->ulpTimeout = tmo;
	icmd->ulpBdeCount = 1;
	icmd->ulpLe = 1;
	icmd->ulpClass = CLASS3;
	icmd->ulpContext = ndlp->nlp_rpi;

353 354 355 356 357 358
	if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
		/* For GEN_REQUEST64_CR, use the RPI */
		icmd->ulpCt_h = 0;
		icmd->ulpCt_l = 0;
	}

已提交
359
	/* Issue GEN REQ IOCB for NPORT <did> */
360 361 362 363 364
	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
			 "0119 Issue GEN REQ IOCB to NPORT x%x "
			 "Data: x%x x%x\n",
			 ndlp->nlp_DID, icmd->ulpIoTag,
			 vport->port_state);
已提交
365 366
	geniocb->iocb_cmpl = cmpl;
	geniocb->drvrTimeout = icmd->ulpTimeout + LPFC_DRVR_TIMEOUT;
J
James Smart 已提交
367
	geniocb->vport = vport;
368
	geniocb->retry = retry;
369
	rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, geniocb, 0);
370 371

	if (rc == IOCB_ERROR) {
372
		lpfc_sli_release_iocbq(phba, geniocb);
已提交
373 374 375 376 377 378 379
		return 1;
	}

	return 0;
}

static int
J
James Smart 已提交
380
lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp,
已提交
381 382 383
	    struct lpfc_dmabuf *bmp, struct lpfc_nodelist *ndlp,
	    void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
			  struct lpfc_iocbq *),
384
	    uint32_t rsp_size, uint8_t retry)
已提交
385
{
J
James Smart 已提交
386
	struct lpfc_hba  *phba = vport->phba;
已提交
387 388 389 390 391 392 393 394 395 396 397 398
	struct ulp_bde64 *bpl = (struct ulp_bde64 *) bmp->virt;
	struct lpfc_dmabuf *outmp;
	int cnt = 0, status;
	int cmdcode = ((struct lpfc_sli_ct_request *) inmp->virt)->
		CommandResponse.bits.CmdRsp;

	bpl++;			/* Skip past ct request */

	/* Put buffer(s) for ct rsp in bpl */
	outmp = lpfc_alloc_ct_rsp(phba, cmdcode, bpl, rsp_size, &cnt);
	if (!outmp)
		return -ENOMEM;
399 400 401 402 403 404
	/*
	 * Form the CT IOCB.  The total number of BDEs in this IOCB
	 * is the single command plus response count from
	 * lpfc_alloc_ct_rsp.
	 */
	cnt += 1;
J
James Smart 已提交
405
	status = lpfc_gen_req(vport, bmp, inmp, outmp, cmpl, ndlp, 0,
406
			      cnt, 0, retry);
已提交
407 408 409 410 411 412 413
	if (status) {
		lpfc_free_ct_rsp(phba, outmp);
		return -ENOMEM;
	}
	return 0;
}

414
struct lpfc_vport *
415 416
lpfc_find_vport_by_did(struct lpfc_hba *phba, uint32_t did) {
	struct lpfc_vport *vport_curr;
417
	unsigned long flags;
418

419
	spin_lock_irqsave(&phba->hbalock, flags);
420
	list_for_each_entry(vport_curr, &phba->port_list, listentry) {
421 422
		if ((vport_curr->fc_myDID) && (vport_curr->fc_myDID == did)) {
			spin_unlock_irqrestore(&phba->hbalock, flags);
423
			return vport_curr;
424
		}
425
	}
426
	spin_unlock_irqrestore(&phba->hbalock, flags);
427 428 429
	return NULL;
}

已提交
430
static int
J
James Smart 已提交
431
lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
已提交
432
{
J
James Smart 已提交
433
	struct lpfc_hba  *phba = vport->phba;
已提交
434 435 436 437 438
	struct lpfc_sli_ct_request *Response =
		(struct lpfc_sli_ct_request *) mp->virt;
	struct lpfc_nodelist *ndlp = NULL;
	struct lpfc_dmabuf *mlast, *next_mp;
	uint32_t *ctptr = (uint32_t *) & Response->un.gid.PortType;
J
James Smart 已提交
439
	uint32_t Did, CTentry;
已提交
440 441 442
	int Cnt;
	struct list_head head;

J
James Smart 已提交
443
	lpfc_set_disctmo(vport);
444
	vport->num_disc_nodes = 0;
445
	vport->fc_ns_retry = 0;
已提交
446 447 448 449 450 451


	list_add_tail(&head, &mp->list);
	list_for_each_entry_safe(mp, next_mp, &head, list) {
		mlast = mp;

452 453
		Cnt = Size  > FCELSSIZE ? FCELSSIZE : Size;

已提交
454 455
		Size -= Cnt;

456
		if (!ctptr) {
已提交
457
			ctptr = (uint32_t *) mlast->virt;
458
		} else
已提交
459 460 461
			Cnt -= 16;	/* subtract length of CT header */

		/* Loop through entire NameServer list of DIDs */
462
		while (Cnt >= sizeof (uint32_t)) {
已提交
463 464 465
			/* Get next DID from NameServer List */
			CTentry = *ctptr++;
			Did = ((be32_to_cpu(CTentry)) & Mask_DID);
466

已提交
467
			ndlp = NULL;
468 469 470 471 472 473 474 475

			/*
			 * Check for rscn processing or not
			 * To conserve rpi's, filter out addresses for other
			 * vports on the same physical HBAs.
			 */
			if ((Did != vport->fc_myDID) &&
			    ((lpfc_find_vport_by_did(phba, Did) == NULL) ||
476
			     vport->cfg_peer_port_login)) {
477
				if ((vport->port_type != LPFC_NPIV_PORT) ||
478
				    (!(vport->ct_flags & FC_CT_RFF_ID)) ||
479
				    (!vport->cfg_restrict_login)) {
480
					ndlp = lpfc_setup_disc_node(vport, Did);
481
					if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
J
James Smart 已提交
482 483 484 485 486 487 488
						lpfc_debugfs_disc_trc(vport,
						LPFC_DISC_TRC_CT,
						"Parse GID_FTrsp: "
						"did:x%x flg:x%x x%x",
						Did, ndlp->nlp_flag,
						vport->fc_flag);

489 490
						lpfc_printf_vlog(vport,
							KERN_INFO,
491
							LOG_DISCOVERY,
492
							"0238 Process "
493 494
							"x%x NameServer Rsp"
							"Data: x%x x%x x%x\n",
495
							Did, ndlp->nlp_flag,
496 497 498
							vport->fc_flag,
							vport->fc_rscn_id_cnt);
					} else {
J
James Smart 已提交
499 500 501 502 503 504 505
						lpfc_debugfs_disc_trc(vport,
						LPFC_DISC_TRC_CT,
						"Skip1 GID_FTrsp: "
						"did:x%x flg:x%x cnt:%d",
						Did, vport->fc_flag,
						vport->fc_rscn_id_cnt);

506 507
						lpfc_printf_vlog(vport,
							KERN_INFO,
508
							LOG_DISCOVERY,
509
							"0239 Skip x%x "
510 511
							"NameServer Rsp Data: "
							"x%x x%x\n",
512
							Did, vport->fc_flag,
513 514 515 516 517 518
							vport->fc_rscn_id_cnt);
					}

				} else {
					if (!(vport->fc_flag & FC_RSCN_MODE) ||
					(lpfc_rscn_payload_check(vport, Did))) {
J
James Smart 已提交
519 520 521 522 523 524 525
						lpfc_debugfs_disc_trc(vport,
						LPFC_DISC_TRC_CT,
						"Query GID_FTrsp: "
						"did:x%x flg:x%x cnt:%d",
						Did, vport->fc_flag,
						vport->fc_rscn_id_cnt);

526 527 528 529 530 531
						/* This NPortID was previously
						 * a FCP target, * Don't even
						 * bother to send GFF_ID.
						 */
						ndlp = lpfc_findnode_did(vport,
							Did);
532 533 534 535
						if (ndlp &&
						    NLP_CHK_NODE_ACT(ndlp)
						    && (ndlp->nlp_type &
						     NLP_FCP_TARGET))
536 537 538
							lpfc_setup_disc_node
								(vport, Did);
						else if (lpfc_ns_cmd(vport,
539 540 541
							SLI_CTNS_GFF_ID,
							0, Did) == 0)
							vport->num_disc_nodes++;
542 543 544
						else
							lpfc_setup_disc_node
								(vport, Did);
545 546
					}
					else {
J
James Smart 已提交
547 548 549 550 551 552 553
						lpfc_debugfs_disc_trc(vport,
						LPFC_DISC_TRC_CT,
						"Skip2 GID_FTrsp: "
						"did:x%x flg:x%x cnt:%d",
						Did, vport->fc_flag,
						vport->fc_rscn_id_cnt);

554 555
						lpfc_printf_vlog(vport,
							KERN_INFO,
556
							LOG_DISCOVERY,
557
							"0245 Skip x%x "
558 559
							"NameServer Rsp Data: "
							"x%x x%x\n",
560
							Did, vport->fc_flag,
561 562 563
							vport->fc_rscn_id_cnt);
					}
				}
已提交
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
			}
			if (CTentry & (be32_to_cpu(SLI_CT_LAST_ENTRY)))
				goto nsout1;
			Cnt -= sizeof (uint32_t);
		}
		ctptr = NULL;

	}

nsout1:
	list_del(&head);
	return 0;
}

static void
J
James Smart 已提交
579 580
lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
			struct lpfc_iocbq *rspiocb)
已提交
581
{
J
James Smart 已提交
582
	struct lpfc_vport *vport = cmdiocb->vport;
583
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
已提交
584 585 586 587
	IOCB_t *irsp;
	struct lpfc_dmabuf *bmp;
	struct lpfc_dmabuf *outp;
	struct lpfc_sli_ct_request *CTrsp;
588
	struct lpfc_nodelist *ndlp;
589
	int rc;
已提交
590

591 592 593
	/* First save ndlp, before we overwrite it */
	ndlp = cmdiocb->context_un.ndlp;

已提交
594 595 596 597 598
	/* we pass cmdiocb to state machine which needs rspiocb as well */
	cmdiocb->context_un.rsp_iocb = rspiocb;

	outp = (struct lpfc_dmabuf *) cmdiocb->context2;
	bmp = (struct lpfc_dmabuf *) cmdiocb->context3;
J
James Smart 已提交
599 600 601 602 603
	irsp = &rspiocb->iocb;

	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
		 "GID_FT cmpl:     status:x%x/x%x rtry:%d",
		irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_ns_retry);
已提交
604

605
	/* Don't bother processing response if vport is being torn down. */
606 607 608
	if (vport->load_flag & FC_UNLOADING) {
		if (vport->fc_flag & FC_RSCN_MODE)
			lpfc_els_flush_rscn(vport);
609
		goto out;
610
	}
611

612
	if (lpfc_els_chk_latt(vport)) {
613 614
		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
				 "0216 Link event during NS query\n");
615 616
		if (vport->fc_flag & FC_RSCN_MODE)
			lpfc_els_flush_rscn(vport);
J
James Smart 已提交
617 618 619
		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
		goto out;
	}
620 621 622
	if (lpfc_error_lost_link(irsp)) {
		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
				 "0226 NS query failed due to link event\n");
623 624
		if (vport->fc_flag & FC_RSCN_MODE)
			lpfc_els_flush_rscn(vport);
625 626
		goto out;
	}
J
James Smart 已提交
627
	if (irsp->ulpStatus) {
已提交
628
		/* Check for retry */
J
James Smart 已提交
629
		if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) {
630 631
			if (irsp->ulpStatus != IOSTAT_LOCAL_REJECT ||
			    irsp->un.ulpWord[4] != IOERR_NO_RESOURCES)
J
James Smart 已提交
632
				vport->fc_ns_retry++;
633

634 635
			/* CT command is being retried */
			rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT,
636
					 vport->fc_ns_retry, 0);
637 638
			if (rc == 0)
				goto out;
639
		}
640 641
		if (vport->fc_flag & FC_RSCN_MODE)
			lpfc_els_flush_rscn(vport);
642
		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
643 644 645
		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
				 "0257 GID_FT Query error: 0x%x 0x%x\n",
				 irsp->ulpStatus, vport->fc_ns_retry);
已提交
646 647 648 649 650
	} else {
		/* Good status, continue checking */
		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
		if (CTrsp->CommandResponse.bits.CmdRsp ==
		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) {
651 652 653
			lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
					 "0208 NameServer Rsp Data: x%x\n",
					 vport->fc_flag);
J
James Smart 已提交
654
			lpfc_ns_rsp(vport, outp,
已提交
655 656 657 658
				    (uint32_t) (irsp->un.genreq64.bdl.bdeSize));
		} else if (CTrsp->CommandResponse.bits.CmdRsp ==
			   be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
			/* NameServer Rsp Error */
659 660
			if ((CTrsp->ReasonCode == SLI_CT_UNABLE_TO_PERFORM_REQ)
			    && (CTrsp->Explanation == SLI_CT_NO_FC4_TYPES)) {
661 662 663
				lpfc_printf_vlog(vport, KERN_INFO,
					LOG_DISCOVERY,
					"0269 No NameServer Entries "
664 665 666 667 668 669 670 671 672 673 674
					"Data: x%x x%x x%x x%x\n",
					CTrsp->CommandResponse.bits.CmdRsp,
					(uint32_t) CTrsp->ReasonCode,
					(uint32_t) CTrsp->Explanation,
					vport->fc_flag);

				lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
				"GID_FT no entry  cmd:x%x rsn:x%x exp:x%x",
				(uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
				(uint32_t) CTrsp->ReasonCode,
				(uint32_t) CTrsp->Explanation);
675 676 677 678
			} else {
				lpfc_printf_vlog(vport, KERN_INFO,
					LOG_DISCOVERY,
					"0240 NameServer Rsp Error "
已提交
679 680 681 682
					"Data: x%x x%x x%x x%x\n",
					CTrsp->CommandResponse.bits.CmdRsp,
					(uint32_t) CTrsp->ReasonCode,
					(uint32_t) CTrsp->Explanation,
J
James Smart 已提交
683
					vport->fc_flag);
J
James Smart 已提交
684

685
				lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
J
James Smart 已提交
686 687 688 689
				"GID_FT rsp err1  cmd:x%x rsn:x%x exp:x%x",
				(uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
				(uint32_t) CTrsp->ReasonCode,
				(uint32_t) CTrsp->Explanation);
690 691
			}

J
James Smart 已提交
692

已提交
693 694
		} else {
			/* NameServer Rsp Error */
695 696
			lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
					"0241 NameServer Rsp Error "
已提交
697 698 699 700
					"Data: x%x x%x x%x x%x\n",
					CTrsp->CommandResponse.bits.CmdRsp,
					(uint32_t) CTrsp->ReasonCode,
					(uint32_t) CTrsp->Explanation,
J
James Smart 已提交
701
					vport->fc_flag);
J
James Smart 已提交
702 703 704 705 706 707

			lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
				"GID_FT rsp err2  cmd:x%x rsn:x%x exp:x%x",
				(uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
				(uint32_t) CTrsp->ReasonCode,
				(uint32_t) CTrsp->Explanation);
已提交
708 709 710
		}
	}
	/* Link up / RSCN discovery */
711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730
	if (vport->num_disc_nodes == 0) {
		/*
		 * The driver has cycled through all Nports in the RSCN payload.
		 * Complete the handling by cleaning up and marking the
		 * current driver state.
		 */
		if (vport->port_state >= LPFC_DISC_AUTH) {
			if (vport->fc_flag & FC_RSCN_MODE) {
				lpfc_els_flush_rscn(vport);
				spin_lock_irq(shost->host_lock);
				vport->fc_flag |= FC_RSCN_MODE; /* RSCN still */
				spin_unlock_irq(shost->host_lock);
			}
			else
				lpfc_els_flush_rscn(vport);
		}

		lpfc_disc_start(vport);
	}
out:
731
	cmdiocb->context_un.ndlp = ndlp; /* Now restore ndlp for free */
J
James Smart 已提交
732
	lpfc_ct_free_iocb(phba, cmdiocb);
733 734 735
	return;
}

J
James Smart 已提交
736
static void
737 738 739 740 741 742 743 744 745
lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
			struct lpfc_iocbq *rspiocb)
{
	struct lpfc_vport *vport = cmdiocb->vport;
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	IOCB_t *irsp = &rspiocb->iocb;
	struct lpfc_dmabuf *inp = (struct lpfc_dmabuf *) cmdiocb->context1;
	struct lpfc_dmabuf *outp = (struct lpfc_dmabuf *) cmdiocb->context2;
	struct lpfc_sli_ct_request *CTrsp;
746
	int did, rc, retry;
747 748 749 750 751 752
	uint8_t fbits;
	struct lpfc_nodelist *ndlp;

	did = ((struct lpfc_sli_ct_request *) inp->virt)->un.gff.PortId;
	did = be32_to_cpu(did);

J
James Smart 已提交
753 754 755 756
	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
		"GFF_ID cmpl:     status:x%x/x%x did:x%x",
		irsp->ulpStatus, irsp->un.ulpWord[4], did);

757 758 759 760 761 762 763 764 765
	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
		/* Good status, continue checking */
		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
		fbits = CTrsp->un.gff_acc.fbits[FCP_TYPE_FEATURE_OFFSET];

		if (CTrsp->CommandResponse.bits.CmdRsp ==
		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) {
			if ((fbits & FC4_FEATURE_INIT) &&
			    !(fbits & FC4_FEATURE_TARGET)) {
766 767 768 769 770 771
				lpfc_printf_vlog(vport, KERN_INFO,
						 LOG_DISCOVERY,
						 "0270 Skip x%x GFF "
						 "NameServer Rsp Data: (init) "
						 "x%x x%x\n", did, fbits,
						 vport->fc_rscn_id_cnt);
772 773 774 775
				goto out;
			}
		}
	}
J
James Smart 已提交
776
	else {
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809
		/* Check for retry */
		if (cmdiocb->retry < LPFC_MAX_NS_RETRY) {
			retry = 1;
			if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
				switch (irsp->un.ulpWord[4]) {
				case IOERR_NO_RESOURCES:
					/* We don't increment the retry
					 * count for this case.
					 */
					break;
				case IOERR_LINK_DOWN:
				case IOERR_SLI_ABORTED:
				case IOERR_SLI_DOWN:
					retry = 0;
					break;
				default:
					cmdiocb->retry++;
				}
			}
			else
				cmdiocb->retry++;

			if (retry) {
				/* CT command is being retried */
				rc = lpfc_ns_cmd(vport, SLI_CTNS_GFF_ID,
					 cmdiocb->retry, did);
				if (rc == 0) {
					/* success */
					lpfc_ct_free_iocb(phba, cmdiocb);
					return;
				}
			}
		}
810 811 812 813
		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
				 "0267 NameServer GFF Rsp "
				 "x%x Error (%d %d) Data: x%x x%x\n",
				 did, irsp->ulpStatus, irsp->un.ulpWord[4],
814
				 vport->fc_flag, vport->fc_rscn_id_cnt);
J
James Smart 已提交
815 816
	}

817 818
	/* This is a target port, unregistered port, or the GFF_ID failed */
	ndlp = lpfc_setup_disc_node(vport, did);
819
	if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
820 821 822 823 824
		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
				 "0242 Process x%x GFF "
				 "NameServer Rsp Data: x%x x%x x%x\n",
				 did, ndlp->nlp_flag, vport->fc_flag,
				 vport->fc_rscn_id_cnt);
825
	} else {
826 827 828 829
		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
				 "0243 Skip x%x GFF "
				 "NameServer Rsp Data: x%x x%x\n", did,
				 vport->fc_flag, vport->fc_rscn_id_cnt);
830
	}
已提交
831
out:
832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852
	/* Link up / RSCN discovery */
	if (vport->num_disc_nodes)
		vport->num_disc_nodes--;
	if (vport->num_disc_nodes == 0) {
		/*
		 * The driver has cycled through all Nports in the RSCN payload.
		 * Complete the handling by cleaning up and marking the
		 * current driver state.
		 */
		if (vport->port_state >= LPFC_DISC_AUTH) {
			if (vport->fc_flag & FC_RSCN_MODE) {
				lpfc_els_flush_rscn(vport);
				spin_lock_irq(shost->host_lock);
				vport->fc_flag |= FC_RSCN_MODE; /* RSCN still */
				spin_unlock_irq(shost->host_lock);
			}
			else
				lpfc_els_flush_rscn(vport);
		}
		lpfc_disc_start(vport);
	}
J
James Smart 已提交
853
	lpfc_ct_free_iocb(phba, cmdiocb);
已提交
854 855 856
	return;
}

857

已提交
858
static void
J
James Smart 已提交
859 860
lpfc_cmpl_ct(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
	     struct lpfc_iocbq *rspiocb)
已提交
861
{
862
	struct lpfc_vport *vport = cmdiocb->vport;
已提交
863 864 865 866
	struct lpfc_dmabuf *inp;
	struct lpfc_dmabuf *outp;
	IOCB_t *irsp;
	struct lpfc_sli_ct_request *CTrsp;
867
	struct lpfc_nodelist *ndlp;
868 869
	int cmdcode, rc;
	uint8_t retry;
J
James Smart 已提交
870
	uint32_t latt;
已提交
871

872 873 874
	/* First save ndlp, before we overwrite it */
	ndlp = cmdiocb->context_un.ndlp;

已提交
875 876 877 878 879 880 881
	/* we pass cmdiocb to state machine which needs rspiocb as well */
	cmdiocb->context_un.rsp_iocb = rspiocb;

	inp = (struct lpfc_dmabuf *) cmdiocb->context1;
	outp = (struct lpfc_dmabuf *) cmdiocb->context2;
	irsp = &rspiocb->iocb;

882 883
	cmdcode = be16_to_cpu(((struct lpfc_sli_ct_request *) inp->virt)->
					CommandResponse.bits.CmdRsp);
已提交
884 885
	CTrsp = (struct lpfc_sli_ct_request *) outp->virt;

J
James Smart 已提交
886 887 888
	latt = lpfc_els_chk_latt(vport);

	/* RFT request completes status <ulpStatus> CmdRsp <CmdRsp> */
889
	lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
J
James Smart 已提交
890
			 "0209 CT Request completes, latt %d, "
891 892 893 894
			 "ulpStatus x%x CmdRsp x%x, Context x%x, Tag x%x\n",
			 latt, irsp->ulpStatus,
			 CTrsp->CommandResponse.bits.CmdRsp,
			 cmdiocb->iocb.ulpContext, cmdiocb->iocb.ulpIoTag);
已提交
895

J
James Smart 已提交
896 897 898 899
	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
		"CT cmd cmpl:     status:x%x/x%x cmd:x%x",
		irsp->ulpStatus, irsp->un.ulpWord[4], cmdcode);

900
	if (irsp->ulpStatus) {
901 902 903
		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
				 "0268 NS cmd %x Error (%d %d)\n",
				 cmdcode, irsp->ulpStatus, irsp->un.ulpWord[4]);
J
James Smart 已提交
904

905 906 907 908 909 910 911 912 913 914
		if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
			((irsp->un.ulpWord[4] == IOERR_SLI_DOWN) ||
			 (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED)))
			goto out;

		retry = cmdiocb->retry;
		if (retry >= LPFC_MAX_NS_RETRY)
			goto out;

		retry++;
915
		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
916
				 "0250 Retrying NS cmd %x\n", cmdcode);
917 918 919 920 921 922
		rc = lpfc_ns_cmd(vport, cmdcode, retry, 0);
		if (rc == 0)
			goto out;
	}

out:
923
	cmdiocb->context_un.ndlp = ndlp; /* Now restore ndlp for free */
J
James Smart 已提交
924
	lpfc_ct_free_iocb(phba, cmdiocb);
已提交
925 926 927
	return;
}

J
James Smart 已提交
928 929 930 931 932 933 934
static void
lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
			struct lpfc_iocbq *rspiocb)
{
	IOCB_t *irsp = &rspiocb->iocb;
	struct lpfc_vport *vport = cmdiocb->vport;

935 936 937 938 939 940 941 942 943 944
	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
		struct lpfc_dmabuf *outp;
		struct lpfc_sli_ct_request *CTrsp;

		outp = (struct lpfc_dmabuf *) cmdiocb->context2;
		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
		if (CTrsp->CommandResponse.bits.CmdRsp ==
		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
			vport->ct_flags |= FC_CT_RFT_ID;
	}
J
James Smart 已提交
945 946 947 948
	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
	return;
}

已提交
949
static void
J
James Smart 已提交
950 951
lpfc_cmpl_ct_cmd_rnn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
			struct lpfc_iocbq *rspiocb)
已提交
952
{
J
James Smart 已提交
953 954 955
	IOCB_t *irsp = &rspiocb->iocb;
	struct lpfc_vport *vport = cmdiocb->vport;

956 957 958 959 960 961 962 963 964 965
	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
		struct lpfc_dmabuf *outp;
		struct lpfc_sli_ct_request *CTrsp;

		outp = (struct lpfc_dmabuf *) cmdiocb->context2;
		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
		if (CTrsp->CommandResponse.bits.CmdRsp ==
		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
			vport->ct_flags |= FC_CT_RNN_ID;
	}
J
James Smart 已提交
966
	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
已提交
967 968 969
	return;
}

970 971 972 973
static void
lpfc_cmpl_ct_cmd_rspn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
			 struct lpfc_iocbq *rspiocb)
{
J
James Smart 已提交
974 975 976
	IOCB_t *irsp = &rspiocb->iocb;
	struct lpfc_vport *vport = cmdiocb->vport;

977 978 979 980 981 982 983 984 985 986
	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
		struct lpfc_dmabuf *outp;
		struct lpfc_sli_ct_request *CTrsp;

		outp = (struct lpfc_dmabuf *) cmdiocb->context2;
		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
		if (CTrsp->CommandResponse.bits.CmdRsp ==
		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
			vport->ct_flags |= FC_CT_RSPN_ID;
	}
J
James Smart 已提交
987
	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
988 989 990
	return;
}

已提交
991
static void
J
James Smart 已提交
992 993
lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
			 struct lpfc_iocbq *rspiocb)
已提交
994
{
J
James Smart 已提交
995 996 997
	IOCB_t *irsp = &rspiocb->iocb;
	struct lpfc_vport *vport = cmdiocb->vport;

998 999 1000 1001 1002 1003 1004 1005 1006 1007
	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
		struct lpfc_dmabuf *outp;
		struct lpfc_sli_ct_request *CTrsp;

		outp = (struct lpfc_dmabuf *) cmdiocb->context2;
		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
		if (CTrsp->CommandResponse.bits.CmdRsp ==
		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
			vport->ct_flags |= FC_CT_RSNN_NN;
	}
J
James Smart 已提交
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020
	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
	return;
}

static void
lpfc_cmpl_ct_cmd_da_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 struct lpfc_iocbq *rspiocb)
{
	struct lpfc_vport *vport = cmdiocb->vport;

	/* even if it fails we will act as though it succeeded. */
	vport->ct_flags = 0;
	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
已提交
1021 1022 1023
	return;
}

J
James Smart 已提交
1024
static void
1025 1026
lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
			struct lpfc_iocbq *rspiocb)
J
James Smart 已提交
1027
{
1028 1029 1030
	IOCB_t *irsp = &rspiocb->iocb;
	struct lpfc_vport *vport = cmdiocb->vport;

1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
	if (irsp->ulpStatus == IOSTAT_SUCCESS) {
		struct lpfc_dmabuf *outp;
		struct lpfc_sli_ct_request *CTrsp;

		outp = (struct lpfc_dmabuf *) cmdiocb->context2;
		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
		if (CTrsp->CommandResponse.bits.CmdRsp ==
		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
			vport->ct_flags |= FC_CT_RFF_ID;
	}
J
James Smart 已提交
1041
	lpfc_cmpl_ct(phba, cmdiocb, rspiocb);
J
James Smart 已提交
1042 1043 1044
	return;
}

1045
int
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062
lpfc_vport_symbolic_port_name(struct lpfc_vport *vport, char *symbol,
	size_t size)
{
	int n;
	uint8_t *wwn = vport->phba->wwpn;

	n = snprintf(symbol, size,
		     "Emulex PPN-%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
		     wwn[0], wwn[1], wwn[2], wwn[3],
		     wwn[4], wwn[5], wwn[6], wwn[7]);

	if (vport->port_type == LPFC_PHYSICAL_PORT)
		return n;

	if (n < size)
		n += snprintf(symbol + n, size - n, " VPort-%d", vport->vpi);

1063 1064 1065 1066
	if (n < size &&
	    strlen(vport->fc_vport->symbolic_name))
		n += snprintf(symbol + n, size - n, " VName-%s",
			      vport->fc_vport->symbolic_name);
1067 1068 1069 1070 1071 1072
	return n;
}

int
lpfc_vport_symbolic_node_name(struct lpfc_vport *vport, char *symbol,
	size_t size)
已提交
1073 1074
{
	char fwrev[16];
1075
	int n;
已提交
1076

1077
	lpfc_decode_firmware_rev(vport->phba, fwrev, 0);
已提交
1078

1079 1080 1081
	n = snprintf(symbol, size, "Emulex %s FV%s DV%s",
		vport->phba->ModelName, fwrev, lpfc_release_version);
	return n;
已提交
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091
}

/*
 * lpfc_ns_cmd
 * Description:
 *    Issue Cmd to NameServer
 *       SLI_CTNS_GID_FT
 *       LI_CTNS_RFT_ID
 */
int
1092 1093
lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
	    uint8_t retry, uint32_t context)
已提交
1094
{
1095
	struct lpfc_nodelist * ndlp;
J
James Smart 已提交
1096
	struct lpfc_hba *phba = vport->phba;
已提交
1097 1098 1099 1100 1101 1102
	struct lpfc_dmabuf *mp, *bmp;
	struct lpfc_sli_ct_request *CtReq;
	struct ulp_bde64 *bpl;
	void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
		      struct lpfc_iocbq *) = NULL;
	uint32_t rsp_size = 1024;
1103
	size_t   size;
J
James Smart 已提交
1104
	int rc = 0;
1105 1106

	ndlp = lpfc_findnode_did(vport, NameServer_DID);
1107 1108
	if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)
	    || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) {
J
James Smart 已提交
1109 1110 1111
		rc=1;
		goto ns_cmd_exit;
	}
已提交
1112 1113 1114 1115

	/* fill in BDEs for command */
	/* Allocate buffer for command payload */
	mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
J
James Smart 已提交
1116 1117
	if (!mp) {
		rc=2;
已提交
1118
		goto ns_cmd_exit;
J
James Smart 已提交
1119
	}
已提交
1120 1121 1122

	INIT_LIST_HEAD(&mp->list);
	mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys));
J
James Smart 已提交
1123 1124
	if (!mp->virt) {
		rc=3;
已提交
1125
		goto ns_cmd_free_mp;
J
James Smart 已提交
1126
	}
已提交
1127 1128 1129

	/* Allocate buffer for Buffer ptr list */
	bmp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
J
James Smart 已提交
1130 1131
	if (!bmp) {
		rc=4;
已提交
1132
		goto ns_cmd_free_mpvirt;
J
James Smart 已提交
1133
	}
已提交
1134 1135 1136

	INIT_LIST_HEAD(&bmp->list);
	bmp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(bmp->phys));
J
James Smart 已提交
1137 1138
	if (!bmp->virt) {
		rc=5;
已提交
1139
		goto ns_cmd_free_bmp;
J
James Smart 已提交
1140
	}
已提交
1141 1142

	/* NameServer Req */
1143 1144 1145
	lpfc_printf_vlog(vport, KERN_INFO ,LOG_DISCOVERY,
			 "0236 NameServer Req Data: x%x x%x x%x\n",
			 cmdcode, vport->fc_flag, vport->fc_rscn_id_cnt);
已提交
1146 1147 1148

	bpl = (struct ulp_bde64 *) bmp->virt;
	memset(bpl, 0, sizeof(struct ulp_bde64));
1149 1150
	bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys) );
	bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys) );
已提交
1151 1152 1153
	bpl->tus.f.bdeFlags = 0;
	if (cmdcode == SLI_CTNS_GID_FT)
		bpl->tus.f.bdeSize = GID_REQUEST_SZ;
1154 1155
	else if (cmdcode == SLI_CTNS_GFF_ID)
		bpl->tus.f.bdeSize = GFF_REQUEST_SZ;
已提交
1156 1157 1158 1159
	else if (cmdcode == SLI_CTNS_RFT_ID)
		bpl->tus.f.bdeSize = RFT_REQUEST_SZ;
	else if (cmdcode == SLI_CTNS_RNN_ID)
		bpl->tus.f.bdeSize = RNN_REQUEST_SZ;
1160 1161
	else if (cmdcode == SLI_CTNS_RSPN_ID)
		bpl->tus.f.bdeSize = RSPN_REQUEST_SZ;
已提交
1162 1163
	else if (cmdcode == SLI_CTNS_RSNN_NN)
		bpl->tus.f.bdeSize = RSNN_REQUEST_SZ;
J
James Smart 已提交
1164 1165
	else if (cmdcode == SLI_CTNS_DA_ID)
		bpl->tus.f.bdeSize = DA_ID_REQUEST_SZ;
J
James Smart 已提交
1166 1167
	else if (cmdcode == SLI_CTNS_RFF_ID)
		bpl->tus.f.bdeSize = RFF_REQUEST_SZ;
已提交
1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183
	else
		bpl->tus.f.bdeSize = 0;
	bpl->tus.w = le32_to_cpu(bpl->tus.w);

	CtReq = (struct lpfc_sli_ct_request *) mp->virt;
	memset(CtReq, 0, sizeof (struct lpfc_sli_ct_request));
	CtReq->RevisionId.bits.Revision = SLI_CT_REVISION;
	CtReq->RevisionId.bits.InId = 0;
	CtReq->FsType = SLI_CT_DIRECTORY_SERVICE;
	CtReq->FsSubType = SLI_CT_DIRECTORY_NAME_SERVER;
	CtReq->CommandResponse.bits.Size = 0;
	switch (cmdcode) {
	case SLI_CTNS_GID_FT:
		CtReq->CommandResponse.bits.CmdRsp =
		    be16_to_cpu(SLI_CTNS_GID_FT);
		CtReq->un.gid.Fc4Type = SLI_CTPT_FCP;
1184
		if (vport->port_state < LPFC_NS_QRY)
J
James Smart 已提交
1185 1186
			vport->port_state = LPFC_NS_QRY;
		lpfc_set_disctmo(vport);
已提交
1187 1188 1189 1190
		cmpl = lpfc_cmpl_ct_cmd_gid_ft;
		rsp_size = FC_MAX_NS_RSP;
		break;

1191 1192 1193
	case SLI_CTNS_GFF_ID:
		CtReq->CommandResponse.bits.CmdRsp =
			be16_to_cpu(SLI_CTNS_GFF_ID);
1194
		CtReq->un.gff.PortId = cpu_to_be32(context);
1195 1196 1197
		cmpl = lpfc_cmpl_ct_cmd_gff_id;
		break;

已提交
1198
	case SLI_CTNS_RFT_ID:
J
James Smart 已提交
1199
		vport->ct_flags &= ~FC_CT_RFT_ID;
已提交
1200 1201
		CtReq->CommandResponse.bits.CmdRsp =
		    be16_to_cpu(SLI_CTNS_RFT_ID);
1202
		CtReq->un.rft.PortId = cpu_to_be32(vport->fc_myDID);
已提交
1203 1204 1205 1206 1207
		CtReq->un.rft.fcpReg = 1;
		cmpl = lpfc_cmpl_ct_cmd_rft_id;
		break;

	case SLI_CTNS_RNN_ID:
J
James Smart 已提交
1208
		vport->ct_flags &= ~FC_CT_RNN_ID;
已提交
1209 1210
		CtReq->CommandResponse.bits.CmdRsp =
		    be16_to_cpu(SLI_CTNS_RNN_ID);
1211
		CtReq->un.rnn.PortId = cpu_to_be32(vport->fc_myDID);
J
James Smart 已提交
1212
		memcpy(CtReq->un.rnn.wwnn,  &vport->fc_nodename,
已提交
1213 1214 1215 1216
		       sizeof (struct lpfc_name));
		cmpl = lpfc_cmpl_ct_cmd_rnn_id;
		break;

1217
	case SLI_CTNS_RSPN_ID:
J
James Smart 已提交
1218
		vport->ct_flags &= ~FC_CT_RSPN_ID;
1219 1220
		CtReq->CommandResponse.bits.CmdRsp =
		    be16_to_cpu(SLI_CTNS_RSPN_ID);
1221
		CtReq->un.rspn.PortId = cpu_to_be32(vport->fc_myDID);
1222 1223 1224 1225 1226 1227
		size = sizeof(CtReq->un.rspn.symbname);
		CtReq->un.rspn.len =
			lpfc_vport_symbolic_port_name(vport,
			CtReq->un.rspn.symbname, size);
		cmpl = lpfc_cmpl_ct_cmd_rspn_id;
		break;
已提交
1228
	case SLI_CTNS_RSNN_NN:
J
James Smart 已提交
1229
		vport->ct_flags &= ~FC_CT_RSNN_NN;
已提交
1230 1231
		CtReq->CommandResponse.bits.CmdRsp =
		    be16_to_cpu(SLI_CTNS_RSNN_NN);
J
James Smart 已提交
1232
		memcpy(CtReq->un.rsnn.wwnn, &vport->fc_nodename,
已提交
1233
		       sizeof (struct lpfc_name));
1234 1235 1236 1237
		size = sizeof(CtReq->un.rsnn.symbname);
		CtReq->un.rsnn.len =
			lpfc_vport_symbolic_node_name(vport,
			CtReq->un.rsnn.symbname, size);
已提交
1238 1239
		cmpl = lpfc_cmpl_ct_cmd_rsnn_nn;
		break;
J
James Smart 已提交
1240 1241 1242 1243
	case SLI_CTNS_DA_ID:
		/* Implement DA_ID Nameserver request */
		CtReq->CommandResponse.bits.CmdRsp =
			be16_to_cpu(SLI_CTNS_DA_ID);
1244
		CtReq->un.da_id.port_id = cpu_to_be32(vport->fc_myDID);
J
James Smart 已提交
1245 1246
		cmpl = lpfc_cmpl_ct_cmd_da_id;
		break;
1247
	case SLI_CTNS_RFF_ID:
J
James Smart 已提交
1248
		vport->ct_flags &= ~FC_CT_RFF_ID;
1249 1250
		CtReq->CommandResponse.bits.CmdRsp =
		    be16_to_cpu(SLI_CTNS_RFF_ID);
1251
		CtReq->un.rff.PortId = cpu_to_be32(vport->fc_myDID);
1252
		CtReq->un.rff.fbits = FC4_FEATURE_INIT;
1253
		CtReq->un.rff.type_code = FC_TYPE_FCP;
1254 1255
		cmpl = lpfc_cmpl_ct_cmd_rff_id;
		break;
已提交
1256
	}
1257 1258 1259
	/* The lpfc_ct_cmd/lpfc_get_req shall increment ndlp reference count
	 * to hold ndlp reference for the corresponding callback function.
	 */
J
James Smart 已提交
1260
	if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, retry)) {
已提交
1261
		/* On success, The cmpl function will free the buffers */
J
James Smart 已提交
1262 1263 1264
		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
			"Issue CT cmd:    cmd:x%x did:x%x",
			cmdcode, ndlp->nlp_DID, 0);
已提交
1265
		return 0;
J
James Smart 已提交
1266 1267
	}
	rc=6;
1268 1269 1270 1271

	/* Decrement ndlp reference count to release ndlp reference held
	 * for the failed command's callback function.
	 */
1272
	lpfc_nlp_put(ndlp);
1273

已提交
1274 1275 1276 1277 1278 1279 1280 1281
	lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
ns_cmd_free_bmp:
	kfree(bmp);
ns_cmd_free_mpvirt:
	lpfc_mbuf_free(phba, mp->virt, mp->phys);
ns_cmd_free_mp:
	kfree(mp);
ns_cmd_exit:
1282 1283 1284
	lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
			 "0266 Issue NameServer Req x%x err %d Data: x%x x%x\n",
			 cmdcode, rc, vport->fc_flag, vport->fc_rscn_id_cnt);
已提交
1285 1286 1287 1288
	return 1;
}

static void
J
James Smart 已提交
1289 1290
lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
		      struct lpfc_iocbq * rspiocb)
已提交
1291 1292 1293 1294 1295 1296 1297 1298
{
	struct lpfc_dmabuf *inp = cmdiocb->context1;
	struct lpfc_dmabuf *outp = cmdiocb->context2;
	struct lpfc_sli_ct_request *CTrsp = outp->virt;
	struct lpfc_sli_ct_request *CTcmd = inp->virt;
	struct lpfc_nodelist *ndlp;
	uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
	uint16_t fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp;
J
James Smart 已提交
1299
	struct lpfc_vport *vport = cmdiocb->vport;
J
James Smart 已提交
1300 1301 1302 1303 1304 1305 1306 1307 1308 1309
	IOCB_t *irsp = &rspiocb->iocb;
	uint32_t latt;

	latt = lpfc_els_chk_latt(vport);

	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
		"FDMI cmpl:       status:x%x/x%x latt:%d",
		irsp->ulpStatus, irsp->un.ulpWord[4], latt);

	if (latt || irsp->ulpStatus) {
1310 1311 1312 1313 1314
		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
				 "0229 FDMI cmd %04x failed, latt = %d "
				 "ulpStatus: x%x, rid x%x\n",
				 be16_to_cpu(fdmi_cmd), latt, irsp->ulpStatus,
				 irsp->un.ulpWord[4]);
J
James Smart 已提交
1315 1316 1317
		lpfc_ct_free_iocb(phba, cmdiocb);
		return;
	}
已提交
1318

J
James Smart 已提交
1319
	ndlp = lpfc_findnode_did(vport, FDMI_DID);
1320 1321 1322
	if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
		goto fail_out;

已提交
1323 1324
	if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
		/* FDMI rsp failed */
1325 1326 1327
		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
				 "0220 FDMI rsp failed Data: x%x\n",
				 be16_to_cpu(fdmi_cmd));
已提交
1328 1329 1330 1331
	}

	switch (be16_to_cpu(fdmi_cmd)) {
	case SLI_MGMT_RHBA:
J
James Smart 已提交
1332
		lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA);
已提交
1333 1334 1335 1336 1337 1338
		break;

	case SLI_MGMT_RPA:
		break;

	case SLI_MGMT_DHBA:
J
James Smart 已提交
1339
		lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT);
已提交
1340 1341 1342
		break;

	case SLI_MGMT_DPRT:
J
James Smart 已提交
1343
		lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA);
已提交
1344 1345
		break;
	}
1346 1347

fail_out:
J
James Smart 已提交
1348
	lpfc_ct_free_iocb(phba, cmdiocb);
已提交
1349 1350
	return;
}
J
James Smart 已提交
1351

已提交
1352
int
J
James Smart 已提交
1353
lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
已提交
1354
{
J
James Smart 已提交
1355
	struct lpfc_hba *phba = vport->phba;
已提交
1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391
	struct lpfc_dmabuf *mp, *bmp;
	struct lpfc_sli_ct_request *CtReq;
	struct ulp_bde64 *bpl;
	uint32_t size;
	REG_HBA *rh;
	PORT_ENTRY *pe;
	REG_PORT_ATTRIBUTE *pab;
	ATTRIBUTE_BLOCK *ab;
	ATTRIBUTE_ENTRY *ae;
	void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
		      struct lpfc_iocbq *);


	/* fill in BDEs for command */
	/* Allocate buffer for command payload */
	mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
	if (!mp)
		goto fdmi_cmd_exit;

	mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys));
	if (!mp->virt)
		goto fdmi_cmd_free_mp;

	/* Allocate buffer for Buffer ptr list */
	bmp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
	if (!bmp)
		goto fdmi_cmd_free_mpvirt;

	bmp->virt = lpfc_mbuf_alloc(phba, 0, &(bmp->phys));
	if (!bmp->virt)
		goto fdmi_cmd_free_bmp;

	INIT_LIST_HEAD(&mp->list);
	INIT_LIST_HEAD(&bmp->list);

	/* FDMI request */
1392 1393 1394
	lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
			 "0218 FDMI Request Data: x%x x%x x%x\n",
			 vport->fc_flag, vport->port_state, cmdcode);
已提交
1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415
	CtReq = (struct lpfc_sli_ct_request *) mp->virt;

	memset(CtReq, 0, sizeof(struct lpfc_sli_ct_request));
	CtReq->RevisionId.bits.Revision = SLI_CT_REVISION;
	CtReq->RevisionId.bits.InId = 0;

	CtReq->FsType = SLI_CT_MANAGEMENT_SERVICE;
	CtReq->FsSubType = SLI_CT_FDMI_Subtypes;
	size = 0;

	switch (cmdcode) {
	case SLI_MGMT_RHBA:
		{
			lpfc_vpd_t *vp = &phba->vpd;
			uint32_t i, j, incr;
			int len;

			CtReq->CommandResponse.bits.CmdRsp =
			    be16_to_cpu(SLI_MGMT_RHBA);
			CtReq->CommandResponse.bits.Size = 0;
			rh = (REG_HBA *) & CtReq->un.PortID;
J
James Smart 已提交
1416
			memcpy(&rh->hi.PortName, &vport->fc_sparam.portName,
已提交
1417 1418 1419
			       sizeof (struct lpfc_name));
			/* One entry (port) per adapter */
			rh->rpl.EntryCnt = be32_to_cpu(1);
J
James Smart 已提交
1420
			memcpy(&rh->rpl.pe, &vport->fc_sparam.portName,
已提交
1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435
			       sizeof (struct lpfc_name));

			/* point to the HBA attribute block */
			size = 2 * sizeof (struct lpfc_name) + FOURBYTES;
			ab = (ATTRIBUTE_BLOCK *) ((uint8_t *) rh + size);
			ab->EntryCnt = 0;

			/* Point to the beginning of the first HBA attribute
			   entry */
			/* #1 HBA attribute entry */
			size += FOURBYTES;
			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
			ae->ad.bits.AttrType = be16_to_cpu(NODE_NAME);
			ae->ad.bits.AttrLen =  be16_to_cpu(FOURBYTES
						+ sizeof (struct lpfc_name));
J
James Smart 已提交
1436
			memcpy(&ae->un.NodeName, &vport->fc_sparam.nodeName,
已提交
1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536
			       sizeof (struct lpfc_name));
			ab->EntryCnt++;
			size += FOURBYTES + sizeof (struct lpfc_name);

			/* #2 HBA attribute entry */
			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
			ae->ad.bits.AttrType = be16_to_cpu(MANUFACTURER);
			strcpy(ae->un.Manufacturer, "Emulex Corporation");
			len = strlen(ae->un.Manufacturer);
			len += (len & 3) ? (4 - (len & 3)) : 4;
			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len);
			ab->EntryCnt++;
			size += FOURBYTES + len;

			/* #3 HBA attribute entry */
			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
			ae->ad.bits.AttrType = be16_to_cpu(SERIAL_NUMBER);
			strcpy(ae->un.SerialNumber, phba->SerialNumber);
			len = strlen(ae->un.SerialNumber);
			len += (len & 3) ? (4 - (len & 3)) : 4;
			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len);
			ab->EntryCnt++;
			size += FOURBYTES + len;

			/* #4 HBA attribute entry */
			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
			ae->ad.bits.AttrType = be16_to_cpu(MODEL);
			strcpy(ae->un.Model, phba->ModelName);
			len = strlen(ae->un.Model);
			len += (len & 3) ? (4 - (len & 3)) : 4;
			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len);
			ab->EntryCnt++;
			size += FOURBYTES + len;

			/* #5 HBA attribute entry */
			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
			ae->ad.bits.AttrType = be16_to_cpu(MODEL_DESCRIPTION);
			strcpy(ae->un.ModelDescription, phba->ModelDesc);
			len = strlen(ae->un.ModelDescription);
			len += (len & 3) ? (4 - (len & 3)) : 4;
			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len);
			ab->EntryCnt++;
			size += FOURBYTES + len;

			/* #6 HBA attribute entry */
			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
			ae->ad.bits.AttrType = be16_to_cpu(HARDWARE_VERSION);
			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 8);
			/* Convert JEDEC ID to ascii for hardware version */
			incr = vp->rev.biuRev;
			for (i = 0; i < 8; i++) {
				j = (incr & 0xf);
				if (j <= 9)
					ae->un.HardwareVersion[7 - i] =
					    (char)((uint8_t) 0x30 +
						   (uint8_t) j);
				else
					ae->un.HardwareVersion[7 - i] =
					    (char)((uint8_t) 0x61 +
						   (uint8_t) (j - 10));
				incr = (incr >> 4);
			}
			ab->EntryCnt++;
			size += FOURBYTES + 8;

			/* #7 HBA attribute entry */
			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
			ae->ad.bits.AttrType = be16_to_cpu(DRIVER_VERSION);
			strcpy(ae->un.DriverVersion, lpfc_release_version);
			len = strlen(ae->un.DriverVersion);
			len += (len & 3) ? (4 - (len & 3)) : 4;
			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len);
			ab->EntryCnt++;
			size += FOURBYTES + len;

			/* #8 HBA attribute entry */
			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
			ae->ad.bits.AttrType = be16_to_cpu(OPTION_ROM_VERSION);
			strcpy(ae->un.OptionROMVersion, phba->OptionROMVersion);
			len = strlen(ae->un.OptionROMVersion);
			len += (len & 3) ? (4 - (len & 3)) : 4;
			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len);
			ab->EntryCnt++;
			size += FOURBYTES + len;

			/* #9 HBA attribute entry */
			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
			ae->ad.bits.AttrType = be16_to_cpu(FIRMWARE_VERSION);
			lpfc_decode_firmware_rev(phba, ae->un.FirmwareVersion,
				1);
			len = strlen(ae->un.FirmwareVersion);
			len += (len & 3) ? (4 - (len & 3)) : 4;
			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len);
			ab->EntryCnt++;
			size += FOURBYTES + len;

			/* #10 HBA attribute entry */
			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
			ae->ad.bits.AttrType = be16_to_cpu(OS_NAME_VERSION);
			sprintf(ae->un.OsNameVersion, "%s %s %s",
J
James Smart 已提交
1537 1538
				init_utsname()->sysname,
				init_utsname()->release,
1539
				init_utsname()->version);
已提交
1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573
			len = strlen(ae->un.OsNameVersion);
			len += (len & 3) ? (4 - (len & 3)) : 4;
			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len);
			ab->EntryCnt++;
			size += FOURBYTES + len;

			/* #11 HBA attribute entry */
			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
			ae->ad.bits.AttrType = be16_to_cpu(MAX_CT_PAYLOAD_LEN);
			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4);
			ae->un.MaxCTPayloadLen = (65 * 4096);
			ab->EntryCnt++;
			size += FOURBYTES + 4;

			ab->EntryCnt = be32_to_cpu(ab->EntryCnt);
			/* Total size */
			size = GID_REQUEST_SZ - 4 + size;
		}
		break;

	case SLI_MGMT_RPA:
		{
			lpfc_vpd_t *vp;
			struct serv_parm *hsp;
			int len;

			vp = &phba->vpd;

			CtReq->CommandResponse.bits.CmdRsp =
			    be16_to_cpu(SLI_MGMT_RPA);
			CtReq->CommandResponse.bits.Size = 0;
			pab = (REG_PORT_ATTRIBUTE *) & CtReq->un.PortID;
			size = sizeof (struct lpfc_name) + FOURBYTES;
			memcpy((uint8_t *) & pab->PortName,
J
James Smart 已提交
1574
			       (uint8_t *) & vport->fc_sparam.portName,
已提交
1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590
			       sizeof (struct lpfc_name));
			pab->ab.EntryCnt = 0;

			/* #1 Port attribute entry */
			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size);
			ae->ad.bits.AttrType = be16_to_cpu(SUPPORTED_FC4_TYPES);
			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 32);
			ae->un.SupportFC4Types[2] = 1;
			ae->un.SupportFC4Types[7] = 1;
			pab->ab.EntryCnt++;
			size += FOURBYTES + 32;

			/* #2 Port attribute entry */
			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size);
			ae->ad.bits.AttrType = be16_to_cpu(SUPPORTED_SPEED);
			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4);
1591 1592 1593

			ae->un.SupportSpeed = 0;
			if (phba->lmt & LMT_10Gb)
已提交
1594
				ae->un.SupportSpeed = HBA_PORTSPEED_10GBIT;
1595 1596 1597 1598 1599 1600 1601 1602 1603
			if (phba->lmt & LMT_8Gb)
				ae->un.SupportSpeed |= HBA_PORTSPEED_8GBIT;
			if (phba->lmt & LMT_4Gb)
				ae->un.SupportSpeed |= HBA_PORTSPEED_4GBIT;
			if (phba->lmt & LMT_2Gb)
				ae->un.SupportSpeed |= HBA_PORTSPEED_2GBIT;
			if (phba->lmt & LMT_1Gb)
				ae->un.SupportSpeed |= HBA_PORTSPEED_1GBIT;

已提交
1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620
			pab->ab.EntryCnt++;
			size += FOURBYTES + 4;

			/* #3 Port attribute entry */
			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size);
			ae->ad.bits.AttrType = be16_to_cpu(PORT_SPEED);
			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4);
			switch(phba->fc_linkspeed) {
				case LA_1GHZ_LINK:
					ae->un.PortSpeed = HBA_PORTSPEED_1GBIT;
				break;
				case LA_2GHZ_LINK:
					ae->un.PortSpeed = HBA_PORTSPEED_2GBIT;
				break;
				case LA_4GHZ_LINK:
					ae->un.PortSpeed = HBA_PORTSPEED_4GBIT;
				break;
1621 1622 1623
				case LA_8GHZ_LINK:
					ae->un.PortSpeed = HBA_PORTSPEED_8GBIT;
				break;
1624 1625 1626
				case LA_10GHZ_LINK:
					ae->un.PortSpeed = HBA_PORTSPEED_10GBIT;
				break;
已提交
1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638
				default:
					ae->un.PortSpeed =
						HBA_PORTSPEED_UNKNOWN;
				break;
			}
			pab->ab.EntryCnt++;
			size += FOURBYTES + 4;

			/* #4 Port attribute entry */
			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size);
			ae->ad.bits.AttrType = be16_to_cpu(MAX_FRAME_SIZE);
			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4);
J
James Smart 已提交
1639
			hsp = (struct serv_parm *) & vport->fc_sparam;
已提交
1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656
			ae->un.MaxFrameSize =
			    (((uint32_t) hsp->cmn.
			      bbRcvSizeMsb) << 8) | (uint32_t) hsp->cmn.
			    bbRcvSizeLsb;
			pab->ab.EntryCnt++;
			size += FOURBYTES + 4;

			/* #5 Port attribute entry */
			ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size);
			ae->ad.bits.AttrType = be16_to_cpu(OS_DEVICE_NAME);
			strcpy((char *)ae->un.OsDeviceName, LPFC_DRIVER_NAME);
			len = strlen((char *)ae->un.OsDeviceName);
			len += (len & 3) ? (4 - (len & 3)) : 4;
			ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len);
			pab->ab.EntryCnt++;
			size += FOURBYTES + len;

1657
			if (vport->cfg_fdmi_on == 2) {
已提交
1658 1659 1660 1661 1662
				/* #6 Port attribute entry */
				ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab +
							  size);
				ae->ad.bits.AttrType = be16_to_cpu(HOST_NAME);
				sprintf(ae->un.HostName, "%s",
1663
					init_utsname()->nodename);
已提交
1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682
				len = strlen(ae->un.HostName);
				len += (len & 3) ? (4 - (len & 3)) : 4;
				ae->ad.bits.AttrLen =
				    be16_to_cpu(FOURBYTES + len);
				pab->ab.EntryCnt++;
				size += FOURBYTES + len;
			}

			pab->ab.EntryCnt = be32_to_cpu(pab->ab.EntryCnt);
			/* Total size */
			size = GID_REQUEST_SZ - 4 + size;
		}
		break;

	case SLI_MGMT_DHBA:
		CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_MGMT_DHBA);
		CtReq->CommandResponse.bits.Size = 0;
		pe = (PORT_ENTRY *) & CtReq->un.PortID;
		memcpy((uint8_t *) & pe->PortName,
J
James Smart 已提交
1683
		       (uint8_t *) & vport->fc_sparam.portName,
已提交
1684 1685 1686 1687 1688 1689 1690 1691 1692
		       sizeof (struct lpfc_name));
		size = GID_REQUEST_SZ - 4 + sizeof (struct lpfc_name);
		break;

	case SLI_MGMT_DPRT:
		CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_MGMT_DPRT);
		CtReq->CommandResponse.bits.Size = 0;
		pe = (PORT_ENTRY *) & CtReq->un.PortID;
		memcpy((uint8_t *) & pe->PortName,
J
James Smart 已提交
1693
		       (uint8_t *) & vport->fc_sparam.portName,
已提交
1694 1695 1696 1697 1698 1699
		       sizeof (struct lpfc_name));
		size = GID_REQUEST_SZ - 4 + sizeof (struct lpfc_name);
		break;
	}

	bpl = (struct ulp_bde64 *) bmp->virt;
1700 1701
	bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys) );
	bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys) );
已提交
1702 1703 1704 1705 1706 1707
	bpl->tus.f.bdeFlags = 0;
	bpl->tus.f.bdeSize = size;
	bpl->tus.w = le32_to_cpu(bpl->tus.w);

	cmpl = lpfc_cmpl_ct_cmd_fdmi;

1708 1709 1710
	/* The lpfc_ct_cmd/lpfc_get_req shall increment ndlp reference count
	 * to hold ndlp reference for the corresponding callback function.
	 */
1711
	if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, FC_MAX_NS_RSP, 0))
已提交
1712 1713
		return 0;

1714 1715 1716
	/* Decrement ndlp reference count to release ndlp reference held
	 * for the failed command's callback function.
	 */
1717
	lpfc_nlp_put(ndlp);
1718

已提交
1719 1720 1721 1722 1723 1724 1725 1726 1727
	lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
fdmi_cmd_free_bmp:
	kfree(bmp);
fdmi_cmd_free_mpvirt:
	lpfc_mbuf_free(phba, mp->virt, mp->phys);
fdmi_cmd_free_mp:
	kfree(mp);
fdmi_cmd_exit:
	/* Issue FDMI request failed */
1728 1729 1730
	lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
			 "0244 Issue FDMI request failed Data: x%x\n",
			 cmdcode);
已提交
1731 1732 1733 1734 1735 1736
	return 1;
}

void
lpfc_fdmi_tmo(unsigned long ptr)
{
J
James Smart 已提交
1737 1738
	struct lpfc_vport *vport = (struct lpfc_vport *)ptr;
	struct lpfc_hba   *phba = vport->phba;
1739
	uint32_t tmo_posted;
已提交
1740 1741
	unsigned long iflag;

J
James Smart 已提交
1742
	spin_lock_irqsave(&vport->work_port_lock, iflag);
1743 1744
	tmo_posted = vport->work_port_events & WORKER_FDMI_TMO;
	if (!tmo_posted)
J
James Smart 已提交
1745
		vport->work_port_events |= WORKER_FDMI_TMO;
1746
	spin_unlock_irqrestore(&vport->work_port_lock, iflag);
1747

1748 1749 1750
	if (!tmo_posted)
		lpfc_worker_wake_up(phba);
	return;
已提交
1751 1752 1753
}

void
J
James Smart 已提交
1754
lpfc_fdmi_timeout_handler(struct lpfc_vport *vport)
已提交
1755 1756 1757
{
	struct lpfc_nodelist *ndlp;

J
James Smart 已提交
1758
	ndlp = lpfc_findnode_did(vport, FDMI_DID);
1759
	if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
J
James Smart 已提交
1760 1761 1762 1763
		if (init_utsname()->nodename[0] != '\0')
			lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA);
		else
			mod_timer(&vport->fc_fdmitmo, jiffies + HZ * 60);
已提交
1764 1765 1766 1767 1768
	}
	return;
}

void
J
James Smart 已提交
1769
lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag)
已提交
1770 1771 1772 1773 1774 1775 1776 1777
{
	struct lpfc_sli *psli = &phba->sli;
	lpfc_vpd_t *vp = &phba->vpd;
	uint32_t b1, b2, b3, b4, i, rev;
	char c;
	uint32_t *ptr, str[4];
	uint8_t *fwname;

1778 1779 1780
	if (phba->sli_rev == LPFC_SLI_REV4)
		sprintf(fwrevision, "%s", vp->rev.opFwName);
	else if (vp->rev.rBit) {
1781
		if (psli->sli_flag & LPFC_SLI_ACTIVE)
已提交
1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806
			rev = vp->rev.sli2FwRev;
		else
			rev = vp->rev.sli1FwRev;

		b1 = (rev & 0x0000f000) >> 12;
		b2 = (rev & 0x00000f00) >> 8;
		b3 = (rev & 0x000000c0) >> 6;
		b4 = (rev & 0x00000030) >> 4;

		switch (b4) {
		case 0:
			c = 'N';
			break;
		case 1:
			c = 'A';
			break;
		case 2:
			c = 'B';
			break;
		default:
			c = 0;
			break;
		}
		b4 = (rev & 0x0000000f);

1807
		if (psli->sli_flag & LPFC_SLI_ACTIVE)
已提交
1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845
			fwname = vp->rev.sli2FwName;
		else
			fwname = vp->rev.sli1FwName;

		for (i = 0; i < 16; i++)
			if (fwname[i] == 0x20)
				fwname[i] = 0;

		ptr = (uint32_t*)fwname;

		for (i = 0; i < 3; i++)
			str[i] = be32_to_cpu(*ptr++);

		if (c == 0) {
			if (flag)
				sprintf(fwrevision, "%d.%d%d (%s)",
					b1, b2, b3, (char *)str);
			else
				sprintf(fwrevision, "%d.%d%d", b1,
					b2, b3);
		} else {
			if (flag)
				sprintf(fwrevision, "%d.%d%d%c%d (%s)",
					b1, b2, b3, c,
					b4, (char *)str);
			else
				sprintf(fwrevision, "%d.%d%d%c%d",
					b1, b2, b3, c, b4);
		}
	} else {
		rev = vp->rev.smFwRev;

		b1 = (rev & 0xff000000) >> 24;
		b2 = (rev & 0x00f00000) >> 20;
		b3 = (rev & 0x000f0000) >> 16;
		c  = (rev & 0x0000ff00) >> 8;
		b4 = (rev & 0x000000ff);

1846
		sprintf(fwrevision, "%d.%d%d%c%d", b1, b2, b3, c, b4);
已提交
1847 1848 1849
	}
	return;
}