18c2ecf20Sopenharmony_ci/*******************************************************************
28c2ecf20Sopenharmony_ci * This file is part of the Emulex Linux Device Driver for         *
38c2ecf20Sopenharmony_ci * Fibre Channel Host Bus Adapters.                                *
48c2ecf20Sopenharmony_ci * Copyright (C) 2017-2020 Broadcom. All Rights Reserved. The term *
58c2ecf20Sopenharmony_ci * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.     *
68c2ecf20Sopenharmony_ci * Copyright (C) 2004-2016 Emulex.  All rights reserved.           *
78c2ecf20Sopenharmony_ci * EMULEX and SLI are trademarks of Emulex.                        *
88c2ecf20Sopenharmony_ci * www.broadcom.com                                                *
98c2ecf20Sopenharmony_ci * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
108c2ecf20Sopenharmony_ci *                                                                 *
118c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or   *
128c2ecf20Sopenharmony_ci * modify it under the terms of version 2 of the GNU General       *
138c2ecf20Sopenharmony_ci * Public License as published by the Free Software Foundation.    *
148c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful. *
158c2ecf20Sopenharmony_ci * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
168c2ecf20Sopenharmony_ci * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
178c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
188c2ecf20Sopenharmony_ci * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
198c2ecf20Sopenharmony_ci * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
208c2ecf20Sopenharmony_ci * more details, a copy of which can be found in the file COPYING  *
218c2ecf20Sopenharmony_ci * included with this package.                                     *
228c2ecf20Sopenharmony_ci *******************************************************************/
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
258c2ecf20Sopenharmony_ci#include <linux/delay.h>
268c2ecf20Sopenharmony_ci#include <linux/slab.h>
278c2ecf20Sopenharmony_ci#include <linux/pci.h>
288c2ecf20Sopenharmony_ci#include <linux/kthread.h>
298c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
308c2ecf20Sopenharmony_ci#include <linux/lockdep.h>
318c2ecf20Sopenharmony_ci#include <linux/utsname.h>
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#include <scsi/scsi.h>
348c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h>
358c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h>
368c2ecf20Sopenharmony_ci#include <scsi/scsi_transport_fc.h>
378c2ecf20Sopenharmony_ci#include <scsi/fc/fc_fs.h>
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#include "lpfc_hw4.h"
408c2ecf20Sopenharmony_ci#include "lpfc_hw.h"
418c2ecf20Sopenharmony_ci#include "lpfc_nl.h"
428c2ecf20Sopenharmony_ci#include "lpfc_disc.h"
438c2ecf20Sopenharmony_ci#include "lpfc_sli.h"
448c2ecf20Sopenharmony_ci#include "lpfc_sli4.h"
458c2ecf20Sopenharmony_ci#include "lpfc.h"
468c2ecf20Sopenharmony_ci#include "lpfc_scsi.h"
478c2ecf20Sopenharmony_ci#include "lpfc_nvme.h"
488c2ecf20Sopenharmony_ci#include "lpfc_logmsg.h"
498c2ecf20Sopenharmony_ci#include "lpfc_crtn.h"
508c2ecf20Sopenharmony_ci#include "lpfc_vport.h"
518c2ecf20Sopenharmony_ci#include "lpfc_debugfs.h"
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci/* AlpaArray for assignment of scsid for scan-down and bind_method */
548c2ecf20Sopenharmony_cistatic uint8_t lpfcAlpaArray[] = {
558c2ecf20Sopenharmony_ci	0xEF, 0xE8, 0xE4, 0xE2, 0xE1, 0xE0, 0xDC, 0xDA, 0xD9, 0xD6,
568c2ecf20Sopenharmony_ci	0xD5, 0xD4, 0xD3, 0xD2, 0xD1, 0xCE, 0xCD, 0xCC, 0xCB, 0xCA,
578c2ecf20Sopenharmony_ci	0xC9, 0xC7, 0xC6, 0xC5, 0xC3, 0xBC, 0xBA, 0xB9, 0xB6, 0xB5,
588c2ecf20Sopenharmony_ci	0xB4, 0xB3, 0xB2, 0xB1, 0xAE, 0xAD, 0xAC, 0xAB, 0xAA, 0xA9,
598c2ecf20Sopenharmony_ci	0xA7, 0xA6, 0xA5, 0xA3, 0x9F, 0x9E, 0x9D, 0x9B, 0x98, 0x97,
608c2ecf20Sopenharmony_ci	0x90, 0x8F, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7C, 0x7A, 0x79,
618c2ecf20Sopenharmony_ci	0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x6E, 0x6D, 0x6C, 0x6B,
628c2ecf20Sopenharmony_ci	0x6A, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5C, 0x5A, 0x59, 0x56,
638c2ecf20Sopenharmony_ci	0x55, 0x54, 0x53, 0x52, 0x51, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A,
648c2ecf20Sopenharmony_ci	0x49, 0x47, 0x46, 0x45, 0x43, 0x3C, 0x3A, 0x39, 0x36, 0x35,
658c2ecf20Sopenharmony_ci	0x34, 0x33, 0x32, 0x31, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29,
668c2ecf20Sopenharmony_ci	0x27, 0x26, 0x25, 0x23, 0x1F, 0x1E, 0x1D, 0x1B, 0x18, 0x17,
678c2ecf20Sopenharmony_ci	0x10, 0x0F, 0x08, 0x04, 0x02, 0x01
688c2ecf20Sopenharmony_ci};
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic void lpfc_disc_timeout_handler(struct lpfc_vport *);
718c2ecf20Sopenharmony_cistatic void lpfc_disc_flush_list(struct lpfc_vport *vport);
728c2ecf20Sopenharmony_cistatic void lpfc_unregister_fcfi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
738c2ecf20Sopenharmony_cistatic int lpfc_fcf_inuse(struct lpfc_hba *);
748c2ecf20Sopenharmony_cistatic void lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_civoid
778c2ecf20Sopenharmony_cilpfc_terminate_rport_io(struct fc_rport *rport)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	struct lpfc_rport_data *rdata;
808c2ecf20Sopenharmony_ci	struct lpfc_nodelist * ndlp;
818c2ecf20Sopenharmony_ci	struct lpfc_hba *phba;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	rdata = rport->dd_data;
848c2ecf20Sopenharmony_ci	ndlp = rdata->pnode;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) {
878c2ecf20Sopenharmony_ci		if (rport->roles & FC_RPORT_ROLE_FCP_TARGET)
888c2ecf20Sopenharmony_ci			printk(KERN_ERR "Cannot find remote node"
898c2ecf20Sopenharmony_ci			" to terminate I/O Data x%x\n",
908c2ecf20Sopenharmony_ci			rport->port_id);
918c2ecf20Sopenharmony_ci		return;
928c2ecf20Sopenharmony_ci	}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	phba  = ndlp->phba;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_RPORT,
978c2ecf20Sopenharmony_ci		"rport terminate: sid:x%x did:x%x flg:x%x",
988c2ecf20Sopenharmony_ci		ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	if (ndlp->nlp_sid != NLP_NO_SID) {
1018c2ecf20Sopenharmony_ci		lpfc_sli_abort_iocb(ndlp->vport,
1028c2ecf20Sopenharmony_ci			&phba->sli.sli3_ring[LPFC_FCP_RING],
1038c2ecf20Sopenharmony_ci			ndlp->nlp_sid, 0, LPFC_CTX_TGT);
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci/*
1088c2ecf20Sopenharmony_ci * This function will be called when dev_loss_tmo fire.
1098c2ecf20Sopenharmony_ci */
1108c2ecf20Sopenharmony_civoid
1118c2ecf20Sopenharmony_cilpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	struct lpfc_rport_data *rdata;
1148c2ecf20Sopenharmony_ci	struct lpfc_nodelist * ndlp;
1158c2ecf20Sopenharmony_ci	struct lpfc_vport *vport;
1168c2ecf20Sopenharmony_ci	struct Scsi_Host *shost;
1178c2ecf20Sopenharmony_ci	struct lpfc_hba   *phba;
1188c2ecf20Sopenharmony_ci	struct lpfc_work_evt *evtp;
1198c2ecf20Sopenharmony_ci	int  put_node;
1208c2ecf20Sopenharmony_ci	int  put_rport;
1218c2ecf20Sopenharmony_ci	unsigned long iflags;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	rdata = rport->dd_data;
1248c2ecf20Sopenharmony_ci	ndlp = rdata->pnode;
1258c2ecf20Sopenharmony_ci	if (!ndlp || !NLP_CHK_NODE_ACT(ndlp))
1268c2ecf20Sopenharmony_ci		return;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	vport = ndlp->vport;
1298c2ecf20Sopenharmony_ci	phba  = vport->phba;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
1328c2ecf20Sopenharmony_ci		"rport devlosscb: sid:x%x did:x%x flg:x%x",
1338c2ecf20Sopenharmony_ci		ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag);
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE,
1368c2ecf20Sopenharmony_ci			 "3181 dev_loss_callbk x%06x, rport x%px flg x%x\n",
1378c2ecf20Sopenharmony_ci			 ndlp->nlp_DID, ndlp->rport, ndlp->nlp_flag);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	/* Don't defer this if we are in the process of deleting the vport
1408c2ecf20Sopenharmony_ci	 * or unloading the driver. The unload will cleanup the node
1418c2ecf20Sopenharmony_ci	 * appropriately we just need to cleanup the ndlp rport info here.
1428c2ecf20Sopenharmony_ci	 */
1438c2ecf20Sopenharmony_ci	if (vport->load_flag & FC_UNLOADING) {
1448c2ecf20Sopenharmony_ci		put_node = rdata->pnode != NULL;
1458c2ecf20Sopenharmony_ci		put_rport = ndlp->rport != NULL;
1468c2ecf20Sopenharmony_ci		rdata->pnode = NULL;
1478c2ecf20Sopenharmony_ci		ndlp->rport = NULL;
1488c2ecf20Sopenharmony_ci		if (put_node)
1498c2ecf20Sopenharmony_ci			lpfc_nlp_put(ndlp);
1508c2ecf20Sopenharmony_ci		if (put_rport)
1518c2ecf20Sopenharmony_ci			put_device(&rport->dev);
1528c2ecf20Sopenharmony_ci		return;
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	if (ndlp->nlp_state == NLP_STE_MAPPED_NODE)
1568c2ecf20Sopenharmony_ci		return;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	if (rport->port_name != wwn_to_u64(ndlp->nlp_portname.u.wwn))
1598c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
1608c2ecf20Sopenharmony_ci				 "6789 rport name %llx != node port name %llx",
1618c2ecf20Sopenharmony_ci				 rport->port_name,
1628c2ecf20Sopenharmony_ci				 wwn_to_u64(ndlp->nlp_portname.u.wwn));
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	evtp = &ndlp->dev_loss_evt;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	if (!list_empty(&evtp->evt_listp)) {
1678c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
1688c2ecf20Sopenharmony_ci				 "6790 rport name %llx dev_loss_evt pending",
1698c2ecf20Sopenharmony_ci				 rport->port_name);
1708c2ecf20Sopenharmony_ci		return;
1718c2ecf20Sopenharmony_ci	}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	shost = lpfc_shost_from_vport(vport);
1748c2ecf20Sopenharmony_ci	spin_lock_irqsave(shost->host_lock, iflags);
1758c2ecf20Sopenharmony_ci	ndlp->nlp_flag |= NLP_IN_DEV_LOSS;
1768c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(shost->host_lock, iflags);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	/* We need to hold the node by incrementing the reference
1798c2ecf20Sopenharmony_ci	 * count until this queued work is done
1808c2ecf20Sopenharmony_ci	 */
1818c2ecf20Sopenharmony_ci	evtp->evt_arg1  = lpfc_nlp_get(ndlp);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
1848c2ecf20Sopenharmony_ci	if (evtp->evt_arg1) {
1858c2ecf20Sopenharmony_ci		evtp->evt = LPFC_EVT_DEV_LOSS;
1868c2ecf20Sopenharmony_ci		list_add_tail(&evtp->evt_listp, &phba->work_list);
1878c2ecf20Sopenharmony_ci		lpfc_worker_wake_up(phba);
1888c2ecf20Sopenharmony_ci	}
1898c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	return;
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci/**
1958c2ecf20Sopenharmony_ci * lpfc_dev_loss_tmo_handler - Remote node devloss timeout handler
1968c2ecf20Sopenharmony_ci * @ndlp: Pointer to remote node object.
1978c2ecf20Sopenharmony_ci *
1988c2ecf20Sopenharmony_ci * This function is called from the worker thread when devloss timeout timer
1998c2ecf20Sopenharmony_ci * expires. For SLI4 host, this routine shall return 1 when at lease one
2008c2ecf20Sopenharmony_ci * remote node, including this @ndlp, is still in use of FCF; otherwise, this
2018c2ecf20Sopenharmony_ci * routine shall return 0 when there is no remote node is still in use of FCF
2028c2ecf20Sopenharmony_ci * when devloss timeout happened to this @ndlp.
2038c2ecf20Sopenharmony_ci **/
2048c2ecf20Sopenharmony_cistatic int
2058c2ecf20Sopenharmony_cilpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	struct lpfc_rport_data *rdata;
2088c2ecf20Sopenharmony_ci	struct fc_rport   *rport;
2098c2ecf20Sopenharmony_ci	struct lpfc_vport *vport;
2108c2ecf20Sopenharmony_ci	struct lpfc_hba   *phba;
2118c2ecf20Sopenharmony_ci	struct Scsi_Host  *shost;
2128c2ecf20Sopenharmony_ci	uint8_t *name;
2138c2ecf20Sopenharmony_ci	int  put_node;
2148c2ecf20Sopenharmony_ci	int warn_on = 0;
2158c2ecf20Sopenharmony_ci	int fcf_inuse = 0;
2168c2ecf20Sopenharmony_ci	unsigned long iflags;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	rport = ndlp->rport;
2198c2ecf20Sopenharmony_ci	vport = ndlp->vport;
2208c2ecf20Sopenharmony_ci	shost = lpfc_shost_from_vport(vport);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	spin_lock_irqsave(shost->host_lock, iflags);
2238c2ecf20Sopenharmony_ci	ndlp->nlp_flag &= ~NLP_IN_DEV_LOSS;
2248c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(shost->host_lock, iflags);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	if (!rport)
2278c2ecf20Sopenharmony_ci		return fcf_inuse;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	name = (uint8_t *) &ndlp->nlp_portname;
2308c2ecf20Sopenharmony_ci	phba  = vport->phba;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	if (phba->sli_rev == LPFC_SLI_REV4)
2338c2ecf20Sopenharmony_ci		fcf_inuse = lpfc_fcf_inuse(phba);
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
2368c2ecf20Sopenharmony_ci		"rport devlosstmo:did:x%x type:x%x id:x%x",
2378c2ecf20Sopenharmony_ci		ndlp->nlp_DID, ndlp->nlp_type, rport->scsi_target_id);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE,
2408c2ecf20Sopenharmony_ci			 "3182 dev_loss_tmo_handler x%06x, rport x%px flg x%x\n",
2418c2ecf20Sopenharmony_ci			 ndlp->nlp_DID, ndlp->rport, ndlp->nlp_flag);
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	/*
2448c2ecf20Sopenharmony_ci	 * lpfc_nlp_remove if reached with dangling rport drops the
2458c2ecf20Sopenharmony_ci	 * reference. To make sure that does not happen clear rport
2468c2ecf20Sopenharmony_ci	 * pointer in ndlp before lpfc_nlp_put.
2478c2ecf20Sopenharmony_ci	 */
2488c2ecf20Sopenharmony_ci	rdata = rport->dd_data;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	/* Don't defer this if we are in the process of deleting the vport
2518c2ecf20Sopenharmony_ci	 * or unloading the driver. The unload will cleanup the node
2528c2ecf20Sopenharmony_ci	 * appropriately we just need to cleanup the ndlp rport info here.
2538c2ecf20Sopenharmony_ci	 */
2548c2ecf20Sopenharmony_ci	if (vport->load_flag & FC_UNLOADING) {
2558c2ecf20Sopenharmony_ci		if (ndlp->nlp_sid != NLP_NO_SID) {
2568c2ecf20Sopenharmony_ci			/* flush the target */
2578c2ecf20Sopenharmony_ci			lpfc_sli_abort_iocb(vport,
2588c2ecf20Sopenharmony_ci					    &phba->sli.sli3_ring[LPFC_FCP_RING],
2598c2ecf20Sopenharmony_ci					    ndlp->nlp_sid, 0, LPFC_CTX_TGT);
2608c2ecf20Sopenharmony_ci		}
2618c2ecf20Sopenharmony_ci		put_node = rdata->pnode != NULL;
2628c2ecf20Sopenharmony_ci		rdata->pnode = NULL;
2638c2ecf20Sopenharmony_ci		ndlp->rport = NULL;
2648c2ecf20Sopenharmony_ci		if (put_node)
2658c2ecf20Sopenharmony_ci			lpfc_nlp_put(ndlp);
2668c2ecf20Sopenharmony_ci		put_device(&rport->dev);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci		return fcf_inuse;
2698c2ecf20Sopenharmony_ci	}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) {
2728c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
2738c2ecf20Sopenharmony_ci				 "0284 Devloss timeout Ignored on "
2748c2ecf20Sopenharmony_ci				 "WWPN %x:%x:%x:%x:%x:%x:%x:%x "
2758c2ecf20Sopenharmony_ci				 "NPort x%x\n",
2768c2ecf20Sopenharmony_ci				 *name, *(name+1), *(name+2), *(name+3),
2778c2ecf20Sopenharmony_ci				 *(name+4), *(name+5), *(name+6), *(name+7),
2788c2ecf20Sopenharmony_ci				 ndlp->nlp_DID);
2798c2ecf20Sopenharmony_ci		return fcf_inuse;
2808c2ecf20Sopenharmony_ci	}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	put_node = rdata->pnode != NULL;
2838c2ecf20Sopenharmony_ci	rdata->pnode = NULL;
2848c2ecf20Sopenharmony_ci	ndlp->rport = NULL;
2858c2ecf20Sopenharmony_ci	if (put_node)
2868c2ecf20Sopenharmony_ci		lpfc_nlp_put(ndlp);
2878c2ecf20Sopenharmony_ci	put_device(&rport->dev);
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	if (ndlp->nlp_type & NLP_FABRIC)
2908c2ecf20Sopenharmony_ci		return fcf_inuse;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	if (ndlp->nlp_sid != NLP_NO_SID) {
2938c2ecf20Sopenharmony_ci		warn_on = 1;
2948c2ecf20Sopenharmony_ci		lpfc_sli_abort_iocb(vport, &phba->sli.sli3_ring[LPFC_FCP_RING],
2958c2ecf20Sopenharmony_ci				    ndlp->nlp_sid, 0, LPFC_CTX_TGT);
2968c2ecf20Sopenharmony_ci	}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	if (warn_on) {
2998c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
3008c2ecf20Sopenharmony_ci				 "0203 Devloss timeout on "
3018c2ecf20Sopenharmony_ci				 "WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x "
3028c2ecf20Sopenharmony_ci				 "NPort x%06x Data: x%x x%x x%x\n",
3038c2ecf20Sopenharmony_ci				 *name, *(name+1), *(name+2), *(name+3),
3048c2ecf20Sopenharmony_ci				 *(name+4), *(name+5), *(name+6), *(name+7),
3058c2ecf20Sopenharmony_ci				 ndlp->nlp_DID, ndlp->nlp_flag,
3068c2ecf20Sopenharmony_ci				 ndlp->nlp_state, ndlp->nlp_rpi);
3078c2ecf20Sopenharmony_ci	} else {
3088c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_INFO, LOG_TRACE_EVENT,
3098c2ecf20Sopenharmony_ci				 "0204 Devloss timeout on "
3108c2ecf20Sopenharmony_ci				 "WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x "
3118c2ecf20Sopenharmony_ci				 "NPort x%06x Data: x%x x%x x%x\n",
3128c2ecf20Sopenharmony_ci				 *name, *(name+1), *(name+2), *(name+3),
3138c2ecf20Sopenharmony_ci				 *(name+4), *(name+5), *(name+6), *(name+7),
3148c2ecf20Sopenharmony_ci				 ndlp->nlp_DID, ndlp->nlp_flag,
3158c2ecf20Sopenharmony_ci				 ndlp->nlp_state, ndlp->nlp_rpi);
3168c2ecf20Sopenharmony_ci	}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	if (!(ndlp->nlp_flag & NLP_DELAY_TMO) &&
3198c2ecf20Sopenharmony_ci	    !(ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
3208c2ecf20Sopenharmony_ci	    (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
3218c2ecf20Sopenharmony_ci	    (ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE) &&
3228c2ecf20Sopenharmony_ci	    (ndlp->nlp_state != NLP_STE_PRLI_ISSUE))
3238c2ecf20Sopenharmony_ci		lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	return fcf_inuse;
3268c2ecf20Sopenharmony_ci}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci/**
3298c2ecf20Sopenharmony_ci * lpfc_sli4_post_dev_loss_tmo_handler - SLI4 post devloss timeout handler
3308c2ecf20Sopenharmony_ci * @phba: Pointer to hba context object.
3318c2ecf20Sopenharmony_ci * @fcf_inuse: SLI4 FCF in-use state reported from devloss timeout handler.
3328c2ecf20Sopenharmony_ci * @nlp_did: remote node identifer with devloss timeout.
3338c2ecf20Sopenharmony_ci *
3348c2ecf20Sopenharmony_ci * This function is called from the worker thread after invoking devloss
3358c2ecf20Sopenharmony_ci * timeout handler and releasing the reference count for the ndlp with
3368c2ecf20Sopenharmony_ci * which the devloss timeout was handled for SLI4 host. For the devloss
3378c2ecf20Sopenharmony_ci * timeout of the last remote node which had been in use of FCF, when this
3388c2ecf20Sopenharmony_ci * routine is invoked, it shall be guaranteed that none of the remote are
3398c2ecf20Sopenharmony_ci * in-use of FCF. When devloss timeout to the last remote using the FCF,
3408c2ecf20Sopenharmony_ci * if the FIP engine is neither in FCF table scan process nor roundrobin
3418c2ecf20Sopenharmony_ci * failover process, the in-use FCF shall be unregistered. If the FIP
3428c2ecf20Sopenharmony_ci * engine is in FCF discovery process, the devloss timeout state shall
3438c2ecf20Sopenharmony_ci * be set for either the FCF table scan process or roundrobin failover
3448c2ecf20Sopenharmony_ci * process to unregister the in-use FCF.
3458c2ecf20Sopenharmony_ci **/
3468c2ecf20Sopenharmony_cistatic void
3478c2ecf20Sopenharmony_cilpfc_sli4_post_dev_loss_tmo_handler(struct lpfc_hba *phba, int fcf_inuse,
3488c2ecf20Sopenharmony_ci				    uint32_t nlp_did)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	/* If devloss timeout happened to a remote node when FCF had no
3518c2ecf20Sopenharmony_ci	 * longer been in-use, do nothing.
3528c2ecf20Sopenharmony_ci	 */
3538c2ecf20Sopenharmony_ci	if (!fcf_inuse)
3548c2ecf20Sopenharmony_ci		return;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	if ((phba->hba_flag & HBA_FIP_SUPPORT) && !lpfc_fcf_inuse(phba)) {
3578c2ecf20Sopenharmony_ci		spin_lock_irq(&phba->hbalock);
3588c2ecf20Sopenharmony_ci		if (phba->fcf.fcf_flag & FCF_DISCOVERY) {
3598c2ecf20Sopenharmony_ci			if (phba->hba_flag & HBA_DEVLOSS_TMO) {
3608c2ecf20Sopenharmony_ci				spin_unlock_irq(&phba->hbalock);
3618c2ecf20Sopenharmony_ci				return;
3628c2ecf20Sopenharmony_ci			}
3638c2ecf20Sopenharmony_ci			phba->hba_flag |= HBA_DEVLOSS_TMO;
3648c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
3658c2ecf20Sopenharmony_ci					"2847 Last remote node (x%x) using "
3668c2ecf20Sopenharmony_ci					"FCF devloss tmo\n", nlp_did);
3678c2ecf20Sopenharmony_ci		}
3688c2ecf20Sopenharmony_ci		if (phba->fcf.fcf_flag & FCF_REDISC_PROG) {
3698c2ecf20Sopenharmony_ci			spin_unlock_irq(&phba->hbalock);
3708c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
3718c2ecf20Sopenharmony_ci					"2868 Devloss tmo to FCF rediscovery "
3728c2ecf20Sopenharmony_ci					"in progress\n");
3738c2ecf20Sopenharmony_ci			return;
3748c2ecf20Sopenharmony_ci		}
3758c2ecf20Sopenharmony_ci		if (!(phba->hba_flag & (FCF_TS_INPROG | FCF_RR_INPROG))) {
3768c2ecf20Sopenharmony_ci			spin_unlock_irq(&phba->hbalock);
3778c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
3788c2ecf20Sopenharmony_ci					"2869 Devloss tmo to idle FIP engine, "
3798c2ecf20Sopenharmony_ci					"unreg in-use FCF and rescan.\n");
3808c2ecf20Sopenharmony_ci			/* Unregister in-use FCF and rescan */
3818c2ecf20Sopenharmony_ci			lpfc_unregister_fcf_rescan(phba);
3828c2ecf20Sopenharmony_ci			return;
3838c2ecf20Sopenharmony_ci		}
3848c2ecf20Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
3858c2ecf20Sopenharmony_ci		if (phba->hba_flag & FCF_TS_INPROG)
3868c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
3878c2ecf20Sopenharmony_ci					"2870 FCF table scan in progress\n");
3888c2ecf20Sopenharmony_ci		if (phba->hba_flag & FCF_RR_INPROG)
3898c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
3908c2ecf20Sopenharmony_ci					"2871 FLOGI roundrobin FCF failover "
3918c2ecf20Sopenharmony_ci					"in progress\n");
3928c2ecf20Sopenharmony_ci	}
3938c2ecf20Sopenharmony_ci	lpfc_unregister_unused_fcf(phba);
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci/**
3978c2ecf20Sopenharmony_ci * lpfc_alloc_fast_evt - Allocates data structure for posting event
3988c2ecf20Sopenharmony_ci * @phba: Pointer to hba context object.
3998c2ecf20Sopenharmony_ci *
4008c2ecf20Sopenharmony_ci * This function is called from the functions which need to post
4018c2ecf20Sopenharmony_ci * events from interrupt context. This function allocates data
4028c2ecf20Sopenharmony_ci * structure required for posting event. It also keeps track of
4038c2ecf20Sopenharmony_ci * number of events pending and prevent event storm when there are
4048c2ecf20Sopenharmony_ci * too many events.
4058c2ecf20Sopenharmony_ci **/
4068c2ecf20Sopenharmony_cistruct lpfc_fast_path_event *
4078c2ecf20Sopenharmony_cilpfc_alloc_fast_evt(struct lpfc_hba *phba) {
4088c2ecf20Sopenharmony_ci	struct lpfc_fast_path_event *ret;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	/* If there are lot of fast event do not exhaust memory due to this */
4118c2ecf20Sopenharmony_ci	if (atomic_read(&phba->fast_event_count) > LPFC_MAX_EVT_COUNT)
4128c2ecf20Sopenharmony_ci		return NULL;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	ret = kzalloc(sizeof(struct lpfc_fast_path_event),
4158c2ecf20Sopenharmony_ci			GFP_ATOMIC);
4168c2ecf20Sopenharmony_ci	if (ret) {
4178c2ecf20Sopenharmony_ci		atomic_inc(&phba->fast_event_count);
4188c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&ret->work_evt.evt_listp);
4198c2ecf20Sopenharmony_ci		ret->work_evt.evt = LPFC_EVT_FASTPATH_MGMT_EVT;
4208c2ecf20Sopenharmony_ci	}
4218c2ecf20Sopenharmony_ci	return ret;
4228c2ecf20Sopenharmony_ci}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci/**
4258c2ecf20Sopenharmony_ci * lpfc_free_fast_evt - Frees event data structure
4268c2ecf20Sopenharmony_ci * @phba: Pointer to hba context object.
4278c2ecf20Sopenharmony_ci * @evt:  Event object which need to be freed.
4288c2ecf20Sopenharmony_ci *
4298c2ecf20Sopenharmony_ci * This function frees the data structure required for posting
4308c2ecf20Sopenharmony_ci * events.
4318c2ecf20Sopenharmony_ci **/
4328c2ecf20Sopenharmony_civoid
4338c2ecf20Sopenharmony_cilpfc_free_fast_evt(struct lpfc_hba *phba,
4348c2ecf20Sopenharmony_ci		struct lpfc_fast_path_event *evt) {
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	atomic_dec(&phba->fast_event_count);
4378c2ecf20Sopenharmony_ci	kfree(evt);
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci/**
4418c2ecf20Sopenharmony_ci * lpfc_send_fastpath_evt - Posts events generated from fast path
4428c2ecf20Sopenharmony_ci * @phba: Pointer to hba context object.
4438c2ecf20Sopenharmony_ci * @evtp: Event data structure.
4448c2ecf20Sopenharmony_ci *
4458c2ecf20Sopenharmony_ci * This function is called from worker thread, when the interrupt
4468c2ecf20Sopenharmony_ci * context need to post an event. This function posts the event
4478c2ecf20Sopenharmony_ci * to fc transport netlink interface.
4488c2ecf20Sopenharmony_ci **/
4498c2ecf20Sopenharmony_cistatic void
4508c2ecf20Sopenharmony_cilpfc_send_fastpath_evt(struct lpfc_hba *phba,
4518c2ecf20Sopenharmony_ci		struct lpfc_work_evt *evtp)
4528c2ecf20Sopenharmony_ci{
4538c2ecf20Sopenharmony_ci	unsigned long evt_category, evt_sub_category;
4548c2ecf20Sopenharmony_ci	struct lpfc_fast_path_event *fast_evt_data;
4558c2ecf20Sopenharmony_ci	char *evt_data;
4568c2ecf20Sopenharmony_ci	uint32_t evt_data_size;
4578c2ecf20Sopenharmony_ci	struct Scsi_Host *shost;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	fast_evt_data = container_of(evtp, struct lpfc_fast_path_event,
4608c2ecf20Sopenharmony_ci		work_evt);
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	evt_category = (unsigned long) fast_evt_data->un.fabric_evt.event_type;
4638c2ecf20Sopenharmony_ci	evt_sub_category = (unsigned long) fast_evt_data->un.
4648c2ecf20Sopenharmony_ci			fabric_evt.subcategory;
4658c2ecf20Sopenharmony_ci	shost = lpfc_shost_from_vport(fast_evt_data->vport);
4668c2ecf20Sopenharmony_ci	if (evt_category == FC_REG_FABRIC_EVENT) {
4678c2ecf20Sopenharmony_ci		if (evt_sub_category == LPFC_EVENT_FCPRDCHKERR) {
4688c2ecf20Sopenharmony_ci			evt_data = (char *) &fast_evt_data->un.read_check_error;
4698c2ecf20Sopenharmony_ci			evt_data_size = sizeof(fast_evt_data->un.
4708c2ecf20Sopenharmony_ci				read_check_error);
4718c2ecf20Sopenharmony_ci		} else if ((evt_sub_category == LPFC_EVENT_FABRIC_BUSY) ||
4728c2ecf20Sopenharmony_ci			(evt_sub_category == LPFC_EVENT_PORT_BUSY)) {
4738c2ecf20Sopenharmony_ci			evt_data = (char *) &fast_evt_data->un.fabric_evt;
4748c2ecf20Sopenharmony_ci			evt_data_size = sizeof(fast_evt_data->un.fabric_evt);
4758c2ecf20Sopenharmony_ci		} else {
4768c2ecf20Sopenharmony_ci			lpfc_free_fast_evt(phba, fast_evt_data);
4778c2ecf20Sopenharmony_ci			return;
4788c2ecf20Sopenharmony_ci		}
4798c2ecf20Sopenharmony_ci	} else if (evt_category == FC_REG_SCSI_EVENT) {
4808c2ecf20Sopenharmony_ci		switch (evt_sub_category) {
4818c2ecf20Sopenharmony_ci		case LPFC_EVENT_QFULL:
4828c2ecf20Sopenharmony_ci		case LPFC_EVENT_DEVBSY:
4838c2ecf20Sopenharmony_ci			evt_data = (char *) &fast_evt_data->un.scsi_evt;
4848c2ecf20Sopenharmony_ci			evt_data_size = sizeof(fast_evt_data->un.scsi_evt);
4858c2ecf20Sopenharmony_ci			break;
4868c2ecf20Sopenharmony_ci		case LPFC_EVENT_CHECK_COND:
4878c2ecf20Sopenharmony_ci			evt_data = (char *) &fast_evt_data->un.check_cond_evt;
4888c2ecf20Sopenharmony_ci			evt_data_size =  sizeof(fast_evt_data->un.
4898c2ecf20Sopenharmony_ci				check_cond_evt);
4908c2ecf20Sopenharmony_ci			break;
4918c2ecf20Sopenharmony_ci		case LPFC_EVENT_VARQUEDEPTH:
4928c2ecf20Sopenharmony_ci			evt_data = (char *) &fast_evt_data->un.queue_depth_evt;
4938c2ecf20Sopenharmony_ci			evt_data_size = sizeof(fast_evt_data->un.
4948c2ecf20Sopenharmony_ci				queue_depth_evt);
4958c2ecf20Sopenharmony_ci			break;
4968c2ecf20Sopenharmony_ci		default:
4978c2ecf20Sopenharmony_ci			lpfc_free_fast_evt(phba, fast_evt_data);
4988c2ecf20Sopenharmony_ci			return;
4998c2ecf20Sopenharmony_ci		}
5008c2ecf20Sopenharmony_ci	} else {
5018c2ecf20Sopenharmony_ci		lpfc_free_fast_evt(phba, fast_evt_data);
5028c2ecf20Sopenharmony_ci		return;
5038c2ecf20Sopenharmony_ci	}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	if (phba->cfg_enable_fc4_type != LPFC_ENABLE_NVME)
5068c2ecf20Sopenharmony_ci		fc_host_post_vendor_event(shost,
5078c2ecf20Sopenharmony_ci			fc_get_event_number(),
5088c2ecf20Sopenharmony_ci			evt_data_size,
5098c2ecf20Sopenharmony_ci			evt_data,
5108c2ecf20Sopenharmony_ci			LPFC_NL_VENDOR_ID);
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	lpfc_free_fast_evt(phba, fast_evt_data);
5138c2ecf20Sopenharmony_ci	return;
5148c2ecf20Sopenharmony_ci}
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_cistatic void
5178c2ecf20Sopenharmony_cilpfc_work_list_done(struct lpfc_hba *phba)
5188c2ecf20Sopenharmony_ci{
5198c2ecf20Sopenharmony_ci	struct lpfc_work_evt  *evtp = NULL;
5208c2ecf20Sopenharmony_ci	struct lpfc_nodelist  *ndlp;
5218c2ecf20Sopenharmony_ci	int free_evt;
5228c2ecf20Sopenharmony_ci	int fcf_inuse;
5238c2ecf20Sopenharmony_ci	uint32_t nlp_did;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
5268c2ecf20Sopenharmony_ci	while (!list_empty(&phba->work_list)) {
5278c2ecf20Sopenharmony_ci		list_remove_head((&phba->work_list), evtp, typeof(*evtp),
5288c2ecf20Sopenharmony_ci				 evt_listp);
5298c2ecf20Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
5308c2ecf20Sopenharmony_ci		free_evt = 1;
5318c2ecf20Sopenharmony_ci		switch (evtp->evt) {
5328c2ecf20Sopenharmony_ci		case LPFC_EVT_ELS_RETRY:
5338c2ecf20Sopenharmony_ci			ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1);
5348c2ecf20Sopenharmony_ci			lpfc_els_retry_delay_handler(ndlp);
5358c2ecf20Sopenharmony_ci			free_evt = 0; /* evt is part of ndlp */
5368c2ecf20Sopenharmony_ci			/* decrement the node reference count held
5378c2ecf20Sopenharmony_ci			 * for this queued work
5388c2ecf20Sopenharmony_ci			 */
5398c2ecf20Sopenharmony_ci			lpfc_nlp_put(ndlp);
5408c2ecf20Sopenharmony_ci			break;
5418c2ecf20Sopenharmony_ci		case LPFC_EVT_DEV_LOSS:
5428c2ecf20Sopenharmony_ci			ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1);
5438c2ecf20Sopenharmony_ci			fcf_inuse = lpfc_dev_loss_tmo_handler(ndlp);
5448c2ecf20Sopenharmony_ci			free_evt = 0;
5458c2ecf20Sopenharmony_ci			/* decrement the node reference count held for
5468c2ecf20Sopenharmony_ci			 * this queued work
5478c2ecf20Sopenharmony_ci			 */
5488c2ecf20Sopenharmony_ci			nlp_did = ndlp->nlp_DID;
5498c2ecf20Sopenharmony_ci			lpfc_nlp_put(ndlp);
5508c2ecf20Sopenharmony_ci			if (phba->sli_rev == LPFC_SLI_REV4)
5518c2ecf20Sopenharmony_ci				lpfc_sli4_post_dev_loss_tmo_handler(phba,
5528c2ecf20Sopenharmony_ci								    fcf_inuse,
5538c2ecf20Sopenharmony_ci								    nlp_did);
5548c2ecf20Sopenharmony_ci			break;
5558c2ecf20Sopenharmony_ci		case LPFC_EVT_RECOVER_PORT:
5568c2ecf20Sopenharmony_ci			ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1);
5578c2ecf20Sopenharmony_ci			lpfc_sli_abts_recover_port(ndlp->vport, ndlp);
5588c2ecf20Sopenharmony_ci			free_evt = 0;
5598c2ecf20Sopenharmony_ci			/* decrement the node reference count held for
5608c2ecf20Sopenharmony_ci			 * this queued work
5618c2ecf20Sopenharmony_ci			 */
5628c2ecf20Sopenharmony_ci			lpfc_nlp_put(ndlp);
5638c2ecf20Sopenharmony_ci			break;
5648c2ecf20Sopenharmony_ci		case LPFC_EVT_ONLINE:
5658c2ecf20Sopenharmony_ci			if (phba->link_state < LPFC_LINK_DOWN)
5668c2ecf20Sopenharmony_ci				*(int *) (evtp->evt_arg1) = lpfc_online(phba);
5678c2ecf20Sopenharmony_ci			else
5688c2ecf20Sopenharmony_ci				*(int *) (evtp->evt_arg1) = 0;
5698c2ecf20Sopenharmony_ci			complete((struct completion *)(evtp->evt_arg2));
5708c2ecf20Sopenharmony_ci			break;
5718c2ecf20Sopenharmony_ci		case LPFC_EVT_OFFLINE_PREP:
5728c2ecf20Sopenharmony_ci			if (phba->link_state >= LPFC_LINK_DOWN)
5738c2ecf20Sopenharmony_ci				lpfc_offline_prep(phba, LPFC_MBX_WAIT);
5748c2ecf20Sopenharmony_ci			*(int *)(evtp->evt_arg1) = 0;
5758c2ecf20Sopenharmony_ci			complete((struct completion *)(evtp->evt_arg2));
5768c2ecf20Sopenharmony_ci			break;
5778c2ecf20Sopenharmony_ci		case LPFC_EVT_OFFLINE:
5788c2ecf20Sopenharmony_ci			lpfc_offline(phba);
5798c2ecf20Sopenharmony_ci			lpfc_sli_brdrestart(phba);
5808c2ecf20Sopenharmony_ci			*(int *)(evtp->evt_arg1) =
5818c2ecf20Sopenharmony_ci				lpfc_sli_brdready(phba, HS_FFRDY | HS_MBRDY);
5828c2ecf20Sopenharmony_ci			lpfc_unblock_mgmt_io(phba);
5838c2ecf20Sopenharmony_ci			complete((struct completion *)(evtp->evt_arg2));
5848c2ecf20Sopenharmony_ci			break;
5858c2ecf20Sopenharmony_ci		case LPFC_EVT_WARM_START:
5868c2ecf20Sopenharmony_ci			lpfc_offline(phba);
5878c2ecf20Sopenharmony_ci			lpfc_reset_barrier(phba);
5888c2ecf20Sopenharmony_ci			lpfc_sli_brdreset(phba);
5898c2ecf20Sopenharmony_ci			lpfc_hba_down_post(phba);
5908c2ecf20Sopenharmony_ci			*(int *)(evtp->evt_arg1) =
5918c2ecf20Sopenharmony_ci				lpfc_sli_brdready(phba, HS_MBRDY);
5928c2ecf20Sopenharmony_ci			lpfc_unblock_mgmt_io(phba);
5938c2ecf20Sopenharmony_ci			complete((struct completion *)(evtp->evt_arg2));
5948c2ecf20Sopenharmony_ci			break;
5958c2ecf20Sopenharmony_ci		case LPFC_EVT_KILL:
5968c2ecf20Sopenharmony_ci			lpfc_offline(phba);
5978c2ecf20Sopenharmony_ci			*(int *)(evtp->evt_arg1)
5988c2ecf20Sopenharmony_ci				= (phba->pport->stopped)
5998c2ecf20Sopenharmony_ci				        ? 0 : lpfc_sli_brdkill(phba);
6008c2ecf20Sopenharmony_ci			lpfc_unblock_mgmt_io(phba);
6018c2ecf20Sopenharmony_ci			complete((struct completion *)(evtp->evt_arg2));
6028c2ecf20Sopenharmony_ci			break;
6038c2ecf20Sopenharmony_ci		case LPFC_EVT_FASTPATH_MGMT_EVT:
6048c2ecf20Sopenharmony_ci			lpfc_send_fastpath_evt(phba, evtp);
6058c2ecf20Sopenharmony_ci			free_evt = 0;
6068c2ecf20Sopenharmony_ci			break;
6078c2ecf20Sopenharmony_ci		case LPFC_EVT_RESET_HBA:
6088c2ecf20Sopenharmony_ci			if (!(phba->pport->load_flag & FC_UNLOADING))
6098c2ecf20Sopenharmony_ci				lpfc_reset_hba(phba);
6108c2ecf20Sopenharmony_ci			break;
6118c2ecf20Sopenharmony_ci		}
6128c2ecf20Sopenharmony_ci		if (free_evt)
6138c2ecf20Sopenharmony_ci			kfree(evtp);
6148c2ecf20Sopenharmony_ci		spin_lock_irq(&phba->hbalock);
6158c2ecf20Sopenharmony_ci	}
6168c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci}
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_cistatic void
6218c2ecf20Sopenharmony_cilpfc_work_done(struct lpfc_hba *phba)
6228c2ecf20Sopenharmony_ci{
6238c2ecf20Sopenharmony_ci	struct lpfc_sli_ring *pring;
6248c2ecf20Sopenharmony_ci	uint32_t ha_copy, status, control, work_port_events;
6258c2ecf20Sopenharmony_ci	struct lpfc_vport **vports;
6268c2ecf20Sopenharmony_ci	struct lpfc_vport *vport;
6278c2ecf20Sopenharmony_ci	int i;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
6308c2ecf20Sopenharmony_ci	ha_copy = phba->work_ha;
6318c2ecf20Sopenharmony_ci	phba->work_ha = 0;
6328c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	/* First, try to post the next mailbox command to SLI4 device */
6358c2ecf20Sopenharmony_ci	if (phba->pci_dev_grp == LPFC_PCI_DEV_OC)
6368c2ecf20Sopenharmony_ci		lpfc_sli4_post_async_mbox(phba);
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	if (ha_copy & HA_ERATT) {
6398c2ecf20Sopenharmony_ci		/* Handle the error attention event */
6408c2ecf20Sopenharmony_ci		lpfc_handle_eratt(phba);
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci		if (phba->fw_dump_cmpl) {
6438c2ecf20Sopenharmony_ci			complete(phba->fw_dump_cmpl);
6448c2ecf20Sopenharmony_ci			phba->fw_dump_cmpl = NULL;
6458c2ecf20Sopenharmony_ci		}
6468c2ecf20Sopenharmony_ci	}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	if (ha_copy & HA_MBATT)
6498c2ecf20Sopenharmony_ci		lpfc_sli_handle_mb_event(phba);
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	if (ha_copy & HA_LATT)
6528c2ecf20Sopenharmony_ci		lpfc_handle_latt(phba);
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	/* Process SLI4 events */
6558c2ecf20Sopenharmony_ci	if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) {
6568c2ecf20Sopenharmony_ci		if (phba->hba_flag & HBA_RRQ_ACTIVE)
6578c2ecf20Sopenharmony_ci			lpfc_handle_rrq_active(phba);
6588c2ecf20Sopenharmony_ci		if (phba->hba_flag & ELS_XRI_ABORT_EVENT)
6598c2ecf20Sopenharmony_ci			lpfc_sli4_els_xri_abort_event_proc(phba);
6608c2ecf20Sopenharmony_ci		if (phba->hba_flag & ASYNC_EVENT)
6618c2ecf20Sopenharmony_ci			lpfc_sli4_async_event_proc(phba);
6628c2ecf20Sopenharmony_ci		if (phba->hba_flag & HBA_POST_RECEIVE_BUFFER) {
6638c2ecf20Sopenharmony_ci			spin_lock_irq(&phba->hbalock);
6648c2ecf20Sopenharmony_ci			phba->hba_flag &= ~HBA_POST_RECEIVE_BUFFER;
6658c2ecf20Sopenharmony_ci			spin_unlock_irq(&phba->hbalock);
6668c2ecf20Sopenharmony_ci			lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
6678c2ecf20Sopenharmony_ci		}
6688c2ecf20Sopenharmony_ci		if (phba->fcf.fcf_flag & FCF_REDISC_EVT)
6698c2ecf20Sopenharmony_ci			lpfc_sli4_fcf_redisc_event_proc(phba);
6708c2ecf20Sopenharmony_ci	}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	vports = lpfc_create_vport_work_array(phba);
6738c2ecf20Sopenharmony_ci	if (vports != NULL)
6748c2ecf20Sopenharmony_ci		for (i = 0; i <= phba->max_vports; i++) {
6758c2ecf20Sopenharmony_ci			/*
6768c2ecf20Sopenharmony_ci			 * We could have no vports in array if unloading, so if
6778c2ecf20Sopenharmony_ci			 * this happens then just use the pport
6788c2ecf20Sopenharmony_ci			 */
6798c2ecf20Sopenharmony_ci			if (vports[i] == NULL && i == 0)
6808c2ecf20Sopenharmony_ci				vport = phba->pport;
6818c2ecf20Sopenharmony_ci			else
6828c2ecf20Sopenharmony_ci				vport = vports[i];
6838c2ecf20Sopenharmony_ci			if (vport == NULL)
6848c2ecf20Sopenharmony_ci				break;
6858c2ecf20Sopenharmony_ci			spin_lock_irq(&vport->work_port_lock);
6868c2ecf20Sopenharmony_ci			work_port_events = vport->work_port_events;
6878c2ecf20Sopenharmony_ci			vport->work_port_events &= ~work_port_events;
6888c2ecf20Sopenharmony_ci			spin_unlock_irq(&vport->work_port_lock);
6898c2ecf20Sopenharmony_ci			if (work_port_events & WORKER_DISC_TMO)
6908c2ecf20Sopenharmony_ci				lpfc_disc_timeout_handler(vport);
6918c2ecf20Sopenharmony_ci			if (work_port_events & WORKER_ELS_TMO)
6928c2ecf20Sopenharmony_ci				lpfc_els_timeout_handler(vport);
6938c2ecf20Sopenharmony_ci			if (work_port_events & WORKER_HB_TMO)
6948c2ecf20Sopenharmony_ci				lpfc_hb_timeout_handler(phba);
6958c2ecf20Sopenharmony_ci			if (work_port_events & WORKER_MBOX_TMO)
6968c2ecf20Sopenharmony_ci				lpfc_mbox_timeout_handler(phba);
6978c2ecf20Sopenharmony_ci			if (work_port_events & WORKER_FABRIC_BLOCK_TMO)
6988c2ecf20Sopenharmony_ci				lpfc_unblock_fabric_iocbs(phba);
6998c2ecf20Sopenharmony_ci			if (work_port_events & WORKER_RAMP_DOWN_QUEUE)
7008c2ecf20Sopenharmony_ci				lpfc_ramp_down_queue_handler(phba);
7018c2ecf20Sopenharmony_ci			if (work_port_events & WORKER_DELAYED_DISC_TMO)
7028c2ecf20Sopenharmony_ci				lpfc_delayed_disc_timeout_handler(vport);
7038c2ecf20Sopenharmony_ci		}
7048c2ecf20Sopenharmony_ci	lpfc_destroy_vport_work_array(phba, vports);
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	pring = lpfc_phba_elsring(phba);
7078c2ecf20Sopenharmony_ci	status = (ha_copy & (HA_RXMASK  << (4*LPFC_ELS_RING)));
7088c2ecf20Sopenharmony_ci	status >>= (4*LPFC_ELS_RING);
7098c2ecf20Sopenharmony_ci	if (pring && (status & HA_RXMASK ||
7108c2ecf20Sopenharmony_ci		      pring->flag & LPFC_DEFERRED_RING_EVENT ||
7118c2ecf20Sopenharmony_ci		      phba->hba_flag & HBA_SP_QUEUE_EVT)) {
7128c2ecf20Sopenharmony_ci		if (pring->flag & LPFC_STOP_IOCB_EVENT) {
7138c2ecf20Sopenharmony_ci			pring->flag |= LPFC_DEFERRED_RING_EVENT;
7148c2ecf20Sopenharmony_ci			/* Preserve legacy behavior. */
7158c2ecf20Sopenharmony_ci			if (!(phba->hba_flag & HBA_SP_QUEUE_EVT))
7168c2ecf20Sopenharmony_ci				set_bit(LPFC_DATA_READY, &phba->data_flags);
7178c2ecf20Sopenharmony_ci		} else {
7188c2ecf20Sopenharmony_ci			/* Driver could have abort request completed in queue
7198c2ecf20Sopenharmony_ci			 * when link goes down.  Allow for this transition.
7208c2ecf20Sopenharmony_ci			 */
7218c2ecf20Sopenharmony_ci			if (phba->link_state >= LPFC_LINK_DOWN ||
7228c2ecf20Sopenharmony_ci			    phba->link_flag & LS_MDS_LOOPBACK) {
7238c2ecf20Sopenharmony_ci				pring->flag &= ~LPFC_DEFERRED_RING_EVENT;
7248c2ecf20Sopenharmony_ci				lpfc_sli_handle_slow_ring_event(phba, pring,
7258c2ecf20Sopenharmony_ci								(status &
7268c2ecf20Sopenharmony_ci								HA_RXMASK));
7278c2ecf20Sopenharmony_ci			}
7288c2ecf20Sopenharmony_ci		}
7298c2ecf20Sopenharmony_ci		if (phba->sli_rev == LPFC_SLI_REV4)
7308c2ecf20Sopenharmony_ci			lpfc_drain_txq(phba);
7318c2ecf20Sopenharmony_ci		/*
7328c2ecf20Sopenharmony_ci		 * Turn on Ring interrupts
7338c2ecf20Sopenharmony_ci		 */
7348c2ecf20Sopenharmony_ci		if (phba->sli_rev <= LPFC_SLI_REV3) {
7358c2ecf20Sopenharmony_ci			spin_lock_irq(&phba->hbalock);
7368c2ecf20Sopenharmony_ci			control = readl(phba->HCregaddr);
7378c2ecf20Sopenharmony_ci			if (!(control & (HC_R0INT_ENA << LPFC_ELS_RING))) {
7388c2ecf20Sopenharmony_ci				lpfc_debugfs_slow_ring_trc(phba,
7398c2ecf20Sopenharmony_ci					"WRK Enable ring: cntl:x%x hacopy:x%x",
7408c2ecf20Sopenharmony_ci					control, ha_copy, 0);
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci				control |= (HC_R0INT_ENA << LPFC_ELS_RING);
7438c2ecf20Sopenharmony_ci				writel(control, phba->HCregaddr);
7448c2ecf20Sopenharmony_ci				readl(phba->HCregaddr); /* flush */
7458c2ecf20Sopenharmony_ci			} else {
7468c2ecf20Sopenharmony_ci				lpfc_debugfs_slow_ring_trc(phba,
7478c2ecf20Sopenharmony_ci					"WRK Ring ok:     cntl:x%x hacopy:x%x",
7488c2ecf20Sopenharmony_ci					control, ha_copy, 0);
7498c2ecf20Sopenharmony_ci			}
7508c2ecf20Sopenharmony_ci			spin_unlock_irq(&phba->hbalock);
7518c2ecf20Sopenharmony_ci		}
7528c2ecf20Sopenharmony_ci	}
7538c2ecf20Sopenharmony_ci	lpfc_work_list_done(phba);
7548c2ecf20Sopenharmony_ci}
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ciint
7578c2ecf20Sopenharmony_cilpfc_do_work(void *p)
7588c2ecf20Sopenharmony_ci{
7598c2ecf20Sopenharmony_ci	struct lpfc_hba *phba = p;
7608c2ecf20Sopenharmony_ci	int rc;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	set_user_nice(current, MIN_NICE);
7638c2ecf20Sopenharmony_ci	current->flags |= PF_NOFREEZE;
7648c2ecf20Sopenharmony_ci	phba->data_flags = 0;
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	while (!kthread_should_stop()) {
7678c2ecf20Sopenharmony_ci		/* wait and check worker queue activities */
7688c2ecf20Sopenharmony_ci		rc = wait_event_interruptible(phba->work_waitq,
7698c2ecf20Sopenharmony_ci					(test_and_clear_bit(LPFC_DATA_READY,
7708c2ecf20Sopenharmony_ci							    &phba->data_flags)
7718c2ecf20Sopenharmony_ci					 || kthread_should_stop()));
7728c2ecf20Sopenharmony_ci		/* Signal wakeup shall terminate the worker thread */
7738c2ecf20Sopenharmony_ci		if (rc) {
7748c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
7758c2ecf20Sopenharmony_ci					"0433 Wakeup on signal: rc=x%x\n", rc);
7768c2ecf20Sopenharmony_ci			break;
7778c2ecf20Sopenharmony_ci		}
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci		/* Attend pending lpfc data processing */
7808c2ecf20Sopenharmony_ci		lpfc_work_done(phba);
7818c2ecf20Sopenharmony_ci	}
7828c2ecf20Sopenharmony_ci	phba->worker_thread = NULL;
7838c2ecf20Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
7848c2ecf20Sopenharmony_ci			"0432 Worker thread stopped.\n");
7858c2ecf20Sopenharmony_ci	return 0;
7868c2ecf20Sopenharmony_ci}
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci/*
7898c2ecf20Sopenharmony_ci * This is only called to handle FC worker events. Since this a rare
7908c2ecf20Sopenharmony_ci * occurrence, we allocate a struct lpfc_work_evt structure here instead of
7918c2ecf20Sopenharmony_ci * embedding it in the IOCB.
7928c2ecf20Sopenharmony_ci */
7938c2ecf20Sopenharmony_ciint
7948c2ecf20Sopenharmony_cilpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2,
7958c2ecf20Sopenharmony_ci		      uint32_t evt)
7968c2ecf20Sopenharmony_ci{
7978c2ecf20Sopenharmony_ci	struct lpfc_work_evt  *evtp;
7988c2ecf20Sopenharmony_ci	unsigned long flags;
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	/*
8018c2ecf20Sopenharmony_ci	 * All Mailbox completions and LPFC_ELS_RING rcv ring IOCB events will
8028c2ecf20Sopenharmony_ci	 * be queued to worker thread for processing
8038c2ecf20Sopenharmony_ci	 */
8048c2ecf20Sopenharmony_ci	evtp = kmalloc(sizeof(struct lpfc_work_evt), GFP_ATOMIC);
8058c2ecf20Sopenharmony_ci	if (!evtp)
8068c2ecf20Sopenharmony_ci		return 0;
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	evtp->evt_arg1  = arg1;
8098c2ecf20Sopenharmony_ci	evtp->evt_arg2  = arg2;
8108c2ecf20Sopenharmony_ci	evtp->evt       = evt;
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, flags);
8138c2ecf20Sopenharmony_ci	list_add_tail(&evtp->evt_listp, &phba->work_list);
8148c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, flags);
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	lpfc_worker_wake_up(phba);
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	return 1;
8198c2ecf20Sopenharmony_ci}
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_civoid
8228c2ecf20Sopenharmony_cilpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
8238c2ecf20Sopenharmony_ci{
8248c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
8258c2ecf20Sopenharmony_ci	struct lpfc_hba  *phba = vport->phba;
8268c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp, *next_ndlp;
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
8298c2ecf20Sopenharmony_ci		if (!NLP_CHK_NODE_ACT(ndlp))
8308c2ecf20Sopenharmony_ci			continue;
8318c2ecf20Sopenharmony_ci		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
8328c2ecf20Sopenharmony_ci			continue;
8338c2ecf20Sopenharmony_ci		if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) ||
8348c2ecf20Sopenharmony_ci			((vport->port_type == LPFC_NPIV_PORT) &&
8358c2ecf20Sopenharmony_ci			(ndlp->nlp_DID == NameServer_DID)))
8368c2ecf20Sopenharmony_ci			lpfc_unreg_rpi(vport, ndlp);
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci		/* Leave Fabric nodes alone on link down */
8398c2ecf20Sopenharmony_ci		if ((phba->sli_rev < LPFC_SLI_REV4) &&
8408c2ecf20Sopenharmony_ci		    (!remove && ndlp->nlp_type & NLP_FABRIC))
8418c2ecf20Sopenharmony_ci			continue;
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci		/* Notify transport of connectivity loss to trigger cleanup. */
8448c2ecf20Sopenharmony_ci		if (phba->nvmet_support &&
8458c2ecf20Sopenharmony_ci		    ndlp->nlp_state == NLP_STE_UNMAPPED_NODE)
8468c2ecf20Sopenharmony_ci			lpfc_nvmet_invalidate_host(phba, ndlp);
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci		lpfc_disc_state_machine(vport, ndlp, NULL,
8498c2ecf20Sopenharmony_ci					remove
8508c2ecf20Sopenharmony_ci					? NLP_EVT_DEVICE_RM
8518c2ecf20Sopenharmony_ci					: NLP_EVT_DEVICE_RECOVERY);
8528c2ecf20Sopenharmony_ci	}
8538c2ecf20Sopenharmony_ci	if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) {
8548c2ecf20Sopenharmony_ci		if (phba->sli_rev == LPFC_SLI_REV4)
8558c2ecf20Sopenharmony_ci			lpfc_sli4_unreg_all_rpis(vport);
8568c2ecf20Sopenharmony_ci		lpfc_mbx_unreg_vpi(vport);
8578c2ecf20Sopenharmony_ci		spin_lock_irq(shost->host_lock);
8588c2ecf20Sopenharmony_ci		vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
8598c2ecf20Sopenharmony_ci		spin_unlock_irq(shost->host_lock);
8608c2ecf20Sopenharmony_ci	}
8618c2ecf20Sopenharmony_ci}
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_civoid
8648c2ecf20Sopenharmony_cilpfc_port_link_failure(struct lpfc_vport *vport)
8658c2ecf20Sopenharmony_ci{
8668c2ecf20Sopenharmony_ci	lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN);
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	/* Cleanup any outstanding received buffers */
8698c2ecf20Sopenharmony_ci	lpfc_cleanup_rcv_buffers(vport);
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	/* Cleanup any outstanding RSCN activity */
8728c2ecf20Sopenharmony_ci	lpfc_els_flush_rscn(vport);
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	/* Cleanup any outstanding ELS commands */
8758c2ecf20Sopenharmony_ci	lpfc_els_flush_cmd(vport);
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	lpfc_cleanup_rpis(vport, 0);
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	/* Turn off discovery timer if its running */
8808c2ecf20Sopenharmony_ci	lpfc_can_disctmo(vport);
8818c2ecf20Sopenharmony_ci}
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_civoid
8848c2ecf20Sopenharmony_cilpfc_linkdown_port(struct lpfc_vport *vport)
8858c2ecf20Sopenharmony_ci{
8868c2ecf20Sopenharmony_ci	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	if (vport->cfg_enable_fc4_type != LPFC_ENABLE_NVME)
8898c2ecf20Sopenharmony_ci		fc_host_post_event(shost, fc_get_event_number(),
8908c2ecf20Sopenharmony_ci				   FCH_EVT_LINKDOWN, 0);
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
8938c2ecf20Sopenharmony_ci		"Link Down:       state:x%x rtry:x%x flg:x%x",
8948c2ecf20Sopenharmony_ci		vport->port_state, vport->fc_ns_retry, vport->fc_flag);
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	lpfc_port_link_failure(vport);
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	/* Stop delayed Nport discovery */
8998c2ecf20Sopenharmony_ci	spin_lock_irq(shost->host_lock);
9008c2ecf20Sopenharmony_ci	vport->fc_flag &= ~FC_DISC_DELAYED;
9018c2ecf20Sopenharmony_ci	spin_unlock_irq(shost->host_lock);
9028c2ecf20Sopenharmony_ci	del_timer_sync(&vport->delayed_disc_tmo);
9038c2ecf20Sopenharmony_ci}
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ciint
9068c2ecf20Sopenharmony_cilpfc_linkdown(struct lpfc_hba *phba)
9078c2ecf20Sopenharmony_ci{
9088c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = phba->pport;
9098c2ecf20Sopenharmony_ci	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
9108c2ecf20Sopenharmony_ci	struct lpfc_vport **vports;
9118c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t          *mb;
9128c2ecf20Sopenharmony_ci	int i;
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	if (phba->link_state == LPFC_LINK_DOWN)
9158c2ecf20Sopenharmony_ci		return 0;
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci	/* Block all SCSI stack I/Os */
9188c2ecf20Sopenharmony_ci	lpfc_scsi_dev_block(phba);
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	phba->defer_flogi_acc_flag = false;
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
9238c2ecf20Sopenharmony_ci	phba->fcf.fcf_flag &= ~(FCF_AVAILABLE | FCF_SCAN_DONE);
9248c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
9258c2ecf20Sopenharmony_ci	if (phba->link_state > LPFC_LINK_DOWN) {
9268c2ecf20Sopenharmony_ci		phba->link_state = LPFC_LINK_DOWN;
9278c2ecf20Sopenharmony_ci		if (phba->sli4_hba.conf_trunk) {
9288c2ecf20Sopenharmony_ci			phba->trunk_link.link0.state = 0;
9298c2ecf20Sopenharmony_ci			phba->trunk_link.link1.state = 0;
9308c2ecf20Sopenharmony_ci			phba->trunk_link.link2.state = 0;
9318c2ecf20Sopenharmony_ci			phba->trunk_link.link3.state = 0;
9328c2ecf20Sopenharmony_ci			phba->sli4_hba.link_state.logical_speed =
9338c2ecf20Sopenharmony_ci						LPFC_LINK_SPEED_UNKNOWN;
9348c2ecf20Sopenharmony_ci		}
9358c2ecf20Sopenharmony_ci		spin_lock_irq(shost->host_lock);
9368c2ecf20Sopenharmony_ci		phba->pport->fc_flag &= ~FC_LBIT;
9378c2ecf20Sopenharmony_ci		spin_unlock_irq(shost->host_lock);
9388c2ecf20Sopenharmony_ci	}
9398c2ecf20Sopenharmony_ci	vports = lpfc_create_vport_work_array(phba);
9408c2ecf20Sopenharmony_ci	if (vports != NULL) {
9418c2ecf20Sopenharmony_ci		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
9428c2ecf20Sopenharmony_ci			/* Issue a LINK DOWN event to all nodes */
9438c2ecf20Sopenharmony_ci			lpfc_linkdown_port(vports[i]);
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci			vports[i]->fc_myDID = 0;
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci			if ((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
9488c2ecf20Sopenharmony_ci			    (vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME)) {
9498c2ecf20Sopenharmony_ci				if (phba->nvmet_support)
9508c2ecf20Sopenharmony_ci					lpfc_nvmet_update_targetport(phba);
9518c2ecf20Sopenharmony_ci				else
9528c2ecf20Sopenharmony_ci					lpfc_nvme_update_localport(vports[i]);
9538c2ecf20Sopenharmony_ci			}
9548c2ecf20Sopenharmony_ci		}
9558c2ecf20Sopenharmony_ci	}
9568c2ecf20Sopenharmony_ci	lpfc_destroy_vport_work_array(phba, vports);
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	/* Clean up any SLI3 firmware default rpi's */
9598c2ecf20Sopenharmony_ci	if (phba->sli_rev > LPFC_SLI_REV3)
9608c2ecf20Sopenharmony_ci		goto skip_unreg_did;
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci	mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
9638c2ecf20Sopenharmony_ci	if (mb) {
9648c2ecf20Sopenharmony_ci		lpfc_unreg_did(phba, 0xffff, LPFC_UNREG_ALL_DFLT_RPIS, mb);
9658c2ecf20Sopenharmony_ci		mb->vport = vport;
9668c2ecf20Sopenharmony_ci		mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
9678c2ecf20Sopenharmony_ci		if (lpfc_sli_issue_mbox(phba, mb, MBX_NOWAIT)
9688c2ecf20Sopenharmony_ci		    == MBX_NOT_FINISHED) {
9698c2ecf20Sopenharmony_ci			mempool_free(mb, phba->mbox_mem_pool);
9708c2ecf20Sopenharmony_ci		}
9718c2ecf20Sopenharmony_ci	}
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci skip_unreg_did:
9748c2ecf20Sopenharmony_ci	/* Setup myDID for link up if we are in pt2pt mode */
9758c2ecf20Sopenharmony_ci	if (phba->pport->fc_flag & FC_PT2PT) {
9768c2ecf20Sopenharmony_ci		mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
9778c2ecf20Sopenharmony_ci		if (mb) {
9788c2ecf20Sopenharmony_ci			lpfc_config_link(phba, mb);
9798c2ecf20Sopenharmony_ci			mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
9808c2ecf20Sopenharmony_ci			mb->vport = vport;
9818c2ecf20Sopenharmony_ci			if (lpfc_sli_issue_mbox(phba, mb, MBX_NOWAIT)
9828c2ecf20Sopenharmony_ci			    == MBX_NOT_FINISHED) {
9838c2ecf20Sopenharmony_ci				mempool_free(mb, phba->mbox_mem_pool);
9848c2ecf20Sopenharmony_ci			}
9858c2ecf20Sopenharmony_ci		}
9868c2ecf20Sopenharmony_ci		spin_lock_irq(shost->host_lock);
9878c2ecf20Sopenharmony_ci		phba->pport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI);
9888c2ecf20Sopenharmony_ci		phba->pport->rcv_flogi_cnt = 0;
9898c2ecf20Sopenharmony_ci		spin_unlock_irq(shost->host_lock);
9908c2ecf20Sopenharmony_ci	}
9918c2ecf20Sopenharmony_ci	return 0;
9928c2ecf20Sopenharmony_ci}
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_cistatic void
9958c2ecf20Sopenharmony_cilpfc_linkup_cleanup_nodes(struct lpfc_vport *vport)
9968c2ecf20Sopenharmony_ci{
9978c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp;
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
10008c2ecf20Sopenharmony_ci		ndlp->nlp_fc4_type &= ~(NLP_FC4_FCP | NLP_FC4_NVME);
10018c2ecf20Sopenharmony_ci		if (!NLP_CHK_NODE_ACT(ndlp))
10028c2ecf20Sopenharmony_ci			continue;
10038c2ecf20Sopenharmony_ci		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
10048c2ecf20Sopenharmony_ci			continue;
10058c2ecf20Sopenharmony_ci		if (ndlp->nlp_type & NLP_FABRIC) {
10068c2ecf20Sopenharmony_ci			/* On Linkup its safe to clean up the ndlp
10078c2ecf20Sopenharmony_ci			 * from Fabric connections.
10088c2ecf20Sopenharmony_ci			 */
10098c2ecf20Sopenharmony_ci			if (ndlp->nlp_DID != Fabric_DID)
10108c2ecf20Sopenharmony_ci				lpfc_unreg_rpi(vport, ndlp);
10118c2ecf20Sopenharmony_ci			lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
10128c2ecf20Sopenharmony_ci		} else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
10138c2ecf20Sopenharmony_ci			/* Fail outstanding IO now since device is
10148c2ecf20Sopenharmony_ci			 * marked for PLOGI.
10158c2ecf20Sopenharmony_ci			 */
10168c2ecf20Sopenharmony_ci			lpfc_unreg_rpi(vport, ndlp);
10178c2ecf20Sopenharmony_ci		}
10188c2ecf20Sopenharmony_ci	}
10198c2ecf20Sopenharmony_ci}
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_cistatic void
10228c2ecf20Sopenharmony_cilpfc_linkup_port(struct lpfc_vport *vport)
10238c2ecf20Sopenharmony_ci{
10248c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
10258c2ecf20Sopenharmony_ci	struct lpfc_hba  *phba = vport->phba;
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	if ((vport->load_flag & FC_UNLOADING) != 0)
10288c2ecf20Sopenharmony_ci		return;
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
10318c2ecf20Sopenharmony_ci		"Link Up:         top:x%x speed:x%x flg:x%x",
10328c2ecf20Sopenharmony_ci		phba->fc_topology, phba->fc_linkspeed, phba->link_flag);
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	/* If NPIV is not enabled, only bring the physical port up */
10358c2ecf20Sopenharmony_ci	if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
10368c2ecf20Sopenharmony_ci		(vport != phba->pport))
10378c2ecf20Sopenharmony_ci		return;
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	if (vport->cfg_enable_fc4_type != LPFC_ENABLE_NVME)
10408c2ecf20Sopenharmony_ci		fc_host_post_event(shost, fc_get_event_number(),
10418c2ecf20Sopenharmony_ci				   FCH_EVT_LINKUP, 0);
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	spin_lock_irq(shost->host_lock);
10448c2ecf20Sopenharmony_ci	vport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI | FC_ABORT_DISCOVERY |
10458c2ecf20Sopenharmony_ci			    FC_RSCN_MODE | FC_NLP_MORE | FC_RSCN_DISCOVERY);
10468c2ecf20Sopenharmony_ci	vport->fc_flag |= FC_NDISC_ACTIVE;
10478c2ecf20Sopenharmony_ci	vport->fc_ns_retry = 0;
10488c2ecf20Sopenharmony_ci	spin_unlock_irq(shost->host_lock);
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci	if (vport->fc_flag & FC_LBIT)
10518c2ecf20Sopenharmony_ci		lpfc_linkup_cleanup_nodes(vport);
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci}
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_cistatic int
10568c2ecf20Sopenharmony_cilpfc_linkup(struct lpfc_hba *phba)
10578c2ecf20Sopenharmony_ci{
10588c2ecf20Sopenharmony_ci	struct lpfc_vport **vports;
10598c2ecf20Sopenharmony_ci	int i;
10608c2ecf20Sopenharmony_ci	struct Scsi_Host  *shost = lpfc_shost_from_vport(phba->pport);
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	phba->link_state = LPFC_LINK_UP;
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	/* Unblock fabric iocbs if they are blocked */
10658c2ecf20Sopenharmony_ci	clear_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags);
10668c2ecf20Sopenharmony_ci	del_timer_sync(&phba->fabric_block_timer);
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	vports = lpfc_create_vport_work_array(phba);
10698c2ecf20Sopenharmony_ci	if (vports != NULL)
10708c2ecf20Sopenharmony_ci		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++)
10718c2ecf20Sopenharmony_ci			lpfc_linkup_port(vports[i]);
10728c2ecf20Sopenharmony_ci	lpfc_destroy_vport_work_array(phba, vports);
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci	/* Clear the pport flogi counter in case the link down was
10758c2ecf20Sopenharmony_ci	 * absorbed without an ACQE. No lock here - in worker thread
10768c2ecf20Sopenharmony_ci	 * and discovery is synchronized.
10778c2ecf20Sopenharmony_ci	 */
10788c2ecf20Sopenharmony_ci	spin_lock_irq(shost->host_lock);
10798c2ecf20Sopenharmony_ci	phba->pport->rcv_flogi_cnt = 0;
10808c2ecf20Sopenharmony_ci	spin_unlock_irq(shost->host_lock);
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci	/* reinitialize initial FLOGI flag */
10838c2ecf20Sopenharmony_ci	phba->hba_flag &= ~(HBA_FLOGI_ISSUED);
10848c2ecf20Sopenharmony_ci	phba->defer_flogi_acc_flag = false;
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci	return 0;
10878c2ecf20Sopenharmony_ci}
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci/*
10908c2ecf20Sopenharmony_ci * This routine handles processing a CLEAR_LA mailbox
10918c2ecf20Sopenharmony_ci * command upon completion. It is setup in the LPFC_MBOXQ
10928c2ecf20Sopenharmony_ci * as the completion routine when the command is
10938c2ecf20Sopenharmony_ci * handed off to the SLI layer. SLI3 only.
10948c2ecf20Sopenharmony_ci */
10958c2ecf20Sopenharmony_cistatic void
10968c2ecf20Sopenharmony_cilpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
10978c2ecf20Sopenharmony_ci{
10988c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = pmb->vport;
10998c2ecf20Sopenharmony_ci	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
11008c2ecf20Sopenharmony_ci	struct lpfc_sli   *psli = &phba->sli;
11018c2ecf20Sopenharmony_ci	MAILBOX_t *mb = &pmb->u.mb;
11028c2ecf20Sopenharmony_ci	uint32_t control;
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	/* Since we don't do discovery right now, turn these off here */
11058c2ecf20Sopenharmony_ci	psli->sli3_ring[LPFC_EXTRA_RING].flag &= ~LPFC_STOP_IOCB_EVENT;
11068c2ecf20Sopenharmony_ci	psli->sli3_ring[LPFC_FCP_RING].flag &= ~LPFC_STOP_IOCB_EVENT;
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	/* Check for error */
11098c2ecf20Sopenharmony_ci	if ((mb->mbxStatus) && (mb->mbxStatus != 0x1601)) {
11108c2ecf20Sopenharmony_ci		/* CLEAR_LA mbox error <mbxStatus> state <hba_state> */
11118c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
11128c2ecf20Sopenharmony_ci				 "0320 CLEAR_LA mbxStatus error x%x hba "
11138c2ecf20Sopenharmony_ci				 "state x%x\n",
11148c2ecf20Sopenharmony_ci				 mb->mbxStatus, vport->port_state);
11158c2ecf20Sopenharmony_ci		phba->link_state = LPFC_HBA_ERROR;
11168c2ecf20Sopenharmony_ci		goto out;
11178c2ecf20Sopenharmony_ci	}
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	if (vport->port_type == LPFC_PHYSICAL_PORT)
11208c2ecf20Sopenharmony_ci		phba->link_state = LPFC_HBA_READY;
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
11238c2ecf20Sopenharmony_ci	psli->sli_flag |= LPFC_PROCESS_LA;
11248c2ecf20Sopenharmony_ci	control = readl(phba->HCregaddr);
11258c2ecf20Sopenharmony_ci	control |= HC_LAINT_ENA;
11268c2ecf20Sopenharmony_ci	writel(control, phba->HCregaddr);
11278c2ecf20Sopenharmony_ci	readl(phba->HCregaddr); /* flush */
11288c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
11298c2ecf20Sopenharmony_ci	mempool_free(pmb, phba->mbox_mem_pool);
11308c2ecf20Sopenharmony_ci	return;
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ciout:
11338c2ecf20Sopenharmony_ci	/* Device Discovery completes */
11348c2ecf20Sopenharmony_ci	lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
11358c2ecf20Sopenharmony_ci			 "0225 Device Discovery completes\n");
11368c2ecf20Sopenharmony_ci	mempool_free(pmb, phba->mbox_mem_pool);
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	spin_lock_irq(shost->host_lock);
11398c2ecf20Sopenharmony_ci	vport->fc_flag &= ~FC_ABORT_DISCOVERY;
11408c2ecf20Sopenharmony_ci	spin_unlock_irq(shost->host_lock);
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci	lpfc_can_disctmo(vport);
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	/* turn on Link Attention interrupts */
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
11478c2ecf20Sopenharmony_ci	psli->sli_flag |= LPFC_PROCESS_LA;
11488c2ecf20Sopenharmony_ci	control = readl(phba->HCregaddr);
11498c2ecf20Sopenharmony_ci	control |= HC_LAINT_ENA;
11508c2ecf20Sopenharmony_ci	writel(control, phba->HCregaddr);
11518c2ecf20Sopenharmony_ci	readl(phba->HCregaddr); /* flush */
11528c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	return;
11558c2ecf20Sopenharmony_ci}
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_civoid
11588c2ecf20Sopenharmony_cilpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
11598c2ecf20Sopenharmony_ci{
11608c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = pmb->vport;
11618c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t *sparam_mb;
11628c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *sparam_mp;
11638c2ecf20Sopenharmony_ci	u16 status = pmb->u.mb.mbxStatus;
11648c2ecf20Sopenharmony_ci	int rc;
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci	mempool_free(pmb, phba->mbox_mem_pool);
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci	if (status)
11698c2ecf20Sopenharmony_ci		goto out;
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	/* don't perform discovery for SLI4 loopback diagnostic test */
11728c2ecf20Sopenharmony_ci	if ((phba->sli_rev == LPFC_SLI_REV4) &&
11738c2ecf20Sopenharmony_ci	    !(phba->hba_flag & HBA_FCOE_MODE) &&
11748c2ecf20Sopenharmony_ci	    (phba->link_flag & LS_LOOPBACK_MODE))
11758c2ecf20Sopenharmony_ci		return;
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	if (phba->fc_topology == LPFC_TOPOLOGY_LOOP &&
11788c2ecf20Sopenharmony_ci	    vport->fc_flag & FC_PUBLIC_LOOP &&
11798c2ecf20Sopenharmony_ci	    !(vport->fc_flag & FC_LBIT)) {
11808c2ecf20Sopenharmony_ci			/* Need to wait for FAN - use discovery timer
11818c2ecf20Sopenharmony_ci			 * for timeout.  port_state is identically
11828c2ecf20Sopenharmony_ci			 * LPFC_LOCAL_CFG_LINK while waiting for FAN
11838c2ecf20Sopenharmony_ci			 */
11848c2ecf20Sopenharmony_ci			lpfc_set_disctmo(vport);
11858c2ecf20Sopenharmony_ci			return;
11868c2ecf20Sopenharmony_ci	}
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	/* Start discovery by sending a FLOGI. port_state is identically
11898c2ecf20Sopenharmony_ci	 * LPFC_FLOGI while waiting for FLOGI cmpl.
11908c2ecf20Sopenharmony_ci	 */
11918c2ecf20Sopenharmony_ci	if (vport->port_state != LPFC_FLOGI) {
11928c2ecf20Sopenharmony_ci		/* Issue MBX_READ_SPARAM to update CSPs before FLOGI if
11938c2ecf20Sopenharmony_ci		 * bb-credit recovery is in place.
11948c2ecf20Sopenharmony_ci		 */
11958c2ecf20Sopenharmony_ci		if (phba->bbcredit_support && phba->cfg_enable_bbcr &&
11968c2ecf20Sopenharmony_ci		    !(phba->link_flag & LS_LOOPBACK_MODE)) {
11978c2ecf20Sopenharmony_ci			sparam_mb = mempool_alloc(phba->mbox_mem_pool,
11988c2ecf20Sopenharmony_ci						  GFP_KERNEL);
11998c2ecf20Sopenharmony_ci			if (!sparam_mb)
12008c2ecf20Sopenharmony_ci				goto sparam_out;
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci			rc = lpfc_read_sparam(phba, sparam_mb, 0);
12038c2ecf20Sopenharmony_ci			if (rc) {
12048c2ecf20Sopenharmony_ci				mempool_free(sparam_mb, phba->mbox_mem_pool);
12058c2ecf20Sopenharmony_ci				goto sparam_out;
12068c2ecf20Sopenharmony_ci			}
12078c2ecf20Sopenharmony_ci			sparam_mb->vport = vport;
12088c2ecf20Sopenharmony_ci			sparam_mb->mbox_cmpl = lpfc_mbx_cmpl_read_sparam;
12098c2ecf20Sopenharmony_ci			rc = lpfc_sli_issue_mbox(phba, sparam_mb, MBX_NOWAIT);
12108c2ecf20Sopenharmony_ci			if (rc == MBX_NOT_FINISHED) {
12118c2ecf20Sopenharmony_ci				sparam_mp = (struct lpfc_dmabuf *)
12128c2ecf20Sopenharmony_ci						sparam_mb->ctx_buf;
12138c2ecf20Sopenharmony_ci				lpfc_mbuf_free(phba, sparam_mp->virt,
12148c2ecf20Sopenharmony_ci					       sparam_mp->phys);
12158c2ecf20Sopenharmony_ci				kfree(sparam_mp);
12168c2ecf20Sopenharmony_ci				sparam_mb->ctx_buf = NULL;
12178c2ecf20Sopenharmony_ci				mempool_free(sparam_mb, phba->mbox_mem_pool);
12188c2ecf20Sopenharmony_ci				goto sparam_out;
12198c2ecf20Sopenharmony_ci			}
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci			phba->hba_flag |= HBA_DEFER_FLOGI;
12228c2ecf20Sopenharmony_ci		}  else {
12238c2ecf20Sopenharmony_ci			lpfc_initial_flogi(vport);
12248c2ecf20Sopenharmony_ci		}
12258c2ecf20Sopenharmony_ci	} else {
12268c2ecf20Sopenharmony_ci		if (vport->fc_flag & FC_PT2PT)
12278c2ecf20Sopenharmony_ci			lpfc_disc_start(vport);
12288c2ecf20Sopenharmony_ci	}
12298c2ecf20Sopenharmony_ci	return;
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ciout:
12328c2ecf20Sopenharmony_ci	lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
12338c2ecf20Sopenharmony_ci			 "0306 CONFIG_LINK mbxStatus error x%x HBA state x%x\n",
12348c2ecf20Sopenharmony_ci			 status, vport->port_state);
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_cisparam_out:
12378c2ecf20Sopenharmony_ci	lpfc_linkdown(phba);
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci	lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
12408c2ecf20Sopenharmony_ci			 "0200 CONFIG_LINK bad hba state x%x\n",
12418c2ecf20Sopenharmony_ci			 vport->port_state);
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	lpfc_issue_clear_la(phba, vport);
12448c2ecf20Sopenharmony_ci	return;
12458c2ecf20Sopenharmony_ci}
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci/**
12488c2ecf20Sopenharmony_ci * lpfc_sli4_clear_fcf_rr_bmask
12498c2ecf20Sopenharmony_ci * @phba: pointer to the struct lpfc_hba for this port.
12508c2ecf20Sopenharmony_ci * This fucnction resets the round robin bit mask and clears the
12518c2ecf20Sopenharmony_ci * fcf priority list. The list deletions are done while holding the
12528c2ecf20Sopenharmony_ci * hbalock. The ON_LIST flag and the FLOGI_FAILED flags are cleared
12538c2ecf20Sopenharmony_ci * from the lpfc_fcf_pri record.
12548c2ecf20Sopenharmony_ci **/
12558c2ecf20Sopenharmony_civoid
12568c2ecf20Sopenharmony_cilpfc_sli4_clear_fcf_rr_bmask(struct lpfc_hba *phba)
12578c2ecf20Sopenharmony_ci{
12588c2ecf20Sopenharmony_ci	struct lpfc_fcf_pri *fcf_pri;
12598c2ecf20Sopenharmony_ci	struct lpfc_fcf_pri *next_fcf_pri;
12608c2ecf20Sopenharmony_ci	memset(phba->fcf.fcf_rr_bmask, 0, sizeof(*phba->fcf.fcf_rr_bmask));
12618c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
12628c2ecf20Sopenharmony_ci	list_for_each_entry_safe(fcf_pri, next_fcf_pri,
12638c2ecf20Sopenharmony_ci				&phba->fcf.fcf_pri_list, list) {
12648c2ecf20Sopenharmony_ci		list_del_init(&fcf_pri->list);
12658c2ecf20Sopenharmony_ci		fcf_pri->fcf_rec.flag = 0;
12668c2ecf20Sopenharmony_ci	}
12678c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
12688c2ecf20Sopenharmony_ci}
12698c2ecf20Sopenharmony_cistatic void
12708c2ecf20Sopenharmony_cilpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
12718c2ecf20Sopenharmony_ci{
12728c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = mboxq->vport;
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci	if (mboxq->u.mb.mbxStatus) {
12758c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
12768c2ecf20Sopenharmony_ci				 "2017 REG_FCFI mbxStatus error x%x "
12778c2ecf20Sopenharmony_ci				 "HBA state x%x\n", mboxq->u.mb.mbxStatus,
12788c2ecf20Sopenharmony_ci				 vport->port_state);
12798c2ecf20Sopenharmony_ci		goto fail_out;
12808c2ecf20Sopenharmony_ci	}
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci	/* Start FCoE discovery by sending a FLOGI. */
12838c2ecf20Sopenharmony_ci	phba->fcf.fcfi = bf_get(lpfc_reg_fcfi_fcfi, &mboxq->u.mqe.un.reg_fcfi);
12848c2ecf20Sopenharmony_ci	/* Set the FCFI registered flag */
12858c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
12868c2ecf20Sopenharmony_ci	phba->fcf.fcf_flag |= FCF_REGISTERED;
12878c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci	/* If there is a pending FCoE event, restart FCF table scan. */
12908c2ecf20Sopenharmony_ci	if ((!(phba->hba_flag & FCF_RR_INPROG)) &&
12918c2ecf20Sopenharmony_ci		lpfc_check_pending_fcoe_event(phba, LPFC_UNREG_FCF))
12928c2ecf20Sopenharmony_ci		goto fail_out;
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci	/* Mark successful completion of FCF table scan */
12958c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
12968c2ecf20Sopenharmony_ci	phba->fcf.fcf_flag |= (FCF_SCAN_DONE | FCF_IN_USE);
12978c2ecf20Sopenharmony_ci	phba->hba_flag &= ~FCF_TS_INPROG;
12988c2ecf20Sopenharmony_ci	if (vport->port_state != LPFC_FLOGI) {
12998c2ecf20Sopenharmony_ci		phba->hba_flag |= FCF_RR_INPROG;
13008c2ecf20Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
13018c2ecf20Sopenharmony_ci		lpfc_issue_init_vfi(vport);
13028c2ecf20Sopenharmony_ci		goto out;
13038c2ecf20Sopenharmony_ci	}
13048c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
13058c2ecf20Sopenharmony_ci	goto out;
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_cifail_out:
13088c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
13098c2ecf20Sopenharmony_ci	phba->hba_flag &= ~FCF_RR_INPROG;
13108c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
13118c2ecf20Sopenharmony_ciout:
13128c2ecf20Sopenharmony_ci	mempool_free(mboxq, phba->mbox_mem_pool);
13138c2ecf20Sopenharmony_ci}
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci/**
13168c2ecf20Sopenharmony_ci * lpfc_fab_name_match - Check if the fcf fabric name match.
13178c2ecf20Sopenharmony_ci * @fab_name: pointer to fabric name.
13188c2ecf20Sopenharmony_ci * @new_fcf_record: pointer to fcf record.
13198c2ecf20Sopenharmony_ci *
13208c2ecf20Sopenharmony_ci * This routine compare the fcf record's fabric name with provided
13218c2ecf20Sopenharmony_ci * fabric name. If the fabric name are identical this function
13228c2ecf20Sopenharmony_ci * returns 1 else return 0.
13238c2ecf20Sopenharmony_ci **/
13248c2ecf20Sopenharmony_cistatic uint32_t
13258c2ecf20Sopenharmony_cilpfc_fab_name_match(uint8_t *fab_name, struct fcf_record *new_fcf_record)
13268c2ecf20Sopenharmony_ci{
13278c2ecf20Sopenharmony_ci	if (fab_name[0] != bf_get(lpfc_fcf_record_fab_name_0, new_fcf_record))
13288c2ecf20Sopenharmony_ci		return 0;
13298c2ecf20Sopenharmony_ci	if (fab_name[1] != bf_get(lpfc_fcf_record_fab_name_1, new_fcf_record))
13308c2ecf20Sopenharmony_ci		return 0;
13318c2ecf20Sopenharmony_ci	if (fab_name[2] != bf_get(lpfc_fcf_record_fab_name_2, new_fcf_record))
13328c2ecf20Sopenharmony_ci		return 0;
13338c2ecf20Sopenharmony_ci	if (fab_name[3] != bf_get(lpfc_fcf_record_fab_name_3, new_fcf_record))
13348c2ecf20Sopenharmony_ci		return 0;
13358c2ecf20Sopenharmony_ci	if (fab_name[4] != bf_get(lpfc_fcf_record_fab_name_4, new_fcf_record))
13368c2ecf20Sopenharmony_ci		return 0;
13378c2ecf20Sopenharmony_ci	if (fab_name[5] != bf_get(lpfc_fcf_record_fab_name_5, new_fcf_record))
13388c2ecf20Sopenharmony_ci		return 0;
13398c2ecf20Sopenharmony_ci	if (fab_name[6] != bf_get(lpfc_fcf_record_fab_name_6, new_fcf_record))
13408c2ecf20Sopenharmony_ci		return 0;
13418c2ecf20Sopenharmony_ci	if (fab_name[7] != bf_get(lpfc_fcf_record_fab_name_7, new_fcf_record))
13428c2ecf20Sopenharmony_ci		return 0;
13438c2ecf20Sopenharmony_ci	return 1;
13448c2ecf20Sopenharmony_ci}
13458c2ecf20Sopenharmony_ci
13468c2ecf20Sopenharmony_ci/**
13478c2ecf20Sopenharmony_ci * lpfc_sw_name_match - Check if the fcf switch name match.
13488c2ecf20Sopenharmony_ci * @sw_name: pointer to switch name.
13498c2ecf20Sopenharmony_ci * @new_fcf_record: pointer to fcf record.
13508c2ecf20Sopenharmony_ci *
13518c2ecf20Sopenharmony_ci * This routine compare the fcf record's switch name with provided
13528c2ecf20Sopenharmony_ci * switch name. If the switch name are identical this function
13538c2ecf20Sopenharmony_ci * returns 1 else return 0.
13548c2ecf20Sopenharmony_ci **/
13558c2ecf20Sopenharmony_cistatic uint32_t
13568c2ecf20Sopenharmony_cilpfc_sw_name_match(uint8_t *sw_name, struct fcf_record *new_fcf_record)
13578c2ecf20Sopenharmony_ci{
13588c2ecf20Sopenharmony_ci	if (sw_name[0] != bf_get(lpfc_fcf_record_switch_name_0, new_fcf_record))
13598c2ecf20Sopenharmony_ci		return 0;
13608c2ecf20Sopenharmony_ci	if (sw_name[1] != bf_get(lpfc_fcf_record_switch_name_1, new_fcf_record))
13618c2ecf20Sopenharmony_ci		return 0;
13628c2ecf20Sopenharmony_ci	if (sw_name[2] != bf_get(lpfc_fcf_record_switch_name_2, new_fcf_record))
13638c2ecf20Sopenharmony_ci		return 0;
13648c2ecf20Sopenharmony_ci	if (sw_name[3] != bf_get(lpfc_fcf_record_switch_name_3, new_fcf_record))
13658c2ecf20Sopenharmony_ci		return 0;
13668c2ecf20Sopenharmony_ci	if (sw_name[4] != bf_get(lpfc_fcf_record_switch_name_4, new_fcf_record))
13678c2ecf20Sopenharmony_ci		return 0;
13688c2ecf20Sopenharmony_ci	if (sw_name[5] != bf_get(lpfc_fcf_record_switch_name_5, new_fcf_record))
13698c2ecf20Sopenharmony_ci		return 0;
13708c2ecf20Sopenharmony_ci	if (sw_name[6] != bf_get(lpfc_fcf_record_switch_name_6, new_fcf_record))
13718c2ecf20Sopenharmony_ci		return 0;
13728c2ecf20Sopenharmony_ci	if (sw_name[7] != bf_get(lpfc_fcf_record_switch_name_7, new_fcf_record))
13738c2ecf20Sopenharmony_ci		return 0;
13748c2ecf20Sopenharmony_ci	return 1;
13758c2ecf20Sopenharmony_ci}
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci/**
13788c2ecf20Sopenharmony_ci * lpfc_mac_addr_match - Check if the fcf mac address match.
13798c2ecf20Sopenharmony_ci * @mac_addr: pointer to mac address.
13808c2ecf20Sopenharmony_ci * @new_fcf_record: pointer to fcf record.
13818c2ecf20Sopenharmony_ci *
13828c2ecf20Sopenharmony_ci * This routine compare the fcf record's mac address with HBA's
13838c2ecf20Sopenharmony_ci * FCF mac address. If the mac addresses are identical this function
13848c2ecf20Sopenharmony_ci * returns 1 else return 0.
13858c2ecf20Sopenharmony_ci **/
13868c2ecf20Sopenharmony_cistatic uint32_t
13878c2ecf20Sopenharmony_cilpfc_mac_addr_match(uint8_t *mac_addr, struct fcf_record *new_fcf_record)
13888c2ecf20Sopenharmony_ci{
13898c2ecf20Sopenharmony_ci	if (mac_addr[0] != bf_get(lpfc_fcf_record_mac_0, new_fcf_record))
13908c2ecf20Sopenharmony_ci		return 0;
13918c2ecf20Sopenharmony_ci	if (mac_addr[1] != bf_get(lpfc_fcf_record_mac_1, new_fcf_record))
13928c2ecf20Sopenharmony_ci		return 0;
13938c2ecf20Sopenharmony_ci	if (mac_addr[2] != bf_get(lpfc_fcf_record_mac_2, new_fcf_record))
13948c2ecf20Sopenharmony_ci		return 0;
13958c2ecf20Sopenharmony_ci	if (mac_addr[3] != bf_get(lpfc_fcf_record_mac_3, new_fcf_record))
13968c2ecf20Sopenharmony_ci		return 0;
13978c2ecf20Sopenharmony_ci	if (mac_addr[4] != bf_get(lpfc_fcf_record_mac_4, new_fcf_record))
13988c2ecf20Sopenharmony_ci		return 0;
13998c2ecf20Sopenharmony_ci	if (mac_addr[5] != bf_get(lpfc_fcf_record_mac_5, new_fcf_record))
14008c2ecf20Sopenharmony_ci		return 0;
14018c2ecf20Sopenharmony_ci	return 1;
14028c2ecf20Sopenharmony_ci}
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_cistatic bool
14058c2ecf20Sopenharmony_cilpfc_vlan_id_match(uint16_t curr_vlan_id, uint16_t new_vlan_id)
14068c2ecf20Sopenharmony_ci{
14078c2ecf20Sopenharmony_ci	return (curr_vlan_id == new_vlan_id);
14088c2ecf20Sopenharmony_ci}
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci/**
14118c2ecf20Sopenharmony_ci * __lpfc_update_fcf_record_pri - update the lpfc_fcf_pri record.
14128c2ecf20Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
14138c2ecf20Sopenharmony_ci * @fcf_index: Index for the lpfc_fcf_record.
14148c2ecf20Sopenharmony_ci * @new_fcf_record: pointer to hba fcf record.
14158c2ecf20Sopenharmony_ci *
14168c2ecf20Sopenharmony_ci * This routine updates the driver FCF priority record from the new HBA FCF
14178c2ecf20Sopenharmony_ci * record. The hbalock is asserted held in the code path calling this
14188c2ecf20Sopenharmony_ci * routine.
14198c2ecf20Sopenharmony_ci **/
14208c2ecf20Sopenharmony_cistatic void
14218c2ecf20Sopenharmony_ci__lpfc_update_fcf_record_pri(struct lpfc_hba *phba, uint16_t fcf_index,
14228c2ecf20Sopenharmony_ci				 struct fcf_record *new_fcf_record
14238c2ecf20Sopenharmony_ci				 )
14248c2ecf20Sopenharmony_ci{
14258c2ecf20Sopenharmony_ci	struct lpfc_fcf_pri *fcf_pri;
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_ci	fcf_pri = &phba->fcf.fcf_pri[fcf_index];
14288c2ecf20Sopenharmony_ci	fcf_pri->fcf_rec.fcf_index = fcf_index;
14298c2ecf20Sopenharmony_ci	/* FCF record priority */
14308c2ecf20Sopenharmony_ci	fcf_pri->fcf_rec.priority = new_fcf_record->fip_priority;
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci}
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci/**
14358c2ecf20Sopenharmony_ci * lpfc_copy_fcf_record - Copy fcf information to lpfc_hba.
14368c2ecf20Sopenharmony_ci * @fcf_rec: pointer to driver fcf record.
14378c2ecf20Sopenharmony_ci * @new_fcf_record: pointer to fcf record.
14388c2ecf20Sopenharmony_ci *
14398c2ecf20Sopenharmony_ci * This routine copies the FCF information from the FCF
14408c2ecf20Sopenharmony_ci * record to lpfc_hba data structure.
14418c2ecf20Sopenharmony_ci **/
14428c2ecf20Sopenharmony_cistatic void
14438c2ecf20Sopenharmony_cilpfc_copy_fcf_record(struct lpfc_fcf_rec *fcf_rec,
14448c2ecf20Sopenharmony_ci		     struct fcf_record *new_fcf_record)
14458c2ecf20Sopenharmony_ci{
14468c2ecf20Sopenharmony_ci	/* Fabric name */
14478c2ecf20Sopenharmony_ci	fcf_rec->fabric_name[0] =
14488c2ecf20Sopenharmony_ci		bf_get(lpfc_fcf_record_fab_name_0, new_fcf_record);
14498c2ecf20Sopenharmony_ci	fcf_rec->fabric_name[1] =
14508c2ecf20Sopenharmony_ci		bf_get(lpfc_fcf_record_fab_name_1, new_fcf_record);
14518c2ecf20Sopenharmony_ci	fcf_rec->fabric_name[2] =
14528c2ecf20Sopenharmony_ci		bf_get(lpfc_fcf_record_fab_name_2, new_fcf_record);
14538c2ecf20Sopenharmony_ci	fcf_rec->fabric_name[3] =
14548c2ecf20Sopenharmony_ci		bf_get(lpfc_fcf_record_fab_name_3, new_fcf_record);
14558c2ecf20Sopenharmony_ci	fcf_rec->fabric_name[4] =
14568c2ecf20Sopenharmony_ci		bf_get(lpfc_fcf_record_fab_name_4, new_fcf_record);
14578c2ecf20Sopenharmony_ci	fcf_rec->fabric_name[5] =
14588c2ecf20Sopenharmony_ci		bf_get(lpfc_fcf_record_fab_name_5, new_fcf_record);
14598c2ecf20Sopenharmony_ci	fcf_rec->fabric_name[6] =
14608c2ecf20Sopenharmony_ci		bf_get(lpfc_fcf_record_fab_name_6, new_fcf_record);
14618c2ecf20Sopenharmony_ci	fcf_rec->fabric_name[7] =
14628c2ecf20Sopenharmony_ci		bf_get(lpfc_fcf_record_fab_name_7, new_fcf_record);
14638c2ecf20Sopenharmony_ci	/* Mac address */
14648c2ecf20Sopenharmony_ci	fcf_rec->mac_addr[0] = bf_get(lpfc_fcf_record_mac_0, new_fcf_record);
14658c2ecf20Sopenharmony_ci	fcf_rec->mac_addr[1] = bf_get(lpfc_fcf_record_mac_1, new_fcf_record);
14668c2ecf20Sopenharmony_ci	fcf_rec->mac_addr[2] = bf_get(lpfc_fcf_record_mac_2, new_fcf_record);
14678c2ecf20Sopenharmony_ci	fcf_rec->mac_addr[3] = bf_get(lpfc_fcf_record_mac_3, new_fcf_record);
14688c2ecf20Sopenharmony_ci	fcf_rec->mac_addr[4] = bf_get(lpfc_fcf_record_mac_4, new_fcf_record);
14698c2ecf20Sopenharmony_ci	fcf_rec->mac_addr[5] = bf_get(lpfc_fcf_record_mac_5, new_fcf_record);
14708c2ecf20Sopenharmony_ci	/* FCF record index */
14718c2ecf20Sopenharmony_ci	fcf_rec->fcf_indx = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record);
14728c2ecf20Sopenharmony_ci	/* FCF record priority */
14738c2ecf20Sopenharmony_ci	fcf_rec->priority = new_fcf_record->fip_priority;
14748c2ecf20Sopenharmony_ci	/* Switch name */
14758c2ecf20Sopenharmony_ci	fcf_rec->switch_name[0] =
14768c2ecf20Sopenharmony_ci		bf_get(lpfc_fcf_record_switch_name_0, new_fcf_record);
14778c2ecf20Sopenharmony_ci	fcf_rec->switch_name[1] =
14788c2ecf20Sopenharmony_ci		bf_get(lpfc_fcf_record_switch_name_1, new_fcf_record);
14798c2ecf20Sopenharmony_ci	fcf_rec->switch_name[2] =
14808c2ecf20Sopenharmony_ci		bf_get(lpfc_fcf_record_switch_name_2, new_fcf_record);
14818c2ecf20Sopenharmony_ci	fcf_rec->switch_name[3] =
14828c2ecf20Sopenharmony_ci		bf_get(lpfc_fcf_record_switch_name_3, new_fcf_record);
14838c2ecf20Sopenharmony_ci	fcf_rec->switch_name[4] =
14848c2ecf20Sopenharmony_ci		bf_get(lpfc_fcf_record_switch_name_4, new_fcf_record);
14858c2ecf20Sopenharmony_ci	fcf_rec->switch_name[5] =
14868c2ecf20Sopenharmony_ci		bf_get(lpfc_fcf_record_switch_name_5, new_fcf_record);
14878c2ecf20Sopenharmony_ci	fcf_rec->switch_name[6] =
14888c2ecf20Sopenharmony_ci		bf_get(lpfc_fcf_record_switch_name_6, new_fcf_record);
14898c2ecf20Sopenharmony_ci	fcf_rec->switch_name[7] =
14908c2ecf20Sopenharmony_ci		bf_get(lpfc_fcf_record_switch_name_7, new_fcf_record);
14918c2ecf20Sopenharmony_ci}
14928c2ecf20Sopenharmony_ci
14938c2ecf20Sopenharmony_ci/**
14948c2ecf20Sopenharmony_ci * lpfc_update_fcf_record - Update driver fcf record
14958c2ecf20Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
14968c2ecf20Sopenharmony_ci * @fcf_rec: pointer to driver fcf record.
14978c2ecf20Sopenharmony_ci * @new_fcf_record: pointer to hba fcf record.
14988c2ecf20Sopenharmony_ci * @addr_mode: address mode to be set to the driver fcf record.
14998c2ecf20Sopenharmony_ci * @vlan_id: vlan tag to be set to the driver fcf record.
15008c2ecf20Sopenharmony_ci * @flag: flag bits to be set to the driver fcf record.
15018c2ecf20Sopenharmony_ci *
15028c2ecf20Sopenharmony_ci * This routine updates the driver FCF record from the new HBA FCF record
15038c2ecf20Sopenharmony_ci * together with the address mode, vlan_id, and other informations. This
15048c2ecf20Sopenharmony_ci * routine is called with the hbalock held.
15058c2ecf20Sopenharmony_ci **/
15068c2ecf20Sopenharmony_cistatic void
15078c2ecf20Sopenharmony_ci__lpfc_update_fcf_record(struct lpfc_hba *phba, struct lpfc_fcf_rec *fcf_rec,
15088c2ecf20Sopenharmony_ci		       struct fcf_record *new_fcf_record, uint32_t addr_mode,
15098c2ecf20Sopenharmony_ci		       uint16_t vlan_id, uint32_t flag)
15108c2ecf20Sopenharmony_ci{
15118c2ecf20Sopenharmony_ci	lockdep_assert_held(&phba->hbalock);
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci	/* Copy the fields from the HBA's FCF record */
15148c2ecf20Sopenharmony_ci	lpfc_copy_fcf_record(fcf_rec, new_fcf_record);
15158c2ecf20Sopenharmony_ci	/* Update other fields of driver FCF record */
15168c2ecf20Sopenharmony_ci	fcf_rec->addr_mode = addr_mode;
15178c2ecf20Sopenharmony_ci	fcf_rec->vlan_id = vlan_id;
15188c2ecf20Sopenharmony_ci	fcf_rec->flag |= (flag | RECORD_VALID);
15198c2ecf20Sopenharmony_ci	__lpfc_update_fcf_record_pri(phba,
15208c2ecf20Sopenharmony_ci		bf_get(lpfc_fcf_record_fcf_index, new_fcf_record),
15218c2ecf20Sopenharmony_ci				 new_fcf_record);
15228c2ecf20Sopenharmony_ci}
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_ci/**
15258c2ecf20Sopenharmony_ci * lpfc_register_fcf - Register the FCF with hba.
15268c2ecf20Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
15278c2ecf20Sopenharmony_ci *
15288c2ecf20Sopenharmony_ci * This routine issues a register fcfi mailbox command to register
15298c2ecf20Sopenharmony_ci * the fcf with HBA.
15308c2ecf20Sopenharmony_ci **/
15318c2ecf20Sopenharmony_cistatic void
15328c2ecf20Sopenharmony_cilpfc_register_fcf(struct lpfc_hba *phba)
15338c2ecf20Sopenharmony_ci{
15348c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t *fcf_mbxq;
15358c2ecf20Sopenharmony_ci	int rc;
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
15388c2ecf20Sopenharmony_ci	/* If the FCF is not available do nothing. */
15398c2ecf20Sopenharmony_ci	if (!(phba->fcf.fcf_flag & FCF_AVAILABLE)) {
15408c2ecf20Sopenharmony_ci		phba->hba_flag &= ~(FCF_TS_INPROG | FCF_RR_INPROG);
15418c2ecf20Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
15428c2ecf20Sopenharmony_ci		return;
15438c2ecf20Sopenharmony_ci	}
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci	/* The FCF is already registered, start discovery */
15468c2ecf20Sopenharmony_ci	if (phba->fcf.fcf_flag & FCF_REGISTERED) {
15478c2ecf20Sopenharmony_ci		phba->fcf.fcf_flag |= (FCF_SCAN_DONE | FCF_IN_USE);
15488c2ecf20Sopenharmony_ci		phba->hba_flag &= ~FCF_TS_INPROG;
15498c2ecf20Sopenharmony_ci		if (phba->pport->port_state != LPFC_FLOGI &&
15508c2ecf20Sopenharmony_ci		    phba->pport->fc_flag & FC_FABRIC) {
15518c2ecf20Sopenharmony_ci			phba->hba_flag |= FCF_RR_INPROG;
15528c2ecf20Sopenharmony_ci			spin_unlock_irq(&phba->hbalock);
15538c2ecf20Sopenharmony_ci			lpfc_initial_flogi(phba->pport);
15548c2ecf20Sopenharmony_ci			return;
15558c2ecf20Sopenharmony_ci		}
15568c2ecf20Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
15578c2ecf20Sopenharmony_ci		return;
15588c2ecf20Sopenharmony_ci	}
15598c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci	fcf_mbxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
15628c2ecf20Sopenharmony_ci	if (!fcf_mbxq) {
15638c2ecf20Sopenharmony_ci		spin_lock_irq(&phba->hbalock);
15648c2ecf20Sopenharmony_ci		phba->hba_flag &= ~(FCF_TS_INPROG | FCF_RR_INPROG);
15658c2ecf20Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
15668c2ecf20Sopenharmony_ci		return;
15678c2ecf20Sopenharmony_ci	}
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci	lpfc_reg_fcfi(phba, fcf_mbxq);
15708c2ecf20Sopenharmony_ci	fcf_mbxq->vport = phba->pport;
15718c2ecf20Sopenharmony_ci	fcf_mbxq->mbox_cmpl = lpfc_mbx_cmpl_reg_fcfi;
15728c2ecf20Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, fcf_mbxq, MBX_NOWAIT);
15738c2ecf20Sopenharmony_ci	if (rc == MBX_NOT_FINISHED) {
15748c2ecf20Sopenharmony_ci		spin_lock_irq(&phba->hbalock);
15758c2ecf20Sopenharmony_ci		phba->hba_flag &= ~(FCF_TS_INPROG | FCF_RR_INPROG);
15768c2ecf20Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
15778c2ecf20Sopenharmony_ci		mempool_free(fcf_mbxq, phba->mbox_mem_pool);
15788c2ecf20Sopenharmony_ci	}
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci	return;
15818c2ecf20Sopenharmony_ci}
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci/**
15848c2ecf20Sopenharmony_ci * lpfc_match_fcf_conn_list - Check if the FCF record can be used for discovery.
15858c2ecf20Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
15868c2ecf20Sopenharmony_ci * @new_fcf_record: pointer to fcf record.
15878c2ecf20Sopenharmony_ci * @boot_flag: Indicates if this record used by boot bios.
15888c2ecf20Sopenharmony_ci * @addr_mode: The address mode to be used by this FCF
15898c2ecf20Sopenharmony_ci * @vlan_id: The vlan id to be used as vlan tagging by this FCF.
15908c2ecf20Sopenharmony_ci *
15918c2ecf20Sopenharmony_ci * This routine compare the fcf record with connect list obtained from the
15928c2ecf20Sopenharmony_ci * config region to decide if this FCF can be used for SAN discovery. It returns
15938c2ecf20Sopenharmony_ci * 1 if this record can be used for SAN discovery else return zero. If this FCF
15948c2ecf20Sopenharmony_ci * record can be used for SAN discovery, the boot_flag will indicate if this FCF
15958c2ecf20Sopenharmony_ci * is used by boot bios and addr_mode will indicate the addressing mode to be
15968c2ecf20Sopenharmony_ci * used for this FCF when the function returns.
15978c2ecf20Sopenharmony_ci * If the FCF record need to be used with a particular vlan id, the vlan is
15988c2ecf20Sopenharmony_ci * set in the vlan_id on return of the function. If not VLAN tagging need to
15998c2ecf20Sopenharmony_ci * be used with the FCF vlan_id will be set to LPFC_FCOE_NULL_VID;
16008c2ecf20Sopenharmony_ci **/
16018c2ecf20Sopenharmony_cistatic int
16028c2ecf20Sopenharmony_cilpfc_match_fcf_conn_list(struct lpfc_hba *phba,
16038c2ecf20Sopenharmony_ci			struct fcf_record *new_fcf_record,
16048c2ecf20Sopenharmony_ci			uint32_t *boot_flag, uint32_t *addr_mode,
16058c2ecf20Sopenharmony_ci			uint16_t *vlan_id)
16068c2ecf20Sopenharmony_ci{
16078c2ecf20Sopenharmony_ci	struct lpfc_fcf_conn_entry *conn_entry;
16088c2ecf20Sopenharmony_ci	int i, j, fcf_vlan_id = 0;
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ci	/* Find the lowest VLAN id in the FCF record */
16118c2ecf20Sopenharmony_ci	for (i = 0; i < 512; i++) {
16128c2ecf20Sopenharmony_ci		if (new_fcf_record->vlan_bitmap[i]) {
16138c2ecf20Sopenharmony_ci			fcf_vlan_id = i * 8;
16148c2ecf20Sopenharmony_ci			j = 0;
16158c2ecf20Sopenharmony_ci			while (!((new_fcf_record->vlan_bitmap[i] >> j) & 1)) {
16168c2ecf20Sopenharmony_ci				j++;
16178c2ecf20Sopenharmony_ci				fcf_vlan_id++;
16188c2ecf20Sopenharmony_ci			}
16198c2ecf20Sopenharmony_ci			break;
16208c2ecf20Sopenharmony_ci		}
16218c2ecf20Sopenharmony_ci	}
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_ci	/* FCF not valid/available or solicitation in progress */
16248c2ecf20Sopenharmony_ci	if (!bf_get(lpfc_fcf_record_fcf_avail, new_fcf_record) ||
16258c2ecf20Sopenharmony_ci	    !bf_get(lpfc_fcf_record_fcf_valid, new_fcf_record) ||
16268c2ecf20Sopenharmony_ci	    bf_get(lpfc_fcf_record_fcf_sol, new_fcf_record))
16278c2ecf20Sopenharmony_ci		return 0;
16288c2ecf20Sopenharmony_ci
16298c2ecf20Sopenharmony_ci	if (!(phba->hba_flag & HBA_FIP_SUPPORT)) {
16308c2ecf20Sopenharmony_ci		*boot_flag = 0;
16318c2ecf20Sopenharmony_ci		*addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov,
16328c2ecf20Sopenharmony_ci				new_fcf_record);
16338c2ecf20Sopenharmony_ci		if (phba->valid_vlan)
16348c2ecf20Sopenharmony_ci			*vlan_id = phba->vlan_id;
16358c2ecf20Sopenharmony_ci		else
16368c2ecf20Sopenharmony_ci			*vlan_id = LPFC_FCOE_NULL_VID;
16378c2ecf20Sopenharmony_ci		return 1;
16388c2ecf20Sopenharmony_ci	}
16398c2ecf20Sopenharmony_ci
16408c2ecf20Sopenharmony_ci	/*
16418c2ecf20Sopenharmony_ci	 * If there are no FCF connection table entry, driver connect to all
16428c2ecf20Sopenharmony_ci	 * FCFs.
16438c2ecf20Sopenharmony_ci	 */
16448c2ecf20Sopenharmony_ci	if (list_empty(&phba->fcf_conn_rec_list)) {
16458c2ecf20Sopenharmony_ci		*boot_flag = 0;
16468c2ecf20Sopenharmony_ci		*addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov,
16478c2ecf20Sopenharmony_ci			new_fcf_record);
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci		/*
16508c2ecf20Sopenharmony_ci		 * When there are no FCF connect entries, use driver's default
16518c2ecf20Sopenharmony_ci		 * addressing mode - FPMA.
16528c2ecf20Sopenharmony_ci		 */
16538c2ecf20Sopenharmony_ci		if (*addr_mode & LPFC_FCF_FPMA)
16548c2ecf20Sopenharmony_ci			*addr_mode = LPFC_FCF_FPMA;
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_ci		/* If FCF record report a vlan id use that vlan id */
16578c2ecf20Sopenharmony_ci		if (fcf_vlan_id)
16588c2ecf20Sopenharmony_ci			*vlan_id = fcf_vlan_id;
16598c2ecf20Sopenharmony_ci		else
16608c2ecf20Sopenharmony_ci			*vlan_id = LPFC_FCOE_NULL_VID;
16618c2ecf20Sopenharmony_ci		return 1;
16628c2ecf20Sopenharmony_ci	}
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_ci	list_for_each_entry(conn_entry,
16658c2ecf20Sopenharmony_ci			    &phba->fcf_conn_rec_list, list) {
16668c2ecf20Sopenharmony_ci		if (!(conn_entry->conn_rec.flags & FCFCNCT_VALID))
16678c2ecf20Sopenharmony_ci			continue;
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_ci		if ((conn_entry->conn_rec.flags & FCFCNCT_FBNM_VALID) &&
16708c2ecf20Sopenharmony_ci			!lpfc_fab_name_match(conn_entry->conn_rec.fabric_name,
16718c2ecf20Sopenharmony_ci					     new_fcf_record))
16728c2ecf20Sopenharmony_ci			continue;
16738c2ecf20Sopenharmony_ci		if ((conn_entry->conn_rec.flags & FCFCNCT_SWNM_VALID) &&
16748c2ecf20Sopenharmony_ci			!lpfc_sw_name_match(conn_entry->conn_rec.switch_name,
16758c2ecf20Sopenharmony_ci					    new_fcf_record))
16768c2ecf20Sopenharmony_ci			continue;
16778c2ecf20Sopenharmony_ci		if (conn_entry->conn_rec.flags & FCFCNCT_VLAN_VALID) {
16788c2ecf20Sopenharmony_ci			/*
16798c2ecf20Sopenharmony_ci			 * If the vlan bit map does not have the bit set for the
16808c2ecf20Sopenharmony_ci			 * vlan id to be used, then it is not a match.
16818c2ecf20Sopenharmony_ci			 */
16828c2ecf20Sopenharmony_ci			if (!(new_fcf_record->vlan_bitmap
16838c2ecf20Sopenharmony_ci				[conn_entry->conn_rec.vlan_tag / 8] &
16848c2ecf20Sopenharmony_ci				(1 << (conn_entry->conn_rec.vlan_tag % 8))))
16858c2ecf20Sopenharmony_ci				continue;
16868c2ecf20Sopenharmony_ci		}
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_ci		/*
16898c2ecf20Sopenharmony_ci		 * If connection record does not support any addressing mode,
16908c2ecf20Sopenharmony_ci		 * skip the FCF record.
16918c2ecf20Sopenharmony_ci		 */
16928c2ecf20Sopenharmony_ci		if (!(bf_get(lpfc_fcf_record_mac_addr_prov, new_fcf_record)
16938c2ecf20Sopenharmony_ci			& (LPFC_FCF_FPMA | LPFC_FCF_SPMA)))
16948c2ecf20Sopenharmony_ci			continue;
16958c2ecf20Sopenharmony_ci
16968c2ecf20Sopenharmony_ci		/*
16978c2ecf20Sopenharmony_ci		 * Check if the connection record specifies a required
16988c2ecf20Sopenharmony_ci		 * addressing mode.
16998c2ecf20Sopenharmony_ci		 */
17008c2ecf20Sopenharmony_ci		if ((conn_entry->conn_rec.flags & FCFCNCT_AM_VALID) &&
17018c2ecf20Sopenharmony_ci			!(conn_entry->conn_rec.flags & FCFCNCT_AM_PREFERRED)) {
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_ci			/*
17048c2ecf20Sopenharmony_ci			 * If SPMA required but FCF not support this continue.
17058c2ecf20Sopenharmony_ci			 */
17068c2ecf20Sopenharmony_ci			if ((conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) &&
17078c2ecf20Sopenharmony_ci				!(bf_get(lpfc_fcf_record_mac_addr_prov,
17088c2ecf20Sopenharmony_ci					new_fcf_record) & LPFC_FCF_SPMA))
17098c2ecf20Sopenharmony_ci				continue;
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci			/*
17128c2ecf20Sopenharmony_ci			 * If FPMA required but FCF not support this continue.
17138c2ecf20Sopenharmony_ci			 */
17148c2ecf20Sopenharmony_ci			if (!(conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) &&
17158c2ecf20Sopenharmony_ci				!(bf_get(lpfc_fcf_record_mac_addr_prov,
17168c2ecf20Sopenharmony_ci				new_fcf_record) & LPFC_FCF_FPMA))
17178c2ecf20Sopenharmony_ci				continue;
17188c2ecf20Sopenharmony_ci		}
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ci		/*
17218c2ecf20Sopenharmony_ci		 * This fcf record matches filtering criteria.
17228c2ecf20Sopenharmony_ci		 */
17238c2ecf20Sopenharmony_ci		if (conn_entry->conn_rec.flags & FCFCNCT_BOOT)
17248c2ecf20Sopenharmony_ci			*boot_flag = 1;
17258c2ecf20Sopenharmony_ci		else
17268c2ecf20Sopenharmony_ci			*boot_flag = 0;
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ci		/*
17298c2ecf20Sopenharmony_ci		 * If user did not specify any addressing mode, or if the
17308c2ecf20Sopenharmony_ci		 * preferred addressing mode specified by user is not supported
17318c2ecf20Sopenharmony_ci		 * by FCF, allow fabric to pick the addressing mode.
17328c2ecf20Sopenharmony_ci		 */
17338c2ecf20Sopenharmony_ci		*addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov,
17348c2ecf20Sopenharmony_ci				new_fcf_record);
17358c2ecf20Sopenharmony_ci		/*
17368c2ecf20Sopenharmony_ci		 * If the user specified a required address mode, assign that
17378c2ecf20Sopenharmony_ci		 * address mode
17388c2ecf20Sopenharmony_ci		 */
17398c2ecf20Sopenharmony_ci		if ((conn_entry->conn_rec.flags & FCFCNCT_AM_VALID) &&
17408c2ecf20Sopenharmony_ci			(!(conn_entry->conn_rec.flags & FCFCNCT_AM_PREFERRED)))
17418c2ecf20Sopenharmony_ci			*addr_mode = (conn_entry->conn_rec.flags &
17428c2ecf20Sopenharmony_ci				FCFCNCT_AM_SPMA) ?
17438c2ecf20Sopenharmony_ci				LPFC_FCF_SPMA : LPFC_FCF_FPMA;
17448c2ecf20Sopenharmony_ci		/*
17458c2ecf20Sopenharmony_ci		 * If the user specified a preferred address mode, use the
17468c2ecf20Sopenharmony_ci		 * addr mode only if FCF support the addr_mode.
17478c2ecf20Sopenharmony_ci		 */
17488c2ecf20Sopenharmony_ci		else if ((conn_entry->conn_rec.flags & FCFCNCT_AM_VALID) &&
17498c2ecf20Sopenharmony_ci			(conn_entry->conn_rec.flags & FCFCNCT_AM_PREFERRED) &&
17508c2ecf20Sopenharmony_ci			(conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) &&
17518c2ecf20Sopenharmony_ci			(*addr_mode & LPFC_FCF_SPMA))
17528c2ecf20Sopenharmony_ci				*addr_mode = LPFC_FCF_SPMA;
17538c2ecf20Sopenharmony_ci		else if ((conn_entry->conn_rec.flags & FCFCNCT_AM_VALID) &&
17548c2ecf20Sopenharmony_ci			(conn_entry->conn_rec.flags & FCFCNCT_AM_PREFERRED) &&
17558c2ecf20Sopenharmony_ci			!(conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) &&
17568c2ecf20Sopenharmony_ci			(*addr_mode & LPFC_FCF_FPMA))
17578c2ecf20Sopenharmony_ci				*addr_mode = LPFC_FCF_FPMA;
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci		/* If matching connect list has a vlan id, use it */
17608c2ecf20Sopenharmony_ci		if (conn_entry->conn_rec.flags & FCFCNCT_VLAN_VALID)
17618c2ecf20Sopenharmony_ci			*vlan_id = conn_entry->conn_rec.vlan_tag;
17628c2ecf20Sopenharmony_ci		/*
17638c2ecf20Sopenharmony_ci		 * If no vlan id is specified in connect list, use the vlan id
17648c2ecf20Sopenharmony_ci		 * in the FCF record
17658c2ecf20Sopenharmony_ci		 */
17668c2ecf20Sopenharmony_ci		else if (fcf_vlan_id)
17678c2ecf20Sopenharmony_ci			*vlan_id = fcf_vlan_id;
17688c2ecf20Sopenharmony_ci		else
17698c2ecf20Sopenharmony_ci			*vlan_id = LPFC_FCOE_NULL_VID;
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_ci		return 1;
17728c2ecf20Sopenharmony_ci	}
17738c2ecf20Sopenharmony_ci
17748c2ecf20Sopenharmony_ci	return 0;
17758c2ecf20Sopenharmony_ci}
17768c2ecf20Sopenharmony_ci
17778c2ecf20Sopenharmony_ci/**
17788c2ecf20Sopenharmony_ci * lpfc_check_pending_fcoe_event - Check if there is pending fcoe event.
17798c2ecf20Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
17808c2ecf20Sopenharmony_ci * @unreg_fcf: Unregister FCF if FCF table need to be re-scaned.
17818c2ecf20Sopenharmony_ci *
17828c2ecf20Sopenharmony_ci * This function check if there is any fcoe event pending while driver
17838c2ecf20Sopenharmony_ci * scan FCF entries. If there is any pending event, it will restart the
17848c2ecf20Sopenharmony_ci * FCF saning and return 1 else return 0.
17858c2ecf20Sopenharmony_ci */
17868c2ecf20Sopenharmony_ciint
17878c2ecf20Sopenharmony_cilpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf)
17888c2ecf20Sopenharmony_ci{
17898c2ecf20Sopenharmony_ci	/*
17908c2ecf20Sopenharmony_ci	 * If the Link is up and no FCoE events while in the
17918c2ecf20Sopenharmony_ci	 * FCF discovery, no need to restart FCF discovery.
17928c2ecf20Sopenharmony_ci	 */
17938c2ecf20Sopenharmony_ci	if ((phba->link_state  >= LPFC_LINK_UP) &&
17948c2ecf20Sopenharmony_ci	    (phba->fcoe_eventtag == phba->fcoe_eventtag_at_fcf_scan))
17958c2ecf20Sopenharmony_ci		return 0;
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
17988c2ecf20Sopenharmony_ci			"2768 Pending link or FCF event during current "
17998c2ecf20Sopenharmony_ci			"handling of the previous event: link_state:x%x, "
18008c2ecf20Sopenharmony_ci			"evt_tag_at_scan:x%x, evt_tag_current:x%x\n",
18018c2ecf20Sopenharmony_ci			phba->link_state, phba->fcoe_eventtag_at_fcf_scan,
18028c2ecf20Sopenharmony_ci			phba->fcoe_eventtag);
18038c2ecf20Sopenharmony_ci
18048c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
18058c2ecf20Sopenharmony_ci	phba->fcf.fcf_flag &= ~FCF_AVAILABLE;
18068c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
18078c2ecf20Sopenharmony_ci
18088c2ecf20Sopenharmony_ci	if (phba->link_state >= LPFC_LINK_UP) {
18098c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
18108c2ecf20Sopenharmony_ci				"2780 Restart FCF table scan due to "
18118c2ecf20Sopenharmony_ci				"pending FCF event:evt_tag_at_scan:x%x, "
18128c2ecf20Sopenharmony_ci				"evt_tag_current:x%x\n",
18138c2ecf20Sopenharmony_ci				phba->fcoe_eventtag_at_fcf_scan,
18148c2ecf20Sopenharmony_ci				phba->fcoe_eventtag);
18158c2ecf20Sopenharmony_ci		lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST);
18168c2ecf20Sopenharmony_ci	} else {
18178c2ecf20Sopenharmony_ci		/*
18188c2ecf20Sopenharmony_ci		 * Do not continue FCF discovery and clear FCF_TS_INPROG
18198c2ecf20Sopenharmony_ci		 * flag
18208c2ecf20Sopenharmony_ci		 */
18218c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
18228c2ecf20Sopenharmony_ci				"2833 Stop FCF discovery process due to link "
18238c2ecf20Sopenharmony_ci				"state change (x%x)\n", phba->link_state);
18248c2ecf20Sopenharmony_ci		spin_lock_irq(&phba->hbalock);
18258c2ecf20Sopenharmony_ci		phba->hba_flag &= ~(FCF_TS_INPROG | FCF_RR_INPROG);
18268c2ecf20Sopenharmony_ci		phba->fcf.fcf_flag &= ~(FCF_REDISC_FOV | FCF_DISCOVERY);
18278c2ecf20Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
18288c2ecf20Sopenharmony_ci	}
18298c2ecf20Sopenharmony_ci
18308c2ecf20Sopenharmony_ci	/* Unregister the currently registered FCF if required */
18318c2ecf20Sopenharmony_ci	if (unreg_fcf) {
18328c2ecf20Sopenharmony_ci		spin_lock_irq(&phba->hbalock);
18338c2ecf20Sopenharmony_ci		phba->fcf.fcf_flag &= ~FCF_REGISTERED;
18348c2ecf20Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
18358c2ecf20Sopenharmony_ci		lpfc_sli4_unregister_fcf(phba);
18368c2ecf20Sopenharmony_ci	}
18378c2ecf20Sopenharmony_ci	return 1;
18388c2ecf20Sopenharmony_ci}
18398c2ecf20Sopenharmony_ci
18408c2ecf20Sopenharmony_ci/**
18418c2ecf20Sopenharmony_ci * lpfc_sli4_new_fcf_random_select - Randomly select an eligible new fcf record
18428c2ecf20Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
18438c2ecf20Sopenharmony_ci * @fcf_cnt: number of eligible fcf record seen so far.
18448c2ecf20Sopenharmony_ci *
18458c2ecf20Sopenharmony_ci * This function makes an running random selection decision on FCF record to
18468c2ecf20Sopenharmony_ci * use through a sequence of @fcf_cnt eligible FCF records with equal
18478c2ecf20Sopenharmony_ci * probability. To perform integer manunipulation of random numbers with
18488c2ecf20Sopenharmony_ci * size unit32_t, the lower 16 bits of the 32-bit random number returned
18498c2ecf20Sopenharmony_ci * from prandom_u32() are taken as the random random number generated.
18508c2ecf20Sopenharmony_ci *
18518c2ecf20Sopenharmony_ci * Returns true when outcome is for the newly read FCF record should be
18528c2ecf20Sopenharmony_ci * chosen; otherwise, return false when outcome is for keeping the previously
18538c2ecf20Sopenharmony_ci * chosen FCF record.
18548c2ecf20Sopenharmony_ci **/
18558c2ecf20Sopenharmony_cistatic bool
18568c2ecf20Sopenharmony_cilpfc_sli4_new_fcf_random_select(struct lpfc_hba *phba, uint32_t fcf_cnt)
18578c2ecf20Sopenharmony_ci{
18588c2ecf20Sopenharmony_ci	uint32_t rand_num;
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_ci	/* Get 16-bit uniform random number */
18618c2ecf20Sopenharmony_ci	rand_num = 0xFFFF & prandom_u32();
18628c2ecf20Sopenharmony_ci
18638c2ecf20Sopenharmony_ci	/* Decision with probability 1/fcf_cnt */
18648c2ecf20Sopenharmony_ci	if ((fcf_cnt * rand_num) < 0xFFFF)
18658c2ecf20Sopenharmony_ci		return true;
18668c2ecf20Sopenharmony_ci	else
18678c2ecf20Sopenharmony_ci		return false;
18688c2ecf20Sopenharmony_ci}
18698c2ecf20Sopenharmony_ci
18708c2ecf20Sopenharmony_ci/**
18718c2ecf20Sopenharmony_ci * lpfc_sli4_fcf_rec_mbox_parse - Parse read_fcf mbox command.
18728c2ecf20Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
18738c2ecf20Sopenharmony_ci * @mboxq: pointer to mailbox object.
18748c2ecf20Sopenharmony_ci * @next_fcf_index: pointer to holder of next fcf index.
18758c2ecf20Sopenharmony_ci *
18768c2ecf20Sopenharmony_ci * This routine parses the non-embedded fcf mailbox command by performing the
18778c2ecf20Sopenharmony_ci * necessarily error checking, non-embedded read FCF record mailbox command
18788c2ecf20Sopenharmony_ci * SGE parsing, and endianness swapping.
18798c2ecf20Sopenharmony_ci *
18808c2ecf20Sopenharmony_ci * Returns the pointer to the new FCF record in the non-embedded mailbox
18818c2ecf20Sopenharmony_ci * command DMA memory if successfully, other NULL.
18828c2ecf20Sopenharmony_ci */
18838c2ecf20Sopenharmony_cistatic struct fcf_record *
18848c2ecf20Sopenharmony_cilpfc_sli4_fcf_rec_mbox_parse(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
18858c2ecf20Sopenharmony_ci			     uint16_t *next_fcf_index)
18868c2ecf20Sopenharmony_ci{
18878c2ecf20Sopenharmony_ci	void *virt_addr;
18888c2ecf20Sopenharmony_ci	struct lpfc_mbx_sge sge;
18898c2ecf20Sopenharmony_ci	struct lpfc_mbx_read_fcf_tbl *read_fcf;
18908c2ecf20Sopenharmony_ci	uint32_t shdr_status, shdr_add_status, if_type;
18918c2ecf20Sopenharmony_ci	union lpfc_sli4_cfg_shdr *shdr;
18928c2ecf20Sopenharmony_ci	struct fcf_record *new_fcf_record;
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci	/* Get the first SGE entry from the non-embedded DMA memory. This
18958c2ecf20Sopenharmony_ci	 * routine only uses a single SGE.
18968c2ecf20Sopenharmony_ci	 */
18978c2ecf20Sopenharmony_ci	lpfc_sli4_mbx_sge_get(mboxq, 0, &sge);
18988c2ecf20Sopenharmony_ci	if (unlikely(!mboxq->sge_array)) {
18998c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
19008c2ecf20Sopenharmony_ci				"2524 Failed to get the non-embedded SGE "
19018c2ecf20Sopenharmony_ci				"virtual address\n");
19028c2ecf20Sopenharmony_ci		return NULL;
19038c2ecf20Sopenharmony_ci	}
19048c2ecf20Sopenharmony_ci	virt_addr = mboxq->sge_array->addr[0];
19058c2ecf20Sopenharmony_ci
19068c2ecf20Sopenharmony_ci	shdr = (union lpfc_sli4_cfg_shdr *)virt_addr;
19078c2ecf20Sopenharmony_ci	lpfc_sli_pcimem_bcopy(shdr, shdr,
19088c2ecf20Sopenharmony_ci			      sizeof(union lpfc_sli4_cfg_shdr));
19098c2ecf20Sopenharmony_ci	shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
19108c2ecf20Sopenharmony_ci	if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf);
19118c2ecf20Sopenharmony_ci	shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
19128c2ecf20Sopenharmony_ci	if (shdr_status || shdr_add_status) {
19138c2ecf20Sopenharmony_ci		if (shdr_status == STATUS_FCF_TABLE_EMPTY ||
19148c2ecf20Sopenharmony_ci					if_type == LPFC_SLI_INTF_IF_TYPE_2)
19158c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR,
19168c2ecf20Sopenharmony_ci					LOG_TRACE_EVENT,
19178c2ecf20Sopenharmony_ci					"2726 READ_FCF_RECORD Indicates empty "
19188c2ecf20Sopenharmony_ci					"FCF table.\n");
19198c2ecf20Sopenharmony_ci		else
19208c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
19218c2ecf20Sopenharmony_ci					"2521 READ_FCF_RECORD mailbox failed "
19228c2ecf20Sopenharmony_ci					"with status x%x add_status x%x, "
19238c2ecf20Sopenharmony_ci					"mbx\n", shdr_status, shdr_add_status);
19248c2ecf20Sopenharmony_ci		return NULL;
19258c2ecf20Sopenharmony_ci	}
19268c2ecf20Sopenharmony_ci
19278c2ecf20Sopenharmony_ci	/* Interpreting the returned information of the FCF record */
19288c2ecf20Sopenharmony_ci	read_fcf = (struct lpfc_mbx_read_fcf_tbl *)virt_addr;
19298c2ecf20Sopenharmony_ci	lpfc_sli_pcimem_bcopy(read_fcf, read_fcf,
19308c2ecf20Sopenharmony_ci			      sizeof(struct lpfc_mbx_read_fcf_tbl));
19318c2ecf20Sopenharmony_ci	*next_fcf_index = bf_get(lpfc_mbx_read_fcf_tbl_nxt_vindx, read_fcf);
19328c2ecf20Sopenharmony_ci	new_fcf_record = (struct fcf_record *)(virt_addr +
19338c2ecf20Sopenharmony_ci			  sizeof(struct lpfc_mbx_read_fcf_tbl));
19348c2ecf20Sopenharmony_ci	lpfc_sli_pcimem_bcopy(new_fcf_record, new_fcf_record,
19358c2ecf20Sopenharmony_ci				offsetof(struct fcf_record, vlan_bitmap));
19368c2ecf20Sopenharmony_ci	new_fcf_record->word137 = le32_to_cpu(new_fcf_record->word137);
19378c2ecf20Sopenharmony_ci	new_fcf_record->word138 = le32_to_cpu(new_fcf_record->word138);
19388c2ecf20Sopenharmony_ci
19398c2ecf20Sopenharmony_ci	return new_fcf_record;
19408c2ecf20Sopenharmony_ci}
19418c2ecf20Sopenharmony_ci
19428c2ecf20Sopenharmony_ci/**
19438c2ecf20Sopenharmony_ci * lpfc_sli4_log_fcf_record_info - Log the information of a fcf record
19448c2ecf20Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
19458c2ecf20Sopenharmony_ci * @fcf_record: pointer to the fcf record.
19468c2ecf20Sopenharmony_ci * @vlan_id: the lowest vlan identifier associated to this fcf record.
19478c2ecf20Sopenharmony_ci * @next_fcf_index: the index to the next fcf record in hba's fcf table.
19488c2ecf20Sopenharmony_ci *
19498c2ecf20Sopenharmony_ci * This routine logs the detailed FCF record if the LOG_FIP loggin is
19508c2ecf20Sopenharmony_ci * enabled.
19518c2ecf20Sopenharmony_ci **/
19528c2ecf20Sopenharmony_cistatic void
19538c2ecf20Sopenharmony_cilpfc_sli4_log_fcf_record_info(struct lpfc_hba *phba,
19548c2ecf20Sopenharmony_ci			      struct fcf_record *fcf_record,
19558c2ecf20Sopenharmony_ci			      uint16_t vlan_id,
19568c2ecf20Sopenharmony_ci			      uint16_t next_fcf_index)
19578c2ecf20Sopenharmony_ci{
19588c2ecf20Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
19598c2ecf20Sopenharmony_ci			"2764 READ_FCF_RECORD:\n"
19608c2ecf20Sopenharmony_ci			"\tFCF_Index     : x%x\n"
19618c2ecf20Sopenharmony_ci			"\tFCF_Avail     : x%x\n"
19628c2ecf20Sopenharmony_ci			"\tFCF_Valid     : x%x\n"
19638c2ecf20Sopenharmony_ci			"\tFCF_SOL       : x%x\n"
19648c2ecf20Sopenharmony_ci			"\tFIP_Priority  : x%x\n"
19658c2ecf20Sopenharmony_ci			"\tMAC_Provider  : x%x\n"
19668c2ecf20Sopenharmony_ci			"\tLowest VLANID : x%x\n"
19678c2ecf20Sopenharmony_ci			"\tFCF_MAC Addr  : x%x:%x:%x:%x:%x:%x\n"
19688c2ecf20Sopenharmony_ci			"\tFabric_Name   : x%x:%x:%x:%x:%x:%x:%x:%x\n"
19698c2ecf20Sopenharmony_ci			"\tSwitch_Name   : x%x:%x:%x:%x:%x:%x:%x:%x\n"
19708c2ecf20Sopenharmony_ci			"\tNext_FCF_Index: x%x\n",
19718c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_fcf_index, fcf_record),
19728c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_fcf_avail, fcf_record),
19738c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_fcf_valid, fcf_record),
19748c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_fcf_sol, fcf_record),
19758c2ecf20Sopenharmony_ci			fcf_record->fip_priority,
19768c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_mac_addr_prov, fcf_record),
19778c2ecf20Sopenharmony_ci			vlan_id,
19788c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_mac_0, fcf_record),
19798c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_mac_1, fcf_record),
19808c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_mac_2, fcf_record),
19818c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_mac_3, fcf_record),
19828c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_mac_4, fcf_record),
19838c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_mac_5, fcf_record),
19848c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_fab_name_0, fcf_record),
19858c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_fab_name_1, fcf_record),
19868c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_fab_name_2, fcf_record),
19878c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_fab_name_3, fcf_record),
19888c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_fab_name_4, fcf_record),
19898c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_fab_name_5, fcf_record),
19908c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_fab_name_6, fcf_record),
19918c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_fab_name_7, fcf_record),
19928c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_switch_name_0, fcf_record),
19938c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_switch_name_1, fcf_record),
19948c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_switch_name_2, fcf_record),
19958c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_switch_name_3, fcf_record),
19968c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_switch_name_4, fcf_record),
19978c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_switch_name_5, fcf_record),
19988c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_switch_name_6, fcf_record),
19998c2ecf20Sopenharmony_ci			bf_get(lpfc_fcf_record_switch_name_7, fcf_record),
20008c2ecf20Sopenharmony_ci			next_fcf_index);
20018c2ecf20Sopenharmony_ci}
20028c2ecf20Sopenharmony_ci
20038c2ecf20Sopenharmony_ci/**
20048c2ecf20Sopenharmony_ci * lpfc_sli4_fcf_record_match - testing new FCF record for matching existing FCF
20058c2ecf20Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
20068c2ecf20Sopenharmony_ci * @fcf_rec: pointer to an existing FCF record.
20078c2ecf20Sopenharmony_ci * @new_fcf_record: pointer to a new FCF record.
20088c2ecf20Sopenharmony_ci * @new_vlan_id: vlan id from the new FCF record.
20098c2ecf20Sopenharmony_ci *
20108c2ecf20Sopenharmony_ci * This function performs matching test of a new FCF record against an existing
20118c2ecf20Sopenharmony_ci * FCF record. If the new_vlan_id passed in is LPFC_FCOE_IGNORE_VID, vlan id
20128c2ecf20Sopenharmony_ci * will not be used as part of the FCF record matching criteria.
20138c2ecf20Sopenharmony_ci *
20148c2ecf20Sopenharmony_ci * Returns true if all the fields matching, otherwise returns false.
20158c2ecf20Sopenharmony_ci */
20168c2ecf20Sopenharmony_cistatic bool
20178c2ecf20Sopenharmony_cilpfc_sli4_fcf_record_match(struct lpfc_hba *phba,
20188c2ecf20Sopenharmony_ci			   struct lpfc_fcf_rec *fcf_rec,
20198c2ecf20Sopenharmony_ci			   struct fcf_record *new_fcf_record,
20208c2ecf20Sopenharmony_ci			   uint16_t new_vlan_id)
20218c2ecf20Sopenharmony_ci{
20228c2ecf20Sopenharmony_ci	if (new_vlan_id != LPFC_FCOE_IGNORE_VID)
20238c2ecf20Sopenharmony_ci		if (!lpfc_vlan_id_match(fcf_rec->vlan_id, new_vlan_id))
20248c2ecf20Sopenharmony_ci			return false;
20258c2ecf20Sopenharmony_ci	if (!lpfc_mac_addr_match(fcf_rec->mac_addr, new_fcf_record))
20268c2ecf20Sopenharmony_ci		return false;
20278c2ecf20Sopenharmony_ci	if (!lpfc_sw_name_match(fcf_rec->switch_name, new_fcf_record))
20288c2ecf20Sopenharmony_ci		return false;
20298c2ecf20Sopenharmony_ci	if (!lpfc_fab_name_match(fcf_rec->fabric_name, new_fcf_record))
20308c2ecf20Sopenharmony_ci		return false;
20318c2ecf20Sopenharmony_ci	if (fcf_rec->priority != new_fcf_record->fip_priority)
20328c2ecf20Sopenharmony_ci		return false;
20338c2ecf20Sopenharmony_ci	return true;
20348c2ecf20Sopenharmony_ci}
20358c2ecf20Sopenharmony_ci
20368c2ecf20Sopenharmony_ci/**
20378c2ecf20Sopenharmony_ci * lpfc_sli4_fcf_rr_next_proc - processing next roundrobin fcf
20388c2ecf20Sopenharmony_ci * @vport: Pointer to vport object.
20398c2ecf20Sopenharmony_ci * @fcf_index: index to next fcf.
20408c2ecf20Sopenharmony_ci *
20418c2ecf20Sopenharmony_ci * This function processing the roundrobin fcf failover to next fcf index.
20428c2ecf20Sopenharmony_ci * When this function is invoked, there will be a current fcf registered
20438c2ecf20Sopenharmony_ci * for flogi.
20448c2ecf20Sopenharmony_ci * Return: 0 for continue retrying flogi on currently registered fcf;
20458c2ecf20Sopenharmony_ci *         1 for stop flogi on currently registered fcf;
20468c2ecf20Sopenharmony_ci */
20478c2ecf20Sopenharmony_ciint lpfc_sli4_fcf_rr_next_proc(struct lpfc_vport *vport, uint16_t fcf_index)
20488c2ecf20Sopenharmony_ci{
20498c2ecf20Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
20508c2ecf20Sopenharmony_ci	int rc;
20518c2ecf20Sopenharmony_ci
20528c2ecf20Sopenharmony_ci	if (fcf_index == LPFC_FCOE_FCF_NEXT_NONE) {
20538c2ecf20Sopenharmony_ci		spin_lock_irq(&phba->hbalock);
20548c2ecf20Sopenharmony_ci		if (phba->hba_flag & HBA_DEVLOSS_TMO) {
20558c2ecf20Sopenharmony_ci			spin_unlock_irq(&phba->hbalock);
20568c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
20578c2ecf20Sopenharmony_ci					"2872 Devloss tmo with no eligible "
20588c2ecf20Sopenharmony_ci					"FCF, unregister in-use FCF (x%x) "
20598c2ecf20Sopenharmony_ci					"and rescan FCF table\n",
20608c2ecf20Sopenharmony_ci					phba->fcf.current_rec.fcf_indx);
20618c2ecf20Sopenharmony_ci			lpfc_unregister_fcf_rescan(phba);
20628c2ecf20Sopenharmony_ci			goto stop_flogi_current_fcf;
20638c2ecf20Sopenharmony_ci		}
20648c2ecf20Sopenharmony_ci		/* Mark the end to FLOGI roundrobin failover */
20658c2ecf20Sopenharmony_ci		phba->hba_flag &= ~FCF_RR_INPROG;
20668c2ecf20Sopenharmony_ci		/* Allow action to new fcf asynchronous event */
20678c2ecf20Sopenharmony_ci		phba->fcf.fcf_flag &= ~(FCF_AVAILABLE | FCF_SCAN_DONE);
20688c2ecf20Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
20698c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
20708c2ecf20Sopenharmony_ci				"2865 No FCF available, stop roundrobin FCF "
20718c2ecf20Sopenharmony_ci				"failover and change port state:x%x/x%x\n",
20728c2ecf20Sopenharmony_ci				phba->pport->port_state, LPFC_VPORT_UNKNOWN);
20738c2ecf20Sopenharmony_ci		phba->pport->port_state = LPFC_VPORT_UNKNOWN;
20748c2ecf20Sopenharmony_ci
20758c2ecf20Sopenharmony_ci		if (!phba->fcf.fcf_redisc_attempted) {
20768c2ecf20Sopenharmony_ci			lpfc_unregister_fcf(phba);
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_ci			rc = lpfc_sli4_redisc_fcf_table(phba);
20798c2ecf20Sopenharmony_ci			if (!rc) {
20808c2ecf20Sopenharmony_ci				lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
20818c2ecf20Sopenharmony_ci						"3195 Rediscover FCF table\n");
20828c2ecf20Sopenharmony_ci				phba->fcf.fcf_redisc_attempted = 1;
20838c2ecf20Sopenharmony_ci				lpfc_sli4_clear_fcf_rr_bmask(phba);
20848c2ecf20Sopenharmony_ci			} else {
20858c2ecf20Sopenharmony_ci				lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
20868c2ecf20Sopenharmony_ci						"3196 Rediscover FCF table "
20878c2ecf20Sopenharmony_ci						"failed. Status:x%x\n", rc);
20888c2ecf20Sopenharmony_ci			}
20898c2ecf20Sopenharmony_ci		} else {
20908c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
20918c2ecf20Sopenharmony_ci					"3197 Already rediscover FCF table "
20928c2ecf20Sopenharmony_ci					"attempted. No more retry\n");
20938c2ecf20Sopenharmony_ci		}
20948c2ecf20Sopenharmony_ci		goto stop_flogi_current_fcf;
20958c2ecf20Sopenharmony_ci	} else {
20968c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_ELS,
20978c2ecf20Sopenharmony_ci				"2794 Try FLOGI roundrobin FCF failover to "
20988c2ecf20Sopenharmony_ci				"(x%x)\n", fcf_index);
20998c2ecf20Sopenharmony_ci		rc = lpfc_sli4_fcf_rr_read_fcf_rec(phba, fcf_index);
21008c2ecf20Sopenharmony_ci		if (rc)
21018c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | LOG_ELS,
21028c2ecf20Sopenharmony_ci					"2761 FLOGI roundrobin FCF failover "
21038c2ecf20Sopenharmony_ci					"failed (rc:x%x) to read FCF (x%x)\n",
21048c2ecf20Sopenharmony_ci					rc, phba->fcf.current_rec.fcf_indx);
21058c2ecf20Sopenharmony_ci		else
21068c2ecf20Sopenharmony_ci			goto stop_flogi_current_fcf;
21078c2ecf20Sopenharmony_ci	}
21088c2ecf20Sopenharmony_ci	return 0;
21098c2ecf20Sopenharmony_ci
21108c2ecf20Sopenharmony_cistop_flogi_current_fcf:
21118c2ecf20Sopenharmony_ci	lpfc_can_disctmo(vport);
21128c2ecf20Sopenharmony_ci	return 1;
21138c2ecf20Sopenharmony_ci}
21148c2ecf20Sopenharmony_ci
21158c2ecf20Sopenharmony_ci/**
21168c2ecf20Sopenharmony_ci * lpfc_sli4_fcf_pri_list_del
21178c2ecf20Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
21188c2ecf20Sopenharmony_ci * @fcf_index: the index of the fcf record to delete
21198c2ecf20Sopenharmony_ci * This routine checks the on list flag of the fcf_index to be deleted.
21208c2ecf20Sopenharmony_ci * If it is one the list then it is removed from the list, and the flag
21218c2ecf20Sopenharmony_ci * is cleared. This routine grab the hbalock before removing the fcf
21228c2ecf20Sopenharmony_ci * record from the list.
21238c2ecf20Sopenharmony_ci **/
21248c2ecf20Sopenharmony_cistatic void lpfc_sli4_fcf_pri_list_del(struct lpfc_hba *phba,
21258c2ecf20Sopenharmony_ci			uint16_t fcf_index)
21268c2ecf20Sopenharmony_ci{
21278c2ecf20Sopenharmony_ci	struct lpfc_fcf_pri *new_fcf_pri;
21288c2ecf20Sopenharmony_ci
21298c2ecf20Sopenharmony_ci	new_fcf_pri = &phba->fcf.fcf_pri[fcf_index];
21308c2ecf20Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
21318c2ecf20Sopenharmony_ci		"3058 deleting idx x%x pri x%x flg x%x\n",
21328c2ecf20Sopenharmony_ci		fcf_index, new_fcf_pri->fcf_rec.priority,
21338c2ecf20Sopenharmony_ci		 new_fcf_pri->fcf_rec.flag);
21348c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
21358c2ecf20Sopenharmony_ci	if (new_fcf_pri->fcf_rec.flag & LPFC_FCF_ON_PRI_LIST) {
21368c2ecf20Sopenharmony_ci		if (phba->fcf.current_rec.priority ==
21378c2ecf20Sopenharmony_ci				new_fcf_pri->fcf_rec.priority)
21388c2ecf20Sopenharmony_ci			phba->fcf.eligible_fcf_cnt--;
21398c2ecf20Sopenharmony_ci		list_del_init(&new_fcf_pri->list);
21408c2ecf20Sopenharmony_ci		new_fcf_pri->fcf_rec.flag &= ~LPFC_FCF_ON_PRI_LIST;
21418c2ecf20Sopenharmony_ci	}
21428c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
21438c2ecf20Sopenharmony_ci}
21448c2ecf20Sopenharmony_ci
21458c2ecf20Sopenharmony_ci/**
21468c2ecf20Sopenharmony_ci * lpfc_sli4_set_fcf_flogi_fail
21478c2ecf20Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
21488c2ecf20Sopenharmony_ci * @fcf_index: the index of the fcf record to update
21498c2ecf20Sopenharmony_ci * This routine acquires the hbalock and then set the LPFC_FCF_FLOGI_FAILED
21508c2ecf20Sopenharmony_ci * flag so the the round robin slection for the particular priority level
21518c2ecf20Sopenharmony_ci * will try a different fcf record that does not have this bit set.
21528c2ecf20Sopenharmony_ci * If the fcf record is re-read for any reason this flag is cleared brfore
21538c2ecf20Sopenharmony_ci * adding it to the priority list.
21548c2ecf20Sopenharmony_ci **/
21558c2ecf20Sopenharmony_civoid
21568c2ecf20Sopenharmony_cilpfc_sli4_set_fcf_flogi_fail(struct lpfc_hba *phba, uint16_t fcf_index)
21578c2ecf20Sopenharmony_ci{
21588c2ecf20Sopenharmony_ci	struct lpfc_fcf_pri *new_fcf_pri;
21598c2ecf20Sopenharmony_ci	new_fcf_pri = &phba->fcf.fcf_pri[fcf_index];
21608c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
21618c2ecf20Sopenharmony_ci	new_fcf_pri->fcf_rec.flag |= LPFC_FCF_FLOGI_FAILED;
21628c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
21638c2ecf20Sopenharmony_ci}
21648c2ecf20Sopenharmony_ci
21658c2ecf20Sopenharmony_ci/**
21668c2ecf20Sopenharmony_ci * lpfc_sli4_fcf_pri_list_add
21678c2ecf20Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
21688c2ecf20Sopenharmony_ci * @fcf_index: the index of the fcf record to add
21698c2ecf20Sopenharmony_ci * @new_fcf_record: pointer to a new FCF record.
21708c2ecf20Sopenharmony_ci * This routine checks the priority of the fcf_index to be added.
21718c2ecf20Sopenharmony_ci * If it is a lower priority than the current head of the fcf_pri list
21728c2ecf20Sopenharmony_ci * then it is added to the list in the right order.
21738c2ecf20Sopenharmony_ci * If it is the same priority as the current head of the list then it
21748c2ecf20Sopenharmony_ci * is added to the head of the list and its bit in the rr_bmask is set.
21758c2ecf20Sopenharmony_ci * If the fcf_index to be added is of a higher priority than the current
21768c2ecf20Sopenharmony_ci * head of the list then the rr_bmask is cleared, its bit is set in the
21778c2ecf20Sopenharmony_ci * rr_bmask and it is added to the head of the list.
21788c2ecf20Sopenharmony_ci * returns:
21798c2ecf20Sopenharmony_ci * 0=success 1=failure
21808c2ecf20Sopenharmony_ci **/
21818c2ecf20Sopenharmony_cistatic int lpfc_sli4_fcf_pri_list_add(struct lpfc_hba *phba,
21828c2ecf20Sopenharmony_ci	uint16_t fcf_index,
21838c2ecf20Sopenharmony_ci	struct fcf_record *new_fcf_record)
21848c2ecf20Sopenharmony_ci{
21858c2ecf20Sopenharmony_ci	uint16_t current_fcf_pri;
21868c2ecf20Sopenharmony_ci	uint16_t last_index;
21878c2ecf20Sopenharmony_ci	struct lpfc_fcf_pri *fcf_pri;
21888c2ecf20Sopenharmony_ci	struct lpfc_fcf_pri *next_fcf_pri;
21898c2ecf20Sopenharmony_ci	struct lpfc_fcf_pri *new_fcf_pri;
21908c2ecf20Sopenharmony_ci	int ret;
21918c2ecf20Sopenharmony_ci
21928c2ecf20Sopenharmony_ci	new_fcf_pri = &phba->fcf.fcf_pri[fcf_index];
21938c2ecf20Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
21948c2ecf20Sopenharmony_ci		"3059 adding idx x%x pri x%x flg x%x\n",
21958c2ecf20Sopenharmony_ci		fcf_index, new_fcf_record->fip_priority,
21968c2ecf20Sopenharmony_ci		 new_fcf_pri->fcf_rec.flag);
21978c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
21988c2ecf20Sopenharmony_ci	if (new_fcf_pri->fcf_rec.flag & LPFC_FCF_ON_PRI_LIST)
21998c2ecf20Sopenharmony_ci		list_del_init(&new_fcf_pri->list);
22008c2ecf20Sopenharmony_ci	new_fcf_pri->fcf_rec.fcf_index = fcf_index;
22018c2ecf20Sopenharmony_ci	new_fcf_pri->fcf_rec.priority = new_fcf_record->fip_priority;
22028c2ecf20Sopenharmony_ci	if (list_empty(&phba->fcf.fcf_pri_list)) {
22038c2ecf20Sopenharmony_ci		list_add(&new_fcf_pri->list, &phba->fcf.fcf_pri_list);
22048c2ecf20Sopenharmony_ci		ret = lpfc_sli4_fcf_rr_index_set(phba,
22058c2ecf20Sopenharmony_ci				new_fcf_pri->fcf_rec.fcf_index);
22068c2ecf20Sopenharmony_ci		goto out;
22078c2ecf20Sopenharmony_ci	}
22088c2ecf20Sopenharmony_ci
22098c2ecf20Sopenharmony_ci	last_index = find_first_bit(phba->fcf.fcf_rr_bmask,
22108c2ecf20Sopenharmony_ci				LPFC_SLI4_FCF_TBL_INDX_MAX);
22118c2ecf20Sopenharmony_ci	if (last_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
22128c2ecf20Sopenharmony_ci		ret = 0; /* Empty rr list */
22138c2ecf20Sopenharmony_ci		goto out;
22148c2ecf20Sopenharmony_ci	}
22158c2ecf20Sopenharmony_ci	current_fcf_pri = phba->fcf.fcf_pri[last_index].fcf_rec.priority;
22168c2ecf20Sopenharmony_ci	if (new_fcf_pri->fcf_rec.priority <=  current_fcf_pri) {
22178c2ecf20Sopenharmony_ci		list_add(&new_fcf_pri->list, &phba->fcf.fcf_pri_list);
22188c2ecf20Sopenharmony_ci		if (new_fcf_pri->fcf_rec.priority <  current_fcf_pri) {
22198c2ecf20Sopenharmony_ci			memset(phba->fcf.fcf_rr_bmask, 0,
22208c2ecf20Sopenharmony_ci				sizeof(*phba->fcf.fcf_rr_bmask));
22218c2ecf20Sopenharmony_ci			/* fcfs_at_this_priority_level = 1; */
22228c2ecf20Sopenharmony_ci			phba->fcf.eligible_fcf_cnt = 1;
22238c2ecf20Sopenharmony_ci		} else
22248c2ecf20Sopenharmony_ci			/* fcfs_at_this_priority_level++; */
22258c2ecf20Sopenharmony_ci			phba->fcf.eligible_fcf_cnt++;
22268c2ecf20Sopenharmony_ci		ret = lpfc_sli4_fcf_rr_index_set(phba,
22278c2ecf20Sopenharmony_ci				new_fcf_pri->fcf_rec.fcf_index);
22288c2ecf20Sopenharmony_ci		goto out;
22298c2ecf20Sopenharmony_ci	}
22308c2ecf20Sopenharmony_ci
22318c2ecf20Sopenharmony_ci	list_for_each_entry_safe(fcf_pri, next_fcf_pri,
22328c2ecf20Sopenharmony_ci				&phba->fcf.fcf_pri_list, list) {
22338c2ecf20Sopenharmony_ci		if (new_fcf_pri->fcf_rec.priority <=
22348c2ecf20Sopenharmony_ci				fcf_pri->fcf_rec.priority) {
22358c2ecf20Sopenharmony_ci			if (fcf_pri->list.prev == &phba->fcf.fcf_pri_list)
22368c2ecf20Sopenharmony_ci				list_add(&new_fcf_pri->list,
22378c2ecf20Sopenharmony_ci						&phba->fcf.fcf_pri_list);
22388c2ecf20Sopenharmony_ci			else
22398c2ecf20Sopenharmony_ci				list_add(&new_fcf_pri->list,
22408c2ecf20Sopenharmony_ci					 &((struct lpfc_fcf_pri *)
22418c2ecf20Sopenharmony_ci					fcf_pri->list.prev)->list);
22428c2ecf20Sopenharmony_ci			ret = 0;
22438c2ecf20Sopenharmony_ci			goto out;
22448c2ecf20Sopenharmony_ci		} else if (fcf_pri->list.next == &phba->fcf.fcf_pri_list
22458c2ecf20Sopenharmony_ci			|| new_fcf_pri->fcf_rec.priority <
22468c2ecf20Sopenharmony_ci				next_fcf_pri->fcf_rec.priority) {
22478c2ecf20Sopenharmony_ci			list_add(&new_fcf_pri->list, &fcf_pri->list);
22488c2ecf20Sopenharmony_ci			ret = 0;
22498c2ecf20Sopenharmony_ci			goto out;
22508c2ecf20Sopenharmony_ci		}
22518c2ecf20Sopenharmony_ci		if (new_fcf_pri->fcf_rec.priority > fcf_pri->fcf_rec.priority)
22528c2ecf20Sopenharmony_ci			continue;
22538c2ecf20Sopenharmony_ci
22548c2ecf20Sopenharmony_ci	}
22558c2ecf20Sopenharmony_ci	ret = 1;
22568c2ecf20Sopenharmony_ciout:
22578c2ecf20Sopenharmony_ci	/* we use = instead of |= to clear the FLOGI_FAILED flag. */
22588c2ecf20Sopenharmony_ci	new_fcf_pri->fcf_rec.flag = LPFC_FCF_ON_PRI_LIST;
22598c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
22608c2ecf20Sopenharmony_ci	return ret;
22618c2ecf20Sopenharmony_ci}
22628c2ecf20Sopenharmony_ci
22638c2ecf20Sopenharmony_ci/**
22648c2ecf20Sopenharmony_ci * lpfc_mbx_cmpl_fcf_scan_read_fcf_rec - fcf scan read_fcf mbox cmpl handler.
22658c2ecf20Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
22668c2ecf20Sopenharmony_ci * @mboxq: pointer to mailbox object.
22678c2ecf20Sopenharmony_ci *
22688c2ecf20Sopenharmony_ci * This function iterates through all the fcf records available in
22698c2ecf20Sopenharmony_ci * HBA and chooses the optimal FCF record for discovery. After finding
22708c2ecf20Sopenharmony_ci * the FCF for discovery it registers the FCF record and kicks start
22718c2ecf20Sopenharmony_ci * discovery.
22728c2ecf20Sopenharmony_ci * If FCF_IN_USE flag is set in currently used FCF, the routine tries to
22738c2ecf20Sopenharmony_ci * use an FCF record which matches fabric name and mac address of the
22748c2ecf20Sopenharmony_ci * currently used FCF record.
22758c2ecf20Sopenharmony_ci * If the driver supports only one FCF, it will try to use the FCF record
22768c2ecf20Sopenharmony_ci * used by BOOT_BIOS.
22778c2ecf20Sopenharmony_ci */
22788c2ecf20Sopenharmony_civoid
22798c2ecf20Sopenharmony_cilpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
22808c2ecf20Sopenharmony_ci{
22818c2ecf20Sopenharmony_ci	struct fcf_record *new_fcf_record;
22828c2ecf20Sopenharmony_ci	uint32_t boot_flag, addr_mode;
22838c2ecf20Sopenharmony_ci	uint16_t fcf_index, next_fcf_index;
22848c2ecf20Sopenharmony_ci	struct lpfc_fcf_rec *fcf_rec = NULL;
22858c2ecf20Sopenharmony_ci	uint16_t vlan_id = LPFC_FCOE_NULL_VID;
22868c2ecf20Sopenharmony_ci	bool select_new_fcf;
22878c2ecf20Sopenharmony_ci	int rc;
22888c2ecf20Sopenharmony_ci
22898c2ecf20Sopenharmony_ci	/* If there is pending FCoE event restart FCF table scan */
22908c2ecf20Sopenharmony_ci	if (lpfc_check_pending_fcoe_event(phba, LPFC_SKIP_UNREG_FCF)) {
22918c2ecf20Sopenharmony_ci		lpfc_sli4_mbox_cmd_free(phba, mboxq);
22928c2ecf20Sopenharmony_ci		return;
22938c2ecf20Sopenharmony_ci	}
22948c2ecf20Sopenharmony_ci
22958c2ecf20Sopenharmony_ci	/* Parse the FCF record from the non-embedded mailbox command */
22968c2ecf20Sopenharmony_ci	new_fcf_record = lpfc_sli4_fcf_rec_mbox_parse(phba, mboxq,
22978c2ecf20Sopenharmony_ci						      &next_fcf_index);
22988c2ecf20Sopenharmony_ci	if (!new_fcf_record) {
22998c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
23008c2ecf20Sopenharmony_ci				"2765 Mailbox command READ_FCF_RECORD "
23018c2ecf20Sopenharmony_ci				"failed to retrieve a FCF record.\n");
23028c2ecf20Sopenharmony_ci		/* Let next new FCF event trigger fast failover */
23038c2ecf20Sopenharmony_ci		spin_lock_irq(&phba->hbalock);
23048c2ecf20Sopenharmony_ci		phba->hba_flag &= ~FCF_TS_INPROG;
23058c2ecf20Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
23068c2ecf20Sopenharmony_ci		lpfc_sli4_mbox_cmd_free(phba, mboxq);
23078c2ecf20Sopenharmony_ci		return;
23088c2ecf20Sopenharmony_ci	}
23098c2ecf20Sopenharmony_ci
23108c2ecf20Sopenharmony_ci	/* Check the FCF record against the connection list */
23118c2ecf20Sopenharmony_ci	rc = lpfc_match_fcf_conn_list(phba, new_fcf_record, &boot_flag,
23128c2ecf20Sopenharmony_ci				      &addr_mode, &vlan_id);
23138c2ecf20Sopenharmony_ci
23148c2ecf20Sopenharmony_ci	/* Log the FCF record information if turned on */
23158c2ecf20Sopenharmony_ci	lpfc_sli4_log_fcf_record_info(phba, new_fcf_record, vlan_id,
23168c2ecf20Sopenharmony_ci				      next_fcf_index);
23178c2ecf20Sopenharmony_ci
23188c2ecf20Sopenharmony_ci	/*
23198c2ecf20Sopenharmony_ci	 * If the fcf record does not match with connect list entries
23208c2ecf20Sopenharmony_ci	 * read the next entry; otherwise, this is an eligible FCF
23218c2ecf20Sopenharmony_ci	 * record for roundrobin FCF failover.
23228c2ecf20Sopenharmony_ci	 */
23238c2ecf20Sopenharmony_ci	if (!rc) {
23248c2ecf20Sopenharmony_ci		lpfc_sli4_fcf_pri_list_del(phba,
23258c2ecf20Sopenharmony_ci					bf_get(lpfc_fcf_record_fcf_index,
23268c2ecf20Sopenharmony_ci					       new_fcf_record));
23278c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
23288c2ecf20Sopenharmony_ci				"2781 FCF (x%x) failed connection "
23298c2ecf20Sopenharmony_ci				"list check: (x%x/x%x/%x)\n",
23308c2ecf20Sopenharmony_ci				bf_get(lpfc_fcf_record_fcf_index,
23318c2ecf20Sopenharmony_ci				       new_fcf_record),
23328c2ecf20Sopenharmony_ci				bf_get(lpfc_fcf_record_fcf_avail,
23338c2ecf20Sopenharmony_ci				       new_fcf_record),
23348c2ecf20Sopenharmony_ci				bf_get(lpfc_fcf_record_fcf_valid,
23358c2ecf20Sopenharmony_ci				       new_fcf_record),
23368c2ecf20Sopenharmony_ci				bf_get(lpfc_fcf_record_fcf_sol,
23378c2ecf20Sopenharmony_ci				       new_fcf_record));
23388c2ecf20Sopenharmony_ci		if ((phba->fcf.fcf_flag & FCF_IN_USE) &&
23398c2ecf20Sopenharmony_ci		    lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec,
23408c2ecf20Sopenharmony_ci		    new_fcf_record, LPFC_FCOE_IGNORE_VID)) {
23418c2ecf20Sopenharmony_ci			if (bf_get(lpfc_fcf_record_fcf_index, new_fcf_record) !=
23428c2ecf20Sopenharmony_ci			    phba->fcf.current_rec.fcf_indx) {
23438c2ecf20Sopenharmony_ci				lpfc_printf_log(phba, KERN_ERR,
23448c2ecf20Sopenharmony_ci						LOG_TRACE_EVENT,
23458c2ecf20Sopenharmony_ci					"2862 FCF (x%x) matches property "
23468c2ecf20Sopenharmony_ci					"of in-use FCF (x%x)\n",
23478c2ecf20Sopenharmony_ci					bf_get(lpfc_fcf_record_fcf_index,
23488c2ecf20Sopenharmony_ci					       new_fcf_record),
23498c2ecf20Sopenharmony_ci					phba->fcf.current_rec.fcf_indx);
23508c2ecf20Sopenharmony_ci				goto read_next_fcf;
23518c2ecf20Sopenharmony_ci			}
23528c2ecf20Sopenharmony_ci			/*
23538c2ecf20Sopenharmony_ci			 * In case the current in-use FCF record becomes
23548c2ecf20Sopenharmony_ci			 * invalid/unavailable during FCF discovery that
23558c2ecf20Sopenharmony_ci			 * was not triggered by fast FCF failover process,
23568c2ecf20Sopenharmony_ci			 * treat it as fast FCF failover.
23578c2ecf20Sopenharmony_ci			 */
23588c2ecf20Sopenharmony_ci			if (!(phba->fcf.fcf_flag & FCF_REDISC_PEND) &&
23598c2ecf20Sopenharmony_ci			    !(phba->fcf.fcf_flag & FCF_REDISC_FOV)) {
23608c2ecf20Sopenharmony_ci				lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
23618c2ecf20Sopenharmony_ci						"2835 Invalid in-use FCF "
23628c2ecf20Sopenharmony_ci						"(x%x), enter FCF failover "
23638c2ecf20Sopenharmony_ci						"table scan.\n",
23648c2ecf20Sopenharmony_ci						phba->fcf.current_rec.fcf_indx);
23658c2ecf20Sopenharmony_ci				spin_lock_irq(&phba->hbalock);
23668c2ecf20Sopenharmony_ci				phba->fcf.fcf_flag |= FCF_REDISC_FOV;
23678c2ecf20Sopenharmony_ci				spin_unlock_irq(&phba->hbalock);
23688c2ecf20Sopenharmony_ci				lpfc_sli4_mbox_cmd_free(phba, mboxq);
23698c2ecf20Sopenharmony_ci				lpfc_sli4_fcf_scan_read_fcf_rec(phba,
23708c2ecf20Sopenharmony_ci						LPFC_FCOE_FCF_GET_FIRST);
23718c2ecf20Sopenharmony_ci				return;
23728c2ecf20Sopenharmony_ci			}
23738c2ecf20Sopenharmony_ci		}
23748c2ecf20Sopenharmony_ci		goto read_next_fcf;
23758c2ecf20Sopenharmony_ci	} else {
23768c2ecf20Sopenharmony_ci		fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record);
23778c2ecf20Sopenharmony_ci		rc = lpfc_sli4_fcf_pri_list_add(phba, fcf_index,
23788c2ecf20Sopenharmony_ci							new_fcf_record);
23798c2ecf20Sopenharmony_ci		if (rc)
23808c2ecf20Sopenharmony_ci			goto read_next_fcf;
23818c2ecf20Sopenharmony_ci	}
23828c2ecf20Sopenharmony_ci
23838c2ecf20Sopenharmony_ci	/*
23848c2ecf20Sopenharmony_ci	 * If this is not the first FCF discovery of the HBA, use last
23858c2ecf20Sopenharmony_ci	 * FCF record for the discovery. The condition that a rescan
23868c2ecf20Sopenharmony_ci	 * matches the in-use FCF record: fabric name, switch name, mac
23878c2ecf20Sopenharmony_ci	 * address, and vlan_id.
23888c2ecf20Sopenharmony_ci	 */
23898c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
23908c2ecf20Sopenharmony_ci	if (phba->fcf.fcf_flag & FCF_IN_USE) {
23918c2ecf20Sopenharmony_ci		if (phba->cfg_fcf_failover_policy == LPFC_FCF_FOV &&
23928c2ecf20Sopenharmony_ci			lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec,
23938c2ecf20Sopenharmony_ci		    new_fcf_record, vlan_id)) {
23948c2ecf20Sopenharmony_ci			if (bf_get(lpfc_fcf_record_fcf_index, new_fcf_record) ==
23958c2ecf20Sopenharmony_ci			    phba->fcf.current_rec.fcf_indx) {
23968c2ecf20Sopenharmony_ci				phba->fcf.fcf_flag |= FCF_AVAILABLE;
23978c2ecf20Sopenharmony_ci				if (phba->fcf.fcf_flag & FCF_REDISC_PEND)
23988c2ecf20Sopenharmony_ci					/* Stop FCF redisc wait timer */
23998c2ecf20Sopenharmony_ci					__lpfc_sli4_stop_fcf_redisc_wait_timer(
24008c2ecf20Sopenharmony_ci									phba);
24018c2ecf20Sopenharmony_ci				else if (phba->fcf.fcf_flag & FCF_REDISC_FOV)
24028c2ecf20Sopenharmony_ci					/* Fast failover, mark completed */
24038c2ecf20Sopenharmony_ci					phba->fcf.fcf_flag &= ~FCF_REDISC_FOV;
24048c2ecf20Sopenharmony_ci				spin_unlock_irq(&phba->hbalock);
24058c2ecf20Sopenharmony_ci				lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
24068c2ecf20Sopenharmony_ci						"2836 New FCF matches in-use "
24078c2ecf20Sopenharmony_ci						"FCF (x%x), port_state:x%x, "
24088c2ecf20Sopenharmony_ci						"fc_flag:x%x\n",
24098c2ecf20Sopenharmony_ci						phba->fcf.current_rec.fcf_indx,
24108c2ecf20Sopenharmony_ci						phba->pport->port_state,
24118c2ecf20Sopenharmony_ci						phba->pport->fc_flag);
24128c2ecf20Sopenharmony_ci				goto out;
24138c2ecf20Sopenharmony_ci			} else
24148c2ecf20Sopenharmony_ci				lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
24158c2ecf20Sopenharmony_ci					"2863 New FCF (x%x) matches "
24168c2ecf20Sopenharmony_ci					"property of in-use FCF (x%x)\n",
24178c2ecf20Sopenharmony_ci					bf_get(lpfc_fcf_record_fcf_index,
24188c2ecf20Sopenharmony_ci					       new_fcf_record),
24198c2ecf20Sopenharmony_ci					phba->fcf.current_rec.fcf_indx);
24208c2ecf20Sopenharmony_ci		}
24218c2ecf20Sopenharmony_ci		/*
24228c2ecf20Sopenharmony_ci		 * Read next FCF record from HBA searching for the matching
24238c2ecf20Sopenharmony_ci		 * with in-use record only if not during the fast failover
24248c2ecf20Sopenharmony_ci		 * period. In case of fast failover period, it shall try to
24258c2ecf20Sopenharmony_ci		 * determine whether the FCF record just read should be the
24268c2ecf20Sopenharmony_ci		 * next candidate.
24278c2ecf20Sopenharmony_ci		 */
24288c2ecf20Sopenharmony_ci		if (!(phba->fcf.fcf_flag & FCF_REDISC_FOV)) {
24298c2ecf20Sopenharmony_ci			spin_unlock_irq(&phba->hbalock);
24308c2ecf20Sopenharmony_ci			goto read_next_fcf;
24318c2ecf20Sopenharmony_ci		}
24328c2ecf20Sopenharmony_ci	}
24338c2ecf20Sopenharmony_ci	/*
24348c2ecf20Sopenharmony_ci	 * Update on failover FCF record only if it's in FCF fast-failover
24358c2ecf20Sopenharmony_ci	 * period; otherwise, update on current FCF record.
24368c2ecf20Sopenharmony_ci	 */
24378c2ecf20Sopenharmony_ci	if (phba->fcf.fcf_flag & FCF_REDISC_FOV)
24388c2ecf20Sopenharmony_ci		fcf_rec = &phba->fcf.failover_rec;
24398c2ecf20Sopenharmony_ci	else
24408c2ecf20Sopenharmony_ci		fcf_rec = &phba->fcf.current_rec;
24418c2ecf20Sopenharmony_ci
24428c2ecf20Sopenharmony_ci	if (phba->fcf.fcf_flag & FCF_AVAILABLE) {
24438c2ecf20Sopenharmony_ci		/*
24448c2ecf20Sopenharmony_ci		 * If the driver FCF record does not have boot flag
24458c2ecf20Sopenharmony_ci		 * set and new hba fcf record has boot flag set, use
24468c2ecf20Sopenharmony_ci		 * the new hba fcf record.
24478c2ecf20Sopenharmony_ci		 */
24488c2ecf20Sopenharmony_ci		if (boot_flag && !(fcf_rec->flag & BOOT_ENABLE)) {
24498c2ecf20Sopenharmony_ci			/* Choose this FCF record */
24508c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
24518c2ecf20Sopenharmony_ci					"2837 Update current FCF record "
24528c2ecf20Sopenharmony_ci					"(x%x) with new FCF record (x%x)\n",
24538c2ecf20Sopenharmony_ci					fcf_rec->fcf_indx,
24548c2ecf20Sopenharmony_ci					bf_get(lpfc_fcf_record_fcf_index,
24558c2ecf20Sopenharmony_ci					new_fcf_record));
24568c2ecf20Sopenharmony_ci			__lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,
24578c2ecf20Sopenharmony_ci					addr_mode, vlan_id, BOOT_ENABLE);
24588c2ecf20Sopenharmony_ci			spin_unlock_irq(&phba->hbalock);
24598c2ecf20Sopenharmony_ci			goto read_next_fcf;
24608c2ecf20Sopenharmony_ci		}
24618c2ecf20Sopenharmony_ci		/*
24628c2ecf20Sopenharmony_ci		 * If the driver FCF record has boot flag set and the
24638c2ecf20Sopenharmony_ci		 * new hba FCF record does not have boot flag, read
24648c2ecf20Sopenharmony_ci		 * the next FCF record.
24658c2ecf20Sopenharmony_ci		 */
24668c2ecf20Sopenharmony_ci		if (!boot_flag && (fcf_rec->flag & BOOT_ENABLE)) {
24678c2ecf20Sopenharmony_ci			spin_unlock_irq(&phba->hbalock);
24688c2ecf20Sopenharmony_ci			goto read_next_fcf;
24698c2ecf20Sopenharmony_ci		}
24708c2ecf20Sopenharmony_ci		/*
24718c2ecf20Sopenharmony_ci		 * If the new hba FCF record has lower priority value
24728c2ecf20Sopenharmony_ci		 * than the driver FCF record, use the new record.
24738c2ecf20Sopenharmony_ci		 */
24748c2ecf20Sopenharmony_ci		if (new_fcf_record->fip_priority < fcf_rec->priority) {
24758c2ecf20Sopenharmony_ci			/* Choose the new FCF record with lower priority */
24768c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
24778c2ecf20Sopenharmony_ci					"2838 Update current FCF record "
24788c2ecf20Sopenharmony_ci					"(x%x) with new FCF record (x%x)\n",
24798c2ecf20Sopenharmony_ci					fcf_rec->fcf_indx,
24808c2ecf20Sopenharmony_ci					bf_get(lpfc_fcf_record_fcf_index,
24818c2ecf20Sopenharmony_ci					       new_fcf_record));
24828c2ecf20Sopenharmony_ci			__lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,
24838c2ecf20Sopenharmony_ci					addr_mode, vlan_id, 0);
24848c2ecf20Sopenharmony_ci			/* Reset running random FCF selection count */
24858c2ecf20Sopenharmony_ci			phba->fcf.eligible_fcf_cnt = 1;
24868c2ecf20Sopenharmony_ci		} else if (new_fcf_record->fip_priority == fcf_rec->priority) {
24878c2ecf20Sopenharmony_ci			/* Update running random FCF selection count */
24888c2ecf20Sopenharmony_ci			phba->fcf.eligible_fcf_cnt++;
24898c2ecf20Sopenharmony_ci			select_new_fcf = lpfc_sli4_new_fcf_random_select(phba,
24908c2ecf20Sopenharmony_ci						phba->fcf.eligible_fcf_cnt);
24918c2ecf20Sopenharmony_ci			if (select_new_fcf) {
24928c2ecf20Sopenharmony_ci				lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
24938c2ecf20Sopenharmony_ci					"2839 Update current FCF record "
24948c2ecf20Sopenharmony_ci					"(x%x) with new FCF record (x%x)\n",
24958c2ecf20Sopenharmony_ci					fcf_rec->fcf_indx,
24968c2ecf20Sopenharmony_ci					bf_get(lpfc_fcf_record_fcf_index,
24978c2ecf20Sopenharmony_ci					       new_fcf_record));
24988c2ecf20Sopenharmony_ci				/* Choose the new FCF by random selection */
24998c2ecf20Sopenharmony_ci				__lpfc_update_fcf_record(phba, fcf_rec,
25008c2ecf20Sopenharmony_ci							 new_fcf_record,
25018c2ecf20Sopenharmony_ci							 addr_mode, vlan_id, 0);
25028c2ecf20Sopenharmony_ci			}
25038c2ecf20Sopenharmony_ci		}
25048c2ecf20Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
25058c2ecf20Sopenharmony_ci		goto read_next_fcf;
25068c2ecf20Sopenharmony_ci	}
25078c2ecf20Sopenharmony_ci	/*
25088c2ecf20Sopenharmony_ci	 * This is the first suitable FCF record, choose this record for
25098c2ecf20Sopenharmony_ci	 * initial best-fit FCF.
25108c2ecf20Sopenharmony_ci	 */
25118c2ecf20Sopenharmony_ci	if (fcf_rec) {
25128c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
25138c2ecf20Sopenharmony_ci				"2840 Update initial FCF candidate "
25148c2ecf20Sopenharmony_ci				"with FCF (x%x)\n",
25158c2ecf20Sopenharmony_ci				bf_get(lpfc_fcf_record_fcf_index,
25168c2ecf20Sopenharmony_ci				       new_fcf_record));
25178c2ecf20Sopenharmony_ci		__lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,
25188c2ecf20Sopenharmony_ci					 addr_mode, vlan_id, (boot_flag ?
25198c2ecf20Sopenharmony_ci					 BOOT_ENABLE : 0));
25208c2ecf20Sopenharmony_ci		phba->fcf.fcf_flag |= FCF_AVAILABLE;
25218c2ecf20Sopenharmony_ci		/* Setup initial running random FCF selection count */
25228c2ecf20Sopenharmony_ci		phba->fcf.eligible_fcf_cnt = 1;
25238c2ecf20Sopenharmony_ci	}
25248c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
25258c2ecf20Sopenharmony_ci	goto read_next_fcf;
25268c2ecf20Sopenharmony_ci
25278c2ecf20Sopenharmony_ciread_next_fcf:
25288c2ecf20Sopenharmony_ci	lpfc_sli4_mbox_cmd_free(phba, mboxq);
25298c2ecf20Sopenharmony_ci	if (next_fcf_index == LPFC_FCOE_FCF_NEXT_NONE || next_fcf_index == 0) {
25308c2ecf20Sopenharmony_ci		if (phba->fcf.fcf_flag & FCF_REDISC_FOV) {
25318c2ecf20Sopenharmony_ci			/*
25328c2ecf20Sopenharmony_ci			 * Case of FCF fast failover scan
25338c2ecf20Sopenharmony_ci			 */
25348c2ecf20Sopenharmony_ci
25358c2ecf20Sopenharmony_ci			/*
25368c2ecf20Sopenharmony_ci			 * It has not found any suitable FCF record, cancel
25378c2ecf20Sopenharmony_ci			 * FCF scan inprogress, and do nothing
25388c2ecf20Sopenharmony_ci			 */
25398c2ecf20Sopenharmony_ci			if (!(phba->fcf.failover_rec.flag & RECORD_VALID)) {
25408c2ecf20Sopenharmony_ci				lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
25418c2ecf20Sopenharmony_ci					       "2782 No suitable FCF found: "
25428c2ecf20Sopenharmony_ci					       "(x%x/x%x)\n",
25438c2ecf20Sopenharmony_ci					       phba->fcoe_eventtag_at_fcf_scan,
25448c2ecf20Sopenharmony_ci					       bf_get(lpfc_fcf_record_fcf_index,
25458c2ecf20Sopenharmony_ci						      new_fcf_record));
25468c2ecf20Sopenharmony_ci				spin_lock_irq(&phba->hbalock);
25478c2ecf20Sopenharmony_ci				if (phba->hba_flag & HBA_DEVLOSS_TMO) {
25488c2ecf20Sopenharmony_ci					phba->hba_flag &= ~FCF_TS_INPROG;
25498c2ecf20Sopenharmony_ci					spin_unlock_irq(&phba->hbalock);
25508c2ecf20Sopenharmony_ci					/* Unregister in-use FCF and rescan */
25518c2ecf20Sopenharmony_ci					lpfc_printf_log(phba, KERN_INFO,
25528c2ecf20Sopenharmony_ci							LOG_FIP,
25538c2ecf20Sopenharmony_ci							"2864 On devloss tmo "
25548c2ecf20Sopenharmony_ci							"unreg in-use FCF and "
25558c2ecf20Sopenharmony_ci							"rescan FCF table\n");
25568c2ecf20Sopenharmony_ci					lpfc_unregister_fcf_rescan(phba);
25578c2ecf20Sopenharmony_ci					return;
25588c2ecf20Sopenharmony_ci				}
25598c2ecf20Sopenharmony_ci				/*
25608c2ecf20Sopenharmony_ci				 * Let next new FCF event trigger fast failover
25618c2ecf20Sopenharmony_ci				 */
25628c2ecf20Sopenharmony_ci				phba->hba_flag &= ~FCF_TS_INPROG;
25638c2ecf20Sopenharmony_ci				spin_unlock_irq(&phba->hbalock);
25648c2ecf20Sopenharmony_ci				return;
25658c2ecf20Sopenharmony_ci			}
25668c2ecf20Sopenharmony_ci			/*
25678c2ecf20Sopenharmony_ci			 * It has found a suitable FCF record that is not
25688c2ecf20Sopenharmony_ci			 * the same as in-use FCF record, unregister the
25698c2ecf20Sopenharmony_ci			 * in-use FCF record, replace the in-use FCF record
25708c2ecf20Sopenharmony_ci			 * with the new FCF record, mark FCF fast failover
25718c2ecf20Sopenharmony_ci			 * completed, and then start register the new FCF
25728c2ecf20Sopenharmony_ci			 * record.
25738c2ecf20Sopenharmony_ci			 */
25748c2ecf20Sopenharmony_ci
25758c2ecf20Sopenharmony_ci			/* Unregister the current in-use FCF record */
25768c2ecf20Sopenharmony_ci			lpfc_unregister_fcf(phba);
25778c2ecf20Sopenharmony_ci
25788c2ecf20Sopenharmony_ci			/* Replace in-use record with the new record */
25798c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
25808c2ecf20Sopenharmony_ci					"2842 Replace in-use FCF (x%x) "
25818c2ecf20Sopenharmony_ci					"with failover FCF (x%x)\n",
25828c2ecf20Sopenharmony_ci					phba->fcf.current_rec.fcf_indx,
25838c2ecf20Sopenharmony_ci					phba->fcf.failover_rec.fcf_indx);
25848c2ecf20Sopenharmony_ci			memcpy(&phba->fcf.current_rec,
25858c2ecf20Sopenharmony_ci			       &phba->fcf.failover_rec,
25868c2ecf20Sopenharmony_ci			       sizeof(struct lpfc_fcf_rec));
25878c2ecf20Sopenharmony_ci			/*
25888c2ecf20Sopenharmony_ci			 * Mark the fast FCF failover rediscovery completed
25898c2ecf20Sopenharmony_ci			 * and the start of the first round of the roundrobin
25908c2ecf20Sopenharmony_ci			 * FCF failover.
25918c2ecf20Sopenharmony_ci			 */
25928c2ecf20Sopenharmony_ci			spin_lock_irq(&phba->hbalock);
25938c2ecf20Sopenharmony_ci			phba->fcf.fcf_flag &= ~FCF_REDISC_FOV;
25948c2ecf20Sopenharmony_ci			spin_unlock_irq(&phba->hbalock);
25958c2ecf20Sopenharmony_ci			/* Register to the new FCF record */
25968c2ecf20Sopenharmony_ci			lpfc_register_fcf(phba);
25978c2ecf20Sopenharmony_ci		} else {
25988c2ecf20Sopenharmony_ci			/*
25998c2ecf20Sopenharmony_ci			 * In case of transaction period to fast FCF failover,
26008c2ecf20Sopenharmony_ci			 * do nothing when search to the end of the FCF table.
26018c2ecf20Sopenharmony_ci			 */
26028c2ecf20Sopenharmony_ci			if ((phba->fcf.fcf_flag & FCF_REDISC_EVT) ||
26038c2ecf20Sopenharmony_ci			    (phba->fcf.fcf_flag & FCF_REDISC_PEND))
26048c2ecf20Sopenharmony_ci				return;
26058c2ecf20Sopenharmony_ci
26068c2ecf20Sopenharmony_ci			if (phba->cfg_fcf_failover_policy == LPFC_FCF_FOV &&
26078c2ecf20Sopenharmony_ci				phba->fcf.fcf_flag & FCF_IN_USE) {
26088c2ecf20Sopenharmony_ci				/*
26098c2ecf20Sopenharmony_ci				 * In case the current in-use FCF record no
26108c2ecf20Sopenharmony_ci				 * longer existed during FCF discovery that
26118c2ecf20Sopenharmony_ci				 * was not triggered by fast FCF failover
26128c2ecf20Sopenharmony_ci				 * process, treat it as fast FCF failover.
26138c2ecf20Sopenharmony_ci				 */
26148c2ecf20Sopenharmony_ci				lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
26158c2ecf20Sopenharmony_ci						"2841 In-use FCF record (x%x) "
26168c2ecf20Sopenharmony_ci						"not reported, entering fast "
26178c2ecf20Sopenharmony_ci						"FCF failover mode scanning.\n",
26188c2ecf20Sopenharmony_ci						phba->fcf.current_rec.fcf_indx);
26198c2ecf20Sopenharmony_ci				spin_lock_irq(&phba->hbalock);
26208c2ecf20Sopenharmony_ci				phba->fcf.fcf_flag |= FCF_REDISC_FOV;
26218c2ecf20Sopenharmony_ci				spin_unlock_irq(&phba->hbalock);
26228c2ecf20Sopenharmony_ci				lpfc_sli4_fcf_scan_read_fcf_rec(phba,
26238c2ecf20Sopenharmony_ci						LPFC_FCOE_FCF_GET_FIRST);
26248c2ecf20Sopenharmony_ci				return;
26258c2ecf20Sopenharmony_ci			}
26268c2ecf20Sopenharmony_ci			/* Register to the new FCF record */
26278c2ecf20Sopenharmony_ci			lpfc_register_fcf(phba);
26288c2ecf20Sopenharmony_ci		}
26298c2ecf20Sopenharmony_ci	} else
26308c2ecf20Sopenharmony_ci		lpfc_sli4_fcf_scan_read_fcf_rec(phba, next_fcf_index);
26318c2ecf20Sopenharmony_ci	return;
26328c2ecf20Sopenharmony_ci
26338c2ecf20Sopenharmony_ciout:
26348c2ecf20Sopenharmony_ci	lpfc_sli4_mbox_cmd_free(phba, mboxq);
26358c2ecf20Sopenharmony_ci	lpfc_register_fcf(phba);
26368c2ecf20Sopenharmony_ci
26378c2ecf20Sopenharmony_ci	return;
26388c2ecf20Sopenharmony_ci}
26398c2ecf20Sopenharmony_ci
26408c2ecf20Sopenharmony_ci/**
26418c2ecf20Sopenharmony_ci * lpfc_mbx_cmpl_fcf_rr_read_fcf_rec - fcf roundrobin read_fcf mbox cmpl hdler
26428c2ecf20Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
26438c2ecf20Sopenharmony_ci * @mboxq: pointer to mailbox object.
26448c2ecf20Sopenharmony_ci *
26458c2ecf20Sopenharmony_ci * This is the callback function for FLOGI failure roundrobin FCF failover
26468c2ecf20Sopenharmony_ci * read FCF record mailbox command from the eligible FCF record bmask for
26478c2ecf20Sopenharmony_ci * performing the failover. If the FCF read back is not valid/available, it
26488c2ecf20Sopenharmony_ci * fails through to retrying FLOGI to the currently registered FCF again.
26498c2ecf20Sopenharmony_ci * Otherwise, if the FCF read back is valid and available, it will set the
26508c2ecf20Sopenharmony_ci * newly read FCF record to the failover FCF record, unregister currently
26518c2ecf20Sopenharmony_ci * registered FCF record, copy the failover FCF record to the current
26528c2ecf20Sopenharmony_ci * FCF record, and then register the current FCF record before proceeding
26538c2ecf20Sopenharmony_ci * to trying FLOGI on the new failover FCF.
26548c2ecf20Sopenharmony_ci */
26558c2ecf20Sopenharmony_civoid
26568c2ecf20Sopenharmony_cilpfc_mbx_cmpl_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
26578c2ecf20Sopenharmony_ci{
26588c2ecf20Sopenharmony_ci	struct fcf_record *new_fcf_record;
26598c2ecf20Sopenharmony_ci	uint32_t boot_flag, addr_mode;
26608c2ecf20Sopenharmony_ci	uint16_t next_fcf_index, fcf_index;
26618c2ecf20Sopenharmony_ci	uint16_t current_fcf_index;
26628c2ecf20Sopenharmony_ci	uint16_t vlan_id;
26638c2ecf20Sopenharmony_ci	int rc;
26648c2ecf20Sopenharmony_ci
26658c2ecf20Sopenharmony_ci	/* If link state is not up, stop the roundrobin failover process */
26668c2ecf20Sopenharmony_ci	if (phba->link_state < LPFC_LINK_UP) {
26678c2ecf20Sopenharmony_ci		spin_lock_irq(&phba->hbalock);
26688c2ecf20Sopenharmony_ci		phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
26698c2ecf20Sopenharmony_ci		phba->hba_flag &= ~FCF_RR_INPROG;
26708c2ecf20Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
26718c2ecf20Sopenharmony_ci		goto out;
26728c2ecf20Sopenharmony_ci	}
26738c2ecf20Sopenharmony_ci
26748c2ecf20Sopenharmony_ci	/* Parse the FCF record from the non-embedded mailbox command */
26758c2ecf20Sopenharmony_ci	new_fcf_record = lpfc_sli4_fcf_rec_mbox_parse(phba, mboxq,
26768c2ecf20Sopenharmony_ci						      &next_fcf_index);
26778c2ecf20Sopenharmony_ci	if (!new_fcf_record) {
26788c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
26798c2ecf20Sopenharmony_ci				"2766 Mailbox command READ_FCF_RECORD "
26808c2ecf20Sopenharmony_ci				"failed to retrieve a FCF record. "
26818c2ecf20Sopenharmony_ci				"hba_flg x%x fcf_flg x%x\n", phba->hba_flag,
26828c2ecf20Sopenharmony_ci				phba->fcf.fcf_flag);
26838c2ecf20Sopenharmony_ci		lpfc_unregister_fcf_rescan(phba);
26848c2ecf20Sopenharmony_ci		goto out;
26858c2ecf20Sopenharmony_ci	}
26868c2ecf20Sopenharmony_ci
26878c2ecf20Sopenharmony_ci	/* Get the needed parameters from FCF record */
26888c2ecf20Sopenharmony_ci	rc = lpfc_match_fcf_conn_list(phba, new_fcf_record, &boot_flag,
26898c2ecf20Sopenharmony_ci				      &addr_mode, &vlan_id);
26908c2ecf20Sopenharmony_ci
26918c2ecf20Sopenharmony_ci	/* Log the FCF record information if turned on */
26928c2ecf20Sopenharmony_ci	lpfc_sli4_log_fcf_record_info(phba, new_fcf_record, vlan_id,
26938c2ecf20Sopenharmony_ci				      next_fcf_index);
26948c2ecf20Sopenharmony_ci
26958c2ecf20Sopenharmony_ci	fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record);
26968c2ecf20Sopenharmony_ci	if (!rc) {
26978c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
26988c2ecf20Sopenharmony_ci				"2848 Remove ineligible FCF (x%x) from "
26998c2ecf20Sopenharmony_ci				"from roundrobin bmask\n", fcf_index);
27008c2ecf20Sopenharmony_ci		/* Clear roundrobin bmask bit for ineligible FCF */
27018c2ecf20Sopenharmony_ci		lpfc_sli4_fcf_rr_index_clear(phba, fcf_index);
27028c2ecf20Sopenharmony_ci		/* Perform next round of roundrobin FCF failover */
27038c2ecf20Sopenharmony_ci		fcf_index = lpfc_sli4_fcf_rr_next_index_get(phba);
27048c2ecf20Sopenharmony_ci		rc = lpfc_sli4_fcf_rr_next_proc(phba->pport, fcf_index);
27058c2ecf20Sopenharmony_ci		if (rc)
27068c2ecf20Sopenharmony_ci			goto out;
27078c2ecf20Sopenharmony_ci		goto error_out;
27088c2ecf20Sopenharmony_ci	}
27098c2ecf20Sopenharmony_ci
27108c2ecf20Sopenharmony_ci	if (fcf_index == phba->fcf.current_rec.fcf_indx) {
27118c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
27128c2ecf20Sopenharmony_ci				"2760 Perform FLOGI roundrobin FCF failover: "
27138c2ecf20Sopenharmony_ci				"FCF (x%x) back to FCF (x%x)\n",
27148c2ecf20Sopenharmony_ci				phba->fcf.current_rec.fcf_indx, fcf_index);
27158c2ecf20Sopenharmony_ci		/* Wait 500 ms before retrying FLOGI to current FCF */
27168c2ecf20Sopenharmony_ci		msleep(500);
27178c2ecf20Sopenharmony_ci		lpfc_issue_init_vfi(phba->pport);
27188c2ecf20Sopenharmony_ci		goto out;
27198c2ecf20Sopenharmony_ci	}
27208c2ecf20Sopenharmony_ci
27218c2ecf20Sopenharmony_ci	/* Upload new FCF record to the failover FCF record */
27228c2ecf20Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
27238c2ecf20Sopenharmony_ci			"2834 Update current FCF (x%x) with new FCF (x%x)\n",
27248c2ecf20Sopenharmony_ci			phba->fcf.failover_rec.fcf_indx, fcf_index);
27258c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
27268c2ecf20Sopenharmony_ci	__lpfc_update_fcf_record(phba, &phba->fcf.failover_rec,
27278c2ecf20Sopenharmony_ci				 new_fcf_record, addr_mode, vlan_id,
27288c2ecf20Sopenharmony_ci				 (boot_flag ? BOOT_ENABLE : 0));
27298c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
27308c2ecf20Sopenharmony_ci
27318c2ecf20Sopenharmony_ci	current_fcf_index = phba->fcf.current_rec.fcf_indx;
27328c2ecf20Sopenharmony_ci
27338c2ecf20Sopenharmony_ci	/* Unregister the current in-use FCF record */
27348c2ecf20Sopenharmony_ci	lpfc_unregister_fcf(phba);
27358c2ecf20Sopenharmony_ci
27368c2ecf20Sopenharmony_ci	/* Replace in-use record with the new record */
27378c2ecf20Sopenharmony_ci	memcpy(&phba->fcf.current_rec, &phba->fcf.failover_rec,
27388c2ecf20Sopenharmony_ci	       sizeof(struct lpfc_fcf_rec));
27398c2ecf20Sopenharmony_ci
27408c2ecf20Sopenharmony_ci	lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
27418c2ecf20Sopenharmony_ci			"2783 Perform FLOGI roundrobin FCF failover: FCF "
27428c2ecf20Sopenharmony_ci			"(x%x) to FCF (x%x)\n", current_fcf_index, fcf_index);
27438c2ecf20Sopenharmony_ci
27448c2ecf20Sopenharmony_cierror_out:
27458c2ecf20Sopenharmony_ci	lpfc_register_fcf(phba);
27468c2ecf20Sopenharmony_ciout:
27478c2ecf20Sopenharmony_ci	lpfc_sli4_mbox_cmd_free(phba, mboxq);
27488c2ecf20Sopenharmony_ci}
27498c2ecf20Sopenharmony_ci
27508c2ecf20Sopenharmony_ci/**
27518c2ecf20Sopenharmony_ci * lpfc_mbx_cmpl_read_fcf_rec - read fcf completion handler.
27528c2ecf20Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
27538c2ecf20Sopenharmony_ci * @mboxq: pointer to mailbox object.
27548c2ecf20Sopenharmony_ci *
27558c2ecf20Sopenharmony_ci * This is the callback function of read FCF record mailbox command for
27568c2ecf20Sopenharmony_ci * updating the eligible FCF bmask for FLOGI failure roundrobin FCF
27578c2ecf20Sopenharmony_ci * failover when a new FCF event happened. If the FCF read back is
27588c2ecf20Sopenharmony_ci * valid/available and it passes the connection list check, it updates
27598c2ecf20Sopenharmony_ci * the bmask for the eligible FCF record for roundrobin failover.
27608c2ecf20Sopenharmony_ci */
27618c2ecf20Sopenharmony_civoid
27628c2ecf20Sopenharmony_cilpfc_mbx_cmpl_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
27638c2ecf20Sopenharmony_ci{
27648c2ecf20Sopenharmony_ci	struct fcf_record *new_fcf_record;
27658c2ecf20Sopenharmony_ci	uint32_t boot_flag, addr_mode;
27668c2ecf20Sopenharmony_ci	uint16_t fcf_index, next_fcf_index;
27678c2ecf20Sopenharmony_ci	uint16_t vlan_id;
27688c2ecf20Sopenharmony_ci	int rc;
27698c2ecf20Sopenharmony_ci
27708c2ecf20Sopenharmony_ci	/* If link state is not up, no need to proceed */
27718c2ecf20Sopenharmony_ci	if (phba->link_state < LPFC_LINK_UP)
27728c2ecf20Sopenharmony_ci		goto out;
27738c2ecf20Sopenharmony_ci
27748c2ecf20Sopenharmony_ci	/* If FCF discovery period is over, no need to proceed */
27758c2ecf20Sopenharmony_ci	if (!(phba->fcf.fcf_flag & FCF_DISCOVERY))
27768c2ecf20Sopenharmony_ci		goto out;
27778c2ecf20Sopenharmony_ci
27788c2ecf20Sopenharmony_ci	/* Parse the FCF record from the non-embedded mailbox command */
27798c2ecf20Sopenharmony_ci	new_fcf_record = lpfc_sli4_fcf_rec_mbox_parse(phba, mboxq,
27808c2ecf20Sopenharmony_ci						      &next_fcf_index);
27818c2ecf20Sopenharmony_ci	if (!new_fcf_record) {
27828c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
27838c2ecf20Sopenharmony_ci				"2767 Mailbox command READ_FCF_RECORD "
27848c2ecf20Sopenharmony_ci				"failed to retrieve a FCF record.\n");
27858c2ecf20Sopenharmony_ci		goto out;
27868c2ecf20Sopenharmony_ci	}
27878c2ecf20Sopenharmony_ci
27888c2ecf20Sopenharmony_ci	/* Check the connection list for eligibility */
27898c2ecf20Sopenharmony_ci	rc = lpfc_match_fcf_conn_list(phba, new_fcf_record, &boot_flag,
27908c2ecf20Sopenharmony_ci				      &addr_mode, &vlan_id);
27918c2ecf20Sopenharmony_ci
27928c2ecf20Sopenharmony_ci	/* Log the FCF record information if turned on */
27938c2ecf20Sopenharmony_ci	lpfc_sli4_log_fcf_record_info(phba, new_fcf_record, vlan_id,
27948c2ecf20Sopenharmony_ci				      next_fcf_index);
27958c2ecf20Sopenharmony_ci
27968c2ecf20Sopenharmony_ci	if (!rc)
27978c2ecf20Sopenharmony_ci		goto out;
27988c2ecf20Sopenharmony_ci
27998c2ecf20Sopenharmony_ci	/* Update the eligible FCF record index bmask */
28008c2ecf20Sopenharmony_ci	fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record);
28018c2ecf20Sopenharmony_ci
28028c2ecf20Sopenharmony_ci	rc = lpfc_sli4_fcf_pri_list_add(phba, fcf_index, new_fcf_record);
28038c2ecf20Sopenharmony_ci
28048c2ecf20Sopenharmony_ciout:
28058c2ecf20Sopenharmony_ci	lpfc_sli4_mbox_cmd_free(phba, mboxq);
28068c2ecf20Sopenharmony_ci}
28078c2ecf20Sopenharmony_ci
28088c2ecf20Sopenharmony_ci/**
28098c2ecf20Sopenharmony_ci * lpfc_init_vfi_cmpl - Completion handler for init_vfi mbox command.
28108c2ecf20Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
28118c2ecf20Sopenharmony_ci * @mboxq: pointer to mailbox data structure.
28128c2ecf20Sopenharmony_ci *
28138c2ecf20Sopenharmony_ci * This function handles completion of init vfi mailbox command.
28148c2ecf20Sopenharmony_ci */
28158c2ecf20Sopenharmony_cistatic void
28168c2ecf20Sopenharmony_cilpfc_init_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
28178c2ecf20Sopenharmony_ci{
28188c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = mboxq->vport;
28198c2ecf20Sopenharmony_ci
28208c2ecf20Sopenharmony_ci	/*
28218c2ecf20Sopenharmony_ci	 * VFI not supported on interface type 0, just do the flogi
28228c2ecf20Sopenharmony_ci	 * Also continue if the VFI is in use - just use the same one.
28238c2ecf20Sopenharmony_ci	 */
28248c2ecf20Sopenharmony_ci	if (mboxq->u.mb.mbxStatus &&
28258c2ecf20Sopenharmony_ci	    (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
28268c2ecf20Sopenharmony_ci			LPFC_SLI_INTF_IF_TYPE_0) &&
28278c2ecf20Sopenharmony_ci	    mboxq->u.mb.mbxStatus != MBX_VFI_IN_USE) {
28288c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
28298c2ecf20Sopenharmony_ci				 "2891 Init VFI mailbox failed 0x%x\n",
28308c2ecf20Sopenharmony_ci				 mboxq->u.mb.mbxStatus);
28318c2ecf20Sopenharmony_ci		mempool_free(mboxq, phba->mbox_mem_pool);
28328c2ecf20Sopenharmony_ci		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
28338c2ecf20Sopenharmony_ci		return;
28348c2ecf20Sopenharmony_ci	}
28358c2ecf20Sopenharmony_ci
28368c2ecf20Sopenharmony_ci	lpfc_initial_flogi(vport);
28378c2ecf20Sopenharmony_ci	mempool_free(mboxq, phba->mbox_mem_pool);
28388c2ecf20Sopenharmony_ci	return;
28398c2ecf20Sopenharmony_ci}
28408c2ecf20Sopenharmony_ci
28418c2ecf20Sopenharmony_ci/**
28428c2ecf20Sopenharmony_ci * lpfc_issue_init_vfi - Issue init_vfi mailbox command.
28438c2ecf20Sopenharmony_ci * @vport: pointer to lpfc_vport data structure.
28448c2ecf20Sopenharmony_ci *
28458c2ecf20Sopenharmony_ci * This function issue a init_vfi mailbox command to initialize the VFI and
28468c2ecf20Sopenharmony_ci * VPI for the physical port.
28478c2ecf20Sopenharmony_ci */
28488c2ecf20Sopenharmony_civoid
28498c2ecf20Sopenharmony_cilpfc_issue_init_vfi(struct lpfc_vport *vport)
28508c2ecf20Sopenharmony_ci{
28518c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t *mboxq;
28528c2ecf20Sopenharmony_ci	int rc;
28538c2ecf20Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
28548c2ecf20Sopenharmony_ci
28558c2ecf20Sopenharmony_ci	mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
28568c2ecf20Sopenharmony_ci	if (!mboxq) {
28578c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR,
28588c2ecf20Sopenharmony_ci			LOG_TRACE_EVENT, "2892 Failed to allocate "
28598c2ecf20Sopenharmony_ci			"init_vfi mailbox\n");
28608c2ecf20Sopenharmony_ci		return;
28618c2ecf20Sopenharmony_ci	}
28628c2ecf20Sopenharmony_ci	lpfc_init_vfi(mboxq, vport);
28638c2ecf20Sopenharmony_ci	mboxq->mbox_cmpl = lpfc_init_vfi_cmpl;
28648c2ecf20Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
28658c2ecf20Sopenharmony_ci	if (rc == MBX_NOT_FINISHED) {
28668c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
28678c2ecf20Sopenharmony_ci				 "2893 Failed to issue init_vfi mailbox\n");
28688c2ecf20Sopenharmony_ci		mempool_free(mboxq, vport->phba->mbox_mem_pool);
28698c2ecf20Sopenharmony_ci	}
28708c2ecf20Sopenharmony_ci}
28718c2ecf20Sopenharmony_ci
28728c2ecf20Sopenharmony_ci/**
28738c2ecf20Sopenharmony_ci * lpfc_init_vpi_cmpl - Completion handler for init_vpi mbox command.
28748c2ecf20Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
28758c2ecf20Sopenharmony_ci * @mboxq: pointer to mailbox data structure.
28768c2ecf20Sopenharmony_ci *
28778c2ecf20Sopenharmony_ci * This function handles completion of init vpi mailbox command.
28788c2ecf20Sopenharmony_ci */
28798c2ecf20Sopenharmony_civoid
28808c2ecf20Sopenharmony_cilpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
28818c2ecf20Sopenharmony_ci{
28828c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = mboxq->vport;
28838c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp;
28848c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
28858c2ecf20Sopenharmony_ci
28868c2ecf20Sopenharmony_ci	if (mboxq->u.mb.mbxStatus) {
28878c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
28888c2ecf20Sopenharmony_ci				 "2609 Init VPI mailbox failed 0x%x\n",
28898c2ecf20Sopenharmony_ci				 mboxq->u.mb.mbxStatus);
28908c2ecf20Sopenharmony_ci		mempool_free(mboxq, phba->mbox_mem_pool);
28918c2ecf20Sopenharmony_ci		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
28928c2ecf20Sopenharmony_ci		return;
28938c2ecf20Sopenharmony_ci	}
28948c2ecf20Sopenharmony_ci	spin_lock_irq(shost->host_lock);
28958c2ecf20Sopenharmony_ci	vport->fc_flag &= ~FC_VPORT_NEEDS_INIT_VPI;
28968c2ecf20Sopenharmony_ci	spin_unlock_irq(shost->host_lock);
28978c2ecf20Sopenharmony_ci
28988c2ecf20Sopenharmony_ci	/* If this port is physical port or FDISC is done, do reg_vpi */
28998c2ecf20Sopenharmony_ci	if ((phba->pport == vport) || (vport->port_state == LPFC_FDISC)) {
29008c2ecf20Sopenharmony_ci			ndlp = lpfc_findnode_did(vport, Fabric_DID);
29018c2ecf20Sopenharmony_ci			if (!ndlp)
29028c2ecf20Sopenharmony_ci				lpfc_printf_vlog(vport, KERN_ERR,
29038c2ecf20Sopenharmony_ci					LOG_TRACE_EVENT,
29048c2ecf20Sopenharmony_ci					"2731 Cannot find fabric "
29058c2ecf20Sopenharmony_ci					"controller node\n");
29068c2ecf20Sopenharmony_ci			else
29078c2ecf20Sopenharmony_ci				lpfc_register_new_vport(phba, vport, ndlp);
29088c2ecf20Sopenharmony_ci			mempool_free(mboxq, phba->mbox_mem_pool);
29098c2ecf20Sopenharmony_ci			return;
29108c2ecf20Sopenharmony_ci	}
29118c2ecf20Sopenharmony_ci
29128c2ecf20Sopenharmony_ci	if (phba->link_flag & LS_NPIV_FAB_SUPPORTED)
29138c2ecf20Sopenharmony_ci		lpfc_initial_fdisc(vport);
29148c2ecf20Sopenharmony_ci	else {
29158c2ecf20Sopenharmony_ci		lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP);
29168c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
29178c2ecf20Sopenharmony_ci				 "2606 No NPIV Fabric support\n");
29188c2ecf20Sopenharmony_ci	}
29198c2ecf20Sopenharmony_ci	mempool_free(mboxq, phba->mbox_mem_pool);
29208c2ecf20Sopenharmony_ci	return;
29218c2ecf20Sopenharmony_ci}
29228c2ecf20Sopenharmony_ci
29238c2ecf20Sopenharmony_ci/**
29248c2ecf20Sopenharmony_ci * lpfc_issue_init_vpi - Issue init_vpi mailbox command.
29258c2ecf20Sopenharmony_ci * @vport: pointer to lpfc_vport data structure.
29268c2ecf20Sopenharmony_ci *
29278c2ecf20Sopenharmony_ci * This function issue a init_vpi mailbox command to initialize
29288c2ecf20Sopenharmony_ci * VPI for the vport.
29298c2ecf20Sopenharmony_ci */
29308c2ecf20Sopenharmony_civoid
29318c2ecf20Sopenharmony_cilpfc_issue_init_vpi(struct lpfc_vport *vport)
29328c2ecf20Sopenharmony_ci{
29338c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t *mboxq;
29348c2ecf20Sopenharmony_ci	int rc, vpi;
29358c2ecf20Sopenharmony_ci
29368c2ecf20Sopenharmony_ci	if ((vport->port_type != LPFC_PHYSICAL_PORT) && (!vport->vpi)) {
29378c2ecf20Sopenharmony_ci		vpi = lpfc_alloc_vpi(vport->phba);
29388c2ecf20Sopenharmony_ci		if (!vpi) {
29398c2ecf20Sopenharmony_ci			lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
29408c2ecf20Sopenharmony_ci					 "3303 Failed to obtain vport vpi\n");
29418c2ecf20Sopenharmony_ci			lpfc_vport_set_state(vport, FC_VPORT_FAILED);
29428c2ecf20Sopenharmony_ci			return;
29438c2ecf20Sopenharmony_ci		}
29448c2ecf20Sopenharmony_ci		vport->vpi = vpi;
29458c2ecf20Sopenharmony_ci	}
29468c2ecf20Sopenharmony_ci
29478c2ecf20Sopenharmony_ci	mboxq = mempool_alloc(vport->phba->mbox_mem_pool, GFP_KERNEL);
29488c2ecf20Sopenharmony_ci	if (!mboxq) {
29498c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR,
29508c2ecf20Sopenharmony_ci			LOG_TRACE_EVENT, "2607 Failed to allocate "
29518c2ecf20Sopenharmony_ci			"init_vpi mailbox\n");
29528c2ecf20Sopenharmony_ci		return;
29538c2ecf20Sopenharmony_ci	}
29548c2ecf20Sopenharmony_ci	lpfc_init_vpi(vport->phba, mboxq, vport->vpi);
29558c2ecf20Sopenharmony_ci	mboxq->vport = vport;
29568c2ecf20Sopenharmony_ci	mboxq->mbox_cmpl = lpfc_init_vpi_cmpl;
29578c2ecf20Sopenharmony_ci	rc = lpfc_sli_issue_mbox(vport->phba, mboxq, MBX_NOWAIT);
29588c2ecf20Sopenharmony_ci	if (rc == MBX_NOT_FINISHED) {
29598c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
29608c2ecf20Sopenharmony_ci				 "2608 Failed to issue init_vpi mailbox\n");
29618c2ecf20Sopenharmony_ci		mempool_free(mboxq, vport->phba->mbox_mem_pool);
29628c2ecf20Sopenharmony_ci	}
29638c2ecf20Sopenharmony_ci}
29648c2ecf20Sopenharmony_ci
29658c2ecf20Sopenharmony_ci/**
29668c2ecf20Sopenharmony_ci * lpfc_start_fdiscs - send fdiscs for each vports on this port.
29678c2ecf20Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
29688c2ecf20Sopenharmony_ci *
29698c2ecf20Sopenharmony_ci * This function loops through the list of vports on the @phba and issues an
29708c2ecf20Sopenharmony_ci * FDISC if possible.
29718c2ecf20Sopenharmony_ci */
29728c2ecf20Sopenharmony_civoid
29738c2ecf20Sopenharmony_cilpfc_start_fdiscs(struct lpfc_hba *phba)
29748c2ecf20Sopenharmony_ci{
29758c2ecf20Sopenharmony_ci	struct lpfc_vport **vports;
29768c2ecf20Sopenharmony_ci	int i;
29778c2ecf20Sopenharmony_ci
29788c2ecf20Sopenharmony_ci	vports = lpfc_create_vport_work_array(phba);
29798c2ecf20Sopenharmony_ci	if (vports != NULL) {
29808c2ecf20Sopenharmony_ci		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
29818c2ecf20Sopenharmony_ci			if (vports[i]->port_type == LPFC_PHYSICAL_PORT)
29828c2ecf20Sopenharmony_ci				continue;
29838c2ecf20Sopenharmony_ci			/* There are no vpi for this vport */
29848c2ecf20Sopenharmony_ci			if (vports[i]->vpi > phba->max_vpi) {
29858c2ecf20Sopenharmony_ci				lpfc_vport_set_state(vports[i],
29868c2ecf20Sopenharmony_ci						     FC_VPORT_FAILED);
29878c2ecf20Sopenharmony_ci				continue;
29888c2ecf20Sopenharmony_ci			}
29898c2ecf20Sopenharmony_ci			if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
29908c2ecf20Sopenharmony_ci				lpfc_vport_set_state(vports[i],
29918c2ecf20Sopenharmony_ci						     FC_VPORT_LINKDOWN);
29928c2ecf20Sopenharmony_ci				continue;
29938c2ecf20Sopenharmony_ci			}
29948c2ecf20Sopenharmony_ci			if (vports[i]->fc_flag & FC_VPORT_NEEDS_INIT_VPI) {
29958c2ecf20Sopenharmony_ci				lpfc_issue_init_vpi(vports[i]);
29968c2ecf20Sopenharmony_ci				continue;
29978c2ecf20Sopenharmony_ci			}
29988c2ecf20Sopenharmony_ci			if (phba->link_flag & LS_NPIV_FAB_SUPPORTED)
29998c2ecf20Sopenharmony_ci				lpfc_initial_fdisc(vports[i]);
30008c2ecf20Sopenharmony_ci			else {
30018c2ecf20Sopenharmony_ci				lpfc_vport_set_state(vports[i],
30028c2ecf20Sopenharmony_ci						     FC_VPORT_NO_FABRIC_SUPP);
30038c2ecf20Sopenharmony_ci				lpfc_printf_vlog(vports[i], KERN_ERR,
30048c2ecf20Sopenharmony_ci						 LOG_TRACE_EVENT,
30058c2ecf20Sopenharmony_ci						 "0259 No NPIV "
30068c2ecf20Sopenharmony_ci						 "Fabric support\n");
30078c2ecf20Sopenharmony_ci			}
30088c2ecf20Sopenharmony_ci		}
30098c2ecf20Sopenharmony_ci	}
30108c2ecf20Sopenharmony_ci	lpfc_destroy_vport_work_array(phba, vports);
30118c2ecf20Sopenharmony_ci}
30128c2ecf20Sopenharmony_ci
30138c2ecf20Sopenharmony_civoid
30148c2ecf20Sopenharmony_cilpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
30158c2ecf20Sopenharmony_ci{
30168c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *dmabuf = mboxq->ctx_buf;
30178c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = mboxq->vport;
30188c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
30198c2ecf20Sopenharmony_ci
30208c2ecf20Sopenharmony_ci	/*
30218c2ecf20Sopenharmony_ci	 * VFI not supported for interface type 0, so ignore any mailbox
30228c2ecf20Sopenharmony_ci	 * error (except VFI in use) and continue with the discovery.
30238c2ecf20Sopenharmony_ci	 */
30248c2ecf20Sopenharmony_ci	if (mboxq->u.mb.mbxStatus &&
30258c2ecf20Sopenharmony_ci	    (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) !=
30268c2ecf20Sopenharmony_ci			LPFC_SLI_INTF_IF_TYPE_0) &&
30278c2ecf20Sopenharmony_ci	    mboxq->u.mb.mbxStatus != MBX_VFI_IN_USE) {
30288c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
30298c2ecf20Sopenharmony_ci				 "2018 REG_VFI mbxStatus error x%x "
30308c2ecf20Sopenharmony_ci				 "HBA state x%x\n",
30318c2ecf20Sopenharmony_ci				 mboxq->u.mb.mbxStatus, vport->port_state);
30328c2ecf20Sopenharmony_ci		if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
30338c2ecf20Sopenharmony_ci			/* FLOGI failed, use loop map to make discovery list */
30348c2ecf20Sopenharmony_ci			lpfc_disc_list_loopmap(vport);
30358c2ecf20Sopenharmony_ci			/* Start discovery */
30368c2ecf20Sopenharmony_ci			lpfc_disc_start(vport);
30378c2ecf20Sopenharmony_ci			goto out_free_mem;
30388c2ecf20Sopenharmony_ci		}
30398c2ecf20Sopenharmony_ci		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
30408c2ecf20Sopenharmony_ci		goto out_free_mem;
30418c2ecf20Sopenharmony_ci	}
30428c2ecf20Sopenharmony_ci
30438c2ecf20Sopenharmony_ci	/* If the VFI is already registered, there is nothing else to do
30448c2ecf20Sopenharmony_ci	 * Unless this was a VFI update and we are in PT2PT mode, then
30458c2ecf20Sopenharmony_ci	 * we should drop through to set the port state to ready.
30468c2ecf20Sopenharmony_ci	 */
30478c2ecf20Sopenharmony_ci	if (vport->fc_flag & FC_VFI_REGISTERED)
30488c2ecf20Sopenharmony_ci		if (!(phba->sli_rev == LPFC_SLI_REV4 &&
30498c2ecf20Sopenharmony_ci		      vport->fc_flag & FC_PT2PT))
30508c2ecf20Sopenharmony_ci			goto out_free_mem;
30518c2ecf20Sopenharmony_ci
30528c2ecf20Sopenharmony_ci	/* The VPI is implicitly registered when the VFI is registered */
30538c2ecf20Sopenharmony_ci	spin_lock_irq(shost->host_lock);
30548c2ecf20Sopenharmony_ci	vport->vpi_state |= LPFC_VPI_REGISTERED;
30558c2ecf20Sopenharmony_ci	vport->fc_flag |= FC_VFI_REGISTERED;
30568c2ecf20Sopenharmony_ci	vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
30578c2ecf20Sopenharmony_ci	vport->fc_flag &= ~FC_VPORT_NEEDS_INIT_VPI;
30588c2ecf20Sopenharmony_ci	spin_unlock_irq(shost->host_lock);
30598c2ecf20Sopenharmony_ci
30608c2ecf20Sopenharmony_ci	/* In case SLI4 FC loopback test, we are ready */
30618c2ecf20Sopenharmony_ci	if ((phba->sli_rev == LPFC_SLI_REV4) &&
30628c2ecf20Sopenharmony_ci	    (phba->link_flag & LS_LOOPBACK_MODE)) {
30638c2ecf20Sopenharmony_ci		phba->link_state = LPFC_HBA_READY;
30648c2ecf20Sopenharmony_ci		goto out_free_mem;
30658c2ecf20Sopenharmony_ci	}
30668c2ecf20Sopenharmony_ci
30678c2ecf20Sopenharmony_ci	lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI,
30688c2ecf20Sopenharmony_ci			 "3313 cmpl reg vfi  port_state:%x fc_flag:%x myDid:%x "
30698c2ecf20Sopenharmony_ci			 "alpacnt:%d LinkState:%x topology:%x\n",
30708c2ecf20Sopenharmony_ci			 vport->port_state, vport->fc_flag, vport->fc_myDID,
30718c2ecf20Sopenharmony_ci			 vport->phba->alpa_map[0],
30728c2ecf20Sopenharmony_ci			 phba->link_state, phba->fc_topology);
30738c2ecf20Sopenharmony_ci
30748c2ecf20Sopenharmony_ci	if (vport->port_state == LPFC_FABRIC_CFG_LINK) {
30758c2ecf20Sopenharmony_ci		/*
30768c2ecf20Sopenharmony_ci		 * For private loop or for NPort pt2pt,
30778c2ecf20Sopenharmony_ci		 * just start discovery and we are done.
30788c2ecf20Sopenharmony_ci		 */
30798c2ecf20Sopenharmony_ci		if ((vport->fc_flag & FC_PT2PT) ||
30808c2ecf20Sopenharmony_ci		    ((phba->fc_topology == LPFC_TOPOLOGY_LOOP) &&
30818c2ecf20Sopenharmony_ci		    !(vport->fc_flag & FC_PUBLIC_LOOP))) {
30828c2ecf20Sopenharmony_ci
30838c2ecf20Sopenharmony_ci			/* Use loop map to make discovery list */
30848c2ecf20Sopenharmony_ci			lpfc_disc_list_loopmap(vport);
30858c2ecf20Sopenharmony_ci			/* Start discovery */
30868c2ecf20Sopenharmony_ci			if (vport->fc_flag & FC_PT2PT)
30878c2ecf20Sopenharmony_ci				vport->port_state = LPFC_VPORT_READY;
30888c2ecf20Sopenharmony_ci			else
30898c2ecf20Sopenharmony_ci				lpfc_disc_start(vport);
30908c2ecf20Sopenharmony_ci		} else {
30918c2ecf20Sopenharmony_ci			lpfc_start_fdiscs(phba);
30928c2ecf20Sopenharmony_ci			lpfc_do_scr_ns_plogi(phba, vport);
30938c2ecf20Sopenharmony_ci		}
30948c2ecf20Sopenharmony_ci	}
30958c2ecf20Sopenharmony_ci
30968c2ecf20Sopenharmony_ciout_free_mem:
30978c2ecf20Sopenharmony_ci	mempool_free(mboxq, phba->mbox_mem_pool);
30988c2ecf20Sopenharmony_ci	if (dmabuf) {
30998c2ecf20Sopenharmony_ci		lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
31008c2ecf20Sopenharmony_ci		kfree(dmabuf);
31018c2ecf20Sopenharmony_ci	}
31028c2ecf20Sopenharmony_ci	return;
31038c2ecf20Sopenharmony_ci}
31048c2ecf20Sopenharmony_ci
31058c2ecf20Sopenharmony_cistatic void
31068c2ecf20Sopenharmony_cilpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
31078c2ecf20Sopenharmony_ci{
31088c2ecf20Sopenharmony_ci	MAILBOX_t *mb = &pmb->u.mb;
31098c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)pmb->ctx_buf;
31108c2ecf20Sopenharmony_ci	struct lpfc_vport  *vport = pmb->vport;
31118c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
31128c2ecf20Sopenharmony_ci	struct serv_parm *sp = &vport->fc_sparam;
31138c2ecf20Sopenharmony_ci	uint32_t ed_tov;
31148c2ecf20Sopenharmony_ci
31158c2ecf20Sopenharmony_ci	/* Check for error */
31168c2ecf20Sopenharmony_ci	if (mb->mbxStatus) {
31178c2ecf20Sopenharmony_ci		/* READ_SPARAM mbox error <mbxStatus> state <hba_state> */
31188c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
31198c2ecf20Sopenharmony_ci				 "0319 READ_SPARAM mbxStatus error x%x "
31208c2ecf20Sopenharmony_ci				 "hba state x%x>\n",
31218c2ecf20Sopenharmony_ci				 mb->mbxStatus, vport->port_state);
31228c2ecf20Sopenharmony_ci		lpfc_linkdown(phba);
31238c2ecf20Sopenharmony_ci		goto out;
31248c2ecf20Sopenharmony_ci	}
31258c2ecf20Sopenharmony_ci
31268c2ecf20Sopenharmony_ci	memcpy((uint8_t *) &vport->fc_sparam, (uint8_t *) mp->virt,
31278c2ecf20Sopenharmony_ci	       sizeof (struct serv_parm));
31288c2ecf20Sopenharmony_ci
31298c2ecf20Sopenharmony_ci	ed_tov = be32_to_cpu(sp->cmn.e_d_tov);
31308c2ecf20Sopenharmony_ci	if (sp->cmn.edtovResolution)	/* E_D_TOV ticks are in nanoseconds */
31318c2ecf20Sopenharmony_ci		ed_tov = (ed_tov + 999999) / 1000000;
31328c2ecf20Sopenharmony_ci
31338c2ecf20Sopenharmony_ci	phba->fc_edtov = ed_tov;
31348c2ecf20Sopenharmony_ci	phba->fc_ratov = (2 * ed_tov) / 1000;
31358c2ecf20Sopenharmony_ci	if (phba->fc_ratov < FF_DEF_RATOV) {
31368c2ecf20Sopenharmony_ci		/* RA_TOV should be atleast 10sec for initial flogi */
31378c2ecf20Sopenharmony_ci		phba->fc_ratov = FF_DEF_RATOV;
31388c2ecf20Sopenharmony_ci	}
31398c2ecf20Sopenharmony_ci
31408c2ecf20Sopenharmony_ci	lpfc_update_vport_wwn(vport);
31418c2ecf20Sopenharmony_ci	fc_host_port_name(shost) = wwn_to_u64(vport->fc_portname.u.wwn);
31428c2ecf20Sopenharmony_ci	if (vport->port_type == LPFC_PHYSICAL_PORT) {
31438c2ecf20Sopenharmony_ci		memcpy(&phba->wwnn, &vport->fc_nodename, sizeof(phba->wwnn));
31448c2ecf20Sopenharmony_ci		memcpy(&phba->wwpn, &vport->fc_portname, sizeof(phba->wwnn));
31458c2ecf20Sopenharmony_ci	}
31468c2ecf20Sopenharmony_ci
31478c2ecf20Sopenharmony_ci	lpfc_mbuf_free(phba, mp->virt, mp->phys);
31488c2ecf20Sopenharmony_ci	kfree(mp);
31498c2ecf20Sopenharmony_ci	mempool_free(pmb, phba->mbox_mem_pool);
31508c2ecf20Sopenharmony_ci
31518c2ecf20Sopenharmony_ci	/* Check if sending the FLOGI is being deferred to after we get
31528c2ecf20Sopenharmony_ci	 * up to date CSPs from MBX_READ_SPARAM.
31538c2ecf20Sopenharmony_ci	 */
31548c2ecf20Sopenharmony_ci	if (phba->hba_flag & HBA_DEFER_FLOGI) {
31558c2ecf20Sopenharmony_ci		lpfc_initial_flogi(vport);
31568c2ecf20Sopenharmony_ci		phba->hba_flag &= ~HBA_DEFER_FLOGI;
31578c2ecf20Sopenharmony_ci	}
31588c2ecf20Sopenharmony_ci	return;
31598c2ecf20Sopenharmony_ci
31608c2ecf20Sopenharmony_ciout:
31618c2ecf20Sopenharmony_ci	pmb->ctx_buf = NULL;
31628c2ecf20Sopenharmony_ci	lpfc_mbuf_free(phba, mp->virt, mp->phys);
31638c2ecf20Sopenharmony_ci	kfree(mp);
31648c2ecf20Sopenharmony_ci	lpfc_issue_clear_la(phba, vport);
31658c2ecf20Sopenharmony_ci	mempool_free(pmb, phba->mbox_mem_pool);
31668c2ecf20Sopenharmony_ci	return;
31678c2ecf20Sopenharmony_ci}
31688c2ecf20Sopenharmony_ci
31698c2ecf20Sopenharmony_cistatic void
31708c2ecf20Sopenharmony_cilpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
31718c2ecf20Sopenharmony_ci{
31728c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = phba->pport;
31738c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t *sparam_mbox, *cfglink_mbox = NULL;
31748c2ecf20Sopenharmony_ci	struct Scsi_Host *shost;
31758c2ecf20Sopenharmony_ci	int i;
31768c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *mp;
31778c2ecf20Sopenharmony_ci	int rc;
31788c2ecf20Sopenharmony_ci	struct fcf_record *fcf_record;
31798c2ecf20Sopenharmony_ci	uint32_t fc_flags = 0;
31808c2ecf20Sopenharmony_ci	unsigned long iflags;
31818c2ecf20Sopenharmony_ci
31828c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->hbalock, iflags);
31838c2ecf20Sopenharmony_ci	phba->fc_linkspeed = bf_get(lpfc_mbx_read_top_link_spd, la);
31848c2ecf20Sopenharmony_ci
31858c2ecf20Sopenharmony_ci	if (!(phba->hba_flag & HBA_FCOE_MODE)) {
31868c2ecf20Sopenharmony_ci		switch (bf_get(lpfc_mbx_read_top_link_spd, la)) {
31878c2ecf20Sopenharmony_ci		case LPFC_LINK_SPEED_1GHZ:
31888c2ecf20Sopenharmony_ci		case LPFC_LINK_SPEED_2GHZ:
31898c2ecf20Sopenharmony_ci		case LPFC_LINK_SPEED_4GHZ:
31908c2ecf20Sopenharmony_ci		case LPFC_LINK_SPEED_8GHZ:
31918c2ecf20Sopenharmony_ci		case LPFC_LINK_SPEED_10GHZ:
31928c2ecf20Sopenharmony_ci		case LPFC_LINK_SPEED_16GHZ:
31938c2ecf20Sopenharmony_ci		case LPFC_LINK_SPEED_32GHZ:
31948c2ecf20Sopenharmony_ci		case LPFC_LINK_SPEED_64GHZ:
31958c2ecf20Sopenharmony_ci		case LPFC_LINK_SPEED_128GHZ:
31968c2ecf20Sopenharmony_ci			break;
31978c2ecf20Sopenharmony_ci		default:
31988c2ecf20Sopenharmony_ci			phba->fc_linkspeed = LPFC_LINK_SPEED_UNKNOWN;
31998c2ecf20Sopenharmony_ci			break;
32008c2ecf20Sopenharmony_ci		}
32018c2ecf20Sopenharmony_ci	}
32028c2ecf20Sopenharmony_ci
32038c2ecf20Sopenharmony_ci	if (phba->fc_topology &&
32048c2ecf20Sopenharmony_ci	    phba->fc_topology != bf_get(lpfc_mbx_read_top_topology, la)) {
32058c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
32068c2ecf20Sopenharmony_ci				"3314 Toplogy changed was 0x%x is 0x%x\n",
32078c2ecf20Sopenharmony_ci				phba->fc_topology,
32088c2ecf20Sopenharmony_ci				bf_get(lpfc_mbx_read_top_topology, la));
32098c2ecf20Sopenharmony_ci		phba->fc_topology_changed = 1;
32108c2ecf20Sopenharmony_ci	}
32118c2ecf20Sopenharmony_ci
32128c2ecf20Sopenharmony_ci	phba->fc_topology = bf_get(lpfc_mbx_read_top_topology, la);
32138c2ecf20Sopenharmony_ci	phba->link_flag &= ~LS_NPIV_FAB_SUPPORTED;
32148c2ecf20Sopenharmony_ci
32158c2ecf20Sopenharmony_ci	shost = lpfc_shost_from_vport(vport);
32168c2ecf20Sopenharmony_ci	if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
32178c2ecf20Sopenharmony_ci		phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED;
32188c2ecf20Sopenharmony_ci
32198c2ecf20Sopenharmony_ci		/* if npiv is enabled and this adapter supports npiv log
32208c2ecf20Sopenharmony_ci		 * a message that npiv is not supported in this topology
32218c2ecf20Sopenharmony_ci		 */
32228c2ecf20Sopenharmony_ci		if (phba->cfg_enable_npiv && phba->max_vpi)
32238c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
32248c2ecf20Sopenharmony_ci				"1309 Link Up Event npiv not supported in loop "
32258c2ecf20Sopenharmony_ci				"topology\n");
32268c2ecf20Sopenharmony_ci				/* Get Loop Map information */
32278c2ecf20Sopenharmony_ci		if (bf_get(lpfc_mbx_read_top_il, la))
32288c2ecf20Sopenharmony_ci			fc_flags |= FC_LBIT;
32298c2ecf20Sopenharmony_ci
32308c2ecf20Sopenharmony_ci		vport->fc_myDID = bf_get(lpfc_mbx_read_top_alpa_granted, la);
32318c2ecf20Sopenharmony_ci		i = la->lilpBde64.tus.f.bdeSize;
32328c2ecf20Sopenharmony_ci
32338c2ecf20Sopenharmony_ci		if (i == 0) {
32348c2ecf20Sopenharmony_ci			phba->alpa_map[0] = 0;
32358c2ecf20Sopenharmony_ci		} else {
32368c2ecf20Sopenharmony_ci			if (vport->cfg_log_verbose & LOG_LINK_EVENT) {
32378c2ecf20Sopenharmony_ci				int numalpa, j, k;
32388c2ecf20Sopenharmony_ci				union {
32398c2ecf20Sopenharmony_ci					uint8_t pamap[16];
32408c2ecf20Sopenharmony_ci					struct {
32418c2ecf20Sopenharmony_ci						uint32_t wd1;
32428c2ecf20Sopenharmony_ci						uint32_t wd2;
32438c2ecf20Sopenharmony_ci						uint32_t wd3;
32448c2ecf20Sopenharmony_ci						uint32_t wd4;
32458c2ecf20Sopenharmony_ci					} pa;
32468c2ecf20Sopenharmony_ci				} un;
32478c2ecf20Sopenharmony_ci				numalpa = phba->alpa_map[0];
32488c2ecf20Sopenharmony_ci				j = 0;
32498c2ecf20Sopenharmony_ci				while (j < numalpa) {
32508c2ecf20Sopenharmony_ci					memset(un.pamap, 0, 16);
32518c2ecf20Sopenharmony_ci					for (k = 1; j < numalpa; k++) {
32528c2ecf20Sopenharmony_ci						un.pamap[k - 1] =
32538c2ecf20Sopenharmony_ci							phba->alpa_map[j + 1];
32548c2ecf20Sopenharmony_ci						j++;
32558c2ecf20Sopenharmony_ci						if (k == 16)
32568c2ecf20Sopenharmony_ci							break;
32578c2ecf20Sopenharmony_ci					}
32588c2ecf20Sopenharmony_ci					/* Link Up Event ALPA map */
32598c2ecf20Sopenharmony_ci					lpfc_printf_log(phba,
32608c2ecf20Sopenharmony_ci							KERN_WARNING,
32618c2ecf20Sopenharmony_ci							LOG_LINK_EVENT,
32628c2ecf20Sopenharmony_ci							"1304 Link Up Event "
32638c2ecf20Sopenharmony_ci							"ALPA map Data: x%x "
32648c2ecf20Sopenharmony_ci							"x%x x%x x%x\n",
32658c2ecf20Sopenharmony_ci							un.pa.wd1, un.pa.wd2,
32668c2ecf20Sopenharmony_ci							un.pa.wd3, un.pa.wd4);
32678c2ecf20Sopenharmony_ci				}
32688c2ecf20Sopenharmony_ci			}
32698c2ecf20Sopenharmony_ci		}
32708c2ecf20Sopenharmony_ci	} else {
32718c2ecf20Sopenharmony_ci		if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) {
32728c2ecf20Sopenharmony_ci			if (phba->max_vpi && phba->cfg_enable_npiv &&
32738c2ecf20Sopenharmony_ci			   (phba->sli_rev >= LPFC_SLI_REV3))
32748c2ecf20Sopenharmony_ci				phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED;
32758c2ecf20Sopenharmony_ci		}
32768c2ecf20Sopenharmony_ci		vport->fc_myDID = phba->fc_pref_DID;
32778c2ecf20Sopenharmony_ci		fc_flags |= FC_LBIT;
32788c2ecf20Sopenharmony_ci	}
32798c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&phba->hbalock, iflags);
32808c2ecf20Sopenharmony_ci
32818c2ecf20Sopenharmony_ci	if (fc_flags) {
32828c2ecf20Sopenharmony_ci		spin_lock_irqsave(shost->host_lock, iflags);
32838c2ecf20Sopenharmony_ci		vport->fc_flag |= fc_flags;
32848c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(shost->host_lock, iflags);
32858c2ecf20Sopenharmony_ci	}
32868c2ecf20Sopenharmony_ci
32878c2ecf20Sopenharmony_ci	lpfc_linkup(phba);
32888c2ecf20Sopenharmony_ci	sparam_mbox = NULL;
32898c2ecf20Sopenharmony_ci
32908c2ecf20Sopenharmony_ci	sparam_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
32918c2ecf20Sopenharmony_ci	if (!sparam_mbox)
32928c2ecf20Sopenharmony_ci		goto out;
32938c2ecf20Sopenharmony_ci
32948c2ecf20Sopenharmony_ci	rc = lpfc_read_sparam(phba, sparam_mbox, 0);
32958c2ecf20Sopenharmony_ci	if (rc) {
32968c2ecf20Sopenharmony_ci		mempool_free(sparam_mbox, phba->mbox_mem_pool);
32978c2ecf20Sopenharmony_ci		goto out;
32988c2ecf20Sopenharmony_ci	}
32998c2ecf20Sopenharmony_ci	sparam_mbox->vport = vport;
33008c2ecf20Sopenharmony_ci	sparam_mbox->mbox_cmpl = lpfc_mbx_cmpl_read_sparam;
33018c2ecf20Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, sparam_mbox, MBX_NOWAIT);
33028c2ecf20Sopenharmony_ci	if (rc == MBX_NOT_FINISHED) {
33038c2ecf20Sopenharmony_ci		mp = (struct lpfc_dmabuf *)sparam_mbox->ctx_buf;
33048c2ecf20Sopenharmony_ci		lpfc_mbuf_free(phba, mp->virt, mp->phys);
33058c2ecf20Sopenharmony_ci		kfree(mp);
33068c2ecf20Sopenharmony_ci		mempool_free(sparam_mbox, phba->mbox_mem_pool);
33078c2ecf20Sopenharmony_ci		goto out;
33088c2ecf20Sopenharmony_ci	}
33098c2ecf20Sopenharmony_ci
33108c2ecf20Sopenharmony_ci	if (!(phba->hba_flag & HBA_FCOE_MODE)) {
33118c2ecf20Sopenharmony_ci		cfglink_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
33128c2ecf20Sopenharmony_ci		if (!cfglink_mbox)
33138c2ecf20Sopenharmony_ci			goto out;
33148c2ecf20Sopenharmony_ci		vport->port_state = LPFC_LOCAL_CFG_LINK;
33158c2ecf20Sopenharmony_ci		lpfc_config_link(phba, cfglink_mbox);
33168c2ecf20Sopenharmony_ci		cfglink_mbox->vport = vport;
33178c2ecf20Sopenharmony_ci		cfglink_mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link;
33188c2ecf20Sopenharmony_ci		rc = lpfc_sli_issue_mbox(phba, cfglink_mbox, MBX_NOWAIT);
33198c2ecf20Sopenharmony_ci		if (rc == MBX_NOT_FINISHED) {
33208c2ecf20Sopenharmony_ci			mempool_free(cfglink_mbox, phba->mbox_mem_pool);
33218c2ecf20Sopenharmony_ci			goto out;
33228c2ecf20Sopenharmony_ci		}
33238c2ecf20Sopenharmony_ci	} else {
33248c2ecf20Sopenharmony_ci		vport->port_state = LPFC_VPORT_UNKNOWN;
33258c2ecf20Sopenharmony_ci		/*
33268c2ecf20Sopenharmony_ci		 * Add the driver's default FCF record at FCF index 0 now. This
33278c2ecf20Sopenharmony_ci		 * is phase 1 implementation that support FCF index 0 and driver
33288c2ecf20Sopenharmony_ci		 * defaults.
33298c2ecf20Sopenharmony_ci		 */
33308c2ecf20Sopenharmony_ci		if (!(phba->hba_flag & HBA_FIP_SUPPORT)) {
33318c2ecf20Sopenharmony_ci			fcf_record = kzalloc(sizeof(struct fcf_record),
33328c2ecf20Sopenharmony_ci					GFP_KERNEL);
33338c2ecf20Sopenharmony_ci			if (unlikely(!fcf_record)) {
33348c2ecf20Sopenharmony_ci				lpfc_printf_log(phba, KERN_ERR,
33358c2ecf20Sopenharmony_ci					LOG_TRACE_EVENT,
33368c2ecf20Sopenharmony_ci					"2554 Could not allocate memory for "
33378c2ecf20Sopenharmony_ci					"fcf record\n");
33388c2ecf20Sopenharmony_ci				rc = -ENODEV;
33398c2ecf20Sopenharmony_ci				goto out;
33408c2ecf20Sopenharmony_ci			}
33418c2ecf20Sopenharmony_ci
33428c2ecf20Sopenharmony_ci			lpfc_sli4_build_dflt_fcf_record(phba, fcf_record,
33438c2ecf20Sopenharmony_ci						LPFC_FCOE_FCF_DEF_INDEX);
33448c2ecf20Sopenharmony_ci			rc = lpfc_sli4_add_fcf_record(phba, fcf_record);
33458c2ecf20Sopenharmony_ci			if (unlikely(rc)) {
33468c2ecf20Sopenharmony_ci				lpfc_printf_log(phba, KERN_ERR,
33478c2ecf20Sopenharmony_ci					LOG_TRACE_EVENT,
33488c2ecf20Sopenharmony_ci					"2013 Could not manually add FCF "
33498c2ecf20Sopenharmony_ci					"record 0, status %d\n", rc);
33508c2ecf20Sopenharmony_ci				rc = -ENODEV;
33518c2ecf20Sopenharmony_ci				kfree(fcf_record);
33528c2ecf20Sopenharmony_ci				goto out;
33538c2ecf20Sopenharmony_ci			}
33548c2ecf20Sopenharmony_ci			kfree(fcf_record);
33558c2ecf20Sopenharmony_ci		}
33568c2ecf20Sopenharmony_ci		/*
33578c2ecf20Sopenharmony_ci		 * The driver is expected to do FIP/FCF. Call the port
33588c2ecf20Sopenharmony_ci		 * and get the FCF Table.
33598c2ecf20Sopenharmony_ci		 */
33608c2ecf20Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, iflags);
33618c2ecf20Sopenharmony_ci		if (phba->hba_flag & FCF_TS_INPROG) {
33628c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&phba->hbalock, iflags);
33638c2ecf20Sopenharmony_ci			return;
33648c2ecf20Sopenharmony_ci		}
33658c2ecf20Sopenharmony_ci		/* This is the initial FCF discovery scan */
33668c2ecf20Sopenharmony_ci		phba->fcf.fcf_flag |= FCF_INIT_DISC;
33678c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflags);
33688c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
33698c2ecf20Sopenharmony_ci				"2778 Start FCF table scan at linkup\n");
33708c2ecf20Sopenharmony_ci		rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba,
33718c2ecf20Sopenharmony_ci						     LPFC_FCOE_FCF_GET_FIRST);
33728c2ecf20Sopenharmony_ci		if (rc) {
33738c2ecf20Sopenharmony_ci			spin_lock_irqsave(&phba->hbalock, iflags);
33748c2ecf20Sopenharmony_ci			phba->fcf.fcf_flag &= ~FCF_INIT_DISC;
33758c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&phba->hbalock, iflags);
33768c2ecf20Sopenharmony_ci			goto out;
33778c2ecf20Sopenharmony_ci		}
33788c2ecf20Sopenharmony_ci		/* Reset FCF roundrobin bmask for new discovery */
33798c2ecf20Sopenharmony_ci		lpfc_sli4_clear_fcf_rr_bmask(phba);
33808c2ecf20Sopenharmony_ci	}
33818c2ecf20Sopenharmony_ci
33828c2ecf20Sopenharmony_ci	/* Prepare for LINK up registrations */
33838c2ecf20Sopenharmony_ci	memset(phba->os_host_name, 0, sizeof(phba->os_host_name));
33848c2ecf20Sopenharmony_ci	scnprintf(phba->os_host_name, sizeof(phba->os_host_name), "%s",
33858c2ecf20Sopenharmony_ci		  init_utsname()->nodename);
33868c2ecf20Sopenharmony_ci	return;
33878c2ecf20Sopenharmony_ciout:
33888c2ecf20Sopenharmony_ci	lpfc_vport_set_state(vport, FC_VPORT_FAILED);
33898c2ecf20Sopenharmony_ci	lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
33908c2ecf20Sopenharmony_ci			 "0263 Discovery Mailbox error: state: 0x%x : x%px x%px\n",
33918c2ecf20Sopenharmony_ci			 vport->port_state, sparam_mbox, cfglink_mbox);
33928c2ecf20Sopenharmony_ci	lpfc_issue_clear_la(phba, vport);
33938c2ecf20Sopenharmony_ci	return;
33948c2ecf20Sopenharmony_ci}
33958c2ecf20Sopenharmony_ci
33968c2ecf20Sopenharmony_cistatic void
33978c2ecf20Sopenharmony_cilpfc_enable_la(struct lpfc_hba *phba)
33988c2ecf20Sopenharmony_ci{
33998c2ecf20Sopenharmony_ci	uint32_t control;
34008c2ecf20Sopenharmony_ci	struct lpfc_sli *psli = &phba->sli;
34018c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
34028c2ecf20Sopenharmony_ci	psli->sli_flag |= LPFC_PROCESS_LA;
34038c2ecf20Sopenharmony_ci	if (phba->sli_rev <= LPFC_SLI_REV3) {
34048c2ecf20Sopenharmony_ci		control = readl(phba->HCregaddr);
34058c2ecf20Sopenharmony_ci		control |= HC_LAINT_ENA;
34068c2ecf20Sopenharmony_ci		writel(control, phba->HCregaddr);
34078c2ecf20Sopenharmony_ci		readl(phba->HCregaddr); /* flush */
34088c2ecf20Sopenharmony_ci	}
34098c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
34108c2ecf20Sopenharmony_ci}
34118c2ecf20Sopenharmony_ci
34128c2ecf20Sopenharmony_cistatic void
34138c2ecf20Sopenharmony_cilpfc_mbx_issue_link_down(struct lpfc_hba *phba)
34148c2ecf20Sopenharmony_ci{
34158c2ecf20Sopenharmony_ci	lpfc_linkdown(phba);
34168c2ecf20Sopenharmony_ci	lpfc_enable_la(phba);
34178c2ecf20Sopenharmony_ci	lpfc_unregister_unused_fcf(phba);
34188c2ecf20Sopenharmony_ci	/* turn on Link Attention interrupts - no CLEAR_LA needed */
34198c2ecf20Sopenharmony_ci}
34208c2ecf20Sopenharmony_ci
34218c2ecf20Sopenharmony_ci
34228c2ecf20Sopenharmony_ci/*
34238c2ecf20Sopenharmony_ci * This routine handles processing a READ_TOPOLOGY mailbox
34248c2ecf20Sopenharmony_ci * command upon completion. It is setup in the LPFC_MBOXQ
34258c2ecf20Sopenharmony_ci * as the completion routine when the command is
34268c2ecf20Sopenharmony_ci * handed off to the SLI layer. SLI4 only.
34278c2ecf20Sopenharmony_ci */
34288c2ecf20Sopenharmony_civoid
34298c2ecf20Sopenharmony_cilpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
34308c2ecf20Sopenharmony_ci{
34318c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = pmb->vport;
34328c2ecf20Sopenharmony_ci	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
34338c2ecf20Sopenharmony_ci	struct lpfc_mbx_read_top *la;
34348c2ecf20Sopenharmony_ci	struct lpfc_sli_ring *pring;
34358c2ecf20Sopenharmony_ci	MAILBOX_t *mb = &pmb->u.mb;
34368c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)(pmb->ctx_buf);
34378c2ecf20Sopenharmony_ci	uint8_t attn_type;
34388c2ecf20Sopenharmony_ci	unsigned long iflags;
34398c2ecf20Sopenharmony_ci
34408c2ecf20Sopenharmony_ci	/* Unblock ELS traffic */
34418c2ecf20Sopenharmony_ci	pring = lpfc_phba_elsring(phba);
34428c2ecf20Sopenharmony_ci	if (pring)
34438c2ecf20Sopenharmony_ci		pring->flag &= ~LPFC_STOP_IOCB_EVENT;
34448c2ecf20Sopenharmony_ci
34458c2ecf20Sopenharmony_ci	/* Check for error */
34468c2ecf20Sopenharmony_ci	if (mb->mbxStatus) {
34478c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
34488c2ecf20Sopenharmony_ci				"1307 READ_LA mbox error x%x state x%x\n",
34498c2ecf20Sopenharmony_ci				mb->mbxStatus, vport->port_state);
34508c2ecf20Sopenharmony_ci		lpfc_mbx_issue_link_down(phba);
34518c2ecf20Sopenharmony_ci		phba->link_state = LPFC_HBA_ERROR;
34528c2ecf20Sopenharmony_ci		goto lpfc_mbx_cmpl_read_topology_free_mbuf;
34538c2ecf20Sopenharmony_ci	}
34548c2ecf20Sopenharmony_ci
34558c2ecf20Sopenharmony_ci	la = (struct lpfc_mbx_read_top *) &pmb->u.mb.un.varReadTop;
34568c2ecf20Sopenharmony_ci	attn_type = bf_get(lpfc_mbx_read_top_att_type, la);
34578c2ecf20Sopenharmony_ci
34588c2ecf20Sopenharmony_ci	memcpy(&phba->alpa_map[0], mp->virt, 128);
34598c2ecf20Sopenharmony_ci
34608c2ecf20Sopenharmony_ci	spin_lock_irqsave(shost->host_lock, iflags);
34618c2ecf20Sopenharmony_ci	if (bf_get(lpfc_mbx_read_top_pb, la))
34628c2ecf20Sopenharmony_ci		vport->fc_flag |= FC_BYPASSED_MODE;
34638c2ecf20Sopenharmony_ci	else
34648c2ecf20Sopenharmony_ci		vport->fc_flag &= ~FC_BYPASSED_MODE;
34658c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(shost->host_lock, iflags);
34668c2ecf20Sopenharmony_ci
34678c2ecf20Sopenharmony_ci	if (phba->fc_eventTag <= la->eventTag) {
34688c2ecf20Sopenharmony_ci		phba->fc_stat.LinkMultiEvent++;
34698c2ecf20Sopenharmony_ci		if (attn_type == LPFC_ATT_LINK_UP)
34708c2ecf20Sopenharmony_ci			if (phba->fc_eventTag != 0)
34718c2ecf20Sopenharmony_ci				lpfc_linkdown(phba);
34728c2ecf20Sopenharmony_ci	}
34738c2ecf20Sopenharmony_ci
34748c2ecf20Sopenharmony_ci	phba->fc_eventTag = la->eventTag;
34758c2ecf20Sopenharmony_ci	if (phba->sli_rev < LPFC_SLI_REV4) {
34768c2ecf20Sopenharmony_ci		spin_lock_irqsave(&phba->hbalock, iflags);
34778c2ecf20Sopenharmony_ci		if (bf_get(lpfc_mbx_read_top_mm, la))
34788c2ecf20Sopenharmony_ci			phba->sli.sli_flag |= LPFC_MENLO_MAINT;
34798c2ecf20Sopenharmony_ci		else
34808c2ecf20Sopenharmony_ci			phba->sli.sli_flag &= ~LPFC_MENLO_MAINT;
34818c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&phba->hbalock, iflags);
34828c2ecf20Sopenharmony_ci	}
34838c2ecf20Sopenharmony_ci
34848c2ecf20Sopenharmony_ci	phba->link_events++;
34858c2ecf20Sopenharmony_ci	if ((attn_type == LPFC_ATT_LINK_UP) &&
34868c2ecf20Sopenharmony_ci	    !(phba->sli.sli_flag & LPFC_MENLO_MAINT)) {
34878c2ecf20Sopenharmony_ci		phba->fc_stat.LinkUp++;
34888c2ecf20Sopenharmony_ci		if (phba->link_flag & LS_LOOPBACK_MODE) {
34898c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
34908c2ecf20Sopenharmony_ci					"1306 Link Up Event in loop back mode "
34918c2ecf20Sopenharmony_ci					"x%x received Data: x%x x%x x%x x%x\n",
34928c2ecf20Sopenharmony_ci					la->eventTag, phba->fc_eventTag,
34938c2ecf20Sopenharmony_ci					bf_get(lpfc_mbx_read_top_alpa_granted,
34948c2ecf20Sopenharmony_ci					       la),
34958c2ecf20Sopenharmony_ci					bf_get(lpfc_mbx_read_top_link_spd, la),
34968c2ecf20Sopenharmony_ci					phba->alpa_map[0]);
34978c2ecf20Sopenharmony_ci		} else {
34988c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
34998c2ecf20Sopenharmony_ci					"1303 Link Up Event x%x received "
35008c2ecf20Sopenharmony_ci					"Data: x%x x%x x%x x%x x%x x%x %d\n",
35018c2ecf20Sopenharmony_ci					la->eventTag, phba->fc_eventTag,
35028c2ecf20Sopenharmony_ci					bf_get(lpfc_mbx_read_top_alpa_granted,
35038c2ecf20Sopenharmony_ci					       la),
35048c2ecf20Sopenharmony_ci					bf_get(lpfc_mbx_read_top_link_spd, la),
35058c2ecf20Sopenharmony_ci					phba->alpa_map[0],
35068c2ecf20Sopenharmony_ci					bf_get(lpfc_mbx_read_top_mm, la),
35078c2ecf20Sopenharmony_ci					bf_get(lpfc_mbx_read_top_fa, la),
35088c2ecf20Sopenharmony_ci					phba->wait_4_mlo_maint_flg);
35098c2ecf20Sopenharmony_ci		}
35108c2ecf20Sopenharmony_ci		lpfc_mbx_process_link_up(phba, la);
35118c2ecf20Sopenharmony_ci	} else if (attn_type == LPFC_ATT_LINK_DOWN ||
35128c2ecf20Sopenharmony_ci		   attn_type == LPFC_ATT_UNEXP_WWPN) {
35138c2ecf20Sopenharmony_ci		phba->fc_stat.LinkDown++;
35148c2ecf20Sopenharmony_ci		if (phba->link_flag & LS_LOOPBACK_MODE)
35158c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
35168c2ecf20Sopenharmony_ci				"1308 Link Down Event in loop back mode "
35178c2ecf20Sopenharmony_ci				"x%x received "
35188c2ecf20Sopenharmony_ci				"Data: x%x x%x x%x\n",
35198c2ecf20Sopenharmony_ci				la->eventTag, phba->fc_eventTag,
35208c2ecf20Sopenharmony_ci				phba->pport->port_state, vport->fc_flag);
35218c2ecf20Sopenharmony_ci		else if (attn_type == LPFC_ATT_UNEXP_WWPN)
35228c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
35238c2ecf20Sopenharmony_ci				"1313 Link Down Unexpected FA WWPN Event x%x "
35248c2ecf20Sopenharmony_ci				"received Data: x%x x%x x%x x%x x%x\n",
35258c2ecf20Sopenharmony_ci				la->eventTag, phba->fc_eventTag,
35268c2ecf20Sopenharmony_ci				phba->pport->port_state, vport->fc_flag,
35278c2ecf20Sopenharmony_ci				bf_get(lpfc_mbx_read_top_mm, la),
35288c2ecf20Sopenharmony_ci				bf_get(lpfc_mbx_read_top_fa, la));
35298c2ecf20Sopenharmony_ci		else
35308c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
35318c2ecf20Sopenharmony_ci				"1305 Link Down Event x%x received "
35328c2ecf20Sopenharmony_ci				"Data: x%x x%x x%x x%x x%x\n",
35338c2ecf20Sopenharmony_ci				la->eventTag, phba->fc_eventTag,
35348c2ecf20Sopenharmony_ci				phba->pport->port_state, vport->fc_flag,
35358c2ecf20Sopenharmony_ci				bf_get(lpfc_mbx_read_top_mm, la),
35368c2ecf20Sopenharmony_ci				bf_get(lpfc_mbx_read_top_fa, la));
35378c2ecf20Sopenharmony_ci		lpfc_mbx_issue_link_down(phba);
35388c2ecf20Sopenharmony_ci	}
35398c2ecf20Sopenharmony_ci	if (phba->sli.sli_flag & LPFC_MENLO_MAINT &&
35408c2ecf20Sopenharmony_ci	    attn_type == LPFC_ATT_LINK_UP) {
35418c2ecf20Sopenharmony_ci		if (phba->link_state != LPFC_LINK_DOWN) {
35428c2ecf20Sopenharmony_ci			phba->fc_stat.LinkDown++;
35438c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
35448c2ecf20Sopenharmony_ci				"1312 Link Down Event x%x received "
35458c2ecf20Sopenharmony_ci				"Data: x%x x%x x%x\n",
35468c2ecf20Sopenharmony_ci				la->eventTag, phba->fc_eventTag,
35478c2ecf20Sopenharmony_ci				phba->pport->port_state, vport->fc_flag);
35488c2ecf20Sopenharmony_ci			lpfc_mbx_issue_link_down(phba);
35498c2ecf20Sopenharmony_ci		} else
35508c2ecf20Sopenharmony_ci			lpfc_enable_la(phba);
35518c2ecf20Sopenharmony_ci
35528c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
35538c2ecf20Sopenharmony_ci				"1310 Menlo Maint Mode Link up Event x%x rcvd "
35548c2ecf20Sopenharmony_ci				"Data: x%x x%x x%x\n",
35558c2ecf20Sopenharmony_ci				la->eventTag, phba->fc_eventTag,
35568c2ecf20Sopenharmony_ci				phba->pport->port_state, vport->fc_flag);
35578c2ecf20Sopenharmony_ci		/*
35588c2ecf20Sopenharmony_ci		 * The cmnd that triggered this will be waiting for this
35598c2ecf20Sopenharmony_ci		 * signal.
35608c2ecf20Sopenharmony_ci		 */
35618c2ecf20Sopenharmony_ci		/* WAKEUP for MENLO_SET_MODE or MENLO_RESET command. */
35628c2ecf20Sopenharmony_ci		if (phba->wait_4_mlo_maint_flg) {
35638c2ecf20Sopenharmony_ci			phba->wait_4_mlo_maint_flg = 0;
35648c2ecf20Sopenharmony_ci			wake_up_interruptible(&phba->wait_4_mlo_m_q);
35658c2ecf20Sopenharmony_ci		}
35668c2ecf20Sopenharmony_ci	}
35678c2ecf20Sopenharmony_ci
35688c2ecf20Sopenharmony_ci	if ((phba->sli_rev < LPFC_SLI_REV4) &&
35698c2ecf20Sopenharmony_ci	    bf_get(lpfc_mbx_read_top_fa, la)) {
35708c2ecf20Sopenharmony_ci		if (phba->sli.sli_flag & LPFC_MENLO_MAINT)
35718c2ecf20Sopenharmony_ci			lpfc_issue_clear_la(phba, vport);
35728c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
35738c2ecf20Sopenharmony_ci				"1311 fa %d\n",
35748c2ecf20Sopenharmony_ci				bf_get(lpfc_mbx_read_top_fa, la));
35758c2ecf20Sopenharmony_ci	}
35768c2ecf20Sopenharmony_ci
35778c2ecf20Sopenharmony_cilpfc_mbx_cmpl_read_topology_free_mbuf:
35788c2ecf20Sopenharmony_ci	lpfc_mbuf_free(phba, mp->virt, mp->phys);
35798c2ecf20Sopenharmony_ci	kfree(mp);
35808c2ecf20Sopenharmony_ci	mempool_free(pmb, phba->mbox_mem_pool);
35818c2ecf20Sopenharmony_ci	return;
35828c2ecf20Sopenharmony_ci}
35838c2ecf20Sopenharmony_ci
35848c2ecf20Sopenharmony_ci/*
35858c2ecf20Sopenharmony_ci * This routine handles processing a REG_LOGIN mailbox
35868c2ecf20Sopenharmony_ci * command upon completion. It is setup in the LPFC_MBOXQ
35878c2ecf20Sopenharmony_ci * as the completion routine when the command is
35888c2ecf20Sopenharmony_ci * handed off to the SLI layer.
35898c2ecf20Sopenharmony_ci */
35908c2ecf20Sopenharmony_civoid
35918c2ecf20Sopenharmony_cilpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
35928c2ecf20Sopenharmony_ci{
35938c2ecf20Sopenharmony_ci	struct lpfc_vport  *vport = pmb->vport;
35948c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)(pmb->ctx_buf);
35958c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
35968c2ecf20Sopenharmony_ci	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
35978c2ecf20Sopenharmony_ci
35988c2ecf20Sopenharmony_ci	pmb->ctx_buf = NULL;
35998c2ecf20Sopenharmony_ci	pmb->ctx_ndlp = NULL;
36008c2ecf20Sopenharmony_ci
36018c2ecf20Sopenharmony_ci	lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI,
36028c2ecf20Sopenharmony_ci			 "0002 rpi:%x DID:%x flg:%x %d map:%x x%px\n",
36038c2ecf20Sopenharmony_ci			 ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag,
36048c2ecf20Sopenharmony_ci			 kref_read(&ndlp->kref),
36058c2ecf20Sopenharmony_ci			 ndlp->nlp_usg_map, ndlp);
36068c2ecf20Sopenharmony_ci	if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND)
36078c2ecf20Sopenharmony_ci		ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
36088c2ecf20Sopenharmony_ci
36098c2ecf20Sopenharmony_ci	if (ndlp->nlp_flag & NLP_IGNR_REG_CMPL ||
36108c2ecf20Sopenharmony_ci	    ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE) {
36118c2ecf20Sopenharmony_ci		/* We rcvd a rscn after issuing this
36128c2ecf20Sopenharmony_ci		 * mbox reg login, we may have cycled
36138c2ecf20Sopenharmony_ci		 * back through the state and be
36148c2ecf20Sopenharmony_ci		 * back at reg login state so this
36158c2ecf20Sopenharmony_ci		 * mbox needs to be ignored becase
36168c2ecf20Sopenharmony_ci		 * there is another reg login in
36178c2ecf20Sopenharmony_ci		 * process.
36188c2ecf20Sopenharmony_ci		 */
36198c2ecf20Sopenharmony_ci		spin_lock_irq(shost->host_lock);
36208c2ecf20Sopenharmony_ci		ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
36218c2ecf20Sopenharmony_ci		spin_unlock_irq(shost->host_lock);
36228c2ecf20Sopenharmony_ci
36238c2ecf20Sopenharmony_ci		/*
36248c2ecf20Sopenharmony_ci		 * We cannot leave the RPI registered because
36258c2ecf20Sopenharmony_ci		 * if we go thru discovery again for this ndlp
36268c2ecf20Sopenharmony_ci		 * a subsequent REG_RPI will fail.
36278c2ecf20Sopenharmony_ci		 */
36288c2ecf20Sopenharmony_ci		ndlp->nlp_flag |= NLP_RPI_REGISTERED;
36298c2ecf20Sopenharmony_ci		lpfc_unreg_rpi(vport, ndlp);
36308c2ecf20Sopenharmony_ci	}
36318c2ecf20Sopenharmony_ci
36328c2ecf20Sopenharmony_ci	/* Call state machine */
36338c2ecf20Sopenharmony_ci	lpfc_disc_state_machine(vport, ndlp, pmb, NLP_EVT_CMPL_REG_LOGIN);
36348c2ecf20Sopenharmony_ci
36358c2ecf20Sopenharmony_ci	lpfc_mbuf_free(phba, mp->virt, mp->phys);
36368c2ecf20Sopenharmony_ci	kfree(mp);
36378c2ecf20Sopenharmony_ci	mempool_free(pmb, phba->mbox_mem_pool);
36388c2ecf20Sopenharmony_ci	/* decrement the node reference count held for this callback
36398c2ecf20Sopenharmony_ci	 * function.
36408c2ecf20Sopenharmony_ci	 */
36418c2ecf20Sopenharmony_ci	lpfc_nlp_put(ndlp);
36428c2ecf20Sopenharmony_ci
36438c2ecf20Sopenharmony_ci	return;
36448c2ecf20Sopenharmony_ci}
36458c2ecf20Sopenharmony_ci
36468c2ecf20Sopenharmony_cistatic void
36478c2ecf20Sopenharmony_cilpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
36488c2ecf20Sopenharmony_ci{
36498c2ecf20Sopenharmony_ci	MAILBOX_t *mb = &pmb->u.mb;
36508c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = pmb->vport;
36518c2ecf20Sopenharmony_ci	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
36528c2ecf20Sopenharmony_ci
36538c2ecf20Sopenharmony_ci	switch (mb->mbxStatus) {
36548c2ecf20Sopenharmony_ci	case 0x0011:
36558c2ecf20Sopenharmony_ci	case 0x0020:
36568c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
36578c2ecf20Sopenharmony_ci				 "0911 cmpl_unreg_vpi, mb status = 0x%x\n",
36588c2ecf20Sopenharmony_ci				 mb->mbxStatus);
36598c2ecf20Sopenharmony_ci		break;
36608c2ecf20Sopenharmony_ci	/* If VPI is busy, reset the HBA */
36618c2ecf20Sopenharmony_ci	case 0x9700:
36628c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
36638c2ecf20Sopenharmony_ci			"2798 Unreg_vpi failed vpi 0x%x, mb status = 0x%x\n",
36648c2ecf20Sopenharmony_ci			vport->vpi, mb->mbxStatus);
36658c2ecf20Sopenharmony_ci		if (!(phba->pport->load_flag & FC_UNLOADING))
36668c2ecf20Sopenharmony_ci			lpfc_workq_post_event(phba, NULL, NULL,
36678c2ecf20Sopenharmony_ci				LPFC_EVT_RESET_HBA);
36688c2ecf20Sopenharmony_ci	}
36698c2ecf20Sopenharmony_ci	spin_lock_irq(shost->host_lock);
36708c2ecf20Sopenharmony_ci	vport->vpi_state &= ~LPFC_VPI_REGISTERED;
36718c2ecf20Sopenharmony_ci	vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
36728c2ecf20Sopenharmony_ci	spin_unlock_irq(shost->host_lock);
36738c2ecf20Sopenharmony_ci	vport->unreg_vpi_cmpl = VPORT_OK;
36748c2ecf20Sopenharmony_ci	mempool_free(pmb, phba->mbox_mem_pool);
36758c2ecf20Sopenharmony_ci	lpfc_cleanup_vports_rrqs(vport, NULL);
36768c2ecf20Sopenharmony_ci	/*
36778c2ecf20Sopenharmony_ci	 * This shost reference might have been taken at the beginning of
36788c2ecf20Sopenharmony_ci	 * lpfc_vport_delete()
36798c2ecf20Sopenharmony_ci	 */
36808c2ecf20Sopenharmony_ci	if ((vport->load_flag & FC_UNLOADING) && (vport != phba->pport))
36818c2ecf20Sopenharmony_ci		scsi_host_put(shost);
36828c2ecf20Sopenharmony_ci}
36838c2ecf20Sopenharmony_ci
36848c2ecf20Sopenharmony_ciint
36858c2ecf20Sopenharmony_cilpfc_mbx_unreg_vpi(struct lpfc_vport *vport)
36868c2ecf20Sopenharmony_ci{
36878c2ecf20Sopenharmony_ci	struct lpfc_hba  *phba = vport->phba;
36888c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
36898c2ecf20Sopenharmony_ci	int rc;
36908c2ecf20Sopenharmony_ci
36918c2ecf20Sopenharmony_ci	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
36928c2ecf20Sopenharmony_ci	if (!mbox)
36938c2ecf20Sopenharmony_ci		return 1;
36948c2ecf20Sopenharmony_ci
36958c2ecf20Sopenharmony_ci	lpfc_unreg_vpi(phba, vport->vpi, mbox);
36968c2ecf20Sopenharmony_ci	mbox->vport = vport;
36978c2ecf20Sopenharmony_ci	mbox->mbox_cmpl = lpfc_mbx_cmpl_unreg_vpi;
36988c2ecf20Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
36998c2ecf20Sopenharmony_ci	if (rc == MBX_NOT_FINISHED) {
37008c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
37018c2ecf20Sopenharmony_ci				 "1800 Could not issue unreg_vpi\n");
37028c2ecf20Sopenharmony_ci		mempool_free(mbox, phba->mbox_mem_pool);
37038c2ecf20Sopenharmony_ci		vport->unreg_vpi_cmpl = VPORT_ERROR;
37048c2ecf20Sopenharmony_ci		return rc;
37058c2ecf20Sopenharmony_ci	}
37068c2ecf20Sopenharmony_ci	return 0;
37078c2ecf20Sopenharmony_ci}
37088c2ecf20Sopenharmony_ci
37098c2ecf20Sopenharmony_cistatic void
37108c2ecf20Sopenharmony_cilpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
37118c2ecf20Sopenharmony_ci{
37128c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = pmb->vport;
37138c2ecf20Sopenharmony_ci	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
37148c2ecf20Sopenharmony_ci	MAILBOX_t *mb = &pmb->u.mb;
37158c2ecf20Sopenharmony_ci
37168c2ecf20Sopenharmony_ci	switch (mb->mbxStatus) {
37178c2ecf20Sopenharmony_ci	case 0x0011:
37188c2ecf20Sopenharmony_ci	case 0x9601:
37198c2ecf20Sopenharmony_ci	case 0x9602:
37208c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
37218c2ecf20Sopenharmony_ci				 "0912 cmpl_reg_vpi, mb status = 0x%x\n",
37228c2ecf20Sopenharmony_ci				 mb->mbxStatus);
37238c2ecf20Sopenharmony_ci		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
37248c2ecf20Sopenharmony_ci		spin_lock_irq(shost->host_lock);
37258c2ecf20Sopenharmony_ci		vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
37268c2ecf20Sopenharmony_ci		spin_unlock_irq(shost->host_lock);
37278c2ecf20Sopenharmony_ci		vport->fc_myDID = 0;
37288c2ecf20Sopenharmony_ci
37298c2ecf20Sopenharmony_ci		if ((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
37308c2ecf20Sopenharmony_ci		    (vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME)) {
37318c2ecf20Sopenharmony_ci			if (phba->nvmet_support)
37328c2ecf20Sopenharmony_ci				lpfc_nvmet_update_targetport(phba);
37338c2ecf20Sopenharmony_ci			else
37348c2ecf20Sopenharmony_ci				lpfc_nvme_update_localport(vport);
37358c2ecf20Sopenharmony_ci		}
37368c2ecf20Sopenharmony_ci		goto out;
37378c2ecf20Sopenharmony_ci	}
37388c2ecf20Sopenharmony_ci
37398c2ecf20Sopenharmony_ci	spin_lock_irq(shost->host_lock);
37408c2ecf20Sopenharmony_ci	vport->vpi_state |= LPFC_VPI_REGISTERED;
37418c2ecf20Sopenharmony_ci	vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
37428c2ecf20Sopenharmony_ci	spin_unlock_irq(shost->host_lock);
37438c2ecf20Sopenharmony_ci	vport->num_disc_nodes = 0;
37448c2ecf20Sopenharmony_ci	/* go thru NPR list and issue ELS PLOGIs */
37458c2ecf20Sopenharmony_ci	if (vport->fc_npr_cnt)
37468c2ecf20Sopenharmony_ci		lpfc_els_disc_plogi(vport);
37478c2ecf20Sopenharmony_ci
37488c2ecf20Sopenharmony_ci	if (!vport->num_disc_nodes) {
37498c2ecf20Sopenharmony_ci		spin_lock_irq(shost->host_lock);
37508c2ecf20Sopenharmony_ci		vport->fc_flag &= ~FC_NDISC_ACTIVE;
37518c2ecf20Sopenharmony_ci		spin_unlock_irq(shost->host_lock);
37528c2ecf20Sopenharmony_ci		lpfc_can_disctmo(vport);
37538c2ecf20Sopenharmony_ci	}
37548c2ecf20Sopenharmony_ci	vport->port_state = LPFC_VPORT_READY;
37558c2ecf20Sopenharmony_ci
37568c2ecf20Sopenharmony_ciout:
37578c2ecf20Sopenharmony_ci	mempool_free(pmb, phba->mbox_mem_pool);
37588c2ecf20Sopenharmony_ci	return;
37598c2ecf20Sopenharmony_ci}
37608c2ecf20Sopenharmony_ci
37618c2ecf20Sopenharmony_ci/**
37628c2ecf20Sopenharmony_ci * lpfc_create_static_vport - Read HBA config region to create static vports.
37638c2ecf20Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
37648c2ecf20Sopenharmony_ci *
37658c2ecf20Sopenharmony_ci * This routine issue a DUMP mailbox command for config region 22 to get
37668c2ecf20Sopenharmony_ci * the list of static vports to be created. The function create vports
37678c2ecf20Sopenharmony_ci * based on the information returned from the HBA.
37688c2ecf20Sopenharmony_ci **/
37698c2ecf20Sopenharmony_civoid
37708c2ecf20Sopenharmony_cilpfc_create_static_vport(struct lpfc_hba *phba)
37718c2ecf20Sopenharmony_ci{
37728c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t *pmb = NULL;
37738c2ecf20Sopenharmony_ci	MAILBOX_t *mb;
37748c2ecf20Sopenharmony_ci	struct static_vport_info *vport_info;
37758c2ecf20Sopenharmony_ci	int mbx_wait_rc = 0, i;
37768c2ecf20Sopenharmony_ci	struct fc_vport_identifiers vport_id;
37778c2ecf20Sopenharmony_ci	struct fc_vport *new_fc_vport;
37788c2ecf20Sopenharmony_ci	struct Scsi_Host *shost;
37798c2ecf20Sopenharmony_ci	struct lpfc_vport *vport;
37808c2ecf20Sopenharmony_ci	uint16_t offset = 0;
37818c2ecf20Sopenharmony_ci	uint8_t *vport_buff;
37828c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *mp;
37838c2ecf20Sopenharmony_ci	uint32_t byte_count = 0;
37848c2ecf20Sopenharmony_ci
37858c2ecf20Sopenharmony_ci	pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
37868c2ecf20Sopenharmony_ci	if (!pmb) {
37878c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
37888c2ecf20Sopenharmony_ci				"0542 lpfc_create_static_vport failed to"
37898c2ecf20Sopenharmony_ci				" allocate mailbox memory\n");
37908c2ecf20Sopenharmony_ci		return;
37918c2ecf20Sopenharmony_ci	}
37928c2ecf20Sopenharmony_ci	memset(pmb, 0, sizeof(LPFC_MBOXQ_t));
37938c2ecf20Sopenharmony_ci	mb = &pmb->u.mb;
37948c2ecf20Sopenharmony_ci
37958c2ecf20Sopenharmony_ci	vport_info = kzalloc(sizeof(struct static_vport_info), GFP_KERNEL);
37968c2ecf20Sopenharmony_ci	if (!vport_info) {
37978c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
37988c2ecf20Sopenharmony_ci				"0543 lpfc_create_static_vport failed to"
37998c2ecf20Sopenharmony_ci				" allocate vport_info\n");
38008c2ecf20Sopenharmony_ci		mempool_free(pmb, phba->mbox_mem_pool);
38018c2ecf20Sopenharmony_ci		return;
38028c2ecf20Sopenharmony_ci	}
38038c2ecf20Sopenharmony_ci
38048c2ecf20Sopenharmony_ci	vport_buff = (uint8_t *) vport_info;
38058c2ecf20Sopenharmony_ci	do {
38068c2ecf20Sopenharmony_ci		/* free dma buffer from previous round */
38078c2ecf20Sopenharmony_ci		if (pmb->ctx_buf) {
38088c2ecf20Sopenharmony_ci			mp = (struct lpfc_dmabuf *)pmb->ctx_buf;
38098c2ecf20Sopenharmony_ci			lpfc_mbuf_free(phba, mp->virt, mp->phys);
38108c2ecf20Sopenharmony_ci			kfree(mp);
38118c2ecf20Sopenharmony_ci		}
38128c2ecf20Sopenharmony_ci		if (lpfc_dump_static_vport(phba, pmb, offset))
38138c2ecf20Sopenharmony_ci			goto out;
38148c2ecf20Sopenharmony_ci
38158c2ecf20Sopenharmony_ci		pmb->vport = phba->pport;
38168c2ecf20Sopenharmony_ci		mbx_wait_rc = lpfc_sli_issue_mbox_wait(phba, pmb,
38178c2ecf20Sopenharmony_ci							LPFC_MBOX_TMO);
38188c2ecf20Sopenharmony_ci
38198c2ecf20Sopenharmony_ci		if ((mbx_wait_rc != MBX_SUCCESS) || mb->mbxStatus) {
38208c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
38218c2ecf20Sopenharmony_ci				"0544 lpfc_create_static_vport failed to"
38228c2ecf20Sopenharmony_ci				" issue dump mailbox command ret 0x%x "
38238c2ecf20Sopenharmony_ci				"status 0x%x\n",
38248c2ecf20Sopenharmony_ci				mbx_wait_rc, mb->mbxStatus);
38258c2ecf20Sopenharmony_ci			goto out;
38268c2ecf20Sopenharmony_ci		}
38278c2ecf20Sopenharmony_ci
38288c2ecf20Sopenharmony_ci		if (phba->sli_rev == LPFC_SLI_REV4) {
38298c2ecf20Sopenharmony_ci			byte_count = pmb->u.mqe.un.mb_words[5];
38308c2ecf20Sopenharmony_ci			mp = (struct lpfc_dmabuf *)pmb->ctx_buf;
38318c2ecf20Sopenharmony_ci			if (byte_count > sizeof(struct static_vport_info) -
38328c2ecf20Sopenharmony_ci					offset)
38338c2ecf20Sopenharmony_ci				byte_count = sizeof(struct static_vport_info)
38348c2ecf20Sopenharmony_ci					- offset;
38358c2ecf20Sopenharmony_ci			memcpy(vport_buff + offset, mp->virt, byte_count);
38368c2ecf20Sopenharmony_ci			offset += byte_count;
38378c2ecf20Sopenharmony_ci		} else {
38388c2ecf20Sopenharmony_ci			if (mb->un.varDmp.word_cnt >
38398c2ecf20Sopenharmony_ci				sizeof(struct static_vport_info) - offset)
38408c2ecf20Sopenharmony_ci				mb->un.varDmp.word_cnt =
38418c2ecf20Sopenharmony_ci					sizeof(struct static_vport_info)
38428c2ecf20Sopenharmony_ci						- offset;
38438c2ecf20Sopenharmony_ci			byte_count = mb->un.varDmp.word_cnt;
38448c2ecf20Sopenharmony_ci			lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET,
38458c2ecf20Sopenharmony_ci				vport_buff + offset,
38468c2ecf20Sopenharmony_ci				byte_count);
38478c2ecf20Sopenharmony_ci
38488c2ecf20Sopenharmony_ci			offset += byte_count;
38498c2ecf20Sopenharmony_ci		}
38508c2ecf20Sopenharmony_ci
38518c2ecf20Sopenharmony_ci	} while (byte_count &&
38528c2ecf20Sopenharmony_ci		offset < sizeof(struct static_vport_info));
38538c2ecf20Sopenharmony_ci
38548c2ecf20Sopenharmony_ci
38558c2ecf20Sopenharmony_ci	if ((le32_to_cpu(vport_info->signature) != VPORT_INFO_SIG) ||
38568c2ecf20Sopenharmony_ci		((le32_to_cpu(vport_info->rev) & VPORT_INFO_REV_MASK)
38578c2ecf20Sopenharmony_ci			!= VPORT_INFO_REV)) {
38588c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
38598c2ecf20Sopenharmony_ci				"0545 lpfc_create_static_vport bad"
38608c2ecf20Sopenharmony_ci				" information header 0x%x 0x%x\n",
38618c2ecf20Sopenharmony_ci				le32_to_cpu(vport_info->signature),
38628c2ecf20Sopenharmony_ci				le32_to_cpu(vport_info->rev) &
38638c2ecf20Sopenharmony_ci				VPORT_INFO_REV_MASK);
38648c2ecf20Sopenharmony_ci
38658c2ecf20Sopenharmony_ci		goto out;
38668c2ecf20Sopenharmony_ci	}
38678c2ecf20Sopenharmony_ci
38688c2ecf20Sopenharmony_ci	shost = lpfc_shost_from_vport(phba->pport);
38698c2ecf20Sopenharmony_ci
38708c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_STATIC_VPORT_COUNT; i++) {
38718c2ecf20Sopenharmony_ci		memset(&vport_id, 0, sizeof(vport_id));
38728c2ecf20Sopenharmony_ci		vport_id.port_name = wwn_to_u64(vport_info->vport_list[i].wwpn);
38738c2ecf20Sopenharmony_ci		vport_id.node_name = wwn_to_u64(vport_info->vport_list[i].wwnn);
38748c2ecf20Sopenharmony_ci		if (!vport_id.port_name || !vport_id.node_name)
38758c2ecf20Sopenharmony_ci			continue;
38768c2ecf20Sopenharmony_ci
38778c2ecf20Sopenharmony_ci		vport_id.roles = FC_PORT_ROLE_FCP_INITIATOR;
38788c2ecf20Sopenharmony_ci		vport_id.vport_type = FC_PORTTYPE_NPIV;
38798c2ecf20Sopenharmony_ci		vport_id.disable = false;
38808c2ecf20Sopenharmony_ci		new_fc_vport = fc_vport_create(shost, 0, &vport_id);
38818c2ecf20Sopenharmony_ci
38828c2ecf20Sopenharmony_ci		if (!new_fc_vport) {
38838c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
38848c2ecf20Sopenharmony_ci				"0546 lpfc_create_static_vport failed to"
38858c2ecf20Sopenharmony_ci				" create vport\n");
38868c2ecf20Sopenharmony_ci			continue;
38878c2ecf20Sopenharmony_ci		}
38888c2ecf20Sopenharmony_ci
38898c2ecf20Sopenharmony_ci		vport = *(struct lpfc_vport **)new_fc_vport->dd_data;
38908c2ecf20Sopenharmony_ci		vport->vport_flag |= STATIC_VPORT;
38918c2ecf20Sopenharmony_ci	}
38928c2ecf20Sopenharmony_ci
38938c2ecf20Sopenharmony_ciout:
38948c2ecf20Sopenharmony_ci	kfree(vport_info);
38958c2ecf20Sopenharmony_ci	if (mbx_wait_rc != MBX_TIMEOUT) {
38968c2ecf20Sopenharmony_ci		if (pmb->ctx_buf) {
38978c2ecf20Sopenharmony_ci			mp = (struct lpfc_dmabuf *)pmb->ctx_buf;
38988c2ecf20Sopenharmony_ci			lpfc_mbuf_free(phba, mp->virt, mp->phys);
38998c2ecf20Sopenharmony_ci			kfree(mp);
39008c2ecf20Sopenharmony_ci		}
39018c2ecf20Sopenharmony_ci		mempool_free(pmb, phba->mbox_mem_pool);
39028c2ecf20Sopenharmony_ci	}
39038c2ecf20Sopenharmony_ci
39048c2ecf20Sopenharmony_ci	return;
39058c2ecf20Sopenharmony_ci}
39068c2ecf20Sopenharmony_ci
39078c2ecf20Sopenharmony_ci/*
39088c2ecf20Sopenharmony_ci * This routine handles processing a Fabric REG_LOGIN mailbox
39098c2ecf20Sopenharmony_ci * command upon completion. It is setup in the LPFC_MBOXQ
39108c2ecf20Sopenharmony_ci * as the completion routine when the command is
39118c2ecf20Sopenharmony_ci * handed off to the SLI layer.
39128c2ecf20Sopenharmony_ci */
39138c2ecf20Sopenharmony_civoid
39148c2ecf20Sopenharmony_cilpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
39158c2ecf20Sopenharmony_ci{
39168c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = pmb->vport;
39178c2ecf20Sopenharmony_ci	MAILBOX_t *mb = &pmb->u.mb;
39188c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)(pmb->ctx_buf);
39198c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp;
39208c2ecf20Sopenharmony_ci	struct Scsi_Host *shost;
39218c2ecf20Sopenharmony_ci
39228c2ecf20Sopenharmony_ci	ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
39238c2ecf20Sopenharmony_ci	pmb->ctx_ndlp = NULL;
39248c2ecf20Sopenharmony_ci	pmb->ctx_buf = NULL;
39258c2ecf20Sopenharmony_ci
39268c2ecf20Sopenharmony_ci	if (mb->mbxStatus) {
39278c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
39288c2ecf20Sopenharmony_ci				 "0258 Register Fabric login error: 0x%x\n",
39298c2ecf20Sopenharmony_ci				 mb->mbxStatus);
39308c2ecf20Sopenharmony_ci		lpfc_mbuf_free(phba, mp->virt, mp->phys);
39318c2ecf20Sopenharmony_ci		kfree(mp);
39328c2ecf20Sopenharmony_ci		mempool_free(pmb, phba->mbox_mem_pool);
39338c2ecf20Sopenharmony_ci
39348c2ecf20Sopenharmony_ci		if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
39358c2ecf20Sopenharmony_ci			/* FLOGI failed, use loop map to make discovery list */
39368c2ecf20Sopenharmony_ci			lpfc_disc_list_loopmap(vport);
39378c2ecf20Sopenharmony_ci
39388c2ecf20Sopenharmony_ci			/* Start discovery */
39398c2ecf20Sopenharmony_ci			lpfc_disc_start(vport);
39408c2ecf20Sopenharmony_ci			/* Decrement the reference count to ndlp after the
39418c2ecf20Sopenharmony_ci			 * reference to the ndlp are done.
39428c2ecf20Sopenharmony_ci			 */
39438c2ecf20Sopenharmony_ci			lpfc_nlp_put(ndlp);
39448c2ecf20Sopenharmony_ci			return;
39458c2ecf20Sopenharmony_ci		}
39468c2ecf20Sopenharmony_ci
39478c2ecf20Sopenharmony_ci		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
39488c2ecf20Sopenharmony_ci		/* Decrement the reference count to ndlp after the reference
39498c2ecf20Sopenharmony_ci		 * to the ndlp are done.
39508c2ecf20Sopenharmony_ci		 */
39518c2ecf20Sopenharmony_ci		lpfc_nlp_put(ndlp);
39528c2ecf20Sopenharmony_ci		return;
39538c2ecf20Sopenharmony_ci	}
39548c2ecf20Sopenharmony_ci
39558c2ecf20Sopenharmony_ci	if (phba->sli_rev < LPFC_SLI_REV4)
39568c2ecf20Sopenharmony_ci		ndlp->nlp_rpi = mb->un.varWords[0];
39578c2ecf20Sopenharmony_ci	ndlp->nlp_flag |= NLP_RPI_REGISTERED;
39588c2ecf20Sopenharmony_ci	ndlp->nlp_type |= NLP_FABRIC;
39598c2ecf20Sopenharmony_ci	lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
39608c2ecf20Sopenharmony_ci
39618c2ecf20Sopenharmony_ci	if (vport->port_state == LPFC_FABRIC_CFG_LINK) {
39628c2ecf20Sopenharmony_ci		/* when physical port receive logo donot start
39638c2ecf20Sopenharmony_ci		 * vport discovery */
39648c2ecf20Sopenharmony_ci		if (!(vport->fc_flag & FC_LOGO_RCVD_DID_CHNG))
39658c2ecf20Sopenharmony_ci			lpfc_start_fdiscs(phba);
39668c2ecf20Sopenharmony_ci		else {
39678c2ecf20Sopenharmony_ci			shost = lpfc_shost_from_vport(vport);
39688c2ecf20Sopenharmony_ci			spin_lock_irq(shost->host_lock);
39698c2ecf20Sopenharmony_ci			vport->fc_flag &= ~FC_LOGO_RCVD_DID_CHNG ;
39708c2ecf20Sopenharmony_ci			spin_unlock_irq(shost->host_lock);
39718c2ecf20Sopenharmony_ci		}
39728c2ecf20Sopenharmony_ci		lpfc_do_scr_ns_plogi(phba, vport);
39738c2ecf20Sopenharmony_ci	}
39748c2ecf20Sopenharmony_ci
39758c2ecf20Sopenharmony_ci	lpfc_mbuf_free(phba, mp->virt, mp->phys);
39768c2ecf20Sopenharmony_ci	kfree(mp);
39778c2ecf20Sopenharmony_ci	mempool_free(pmb, phba->mbox_mem_pool);
39788c2ecf20Sopenharmony_ci
39798c2ecf20Sopenharmony_ci	/* Drop the reference count from the mbox at the end after
39808c2ecf20Sopenharmony_ci	 * all the current reference to the ndlp have been done.
39818c2ecf20Sopenharmony_ci	 */
39828c2ecf20Sopenharmony_ci	lpfc_nlp_put(ndlp);
39838c2ecf20Sopenharmony_ci	return;
39848c2ecf20Sopenharmony_ci}
39858c2ecf20Sopenharmony_ci
39868c2ecf20Sopenharmony_ci /*
39878c2ecf20Sopenharmony_ci  * This routine will issue a GID_FT for each FC4 Type supported
39888c2ecf20Sopenharmony_ci  * by the driver. ALL GID_FTs must complete before discovery is started.
39898c2ecf20Sopenharmony_ci  */
39908c2ecf20Sopenharmony_ciint
39918c2ecf20Sopenharmony_cilpfc_issue_gidft(struct lpfc_vport *vport)
39928c2ecf20Sopenharmony_ci{
39938c2ecf20Sopenharmony_ci	/* Good status, issue CT Request to NameServer */
39948c2ecf20Sopenharmony_ci	if ((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
39958c2ecf20Sopenharmony_ci	    (vport->cfg_enable_fc4_type == LPFC_ENABLE_FCP)) {
39968c2ecf20Sopenharmony_ci		if (lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, 0, SLI_CTPT_FCP)) {
39978c2ecf20Sopenharmony_ci			/* Cannot issue NameServer FCP Query, so finish up
39988c2ecf20Sopenharmony_ci			 * discovery
39998c2ecf20Sopenharmony_ci			 */
40008c2ecf20Sopenharmony_ci			lpfc_printf_vlog(vport, KERN_ERR,
40018c2ecf20Sopenharmony_ci					 LOG_TRACE_EVENT,
40028c2ecf20Sopenharmony_ci					 "0604 %s FC TYPE %x %s\n",
40038c2ecf20Sopenharmony_ci					 "Failed to issue GID_FT to ",
40048c2ecf20Sopenharmony_ci					 FC_TYPE_FCP,
40058c2ecf20Sopenharmony_ci					 "Finishing discovery.");
40068c2ecf20Sopenharmony_ci			return 0;
40078c2ecf20Sopenharmony_ci		}
40088c2ecf20Sopenharmony_ci		vport->gidft_inp++;
40098c2ecf20Sopenharmony_ci	}
40108c2ecf20Sopenharmony_ci
40118c2ecf20Sopenharmony_ci	if ((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
40128c2ecf20Sopenharmony_ci	    (vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME)) {
40138c2ecf20Sopenharmony_ci		if (lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, 0, SLI_CTPT_NVME)) {
40148c2ecf20Sopenharmony_ci			/* Cannot issue NameServer NVME Query, so finish up
40158c2ecf20Sopenharmony_ci			 * discovery
40168c2ecf20Sopenharmony_ci			 */
40178c2ecf20Sopenharmony_ci			lpfc_printf_vlog(vport, KERN_ERR,
40188c2ecf20Sopenharmony_ci					 LOG_TRACE_EVENT,
40198c2ecf20Sopenharmony_ci					 "0605 %s FC_TYPE %x %s %d\n",
40208c2ecf20Sopenharmony_ci					 "Failed to issue GID_FT to ",
40218c2ecf20Sopenharmony_ci					 FC_TYPE_NVME,
40228c2ecf20Sopenharmony_ci					 "Finishing discovery: gidftinp ",
40238c2ecf20Sopenharmony_ci					 vport->gidft_inp);
40248c2ecf20Sopenharmony_ci			if (vport->gidft_inp == 0)
40258c2ecf20Sopenharmony_ci				return 0;
40268c2ecf20Sopenharmony_ci		} else
40278c2ecf20Sopenharmony_ci			vport->gidft_inp++;
40288c2ecf20Sopenharmony_ci	}
40298c2ecf20Sopenharmony_ci	return vport->gidft_inp;
40308c2ecf20Sopenharmony_ci}
40318c2ecf20Sopenharmony_ci
40328c2ecf20Sopenharmony_ci/**
40338c2ecf20Sopenharmony_ci * lpfc_issue_gidpt - issue a GID_PT for all N_Ports
40348c2ecf20Sopenharmony_ci * @vport: The virtual port for which this call is being executed.
40358c2ecf20Sopenharmony_ci *
40368c2ecf20Sopenharmony_ci * This routine will issue a GID_PT to get a list of all N_Ports
40378c2ecf20Sopenharmony_ci *
40388c2ecf20Sopenharmony_ci * Return value :
40398c2ecf20Sopenharmony_ci *   0 - Failure to issue a GID_PT
40408c2ecf20Sopenharmony_ci *   1 - GID_PT issued
40418c2ecf20Sopenharmony_ci **/
40428c2ecf20Sopenharmony_ciint
40438c2ecf20Sopenharmony_cilpfc_issue_gidpt(struct lpfc_vport *vport)
40448c2ecf20Sopenharmony_ci{
40458c2ecf20Sopenharmony_ci	/* Good status, issue CT Request to NameServer */
40468c2ecf20Sopenharmony_ci	if (lpfc_ns_cmd(vport, SLI_CTNS_GID_PT, 0, GID_PT_N_PORT)) {
40478c2ecf20Sopenharmony_ci		/* Cannot issue NameServer FCP Query, so finish up
40488c2ecf20Sopenharmony_ci		 * discovery
40498c2ecf20Sopenharmony_ci		 */
40508c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
40518c2ecf20Sopenharmony_ci				 "0606 %s Port TYPE %x %s\n",
40528c2ecf20Sopenharmony_ci				 "Failed to issue GID_PT to ",
40538c2ecf20Sopenharmony_ci				 GID_PT_N_PORT,
40548c2ecf20Sopenharmony_ci				 "Finishing discovery.");
40558c2ecf20Sopenharmony_ci		return 0;
40568c2ecf20Sopenharmony_ci	}
40578c2ecf20Sopenharmony_ci	vport->gidft_inp++;
40588c2ecf20Sopenharmony_ci	return 1;
40598c2ecf20Sopenharmony_ci}
40608c2ecf20Sopenharmony_ci
40618c2ecf20Sopenharmony_ci/*
40628c2ecf20Sopenharmony_ci * This routine handles processing a NameServer REG_LOGIN mailbox
40638c2ecf20Sopenharmony_ci * command upon completion. It is setup in the LPFC_MBOXQ
40648c2ecf20Sopenharmony_ci * as the completion routine when the command is
40658c2ecf20Sopenharmony_ci * handed off to the SLI layer.
40668c2ecf20Sopenharmony_ci */
40678c2ecf20Sopenharmony_civoid
40688c2ecf20Sopenharmony_cilpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
40698c2ecf20Sopenharmony_ci{
40708c2ecf20Sopenharmony_ci	MAILBOX_t *mb = &pmb->u.mb;
40718c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)(pmb->ctx_buf);
40728c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
40738c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = pmb->vport;
40748c2ecf20Sopenharmony_ci
40758c2ecf20Sopenharmony_ci	pmb->ctx_buf = NULL;
40768c2ecf20Sopenharmony_ci	pmb->ctx_ndlp = NULL;
40778c2ecf20Sopenharmony_ci	vport->gidft_inp = 0;
40788c2ecf20Sopenharmony_ci
40798c2ecf20Sopenharmony_ci	if (mb->mbxStatus) {
40808c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
40818c2ecf20Sopenharmony_ci				 "0260 Register NameServer error: 0x%x\n",
40828c2ecf20Sopenharmony_ci				 mb->mbxStatus);
40838c2ecf20Sopenharmony_ci
40848c2ecf20Sopenharmony_ciout:
40858c2ecf20Sopenharmony_ci		/* decrement the node reference count held for this
40868c2ecf20Sopenharmony_ci		 * callback function.
40878c2ecf20Sopenharmony_ci		 */
40888c2ecf20Sopenharmony_ci		lpfc_nlp_put(ndlp);
40898c2ecf20Sopenharmony_ci		lpfc_mbuf_free(phba, mp->virt, mp->phys);
40908c2ecf20Sopenharmony_ci		kfree(mp);
40918c2ecf20Sopenharmony_ci		mempool_free(pmb, phba->mbox_mem_pool);
40928c2ecf20Sopenharmony_ci
40938c2ecf20Sopenharmony_ci		/* If no other thread is using the ndlp, free it */
40948c2ecf20Sopenharmony_ci		lpfc_nlp_not_used(ndlp);
40958c2ecf20Sopenharmony_ci
40968c2ecf20Sopenharmony_ci		if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
40978c2ecf20Sopenharmony_ci			/*
40988c2ecf20Sopenharmony_ci			 * RegLogin failed, use loop map to make discovery
40998c2ecf20Sopenharmony_ci			 * list
41008c2ecf20Sopenharmony_ci			 */
41018c2ecf20Sopenharmony_ci			lpfc_disc_list_loopmap(vport);
41028c2ecf20Sopenharmony_ci
41038c2ecf20Sopenharmony_ci			/* Start discovery */
41048c2ecf20Sopenharmony_ci			lpfc_disc_start(vport);
41058c2ecf20Sopenharmony_ci			return;
41068c2ecf20Sopenharmony_ci		}
41078c2ecf20Sopenharmony_ci		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
41088c2ecf20Sopenharmony_ci		return;
41098c2ecf20Sopenharmony_ci	}
41108c2ecf20Sopenharmony_ci
41118c2ecf20Sopenharmony_ci	if (phba->sli_rev < LPFC_SLI_REV4)
41128c2ecf20Sopenharmony_ci		ndlp->nlp_rpi = mb->un.varWords[0];
41138c2ecf20Sopenharmony_ci	ndlp->nlp_flag |= NLP_RPI_REGISTERED;
41148c2ecf20Sopenharmony_ci	ndlp->nlp_type |= NLP_FABRIC;
41158c2ecf20Sopenharmony_ci	lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
41168c2ecf20Sopenharmony_ci	lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY,
41178c2ecf20Sopenharmony_ci			 "0003 rpi:%x DID:%x flg:%x %d map%x x%px\n",
41188c2ecf20Sopenharmony_ci			 ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag,
41198c2ecf20Sopenharmony_ci			 kref_read(&ndlp->kref),
41208c2ecf20Sopenharmony_ci			 ndlp->nlp_usg_map, ndlp);
41218c2ecf20Sopenharmony_ci
41228c2ecf20Sopenharmony_ci	if (vport->port_state < LPFC_VPORT_READY) {
41238c2ecf20Sopenharmony_ci		/* Link up discovery requires Fabric registration. */
41248c2ecf20Sopenharmony_ci		lpfc_ns_cmd(vport, SLI_CTNS_RNN_ID, 0, 0);
41258c2ecf20Sopenharmony_ci		lpfc_ns_cmd(vport, SLI_CTNS_RSNN_NN, 0, 0);
41268c2ecf20Sopenharmony_ci		lpfc_ns_cmd(vport, SLI_CTNS_RSPN_ID, 0, 0);
41278c2ecf20Sopenharmony_ci		lpfc_ns_cmd(vport, SLI_CTNS_RFT_ID, 0, 0);
41288c2ecf20Sopenharmony_ci
41298c2ecf20Sopenharmony_ci		if ((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
41308c2ecf20Sopenharmony_ci		    (vport->cfg_enable_fc4_type == LPFC_ENABLE_FCP))
41318c2ecf20Sopenharmony_ci			lpfc_ns_cmd(vport, SLI_CTNS_RFF_ID, 0, FC_TYPE_FCP);
41328c2ecf20Sopenharmony_ci
41338c2ecf20Sopenharmony_ci		if ((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) ||
41348c2ecf20Sopenharmony_ci		    (vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME))
41358c2ecf20Sopenharmony_ci			lpfc_ns_cmd(vport, SLI_CTNS_RFF_ID, 0,
41368c2ecf20Sopenharmony_ci				    FC_TYPE_NVME);
41378c2ecf20Sopenharmony_ci
41388c2ecf20Sopenharmony_ci		/* Issue SCR just before NameServer GID_FT Query */
41398c2ecf20Sopenharmony_ci		lpfc_issue_els_scr(vport, 0);
41408c2ecf20Sopenharmony_ci
41418c2ecf20Sopenharmony_ci		lpfc_issue_els_rdf(vport, 0);
41428c2ecf20Sopenharmony_ci	}
41438c2ecf20Sopenharmony_ci
41448c2ecf20Sopenharmony_ci	vport->fc_ns_retry = 0;
41458c2ecf20Sopenharmony_ci	if (lpfc_issue_gidft(vport) == 0)
41468c2ecf20Sopenharmony_ci		goto out;
41478c2ecf20Sopenharmony_ci
41488c2ecf20Sopenharmony_ci	/*
41498c2ecf20Sopenharmony_ci	 * At this point in time we may need to wait for multiple
41508c2ecf20Sopenharmony_ci	 * SLI_CTNS_GID_FT CT commands to complete before we start discovery.
41518c2ecf20Sopenharmony_ci	 *
41528c2ecf20Sopenharmony_ci	 * decrement the node reference count held for this
41538c2ecf20Sopenharmony_ci	 * callback function.
41548c2ecf20Sopenharmony_ci	 */
41558c2ecf20Sopenharmony_ci	lpfc_nlp_put(ndlp);
41568c2ecf20Sopenharmony_ci	lpfc_mbuf_free(phba, mp->virt, mp->phys);
41578c2ecf20Sopenharmony_ci	kfree(mp);
41588c2ecf20Sopenharmony_ci	mempool_free(pmb, phba->mbox_mem_pool);
41598c2ecf20Sopenharmony_ci
41608c2ecf20Sopenharmony_ci	return;
41618c2ecf20Sopenharmony_ci}
41628c2ecf20Sopenharmony_ci
41638c2ecf20Sopenharmony_cistatic void
41648c2ecf20Sopenharmony_cilpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
41658c2ecf20Sopenharmony_ci{
41668c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
41678c2ecf20Sopenharmony_ci	struct fc_rport  *rport;
41688c2ecf20Sopenharmony_ci	struct lpfc_rport_data *rdata;
41698c2ecf20Sopenharmony_ci	struct fc_rport_identifiers rport_ids;
41708c2ecf20Sopenharmony_ci	struct lpfc_hba  *phba = vport->phba;
41718c2ecf20Sopenharmony_ci
41728c2ecf20Sopenharmony_ci	if (vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME)
41738c2ecf20Sopenharmony_ci		return;
41748c2ecf20Sopenharmony_ci
41758c2ecf20Sopenharmony_ci	/* Remote port has reappeared. Re-register w/ FC transport */
41768c2ecf20Sopenharmony_ci	rport_ids.node_name = wwn_to_u64(ndlp->nlp_nodename.u.wwn);
41778c2ecf20Sopenharmony_ci	rport_ids.port_name = wwn_to_u64(ndlp->nlp_portname.u.wwn);
41788c2ecf20Sopenharmony_ci	rport_ids.port_id = ndlp->nlp_DID;
41798c2ecf20Sopenharmony_ci	rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
41808c2ecf20Sopenharmony_ci
41818c2ecf20Sopenharmony_ci	/*
41828c2ecf20Sopenharmony_ci	 * We leave our node pointer in rport->dd_data when we unregister a
41838c2ecf20Sopenharmony_ci	 * FCP target port.  But fc_remote_port_add zeros the space to which
41848c2ecf20Sopenharmony_ci	 * rport->dd_data points.  So, if we're reusing a previously
41858c2ecf20Sopenharmony_ci	 * registered port, drop the reference that we took the last time we
41868c2ecf20Sopenharmony_ci	 * registered the port.
41878c2ecf20Sopenharmony_ci	 */
41888c2ecf20Sopenharmony_ci	rport = ndlp->rport;
41898c2ecf20Sopenharmony_ci	if (rport) {
41908c2ecf20Sopenharmony_ci		rdata = rport->dd_data;
41918c2ecf20Sopenharmony_ci		/* break the link before dropping the ref */
41928c2ecf20Sopenharmony_ci		ndlp->rport = NULL;
41938c2ecf20Sopenharmony_ci		if (rdata) {
41948c2ecf20Sopenharmony_ci			if (rdata->pnode == ndlp)
41958c2ecf20Sopenharmony_ci				lpfc_nlp_put(ndlp);
41968c2ecf20Sopenharmony_ci			rdata->pnode = NULL;
41978c2ecf20Sopenharmony_ci		}
41988c2ecf20Sopenharmony_ci		/* drop reference for earlier registeration */
41998c2ecf20Sopenharmony_ci		put_device(&rport->dev);
42008c2ecf20Sopenharmony_ci	}
42018c2ecf20Sopenharmony_ci
42028c2ecf20Sopenharmony_ci	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
42038c2ecf20Sopenharmony_ci		"rport add:       did:x%x flg:x%x type x%x",
42048c2ecf20Sopenharmony_ci		ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type);
42058c2ecf20Sopenharmony_ci
42068c2ecf20Sopenharmony_ci	/* Don't add the remote port if unloading. */
42078c2ecf20Sopenharmony_ci	if (vport->load_flag & FC_UNLOADING)
42088c2ecf20Sopenharmony_ci		return;
42098c2ecf20Sopenharmony_ci
42108c2ecf20Sopenharmony_ci	ndlp->rport = rport = fc_remote_port_add(shost, 0, &rport_ids);
42118c2ecf20Sopenharmony_ci	if (!rport || !get_device(&rport->dev)) {
42128c2ecf20Sopenharmony_ci		dev_printk(KERN_WARNING, &phba->pcidev->dev,
42138c2ecf20Sopenharmony_ci			   "Warning: fc_remote_port_add failed\n");
42148c2ecf20Sopenharmony_ci		return;
42158c2ecf20Sopenharmony_ci	}
42168c2ecf20Sopenharmony_ci
42178c2ecf20Sopenharmony_ci	/* initialize static port data */
42188c2ecf20Sopenharmony_ci	rport->maxframe_size = ndlp->nlp_maxframe;
42198c2ecf20Sopenharmony_ci	rport->supported_classes = ndlp->nlp_class_sup;
42208c2ecf20Sopenharmony_ci	rdata = rport->dd_data;
42218c2ecf20Sopenharmony_ci	rdata->pnode = lpfc_nlp_get(ndlp);
42228c2ecf20Sopenharmony_ci
42238c2ecf20Sopenharmony_ci	if (ndlp->nlp_type & NLP_FCP_TARGET)
42248c2ecf20Sopenharmony_ci		rport_ids.roles |= FC_PORT_ROLE_FCP_TARGET;
42258c2ecf20Sopenharmony_ci	if (ndlp->nlp_type & NLP_FCP_INITIATOR)
42268c2ecf20Sopenharmony_ci		rport_ids.roles |= FC_PORT_ROLE_FCP_INITIATOR;
42278c2ecf20Sopenharmony_ci	if (ndlp->nlp_type & NLP_NVME_INITIATOR)
42288c2ecf20Sopenharmony_ci		rport_ids.roles |= FC_PORT_ROLE_NVME_INITIATOR;
42298c2ecf20Sopenharmony_ci	if (ndlp->nlp_type & NLP_NVME_TARGET)
42308c2ecf20Sopenharmony_ci		rport_ids.roles |= FC_PORT_ROLE_NVME_TARGET;
42318c2ecf20Sopenharmony_ci	if (ndlp->nlp_type & NLP_NVME_DISCOVERY)
42328c2ecf20Sopenharmony_ci		rport_ids.roles |= FC_PORT_ROLE_NVME_DISCOVERY;
42338c2ecf20Sopenharmony_ci
42348c2ecf20Sopenharmony_ci	if (rport_ids.roles !=  FC_RPORT_ROLE_UNKNOWN)
42358c2ecf20Sopenharmony_ci		fc_remote_port_rolechg(rport, rport_ids.roles);
42368c2ecf20Sopenharmony_ci
42378c2ecf20Sopenharmony_ci	lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE,
42388c2ecf20Sopenharmony_ci			 "3183 rport register x%06x, rport x%px role x%x\n",
42398c2ecf20Sopenharmony_ci			 ndlp->nlp_DID, rport, rport_ids.roles);
42408c2ecf20Sopenharmony_ci
42418c2ecf20Sopenharmony_ci	if ((rport->scsi_target_id != -1) &&
42428c2ecf20Sopenharmony_ci	    (rport->scsi_target_id < LPFC_MAX_TARGET)) {
42438c2ecf20Sopenharmony_ci		ndlp->nlp_sid = rport->scsi_target_id;
42448c2ecf20Sopenharmony_ci	}
42458c2ecf20Sopenharmony_ci	return;
42468c2ecf20Sopenharmony_ci}
42478c2ecf20Sopenharmony_ci
42488c2ecf20Sopenharmony_cistatic void
42498c2ecf20Sopenharmony_cilpfc_unregister_remote_port(struct lpfc_nodelist *ndlp)
42508c2ecf20Sopenharmony_ci{
42518c2ecf20Sopenharmony_ci	struct fc_rport *rport = ndlp->rport;
42528c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = ndlp->vport;
42538c2ecf20Sopenharmony_ci
42548c2ecf20Sopenharmony_ci	if (vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME)
42558c2ecf20Sopenharmony_ci		return;
42568c2ecf20Sopenharmony_ci
42578c2ecf20Sopenharmony_ci	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
42588c2ecf20Sopenharmony_ci		"rport delete:    did:x%x flg:x%x type x%x",
42598c2ecf20Sopenharmony_ci		ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type);
42608c2ecf20Sopenharmony_ci
42618c2ecf20Sopenharmony_ci	lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
42628c2ecf20Sopenharmony_ci			 "3184 rport unregister x%06x, rport x%px\n",
42638c2ecf20Sopenharmony_ci			 ndlp->nlp_DID, rport);
42648c2ecf20Sopenharmony_ci
42658c2ecf20Sopenharmony_ci	fc_remote_port_delete(rport);
42668c2ecf20Sopenharmony_ci
42678c2ecf20Sopenharmony_ci	return;
42688c2ecf20Sopenharmony_ci}
42698c2ecf20Sopenharmony_ci
42708c2ecf20Sopenharmony_cistatic void
42718c2ecf20Sopenharmony_cilpfc_nlp_counters(struct lpfc_vport *vport, int state, int count)
42728c2ecf20Sopenharmony_ci{
42738c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
42748c2ecf20Sopenharmony_ci	unsigned long iflags;
42758c2ecf20Sopenharmony_ci
42768c2ecf20Sopenharmony_ci	spin_lock_irqsave(shost->host_lock, iflags);
42778c2ecf20Sopenharmony_ci	switch (state) {
42788c2ecf20Sopenharmony_ci	case NLP_STE_UNUSED_NODE:
42798c2ecf20Sopenharmony_ci		vport->fc_unused_cnt += count;
42808c2ecf20Sopenharmony_ci		break;
42818c2ecf20Sopenharmony_ci	case NLP_STE_PLOGI_ISSUE:
42828c2ecf20Sopenharmony_ci		vport->fc_plogi_cnt += count;
42838c2ecf20Sopenharmony_ci		break;
42848c2ecf20Sopenharmony_ci	case NLP_STE_ADISC_ISSUE:
42858c2ecf20Sopenharmony_ci		vport->fc_adisc_cnt += count;
42868c2ecf20Sopenharmony_ci		break;
42878c2ecf20Sopenharmony_ci	case NLP_STE_REG_LOGIN_ISSUE:
42888c2ecf20Sopenharmony_ci		vport->fc_reglogin_cnt += count;
42898c2ecf20Sopenharmony_ci		break;
42908c2ecf20Sopenharmony_ci	case NLP_STE_PRLI_ISSUE:
42918c2ecf20Sopenharmony_ci		vport->fc_prli_cnt += count;
42928c2ecf20Sopenharmony_ci		break;
42938c2ecf20Sopenharmony_ci	case NLP_STE_UNMAPPED_NODE:
42948c2ecf20Sopenharmony_ci		vport->fc_unmap_cnt += count;
42958c2ecf20Sopenharmony_ci		break;
42968c2ecf20Sopenharmony_ci	case NLP_STE_MAPPED_NODE:
42978c2ecf20Sopenharmony_ci		vport->fc_map_cnt += count;
42988c2ecf20Sopenharmony_ci		break;
42998c2ecf20Sopenharmony_ci	case NLP_STE_NPR_NODE:
43008c2ecf20Sopenharmony_ci		if (vport->fc_npr_cnt == 0 && count == -1)
43018c2ecf20Sopenharmony_ci			vport->fc_npr_cnt = 0;
43028c2ecf20Sopenharmony_ci		else
43038c2ecf20Sopenharmony_ci			vport->fc_npr_cnt += count;
43048c2ecf20Sopenharmony_ci		break;
43058c2ecf20Sopenharmony_ci	}
43068c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(shost->host_lock, iflags);
43078c2ecf20Sopenharmony_ci}
43088c2ecf20Sopenharmony_ci
43098c2ecf20Sopenharmony_cistatic void
43108c2ecf20Sopenharmony_cilpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
43118c2ecf20Sopenharmony_ci		       int old_state, int new_state)
43128c2ecf20Sopenharmony_ci{
43138c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
43148c2ecf20Sopenharmony_ci
43158c2ecf20Sopenharmony_ci	if (new_state == NLP_STE_UNMAPPED_NODE) {
43168c2ecf20Sopenharmony_ci		ndlp->nlp_flag &= ~NLP_NODEV_REMOVE;
43178c2ecf20Sopenharmony_ci		ndlp->nlp_type |= NLP_FC_NODE;
43188c2ecf20Sopenharmony_ci	}
43198c2ecf20Sopenharmony_ci	if (new_state == NLP_STE_MAPPED_NODE)
43208c2ecf20Sopenharmony_ci		ndlp->nlp_flag &= ~NLP_NODEV_REMOVE;
43218c2ecf20Sopenharmony_ci	if (new_state == NLP_STE_NPR_NODE)
43228c2ecf20Sopenharmony_ci		ndlp->nlp_flag &= ~NLP_RCV_PLOGI;
43238c2ecf20Sopenharmony_ci
43248c2ecf20Sopenharmony_ci	/* FCP and NVME Transport interface */
43258c2ecf20Sopenharmony_ci	if ((old_state == NLP_STE_MAPPED_NODE ||
43268c2ecf20Sopenharmony_ci	     old_state == NLP_STE_UNMAPPED_NODE)) {
43278c2ecf20Sopenharmony_ci		if (ndlp->rport) {
43288c2ecf20Sopenharmony_ci			vport->phba->nport_event_cnt++;
43298c2ecf20Sopenharmony_ci			lpfc_unregister_remote_port(ndlp);
43308c2ecf20Sopenharmony_ci		}
43318c2ecf20Sopenharmony_ci
43328c2ecf20Sopenharmony_ci		if (ndlp->nlp_fc4_type & NLP_FC4_NVME) {
43338c2ecf20Sopenharmony_ci			vport->phba->nport_event_cnt++;
43348c2ecf20Sopenharmony_ci			if (vport->phba->nvmet_support == 0) {
43358c2ecf20Sopenharmony_ci				/* Start devloss if target. */
43368c2ecf20Sopenharmony_ci				if (ndlp->nlp_type & NLP_NVME_TARGET)
43378c2ecf20Sopenharmony_ci					lpfc_nvme_unregister_port(vport, ndlp);
43388c2ecf20Sopenharmony_ci			} else {
43398c2ecf20Sopenharmony_ci				/* NVMET has no upcall. */
43408c2ecf20Sopenharmony_ci				lpfc_nlp_put(ndlp);
43418c2ecf20Sopenharmony_ci			}
43428c2ecf20Sopenharmony_ci		}
43438c2ecf20Sopenharmony_ci	}
43448c2ecf20Sopenharmony_ci
43458c2ecf20Sopenharmony_ci	/* FCP and NVME Transport interfaces */
43468c2ecf20Sopenharmony_ci
43478c2ecf20Sopenharmony_ci	if (new_state ==  NLP_STE_MAPPED_NODE ||
43488c2ecf20Sopenharmony_ci	    new_state == NLP_STE_UNMAPPED_NODE) {
43498c2ecf20Sopenharmony_ci		if (ndlp->nlp_fc4_type ||
43508c2ecf20Sopenharmony_ci		    ndlp->nlp_DID == Fabric_DID ||
43518c2ecf20Sopenharmony_ci		    ndlp->nlp_DID == NameServer_DID ||
43528c2ecf20Sopenharmony_ci		    ndlp->nlp_DID == FDMI_DID) {
43538c2ecf20Sopenharmony_ci			vport->phba->nport_event_cnt++;
43548c2ecf20Sopenharmony_ci			/*
43558c2ecf20Sopenharmony_ci			 * Tell the fc transport about the port, if we haven't
43568c2ecf20Sopenharmony_ci			 * already. If we have, and it's a scsi entity, be
43578c2ecf20Sopenharmony_ci			 */
43588c2ecf20Sopenharmony_ci			lpfc_register_remote_port(vport, ndlp);
43598c2ecf20Sopenharmony_ci		}
43608c2ecf20Sopenharmony_ci		/* Notify the NVME transport of this new rport. */
43618c2ecf20Sopenharmony_ci		if (vport->phba->sli_rev >= LPFC_SLI_REV4 &&
43628c2ecf20Sopenharmony_ci		    ndlp->nlp_fc4_type & NLP_FC4_NVME) {
43638c2ecf20Sopenharmony_ci			if (vport->phba->nvmet_support == 0) {
43648c2ecf20Sopenharmony_ci				/* Register this rport with the transport.
43658c2ecf20Sopenharmony_ci				 * Only NVME Target Rports are registered with
43668c2ecf20Sopenharmony_ci				 * the transport.
43678c2ecf20Sopenharmony_ci				 */
43688c2ecf20Sopenharmony_ci				if (ndlp->nlp_type & NLP_NVME_TARGET) {
43698c2ecf20Sopenharmony_ci					vport->phba->nport_event_cnt++;
43708c2ecf20Sopenharmony_ci					lpfc_nvme_register_port(vport, ndlp);
43718c2ecf20Sopenharmony_ci				}
43728c2ecf20Sopenharmony_ci			} else {
43738c2ecf20Sopenharmony_ci				/* Just take an NDLP ref count since the
43748c2ecf20Sopenharmony_ci				 * target does not register rports.
43758c2ecf20Sopenharmony_ci				 */
43768c2ecf20Sopenharmony_ci				lpfc_nlp_get(ndlp);
43778c2ecf20Sopenharmony_ci			}
43788c2ecf20Sopenharmony_ci		}
43798c2ecf20Sopenharmony_ci	}
43808c2ecf20Sopenharmony_ci
43818c2ecf20Sopenharmony_ci	if ((new_state ==  NLP_STE_MAPPED_NODE) &&
43828c2ecf20Sopenharmony_ci		(vport->stat_data_enabled)) {
43838c2ecf20Sopenharmony_ci		/*
43848c2ecf20Sopenharmony_ci		 * A new target is discovered, if there is no buffer for
43858c2ecf20Sopenharmony_ci		 * statistical data collection allocate buffer.
43868c2ecf20Sopenharmony_ci		 */
43878c2ecf20Sopenharmony_ci		ndlp->lat_data = kcalloc(LPFC_MAX_BUCKET_COUNT,
43888c2ecf20Sopenharmony_ci					 sizeof(struct lpfc_scsicmd_bkt),
43898c2ecf20Sopenharmony_ci					 GFP_KERNEL);
43908c2ecf20Sopenharmony_ci
43918c2ecf20Sopenharmony_ci		if (!ndlp->lat_data)
43928c2ecf20Sopenharmony_ci			lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
43938c2ecf20Sopenharmony_ci				"0286 lpfc_nlp_state_cleanup failed to "
43948c2ecf20Sopenharmony_ci				"allocate statistical data buffer DID "
43958c2ecf20Sopenharmony_ci				"0x%x\n", ndlp->nlp_DID);
43968c2ecf20Sopenharmony_ci	}
43978c2ecf20Sopenharmony_ci	/*
43988c2ecf20Sopenharmony_ci	 * If the node just added to Mapped list was an FCP target,
43998c2ecf20Sopenharmony_ci	 * but the remote port registration failed or assigned a target
44008c2ecf20Sopenharmony_ci	 * id outside the presentable range - move the node to the
44018c2ecf20Sopenharmony_ci	 * Unmapped List.
44028c2ecf20Sopenharmony_ci	 */
44038c2ecf20Sopenharmony_ci	if ((new_state == NLP_STE_MAPPED_NODE) &&
44048c2ecf20Sopenharmony_ci	    (ndlp->nlp_type & NLP_FCP_TARGET) &&
44058c2ecf20Sopenharmony_ci	    (!ndlp->rport ||
44068c2ecf20Sopenharmony_ci	     ndlp->rport->scsi_target_id == -1 ||
44078c2ecf20Sopenharmony_ci	     ndlp->rport->scsi_target_id >= LPFC_MAX_TARGET)) {
44088c2ecf20Sopenharmony_ci		spin_lock_irq(shost->host_lock);
44098c2ecf20Sopenharmony_ci		ndlp->nlp_flag |= NLP_TGT_NO_SCSIID;
44108c2ecf20Sopenharmony_ci		spin_unlock_irq(shost->host_lock);
44118c2ecf20Sopenharmony_ci		lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
44128c2ecf20Sopenharmony_ci	}
44138c2ecf20Sopenharmony_ci}
44148c2ecf20Sopenharmony_ci
44158c2ecf20Sopenharmony_cistatic char *
44168c2ecf20Sopenharmony_cilpfc_nlp_state_name(char *buffer, size_t size, int state)
44178c2ecf20Sopenharmony_ci{
44188c2ecf20Sopenharmony_ci	static char *states[] = {
44198c2ecf20Sopenharmony_ci		[NLP_STE_UNUSED_NODE] = "UNUSED",
44208c2ecf20Sopenharmony_ci		[NLP_STE_PLOGI_ISSUE] = "PLOGI",
44218c2ecf20Sopenharmony_ci		[NLP_STE_ADISC_ISSUE] = "ADISC",
44228c2ecf20Sopenharmony_ci		[NLP_STE_REG_LOGIN_ISSUE] = "REGLOGIN",
44238c2ecf20Sopenharmony_ci		[NLP_STE_PRLI_ISSUE] = "PRLI",
44248c2ecf20Sopenharmony_ci		[NLP_STE_LOGO_ISSUE] = "LOGO",
44258c2ecf20Sopenharmony_ci		[NLP_STE_UNMAPPED_NODE] = "UNMAPPED",
44268c2ecf20Sopenharmony_ci		[NLP_STE_MAPPED_NODE] = "MAPPED",
44278c2ecf20Sopenharmony_ci		[NLP_STE_NPR_NODE] = "NPR",
44288c2ecf20Sopenharmony_ci	};
44298c2ecf20Sopenharmony_ci
44308c2ecf20Sopenharmony_ci	if (state < NLP_STE_MAX_STATE && states[state])
44318c2ecf20Sopenharmony_ci		strlcpy(buffer, states[state], size);
44328c2ecf20Sopenharmony_ci	else
44338c2ecf20Sopenharmony_ci		snprintf(buffer, size, "unknown (%d)", state);
44348c2ecf20Sopenharmony_ci	return buffer;
44358c2ecf20Sopenharmony_ci}
44368c2ecf20Sopenharmony_ci
44378c2ecf20Sopenharmony_civoid
44388c2ecf20Sopenharmony_cilpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
44398c2ecf20Sopenharmony_ci		   int state)
44408c2ecf20Sopenharmony_ci{
44418c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
44428c2ecf20Sopenharmony_ci	int  old_state = ndlp->nlp_state;
44438c2ecf20Sopenharmony_ci	char name1[16], name2[16];
44448c2ecf20Sopenharmony_ci
44458c2ecf20Sopenharmony_ci	lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
44468c2ecf20Sopenharmony_ci			 "0904 NPort state transition x%06x, %s -> %s\n",
44478c2ecf20Sopenharmony_ci			 ndlp->nlp_DID,
44488c2ecf20Sopenharmony_ci			 lpfc_nlp_state_name(name1, sizeof(name1), old_state),
44498c2ecf20Sopenharmony_ci			 lpfc_nlp_state_name(name2, sizeof(name2), state));
44508c2ecf20Sopenharmony_ci
44518c2ecf20Sopenharmony_ci	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE,
44528c2ecf20Sopenharmony_ci		"node statechg    did:x%x old:%d ste:%d",
44538c2ecf20Sopenharmony_ci		ndlp->nlp_DID, old_state, state);
44548c2ecf20Sopenharmony_ci
44558c2ecf20Sopenharmony_ci	if (old_state == NLP_STE_NPR_NODE &&
44568c2ecf20Sopenharmony_ci	    state != NLP_STE_NPR_NODE)
44578c2ecf20Sopenharmony_ci		lpfc_cancel_retry_delay_tmo(vport, ndlp);
44588c2ecf20Sopenharmony_ci	if (old_state == NLP_STE_UNMAPPED_NODE) {
44598c2ecf20Sopenharmony_ci		ndlp->nlp_flag &= ~NLP_TGT_NO_SCSIID;
44608c2ecf20Sopenharmony_ci		ndlp->nlp_type &= ~NLP_FC_NODE;
44618c2ecf20Sopenharmony_ci	}
44628c2ecf20Sopenharmony_ci
44638c2ecf20Sopenharmony_ci	if (list_empty(&ndlp->nlp_listp)) {
44648c2ecf20Sopenharmony_ci		spin_lock_irq(shost->host_lock);
44658c2ecf20Sopenharmony_ci		list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes);
44668c2ecf20Sopenharmony_ci		spin_unlock_irq(shost->host_lock);
44678c2ecf20Sopenharmony_ci	} else if (old_state)
44688c2ecf20Sopenharmony_ci		lpfc_nlp_counters(vport, old_state, -1);
44698c2ecf20Sopenharmony_ci
44708c2ecf20Sopenharmony_ci	ndlp->nlp_state = state;
44718c2ecf20Sopenharmony_ci	lpfc_nlp_counters(vport, state, 1);
44728c2ecf20Sopenharmony_ci	lpfc_nlp_state_cleanup(vport, ndlp, old_state, state);
44738c2ecf20Sopenharmony_ci}
44748c2ecf20Sopenharmony_ci
44758c2ecf20Sopenharmony_civoid
44768c2ecf20Sopenharmony_cilpfc_enqueue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
44778c2ecf20Sopenharmony_ci{
44788c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
44798c2ecf20Sopenharmony_ci
44808c2ecf20Sopenharmony_ci	if (list_empty(&ndlp->nlp_listp)) {
44818c2ecf20Sopenharmony_ci		spin_lock_irq(shost->host_lock);
44828c2ecf20Sopenharmony_ci		list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes);
44838c2ecf20Sopenharmony_ci		spin_unlock_irq(shost->host_lock);
44848c2ecf20Sopenharmony_ci	}
44858c2ecf20Sopenharmony_ci}
44868c2ecf20Sopenharmony_ci
44878c2ecf20Sopenharmony_civoid
44888c2ecf20Sopenharmony_cilpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
44898c2ecf20Sopenharmony_ci{
44908c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
44918c2ecf20Sopenharmony_ci
44928c2ecf20Sopenharmony_ci	lpfc_cancel_retry_delay_tmo(vport, ndlp);
44938c2ecf20Sopenharmony_ci	if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp))
44948c2ecf20Sopenharmony_ci		lpfc_nlp_counters(vport, ndlp->nlp_state, -1);
44958c2ecf20Sopenharmony_ci	spin_lock_irq(shost->host_lock);
44968c2ecf20Sopenharmony_ci	list_del_init(&ndlp->nlp_listp);
44978c2ecf20Sopenharmony_ci	spin_unlock_irq(shost->host_lock);
44988c2ecf20Sopenharmony_ci	lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state,
44998c2ecf20Sopenharmony_ci				NLP_STE_UNUSED_NODE);
45008c2ecf20Sopenharmony_ci}
45018c2ecf20Sopenharmony_ci
45028c2ecf20Sopenharmony_cistatic void
45038c2ecf20Sopenharmony_cilpfc_disable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
45048c2ecf20Sopenharmony_ci{
45058c2ecf20Sopenharmony_ci	lpfc_cancel_retry_delay_tmo(vport, ndlp);
45068c2ecf20Sopenharmony_ci	if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp))
45078c2ecf20Sopenharmony_ci		lpfc_nlp_counters(vport, ndlp->nlp_state, -1);
45088c2ecf20Sopenharmony_ci	lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state,
45098c2ecf20Sopenharmony_ci				NLP_STE_UNUSED_NODE);
45108c2ecf20Sopenharmony_ci}
45118c2ecf20Sopenharmony_ci/**
45128c2ecf20Sopenharmony_ci * lpfc_initialize_node - Initialize all fields of node object
45138c2ecf20Sopenharmony_ci * @vport: Pointer to Virtual Port object.
45148c2ecf20Sopenharmony_ci * @ndlp: Pointer to FC node object.
45158c2ecf20Sopenharmony_ci * @did: FC_ID of the node.
45168c2ecf20Sopenharmony_ci *
45178c2ecf20Sopenharmony_ci * This function is always called when node object need to be initialized.
45188c2ecf20Sopenharmony_ci * It initializes all the fields of the node object. Although the reference
45198c2ecf20Sopenharmony_ci * to phba from @ndlp can be obtained indirectly through it's reference to
45208c2ecf20Sopenharmony_ci * @vport, a direct reference to phba is taken here by @ndlp. This is due
45218c2ecf20Sopenharmony_ci * to the life-span of the @ndlp might go beyond the existence of @vport as
45228c2ecf20Sopenharmony_ci * the final release of ndlp is determined by its reference count. And, the
45238c2ecf20Sopenharmony_ci * operation on @ndlp needs the reference to phba.
45248c2ecf20Sopenharmony_ci **/
45258c2ecf20Sopenharmony_cistatic inline void
45268c2ecf20Sopenharmony_cilpfc_initialize_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
45278c2ecf20Sopenharmony_ci	uint32_t did)
45288c2ecf20Sopenharmony_ci{
45298c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp);
45308c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ndlp->dev_loss_evt.evt_listp);
45318c2ecf20Sopenharmony_ci	timer_setup(&ndlp->nlp_delayfunc, lpfc_els_retry_delay, 0);
45328c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ndlp->recovery_evt.evt_listp);
45338c2ecf20Sopenharmony_ci
45348c2ecf20Sopenharmony_ci	ndlp->nlp_DID = did;
45358c2ecf20Sopenharmony_ci	ndlp->vport = vport;
45368c2ecf20Sopenharmony_ci	ndlp->phba = vport->phba;
45378c2ecf20Sopenharmony_ci	ndlp->nlp_sid = NLP_NO_SID;
45388c2ecf20Sopenharmony_ci	ndlp->nlp_fc4_type = NLP_FC4_NONE;
45398c2ecf20Sopenharmony_ci	kref_init(&ndlp->kref);
45408c2ecf20Sopenharmony_ci	NLP_INT_NODE_ACT(ndlp);
45418c2ecf20Sopenharmony_ci	atomic_set(&ndlp->cmd_pending, 0);
45428c2ecf20Sopenharmony_ci	ndlp->cmd_qdepth = vport->cfg_tgt_queue_depth;
45438c2ecf20Sopenharmony_ci	ndlp->nlp_defer_did = NLP_EVT_NOTHING_PENDING;
45448c2ecf20Sopenharmony_ci}
45458c2ecf20Sopenharmony_ci
45468c2ecf20Sopenharmony_cistruct lpfc_nodelist *
45478c2ecf20Sopenharmony_cilpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
45488c2ecf20Sopenharmony_ci		 int state)
45498c2ecf20Sopenharmony_ci{
45508c2ecf20Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
45518c2ecf20Sopenharmony_ci	uint32_t did, flag;
45528c2ecf20Sopenharmony_ci	unsigned long flags;
45538c2ecf20Sopenharmony_ci	unsigned long *active_rrqs_xri_bitmap = NULL;
45548c2ecf20Sopenharmony_ci	int rpi = LPFC_RPI_ALLOC_ERROR;
45558c2ecf20Sopenharmony_ci	uint32_t defer_did = 0;
45568c2ecf20Sopenharmony_ci
45578c2ecf20Sopenharmony_ci	if (!ndlp)
45588c2ecf20Sopenharmony_ci		return NULL;
45598c2ecf20Sopenharmony_ci
45608c2ecf20Sopenharmony_ci	if (phba->sli_rev == LPFC_SLI_REV4) {
45618c2ecf20Sopenharmony_ci		if (ndlp->nlp_rpi == LPFC_RPI_ALLOC_ERROR)
45628c2ecf20Sopenharmony_ci			rpi = lpfc_sli4_alloc_rpi(vport->phba);
45638c2ecf20Sopenharmony_ci		else
45648c2ecf20Sopenharmony_ci			rpi = ndlp->nlp_rpi;
45658c2ecf20Sopenharmony_ci
45668c2ecf20Sopenharmony_ci		if (rpi == LPFC_RPI_ALLOC_ERROR) {
45678c2ecf20Sopenharmony_ci			lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE,
45688c2ecf20Sopenharmony_ci					 "0359 %s: ndlp:x%px "
45698c2ecf20Sopenharmony_ci					 "usgmap:x%x refcnt:%d FAILED RPI "
45708c2ecf20Sopenharmony_ci					 " ALLOC\n",
45718c2ecf20Sopenharmony_ci					 __func__,
45728c2ecf20Sopenharmony_ci					 (void *)ndlp, ndlp->nlp_usg_map,
45738c2ecf20Sopenharmony_ci					 kref_read(&ndlp->kref));
45748c2ecf20Sopenharmony_ci			return NULL;
45758c2ecf20Sopenharmony_ci		}
45768c2ecf20Sopenharmony_ci	}
45778c2ecf20Sopenharmony_ci
45788c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->ndlp_lock, flags);
45798c2ecf20Sopenharmony_ci	/* The ndlp should not be in memory free mode */
45808c2ecf20Sopenharmony_ci	if (NLP_CHK_FREE_REQ(ndlp)) {
45818c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&phba->ndlp_lock, flags);
45828c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE,
45838c2ecf20Sopenharmony_ci				"0277 %s: ndlp:x%px "
45848c2ecf20Sopenharmony_ci				"usgmap:x%x refcnt:%d\n",
45858c2ecf20Sopenharmony_ci				__func__, (void *)ndlp, ndlp->nlp_usg_map,
45868c2ecf20Sopenharmony_ci				kref_read(&ndlp->kref));
45878c2ecf20Sopenharmony_ci		goto free_rpi;
45888c2ecf20Sopenharmony_ci	}
45898c2ecf20Sopenharmony_ci	/* The ndlp should not already be in active mode */
45908c2ecf20Sopenharmony_ci	if (NLP_CHK_NODE_ACT(ndlp)) {
45918c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&phba->ndlp_lock, flags);
45928c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE,
45938c2ecf20Sopenharmony_ci				"0278 %s: ndlp:x%px "
45948c2ecf20Sopenharmony_ci				"usgmap:x%x refcnt:%d\n",
45958c2ecf20Sopenharmony_ci				__func__, (void *)ndlp, ndlp->nlp_usg_map,
45968c2ecf20Sopenharmony_ci				kref_read(&ndlp->kref));
45978c2ecf20Sopenharmony_ci		goto free_rpi;
45988c2ecf20Sopenharmony_ci	}
45998c2ecf20Sopenharmony_ci
46008c2ecf20Sopenharmony_ci	/* First preserve the orginal DID, xri_bitmap and some flags */
46018c2ecf20Sopenharmony_ci	did = ndlp->nlp_DID;
46028c2ecf20Sopenharmony_ci	flag = (ndlp->nlp_flag & NLP_UNREG_INP);
46038c2ecf20Sopenharmony_ci	if (flag & NLP_UNREG_INP)
46048c2ecf20Sopenharmony_ci		defer_did = ndlp->nlp_defer_did;
46058c2ecf20Sopenharmony_ci	if (phba->sli_rev == LPFC_SLI_REV4)
46068c2ecf20Sopenharmony_ci		active_rrqs_xri_bitmap = ndlp->active_rrqs_xri_bitmap;
46078c2ecf20Sopenharmony_ci
46088c2ecf20Sopenharmony_ci	/* Zero ndlp except of ndlp linked list pointer */
46098c2ecf20Sopenharmony_ci	memset((((char *)ndlp) + sizeof (struct list_head)), 0,
46108c2ecf20Sopenharmony_ci		sizeof (struct lpfc_nodelist) - sizeof (struct list_head));
46118c2ecf20Sopenharmony_ci
46128c2ecf20Sopenharmony_ci	/* Next reinitialize and restore saved objects */
46138c2ecf20Sopenharmony_ci	lpfc_initialize_node(vport, ndlp, did);
46148c2ecf20Sopenharmony_ci	ndlp->nlp_flag |= flag;
46158c2ecf20Sopenharmony_ci	if (flag & NLP_UNREG_INP)
46168c2ecf20Sopenharmony_ci		ndlp->nlp_defer_did = defer_did;
46178c2ecf20Sopenharmony_ci	if (phba->sli_rev == LPFC_SLI_REV4)
46188c2ecf20Sopenharmony_ci		ndlp->active_rrqs_xri_bitmap = active_rrqs_xri_bitmap;
46198c2ecf20Sopenharmony_ci
46208c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&phba->ndlp_lock, flags);
46218c2ecf20Sopenharmony_ci	if (vport->phba->sli_rev == LPFC_SLI_REV4) {
46228c2ecf20Sopenharmony_ci		ndlp->nlp_rpi = rpi;
46238c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
46248c2ecf20Sopenharmony_ci				 "0008 rpi:%x DID:%x flg:%x refcnt:%d "
46258c2ecf20Sopenharmony_ci				 "map:%x x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID,
46268c2ecf20Sopenharmony_ci				 ndlp->nlp_flag,
46278c2ecf20Sopenharmony_ci				 kref_read(&ndlp->kref),
46288c2ecf20Sopenharmony_ci				 ndlp->nlp_usg_map, ndlp);
46298c2ecf20Sopenharmony_ci	}
46308c2ecf20Sopenharmony_ci
46318c2ecf20Sopenharmony_ci
46328c2ecf20Sopenharmony_ci	if (state != NLP_STE_UNUSED_NODE)
46338c2ecf20Sopenharmony_ci		lpfc_nlp_set_state(vport, ndlp, state);
46348c2ecf20Sopenharmony_ci	else
46358c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
46368c2ecf20Sopenharmony_ci				 "0013 rpi:%x DID:%x flg:%x refcnt:%d "
46378c2ecf20Sopenharmony_ci				 "map:%x x%px STATE=UNUSED\n",
46388c2ecf20Sopenharmony_ci				 ndlp->nlp_rpi, ndlp->nlp_DID,
46398c2ecf20Sopenharmony_ci				 ndlp->nlp_flag,
46408c2ecf20Sopenharmony_ci				 kref_read(&ndlp->kref),
46418c2ecf20Sopenharmony_ci				 ndlp->nlp_usg_map, ndlp);
46428c2ecf20Sopenharmony_ci
46438c2ecf20Sopenharmony_ci	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE,
46448c2ecf20Sopenharmony_ci		"node enable:       did:x%x",
46458c2ecf20Sopenharmony_ci		ndlp->nlp_DID, 0, 0);
46468c2ecf20Sopenharmony_ci	return ndlp;
46478c2ecf20Sopenharmony_ci
46488c2ecf20Sopenharmony_cifree_rpi:
46498c2ecf20Sopenharmony_ci	if (phba->sli_rev == LPFC_SLI_REV4) {
46508c2ecf20Sopenharmony_ci		lpfc_sli4_free_rpi(vport->phba, rpi);
46518c2ecf20Sopenharmony_ci		ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR;
46528c2ecf20Sopenharmony_ci	}
46538c2ecf20Sopenharmony_ci	return NULL;
46548c2ecf20Sopenharmony_ci}
46558c2ecf20Sopenharmony_ci
46568c2ecf20Sopenharmony_civoid
46578c2ecf20Sopenharmony_cilpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
46588c2ecf20Sopenharmony_ci{
46598c2ecf20Sopenharmony_ci	/*
46608c2ecf20Sopenharmony_ci	 * Use of lpfc_drop_node and UNUSED list: lpfc_drop_node should
46618c2ecf20Sopenharmony_ci	 * be used if we wish to issue the "last" lpfc_nlp_put() to remove
46628c2ecf20Sopenharmony_ci	 * the ndlp from the vport. The ndlp marked as UNUSED on the list
46638c2ecf20Sopenharmony_ci	 * until ALL other outstanding threads have completed. We check
46648c2ecf20Sopenharmony_ci	 * that the ndlp not already in the UNUSED state before we proceed.
46658c2ecf20Sopenharmony_ci	 */
46668c2ecf20Sopenharmony_ci	if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
46678c2ecf20Sopenharmony_ci		return;
46688c2ecf20Sopenharmony_ci	lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
46698c2ecf20Sopenharmony_ci	if (vport->phba->sli_rev == LPFC_SLI_REV4) {
46708c2ecf20Sopenharmony_ci		lpfc_cleanup_vports_rrqs(vport, ndlp);
46718c2ecf20Sopenharmony_ci		lpfc_unreg_rpi(vport, ndlp);
46728c2ecf20Sopenharmony_ci	}
46738c2ecf20Sopenharmony_ci
46748c2ecf20Sopenharmony_ci	lpfc_nlp_put(ndlp);
46758c2ecf20Sopenharmony_ci	return;
46768c2ecf20Sopenharmony_ci}
46778c2ecf20Sopenharmony_ci
46788c2ecf20Sopenharmony_ci/*
46798c2ecf20Sopenharmony_ci * Start / ReStart rescue timer for Discovery / RSCN handling
46808c2ecf20Sopenharmony_ci */
46818c2ecf20Sopenharmony_civoid
46828c2ecf20Sopenharmony_cilpfc_set_disctmo(struct lpfc_vport *vport)
46838c2ecf20Sopenharmony_ci{
46848c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
46858c2ecf20Sopenharmony_ci	struct lpfc_hba  *phba = vport->phba;
46868c2ecf20Sopenharmony_ci	uint32_t tmo;
46878c2ecf20Sopenharmony_ci
46888c2ecf20Sopenharmony_ci	if (vport->port_state == LPFC_LOCAL_CFG_LINK) {
46898c2ecf20Sopenharmony_ci		/* For FAN, timeout should be greater than edtov */
46908c2ecf20Sopenharmony_ci		tmo = (((phba->fc_edtov + 999) / 1000) + 1);
46918c2ecf20Sopenharmony_ci	} else {
46928c2ecf20Sopenharmony_ci		/* Normal discovery timeout should be > than ELS/CT timeout
46938c2ecf20Sopenharmony_ci		 * FC spec states we need 3 * ratov for CT requests
46948c2ecf20Sopenharmony_ci		 */
46958c2ecf20Sopenharmony_ci		tmo = ((phba->fc_ratov * 3) + 3);
46968c2ecf20Sopenharmony_ci	}
46978c2ecf20Sopenharmony_ci
46988c2ecf20Sopenharmony_ci
46998c2ecf20Sopenharmony_ci	if (!timer_pending(&vport->fc_disctmo)) {
47008c2ecf20Sopenharmony_ci		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
47018c2ecf20Sopenharmony_ci			"set disc timer:  tmo:x%x state:x%x flg:x%x",
47028c2ecf20Sopenharmony_ci			tmo, vport->port_state, vport->fc_flag);
47038c2ecf20Sopenharmony_ci	}
47048c2ecf20Sopenharmony_ci
47058c2ecf20Sopenharmony_ci	mod_timer(&vport->fc_disctmo, jiffies + msecs_to_jiffies(1000 * tmo));
47068c2ecf20Sopenharmony_ci	spin_lock_irq(shost->host_lock);
47078c2ecf20Sopenharmony_ci	vport->fc_flag |= FC_DISC_TMO;
47088c2ecf20Sopenharmony_ci	spin_unlock_irq(shost->host_lock);
47098c2ecf20Sopenharmony_ci
47108c2ecf20Sopenharmony_ci	/* Start Discovery Timer state <hba_state> */
47118c2ecf20Sopenharmony_ci	lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
47128c2ecf20Sopenharmony_ci			 "0247 Start Discovery Timer state x%x "
47138c2ecf20Sopenharmony_ci			 "Data: x%x x%lx x%x x%x\n",
47148c2ecf20Sopenharmony_ci			 vport->port_state, tmo,
47158c2ecf20Sopenharmony_ci			 (unsigned long)&vport->fc_disctmo, vport->fc_plogi_cnt,
47168c2ecf20Sopenharmony_ci			 vport->fc_adisc_cnt);
47178c2ecf20Sopenharmony_ci
47188c2ecf20Sopenharmony_ci	return;
47198c2ecf20Sopenharmony_ci}
47208c2ecf20Sopenharmony_ci
47218c2ecf20Sopenharmony_ci/*
47228c2ecf20Sopenharmony_ci * Cancel rescue timer for Discovery / RSCN handling
47238c2ecf20Sopenharmony_ci */
47248c2ecf20Sopenharmony_ciint
47258c2ecf20Sopenharmony_cilpfc_can_disctmo(struct lpfc_vport *vport)
47268c2ecf20Sopenharmony_ci{
47278c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
47288c2ecf20Sopenharmony_ci	unsigned long iflags;
47298c2ecf20Sopenharmony_ci
47308c2ecf20Sopenharmony_ci	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
47318c2ecf20Sopenharmony_ci		"can disc timer:  state:x%x rtry:x%x flg:x%x",
47328c2ecf20Sopenharmony_ci		vport->port_state, vport->fc_ns_retry, vport->fc_flag);
47338c2ecf20Sopenharmony_ci
47348c2ecf20Sopenharmony_ci	/* Turn off discovery timer if its running */
47358c2ecf20Sopenharmony_ci	if (vport->fc_flag & FC_DISC_TMO) {
47368c2ecf20Sopenharmony_ci		spin_lock_irqsave(shost->host_lock, iflags);
47378c2ecf20Sopenharmony_ci		vport->fc_flag &= ~FC_DISC_TMO;
47388c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(shost->host_lock, iflags);
47398c2ecf20Sopenharmony_ci		del_timer_sync(&vport->fc_disctmo);
47408c2ecf20Sopenharmony_ci		spin_lock_irqsave(&vport->work_port_lock, iflags);
47418c2ecf20Sopenharmony_ci		vport->work_port_events &= ~WORKER_DISC_TMO;
47428c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&vport->work_port_lock, iflags);
47438c2ecf20Sopenharmony_ci	}
47448c2ecf20Sopenharmony_ci
47458c2ecf20Sopenharmony_ci	/* Cancel Discovery Timer state <hba_state> */
47468c2ecf20Sopenharmony_ci	lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
47478c2ecf20Sopenharmony_ci			 "0248 Cancel Discovery Timer state x%x "
47488c2ecf20Sopenharmony_ci			 "Data: x%x x%x x%x\n",
47498c2ecf20Sopenharmony_ci			 vport->port_state, vport->fc_flag,
47508c2ecf20Sopenharmony_ci			 vport->fc_plogi_cnt, vport->fc_adisc_cnt);
47518c2ecf20Sopenharmony_ci	return 0;
47528c2ecf20Sopenharmony_ci}
47538c2ecf20Sopenharmony_ci
47548c2ecf20Sopenharmony_ci/*
47558c2ecf20Sopenharmony_ci * Check specified ring for outstanding IOCB on the SLI queue
47568c2ecf20Sopenharmony_ci * Return true if iocb matches the specified nport
47578c2ecf20Sopenharmony_ci */
47588c2ecf20Sopenharmony_ciint
47598c2ecf20Sopenharmony_cilpfc_check_sli_ndlp(struct lpfc_hba *phba,
47608c2ecf20Sopenharmony_ci		    struct lpfc_sli_ring *pring,
47618c2ecf20Sopenharmony_ci		    struct lpfc_iocbq *iocb,
47628c2ecf20Sopenharmony_ci		    struct lpfc_nodelist *ndlp)
47638c2ecf20Sopenharmony_ci{
47648c2ecf20Sopenharmony_ci	IOCB_t *icmd = &iocb->iocb;
47658c2ecf20Sopenharmony_ci	struct lpfc_vport    *vport = ndlp->vport;
47668c2ecf20Sopenharmony_ci
47678c2ecf20Sopenharmony_ci	if (iocb->vport != vport)
47688c2ecf20Sopenharmony_ci		return 0;
47698c2ecf20Sopenharmony_ci
47708c2ecf20Sopenharmony_ci	if (pring->ringno == LPFC_ELS_RING) {
47718c2ecf20Sopenharmony_ci		switch (icmd->ulpCommand) {
47728c2ecf20Sopenharmony_ci		case CMD_GEN_REQUEST64_CR:
47738c2ecf20Sopenharmony_ci			if (iocb->context_un.ndlp == ndlp)
47748c2ecf20Sopenharmony_ci				return 1;
47758c2ecf20Sopenharmony_ci			fallthrough;
47768c2ecf20Sopenharmony_ci		case CMD_ELS_REQUEST64_CR:
47778c2ecf20Sopenharmony_ci			if (icmd->un.elsreq64.remoteID == ndlp->nlp_DID)
47788c2ecf20Sopenharmony_ci				return 1;
47798c2ecf20Sopenharmony_ci			fallthrough;
47808c2ecf20Sopenharmony_ci		case CMD_XMIT_ELS_RSP64_CX:
47818c2ecf20Sopenharmony_ci			if (iocb->context1 == (uint8_t *) ndlp)
47828c2ecf20Sopenharmony_ci				return 1;
47838c2ecf20Sopenharmony_ci		}
47848c2ecf20Sopenharmony_ci	} else if (pring->ringno == LPFC_FCP_RING) {
47858c2ecf20Sopenharmony_ci		/* Skip match check if waiting to relogin to FCP target */
47868c2ecf20Sopenharmony_ci		if ((ndlp->nlp_type & NLP_FCP_TARGET) &&
47878c2ecf20Sopenharmony_ci		    (ndlp->nlp_flag & NLP_DELAY_TMO)) {
47888c2ecf20Sopenharmony_ci			return 0;
47898c2ecf20Sopenharmony_ci		}
47908c2ecf20Sopenharmony_ci		if (icmd->ulpContext == (volatile ushort)ndlp->nlp_rpi) {
47918c2ecf20Sopenharmony_ci			return 1;
47928c2ecf20Sopenharmony_ci		}
47938c2ecf20Sopenharmony_ci	}
47948c2ecf20Sopenharmony_ci	return 0;
47958c2ecf20Sopenharmony_ci}
47968c2ecf20Sopenharmony_ci
47978c2ecf20Sopenharmony_cistatic void
47988c2ecf20Sopenharmony_ci__lpfc_dequeue_nport_iocbs(struct lpfc_hba *phba,
47998c2ecf20Sopenharmony_ci		struct lpfc_nodelist *ndlp, struct lpfc_sli_ring *pring,
48008c2ecf20Sopenharmony_ci		struct list_head *dequeue_list)
48018c2ecf20Sopenharmony_ci{
48028c2ecf20Sopenharmony_ci	struct lpfc_iocbq *iocb, *next_iocb;
48038c2ecf20Sopenharmony_ci
48048c2ecf20Sopenharmony_ci	list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
48058c2ecf20Sopenharmony_ci		/* Check to see if iocb matches the nport */
48068c2ecf20Sopenharmony_ci		if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))
48078c2ecf20Sopenharmony_ci			/* match, dequeue */
48088c2ecf20Sopenharmony_ci			list_move_tail(&iocb->list, dequeue_list);
48098c2ecf20Sopenharmony_ci	}
48108c2ecf20Sopenharmony_ci}
48118c2ecf20Sopenharmony_ci
48128c2ecf20Sopenharmony_cistatic void
48138c2ecf20Sopenharmony_cilpfc_sli3_dequeue_nport_iocbs(struct lpfc_hba *phba,
48148c2ecf20Sopenharmony_ci		struct lpfc_nodelist *ndlp, struct list_head *dequeue_list)
48158c2ecf20Sopenharmony_ci{
48168c2ecf20Sopenharmony_ci	struct lpfc_sli *psli = &phba->sli;
48178c2ecf20Sopenharmony_ci	uint32_t i;
48188c2ecf20Sopenharmony_ci
48198c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
48208c2ecf20Sopenharmony_ci	for (i = 0; i < psli->num_rings; i++)
48218c2ecf20Sopenharmony_ci		__lpfc_dequeue_nport_iocbs(phba, ndlp, &psli->sli3_ring[i],
48228c2ecf20Sopenharmony_ci						dequeue_list);
48238c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
48248c2ecf20Sopenharmony_ci}
48258c2ecf20Sopenharmony_ci
48268c2ecf20Sopenharmony_cistatic void
48278c2ecf20Sopenharmony_cilpfc_sli4_dequeue_nport_iocbs(struct lpfc_hba *phba,
48288c2ecf20Sopenharmony_ci		struct lpfc_nodelist *ndlp, struct list_head *dequeue_list)
48298c2ecf20Sopenharmony_ci{
48308c2ecf20Sopenharmony_ci	struct lpfc_sli_ring *pring;
48318c2ecf20Sopenharmony_ci	struct lpfc_queue *qp = NULL;
48328c2ecf20Sopenharmony_ci
48338c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
48348c2ecf20Sopenharmony_ci	list_for_each_entry(qp, &phba->sli4_hba.lpfc_wq_list, wq_list) {
48358c2ecf20Sopenharmony_ci		pring = qp->pring;
48368c2ecf20Sopenharmony_ci		if (!pring)
48378c2ecf20Sopenharmony_ci			continue;
48388c2ecf20Sopenharmony_ci		spin_lock(&pring->ring_lock);
48398c2ecf20Sopenharmony_ci		__lpfc_dequeue_nport_iocbs(phba, ndlp, pring, dequeue_list);
48408c2ecf20Sopenharmony_ci		spin_unlock(&pring->ring_lock);
48418c2ecf20Sopenharmony_ci	}
48428c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
48438c2ecf20Sopenharmony_ci}
48448c2ecf20Sopenharmony_ci
48458c2ecf20Sopenharmony_ci/*
48468c2ecf20Sopenharmony_ci * Free resources / clean up outstanding I/Os
48478c2ecf20Sopenharmony_ci * associated with nlp_rpi in the LPFC_NODELIST entry.
48488c2ecf20Sopenharmony_ci */
48498c2ecf20Sopenharmony_cistatic int
48508c2ecf20Sopenharmony_cilpfc_no_rpi(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
48518c2ecf20Sopenharmony_ci{
48528c2ecf20Sopenharmony_ci	LIST_HEAD(completions);
48538c2ecf20Sopenharmony_ci
48548c2ecf20Sopenharmony_ci	lpfc_fabric_abort_nport(ndlp);
48558c2ecf20Sopenharmony_ci
48568c2ecf20Sopenharmony_ci	/*
48578c2ecf20Sopenharmony_ci	 * Everything that matches on txcmplq will be returned
48588c2ecf20Sopenharmony_ci	 * by firmware with a no rpi error.
48598c2ecf20Sopenharmony_ci	 */
48608c2ecf20Sopenharmony_ci	if (ndlp->nlp_flag & NLP_RPI_REGISTERED) {
48618c2ecf20Sopenharmony_ci		if (phba->sli_rev != LPFC_SLI_REV4)
48628c2ecf20Sopenharmony_ci			lpfc_sli3_dequeue_nport_iocbs(phba, ndlp, &completions);
48638c2ecf20Sopenharmony_ci		else
48648c2ecf20Sopenharmony_ci			lpfc_sli4_dequeue_nport_iocbs(phba, ndlp, &completions);
48658c2ecf20Sopenharmony_ci	}
48668c2ecf20Sopenharmony_ci
48678c2ecf20Sopenharmony_ci	/* Cancel all the IOCBs from the completions list */
48688c2ecf20Sopenharmony_ci	lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
48698c2ecf20Sopenharmony_ci			      IOERR_SLI_ABORTED);
48708c2ecf20Sopenharmony_ci
48718c2ecf20Sopenharmony_ci	return 0;
48728c2ecf20Sopenharmony_ci}
48738c2ecf20Sopenharmony_ci
48748c2ecf20Sopenharmony_ci/**
48758c2ecf20Sopenharmony_ci * lpfc_nlp_logo_unreg - Unreg mailbox completion handler before LOGO
48768c2ecf20Sopenharmony_ci * @phba: Pointer to HBA context object.
48778c2ecf20Sopenharmony_ci * @pmb: Pointer to mailbox object.
48788c2ecf20Sopenharmony_ci *
48798c2ecf20Sopenharmony_ci * This function will issue an ELS LOGO command after completing
48808c2ecf20Sopenharmony_ci * the UNREG_RPI.
48818c2ecf20Sopenharmony_ci **/
48828c2ecf20Sopenharmony_cistatic void
48838c2ecf20Sopenharmony_cilpfc_nlp_logo_unreg(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
48848c2ecf20Sopenharmony_ci{
48858c2ecf20Sopenharmony_ci	struct lpfc_vport  *vport = pmb->vport;
48868c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp;
48878c2ecf20Sopenharmony_ci
48888c2ecf20Sopenharmony_ci	ndlp = (struct lpfc_nodelist *)(pmb->ctx_ndlp);
48898c2ecf20Sopenharmony_ci	if (!ndlp)
48908c2ecf20Sopenharmony_ci		return;
48918c2ecf20Sopenharmony_ci	lpfc_issue_els_logo(vport, ndlp, 0);
48928c2ecf20Sopenharmony_ci	mempool_free(pmb, phba->mbox_mem_pool);
48938c2ecf20Sopenharmony_ci
48948c2ecf20Sopenharmony_ci	/* Check to see if there are any deferred events to process */
48958c2ecf20Sopenharmony_ci	if ((ndlp->nlp_flag & NLP_UNREG_INP) &&
48968c2ecf20Sopenharmony_ci	    (ndlp->nlp_defer_did != NLP_EVT_NOTHING_PENDING)) {
48978c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
48988c2ecf20Sopenharmony_ci				 "1434 UNREG cmpl deferred logo x%x "
48998c2ecf20Sopenharmony_ci				 "on NPort x%x Data: x%x x%px\n",
49008c2ecf20Sopenharmony_ci				 ndlp->nlp_rpi, ndlp->nlp_DID,
49018c2ecf20Sopenharmony_ci				 ndlp->nlp_defer_did, ndlp);
49028c2ecf20Sopenharmony_ci
49038c2ecf20Sopenharmony_ci		ndlp->nlp_flag &= ~NLP_UNREG_INP;
49048c2ecf20Sopenharmony_ci		ndlp->nlp_defer_did = NLP_EVT_NOTHING_PENDING;
49058c2ecf20Sopenharmony_ci		lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
49068c2ecf20Sopenharmony_ci	} else {
49078c2ecf20Sopenharmony_ci		if (ndlp->nlp_flag & NLP_RELEASE_RPI) {
49088c2ecf20Sopenharmony_ci			lpfc_sli4_free_rpi(vport->phba, ndlp->nlp_rpi);
49098c2ecf20Sopenharmony_ci			ndlp->nlp_flag &= ~NLP_RELEASE_RPI;
49108c2ecf20Sopenharmony_ci			ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR;
49118c2ecf20Sopenharmony_ci		}
49128c2ecf20Sopenharmony_ci		ndlp->nlp_flag &= ~NLP_UNREG_INP;
49138c2ecf20Sopenharmony_ci	}
49148c2ecf20Sopenharmony_ci}
49158c2ecf20Sopenharmony_ci
49168c2ecf20Sopenharmony_ci/*
49178c2ecf20Sopenharmony_ci * Sets the mailbox completion handler to be used for the
49188c2ecf20Sopenharmony_ci * unreg_rpi command. The handler varies based on the state of
49198c2ecf20Sopenharmony_ci * the port and what will be happening to the rpi next.
49208c2ecf20Sopenharmony_ci */
49218c2ecf20Sopenharmony_cistatic void
49228c2ecf20Sopenharmony_cilpfc_set_unreg_login_mbx_cmpl(struct lpfc_hba *phba, struct lpfc_vport *vport,
49238c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp, LPFC_MBOXQ_t *mbox)
49248c2ecf20Sopenharmony_ci{
49258c2ecf20Sopenharmony_ci	unsigned long iflags;
49268c2ecf20Sopenharmony_ci
49278c2ecf20Sopenharmony_ci	if (ndlp->nlp_flag & NLP_ISSUE_LOGO) {
49288c2ecf20Sopenharmony_ci		mbox->ctx_ndlp = ndlp;
49298c2ecf20Sopenharmony_ci		mbox->mbox_cmpl = lpfc_nlp_logo_unreg;
49308c2ecf20Sopenharmony_ci
49318c2ecf20Sopenharmony_ci	} else if (phba->sli_rev == LPFC_SLI_REV4 &&
49328c2ecf20Sopenharmony_ci		   (!(vport->load_flag & FC_UNLOADING)) &&
49338c2ecf20Sopenharmony_ci		    (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >=
49348c2ecf20Sopenharmony_ci				      LPFC_SLI_INTF_IF_TYPE_2) &&
49358c2ecf20Sopenharmony_ci		    (kref_read(&ndlp->kref) > 0)) {
49368c2ecf20Sopenharmony_ci		mbox->ctx_ndlp = lpfc_nlp_get(ndlp);
49378c2ecf20Sopenharmony_ci		mbox->mbox_cmpl = lpfc_sli4_unreg_rpi_cmpl_clr;
49388c2ecf20Sopenharmony_ci	} else {
49398c2ecf20Sopenharmony_ci		if (vport->load_flag & FC_UNLOADING) {
49408c2ecf20Sopenharmony_ci			if (phba->sli_rev == LPFC_SLI_REV4) {
49418c2ecf20Sopenharmony_ci				spin_lock_irqsave(&vport->phba->ndlp_lock,
49428c2ecf20Sopenharmony_ci						  iflags);
49438c2ecf20Sopenharmony_ci				ndlp->nlp_flag |= NLP_RELEASE_RPI;
49448c2ecf20Sopenharmony_ci				spin_unlock_irqrestore(&vport->phba->ndlp_lock,
49458c2ecf20Sopenharmony_ci						       iflags);
49468c2ecf20Sopenharmony_ci			}
49478c2ecf20Sopenharmony_ci			lpfc_nlp_get(ndlp);
49488c2ecf20Sopenharmony_ci		}
49498c2ecf20Sopenharmony_ci		mbox->ctx_ndlp = ndlp;
49508c2ecf20Sopenharmony_ci		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
49518c2ecf20Sopenharmony_ci	}
49528c2ecf20Sopenharmony_ci}
49538c2ecf20Sopenharmony_ci
49548c2ecf20Sopenharmony_ci/*
49558c2ecf20Sopenharmony_ci * Free rpi associated with LPFC_NODELIST entry.
49568c2ecf20Sopenharmony_ci * This routine is called from lpfc_freenode(), when we are removing
49578c2ecf20Sopenharmony_ci * a LPFC_NODELIST entry. It is also called if the driver initiates a
49588c2ecf20Sopenharmony_ci * LOGO that completes successfully, and we are waiting to PLOGI back
49598c2ecf20Sopenharmony_ci * to the remote NPort. In addition, it is called after we receive
49608c2ecf20Sopenharmony_ci * and unsolicated ELS cmd, send back a rsp, the rsp completes and
49618c2ecf20Sopenharmony_ci * we are waiting to PLOGI back to the remote NPort.
49628c2ecf20Sopenharmony_ci */
49638c2ecf20Sopenharmony_ciint
49648c2ecf20Sopenharmony_cilpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
49658c2ecf20Sopenharmony_ci{
49668c2ecf20Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
49678c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t    *mbox;
49688c2ecf20Sopenharmony_ci	int rc, acc_plogi = 1;
49698c2ecf20Sopenharmony_ci	uint16_t rpi;
49708c2ecf20Sopenharmony_ci
49718c2ecf20Sopenharmony_ci	if (ndlp->nlp_flag & NLP_RPI_REGISTERED ||
49728c2ecf20Sopenharmony_ci	    ndlp->nlp_flag & NLP_REG_LOGIN_SEND) {
49738c2ecf20Sopenharmony_ci		if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND)
49748c2ecf20Sopenharmony_ci			lpfc_printf_vlog(vport, KERN_INFO,
49758c2ecf20Sopenharmony_ci					 LOG_NODE | LOG_DISCOVERY,
49768c2ecf20Sopenharmony_ci					 "3366 RPI x%x needs to be "
49778c2ecf20Sopenharmony_ci					 "unregistered nlp_flag x%x "
49788c2ecf20Sopenharmony_ci					 "did x%x\n",
49798c2ecf20Sopenharmony_ci					 ndlp->nlp_rpi, ndlp->nlp_flag,
49808c2ecf20Sopenharmony_ci					 ndlp->nlp_DID);
49818c2ecf20Sopenharmony_ci
49828c2ecf20Sopenharmony_ci		/* If there is already an UNREG in progress for this ndlp,
49838c2ecf20Sopenharmony_ci		 * no need to queue up another one.
49848c2ecf20Sopenharmony_ci		 */
49858c2ecf20Sopenharmony_ci		if (ndlp->nlp_flag & NLP_UNREG_INP) {
49868c2ecf20Sopenharmony_ci			lpfc_printf_vlog(vport, KERN_INFO,
49878c2ecf20Sopenharmony_ci					 LOG_NODE | LOG_DISCOVERY,
49888c2ecf20Sopenharmony_ci					 "1436 unreg_rpi SKIP UNREG x%x on "
49898c2ecf20Sopenharmony_ci					 "NPort x%x deferred x%x  flg x%x "
49908c2ecf20Sopenharmony_ci					 "Data: x%px\n",
49918c2ecf20Sopenharmony_ci					 ndlp->nlp_rpi, ndlp->nlp_DID,
49928c2ecf20Sopenharmony_ci					 ndlp->nlp_defer_did,
49938c2ecf20Sopenharmony_ci					 ndlp->nlp_flag, ndlp);
49948c2ecf20Sopenharmony_ci			goto out;
49958c2ecf20Sopenharmony_ci		}
49968c2ecf20Sopenharmony_ci
49978c2ecf20Sopenharmony_ci		mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
49988c2ecf20Sopenharmony_ci		if (mbox) {
49998c2ecf20Sopenharmony_ci			/* SLI4 ports require the physical rpi value. */
50008c2ecf20Sopenharmony_ci			rpi = ndlp->nlp_rpi;
50018c2ecf20Sopenharmony_ci			if (phba->sli_rev == LPFC_SLI_REV4)
50028c2ecf20Sopenharmony_ci				rpi = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi];
50038c2ecf20Sopenharmony_ci
50048c2ecf20Sopenharmony_ci			lpfc_unreg_login(phba, vport->vpi, rpi, mbox);
50058c2ecf20Sopenharmony_ci			mbox->vport = vport;
50068c2ecf20Sopenharmony_ci			lpfc_set_unreg_login_mbx_cmpl(phba, vport, ndlp, mbox);
50078c2ecf20Sopenharmony_ci			if (mbox->mbox_cmpl == lpfc_sli4_unreg_rpi_cmpl_clr)
50088c2ecf20Sopenharmony_ci				/*
50098c2ecf20Sopenharmony_ci				 * accept PLOGIs after unreg_rpi_cmpl
50108c2ecf20Sopenharmony_ci				 */
50118c2ecf20Sopenharmony_ci				acc_plogi = 0;
50128c2ecf20Sopenharmony_ci			if (((ndlp->nlp_DID & Fabric_DID_MASK) !=
50138c2ecf20Sopenharmony_ci			    Fabric_DID_MASK) &&
50148c2ecf20Sopenharmony_ci			    (!(vport->fc_flag & FC_OFFLINE_MODE)))
50158c2ecf20Sopenharmony_ci				ndlp->nlp_flag |= NLP_UNREG_INP;
50168c2ecf20Sopenharmony_ci
50178c2ecf20Sopenharmony_ci			lpfc_printf_vlog(vport, KERN_INFO,
50188c2ecf20Sopenharmony_ci					 LOG_NODE | LOG_DISCOVERY,
50198c2ecf20Sopenharmony_ci					 "1433 unreg_rpi UNREG x%x on "
50208c2ecf20Sopenharmony_ci					 "NPort x%x deferred flg x%x "
50218c2ecf20Sopenharmony_ci					 "Data:x%px\n",
50228c2ecf20Sopenharmony_ci					 ndlp->nlp_rpi, ndlp->nlp_DID,
50238c2ecf20Sopenharmony_ci					 ndlp->nlp_flag, ndlp);
50248c2ecf20Sopenharmony_ci
50258c2ecf20Sopenharmony_ci			rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
50268c2ecf20Sopenharmony_ci			if (rc == MBX_NOT_FINISHED) {
50278c2ecf20Sopenharmony_ci				mempool_free(mbox, phba->mbox_mem_pool);
50288c2ecf20Sopenharmony_ci				acc_plogi = 1;
50298c2ecf20Sopenharmony_ci			}
50308c2ecf20Sopenharmony_ci		} else {
50318c2ecf20Sopenharmony_ci			lpfc_printf_vlog(vport, KERN_INFO,
50328c2ecf20Sopenharmony_ci					 LOG_NODE | LOG_DISCOVERY,
50338c2ecf20Sopenharmony_ci					 "1444 Failed to allocate mempool "
50348c2ecf20Sopenharmony_ci					 "unreg_rpi UNREG x%x, "
50358c2ecf20Sopenharmony_ci					 "DID x%x, flag x%x, "
50368c2ecf20Sopenharmony_ci					 "ndlp x%px\n",
50378c2ecf20Sopenharmony_ci					 ndlp->nlp_rpi, ndlp->nlp_DID,
50388c2ecf20Sopenharmony_ci					 ndlp->nlp_flag, ndlp);
50398c2ecf20Sopenharmony_ci
50408c2ecf20Sopenharmony_ci			/* Because mempool_alloc failed, we
50418c2ecf20Sopenharmony_ci			 * will issue a LOGO here and keep the rpi alive if
50428c2ecf20Sopenharmony_ci			 * not unloading.
50438c2ecf20Sopenharmony_ci			 */
50448c2ecf20Sopenharmony_ci			if (!(vport->load_flag & FC_UNLOADING)) {
50458c2ecf20Sopenharmony_ci				ndlp->nlp_flag &= ~NLP_UNREG_INP;
50468c2ecf20Sopenharmony_ci				lpfc_issue_els_logo(vport, ndlp, 0);
50478c2ecf20Sopenharmony_ci				ndlp->nlp_prev_state = ndlp->nlp_state;
50488c2ecf20Sopenharmony_ci				lpfc_nlp_set_state(vport, ndlp,
50498c2ecf20Sopenharmony_ci						   NLP_STE_NPR_NODE);
50508c2ecf20Sopenharmony_ci			}
50518c2ecf20Sopenharmony_ci
50528c2ecf20Sopenharmony_ci			return 1;
50538c2ecf20Sopenharmony_ci		}
50548c2ecf20Sopenharmony_ci		lpfc_no_rpi(phba, ndlp);
50558c2ecf20Sopenharmony_ciout:
50568c2ecf20Sopenharmony_ci		if (phba->sli_rev != LPFC_SLI_REV4)
50578c2ecf20Sopenharmony_ci			ndlp->nlp_rpi = 0;
50588c2ecf20Sopenharmony_ci		ndlp->nlp_flag &= ~NLP_RPI_REGISTERED;
50598c2ecf20Sopenharmony_ci		ndlp->nlp_flag &= ~NLP_NPR_ADISC;
50608c2ecf20Sopenharmony_ci		if (acc_plogi)
50618c2ecf20Sopenharmony_ci			ndlp->nlp_flag &= ~NLP_LOGO_ACC;
50628c2ecf20Sopenharmony_ci		return 1;
50638c2ecf20Sopenharmony_ci	}
50648c2ecf20Sopenharmony_ci	ndlp->nlp_flag &= ~NLP_LOGO_ACC;
50658c2ecf20Sopenharmony_ci	return 0;
50668c2ecf20Sopenharmony_ci}
50678c2ecf20Sopenharmony_ci
50688c2ecf20Sopenharmony_ci/**
50698c2ecf20Sopenharmony_ci * lpfc_unreg_hba_rpis - Unregister rpis registered to the hba.
50708c2ecf20Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
50718c2ecf20Sopenharmony_ci *
50728c2ecf20Sopenharmony_ci * This routine is invoked to unregister all the currently registered RPIs
50738c2ecf20Sopenharmony_ci * to the HBA.
50748c2ecf20Sopenharmony_ci **/
50758c2ecf20Sopenharmony_civoid
50768c2ecf20Sopenharmony_cilpfc_unreg_hba_rpis(struct lpfc_hba *phba)
50778c2ecf20Sopenharmony_ci{
50788c2ecf20Sopenharmony_ci	struct lpfc_vport **vports;
50798c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp;
50808c2ecf20Sopenharmony_ci	struct Scsi_Host *shost;
50818c2ecf20Sopenharmony_ci	int i;
50828c2ecf20Sopenharmony_ci
50838c2ecf20Sopenharmony_ci	vports = lpfc_create_vport_work_array(phba);
50848c2ecf20Sopenharmony_ci	if (!vports) {
50858c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
50868c2ecf20Sopenharmony_ci				"2884 Vport array allocation failed \n");
50878c2ecf20Sopenharmony_ci		return;
50888c2ecf20Sopenharmony_ci	}
50898c2ecf20Sopenharmony_ci	for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
50908c2ecf20Sopenharmony_ci		shost = lpfc_shost_from_vport(vports[i]);
50918c2ecf20Sopenharmony_ci		spin_lock_irq(shost->host_lock);
50928c2ecf20Sopenharmony_ci		list_for_each_entry(ndlp, &vports[i]->fc_nodes, nlp_listp) {
50938c2ecf20Sopenharmony_ci			if (ndlp->nlp_flag & NLP_RPI_REGISTERED) {
50948c2ecf20Sopenharmony_ci				/* The mempool_alloc might sleep */
50958c2ecf20Sopenharmony_ci				spin_unlock_irq(shost->host_lock);
50968c2ecf20Sopenharmony_ci				lpfc_unreg_rpi(vports[i], ndlp);
50978c2ecf20Sopenharmony_ci				spin_lock_irq(shost->host_lock);
50988c2ecf20Sopenharmony_ci			}
50998c2ecf20Sopenharmony_ci		}
51008c2ecf20Sopenharmony_ci		spin_unlock_irq(shost->host_lock);
51018c2ecf20Sopenharmony_ci	}
51028c2ecf20Sopenharmony_ci	lpfc_destroy_vport_work_array(phba, vports);
51038c2ecf20Sopenharmony_ci}
51048c2ecf20Sopenharmony_ci
51058c2ecf20Sopenharmony_civoid
51068c2ecf20Sopenharmony_cilpfc_unreg_all_rpis(struct lpfc_vport *vport)
51078c2ecf20Sopenharmony_ci{
51088c2ecf20Sopenharmony_ci	struct lpfc_hba  *phba  = vport->phba;
51098c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t     *mbox;
51108c2ecf20Sopenharmony_ci	int rc;
51118c2ecf20Sopenharmony_ci
51128c2ecf20Sopenharmony_ci	if (phba->sli_rev == LPFC_SLI_REV4) {
51138c2ecf20Sopenharmony_ci		lpfc_sli4_unreg_all_rpis(vport);
51148c2ecf20Sopenharmony_ci		return;
51158c2ecf20Sopenharmony_ci	}
51168c2ecf20Sopenharmony_ci
51178c2ecf20Sopenharmony_ci	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
51188c2ecf20Sopenharmony_ci	if (mbox) {
51198c2ecf20Sopenharmony_ci		lpfc_unreg_login(phba, vport->vpi, LPFC_UNREG_ALL_RPIS_VPORT,
51208c2ecf20Sopenharmony_ci				 mbox);
51218c2ecf20Sopenharmony_ci		mbox->vport = vport;
51228c2ecf20Sopenharmony_ci		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
51238c2ecf20Sopenharmony_ci		mbox->ctx_ndlp = NULL;
51248c2ecf20Sopenharmony_ci		rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
51258c2ecf20Sopenharmony_ci		if (rc != MBX_TIMEOUT)
51268c2ecf20Sopenharmony_ci			mempool_free(mbox, phba->mbox_mem_pool);
51278c2ecf20Sopenharmony_ci
51288c2ecf20Sopenharmony_ci		if ((rc == MBX_TIMEOUT) || (rc == MBX_NOT_FINISHED))
51298c2ecf20Sopenharmony_ci			lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
51308c2ecf20Sopenharmony_ci					 "1836 Could not issue "
51318c2ecf20Sopenharmony_ci					 "unreg_login(all_rpis) status %d\n",
51328c2ecf20Sopenharmony_ci					 rc);
51338c2ecf20Sopenharmony_ci	}
51348c2ecf20Sopenharmony_ci}
51358c2ecf20Sopenharmony_ci
51368c2ecf20Sopenharmony_civoid
51378c2ecf20Sopenharmony_cilpfc_unreg_default_rpis(struct lpfc_vport *vport)
51388c2ecf20Sopenharmony_ci{
51398c2ecf20Sopenharmony_ci	struct lpfc_hba  *phba  = vport->phba;
51408c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t     *mbox;
51418c2ecf20Sopenharmony_ci	int rc;
51428c2ecf20Sopenharmony_ci
51438c2ecf20Sopenharmony_ci	/* Unreg DID is an SLI3 operation. */
51448c2ecf20Sopenharmony_ci	if (phba->sli_rev > LPFC_SLI_REV3)
51458c2ecf20Sopenharmony_ci		return;
51468c2ecf20Sopenharmony_ci
51478c2ecf20Sopenharmony_ci	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
51488c2ecf20Sopenharmony_ci	if (mbox) {
51498c2ecf20Sopenharmony_ci		lpfc_unreg_did(phba, vport->vpi, LPFC_UNREG_ALL_DFLT_RPIS,
51508c2ecf20Sopenharmony_ci			       mbox);
51518c2ecf20Sopenharmony_ci		mbox->vport = vport;
51528c2ecf20Sopenharmony_ci		mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
51538c2ecf20Sopenharmony_ci		mbox->ctx_ndlp = NULL;
51548c2ecf20Sopenharmony_ci		rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO);
51558c2ecf20Sopenharmony_ci		if (rc != MBX_TIMEOUT)
51568c2ecf20Sopenharmony_ci			mempool_free(mbox, phba->mbox_mem_pool);
51578c2ecf20Sopenharmony_ci
51588c2ecf20Sopenharmony_ci		if ((rc == MBX_TIMEOUT) || (rc == MBX_NOT_FINISHED))
51598c2ecf20Sopenharmony_ci			lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
51608c2ecf20Sopenharmony_ci					 "1815 Could not issue "
51618c2ecf20Sopenharmony_ci					 "unreg_did (default rpis) status %d\n",
51628c2ecf20Sopenharmony_ci					 rc);
51638c2ecf20Sopenharmony_ci	}
51648c2ecf20Sopenharmony_ci}
51658c2ecf20Sopenharmony_ci
51668c2ecf20Sopenharmony_ci/*
51678c2ecf20Sopenharmony_ci * Free resources associated with LPFC_NODELIST entry
51688c2ecf20Sopenharmony_ci * so it can be freed.
51698c2ecf20Sopenharmony_ci */
51708c2ecf20Sopenharmony_cistatic int
51718c2ecf20Sopenharmony_cilpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
51728c2ecf20Sopenharmony_ci{
51738c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
51748c2ecf20Sopenharmony_ci	struct lpfc_hba  *phba = vport->phba;
51758c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t *mb, *nextmb;
51768c2ecf20Sopenharmony_ci	struct lpfc_dmabuf *mp;
51778c2ecf20Sopenharmony_ci	unsigned long iflags;
51788c2ecf20Sopenharmony_ci
51798c2ecf20Sopenharmony_ci	/* Cleanup node for NPort <nlp_DID> */
51808c2ecf20Sopenharmony_ci	lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
51818c2ecf20Sopenharmony_ci			 "0900 Cleanup node for NPort x%x "
51828c2ecf20Sopenharmony_ci			 "Data: x%x x%x x%x\n",
51838c2ecf20Sopenharmony_ci			 ndlp->nlp_DID, ndlp->nlp_flag,
51848c2ecf20Sopenharmony_ci			 ndlp->nlp_state, ndlp->nlp_rpi);
51858c2ecf20Sopenharmony_ci	if (NLP_CHK_FREE_REQ(ndlp)) {
51868c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE,
51878c2ecf20Sopenharmony_ci				"0280 %s: ndlp:x%px "
51888c2ecf20Sopenharmony_ci				"usgmap:x%x refcnt:%d\n",
51898c2ecf20Sopenharmony_ci				__func__, (void *)ndlp, ndlp->nlp_usg_map,
51908c2ecf20Sopenharmony_ci				kref_read(&ndlp->kref));
51918c2ecf20Sopenharmony_ci		lpfc_dequeue_node(vport, ndlp);
51928c2ecf20Sopenharmony_ci	} else {
51938c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE,
51948c2ecf20Sopenharmony_ci				"0281 %s: ndlp:x%px "
51958c2ecf20Sopenharmony_ci				"usgmap:x%x refcnt:%d\n",
51968c2ecf20Sopenharmony_ci				__func__, (void *)ndlp, ndlp->nlp_usg_map,
51978c2ecf20Sopenharmony_ci				kref_read(&ndlp->kref));
51988c2ecf20Sopenharmony_ci		lpfc_disable_node(vport, ndlp);
51998c2ecf20Sopenharmony_ci	}
52008c2ecf20Sopenharmony_ci
52018c2ecf20Sopenharmony_ci
52028c2ecf20Sopenharmony_ci	/* Don't need to clean up REG_LOGIN64 cmds for Default RPI cleanup */
52038c2ecf20Sopenharmony_ci
52048c2ecf20Sopenharmony_ci	/* cleanup any ndlp on mbox q waiting for reglogin cmpl */
52058c2ecf20Sopenharmony_ci	if ((mb = phba->sli.mbox_active)) {
52068c2ecf20Sopenharmony_ci		if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) &&
52078c2ecf20Sopenharmony_ci		   !(mb->mbox_flag & LPFC_MBX_IMED_UNREG) &&
52088c2ecf20Sopenharmony_ci		   (ndlp == (struct lpfc_nodelist *)mb->ctx_ndlp)) {
52098c2ecf20Sopenharmony_ci			mb->ctx_ndlp = NULL;
52108c2ecf20Sopenharmony_ci			mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
52118c2ecf20Sopenharmony_ci		}
52128c2ecf20Sopenharmony_ci	}
52138c2ecf20Sopenharmony_ci
52148c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
52158c2ecf20Sopenharmony_ci	/* Cleanup REG_LOGIN completions which are not yet processed */
52168c2ecf20Sopenharmony_ci	list_for_each_entry(mb, &phba->sli.mboxq_cmpl, list) {
52178c2ecf20Sopenharmony_ci		if ((mb->u.mb.mbxCommand != MBX_REG_LOGIN64) ||
52188c2ecf20Sopenharmony_ci			(mb->mbox_flag & LPFC_MBX_IMED_UNREG) ||
52198c2ecf20Sopenharmony_ci			(ndlp != (struct lpfc_nodelist *)mb->ctx_ndlp))
52208c2ecf20Sopenharmony_ci			continue;
52218c2ecf20Sopenharmony_ci
52228c2ecf20Sopenharmony_ci		mb->ctx_ndlp = NULL;
52238c2ecf20Sopenharmony_ci		mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
52248c2ecf20Sopenharmony_ci	}
52258c2ecf20Sopenharmony_ci
52268c2ecf20Sopenharmony_ci	list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
52278c2ecf20Sopenharmony_ci		if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) &&
52288c2ecf20Sopenharmony_ci		   !(mb->mbox_flag & LPFC_MBX_IMED_UNREG) &&
52298c2ecf20Sopenharmony_ci		    (ndlp == (struct lpfc_nodelist *)mb->ctx_ndlp)) {
52308c2ecf20Sopenharmony_ci			mp = (struct lpfc_dmabuf *)(mb->ctx_buf);
52318c2ecf20Sopenharmony_ci			if (mp) {
52328c2ecf20Sopenharmony_ci				__lpfc_mbuf_free(phba, mp->virt, mp->phys);
52338c2ecf20Sopenharmony_ci				kfree(mp);
52348c2ecf20Sopenharmony_ci			}
52358c2ecf20Sopenharmony_ci			list_del(&mb->list);
52368c2ecf20Sopenharmony_ci			mempool_free(mb, phba->mbox_mem_pool);
52378c2ecf20Sopenharmony_ci			/* We shall not invoke the lpfc_nlp_put to decrement
52388c2ecf20Sopenharmony_ci			 * the ndlp reference count as we are in the process
52398c2ecf20Sopenharmony_ci			 * of lpfc_nlp_release.
52408c2ecf20Sopenharmony_ci			 */
52418c2ecf20Sopenharmony_ci		}
52428c2ecf20Sopenharmony_ci	}
52438c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
52448c2ecf20Sopenharmony_ci
52458c2ecf20Sopenharmony_ci	lpfc_els_abort(phba, ndlp);
52468c2ecf20Sopenharmony_ci
52478c2ecf20Sopenharmony_ci	spin_lock_irq(shost->host_lock);
52488c2ecf20Sopenharmony_ci	ndlp->nlp_flag &= ~NLP_DELAY_TMO;
52498c2ecf20Sopenharmony_ci	spin_unlock_irq(shost->host_lock);
52508c2ecf20Sopenharmony_ci
52518c2ecf20Sopenharmony_ci	ndlp->nlp_last_elscmd = 0;
52528c2ecf20Sopenharmony_ci	del_timer_sync(&ndlp->nlp_delayfunc);
52538c2ecf20Sopenharmony_ci
52548c2ecf20Sopenharmony_ci	list_del_init(&ndlp->els_retry_evt.evt_listp);
52558c2ecf20Sopenharmony_ci	list_del_init(&ndlp->dev_loss_evt.evt_listp);
52568c2ecf20Sopenharmony_ci	list_del_init(&ndlp->recovery_evt.evt_listp);
52578c2ecf20Sopenharmony_ci	lpfc_cleanup_vports_rrqs(vport, ndlp);
52588c2ecf20Sopenharmony_ci	if (phba->sli_rev == LPFC_SLI_REV4)
52598c2ecf20Sopenharmony_ci		ndlp->nlp_flag |= NLP_RELEASE_RPI;
52608c2ecf20Sopenharmony_ci	if (!lpfc_unreg_rpi(vport, ndlp)) {
52618c2ecf20Sopenharmony_ci		/* Clean up unregistered and non freed rpis */
52628c2ecf20Sopenharmony_ci		if ((ndlp->nlp_flag & NLP_RELEASE_RPI) &&
52638c2ecf20Sopenharmony_ci		    !(ndlp->nlp_rpi == LPFC_RPI_ALLOC_ERROR)) {
52648c2ecf20Sopenharmony_ci			lpfc_sli4_free_rpi(vport->phba,
52658c2ecf20Sopenharmony_ci					   ndlp->nlp_rpi);
52668c2ecf20Sopenharmony_ci			spin_lock_irqsave(&vport->phba->ndlp_lock,
52678c2ecf20Sopenharmony_ci					  iflags);
52688c2ecf20Sopenharmony_ci			ndlp->nlp_flag &= ~NLP_RELEASE_RPI;
52698c2ecf20Sopenharmony_ci			ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR;
52708c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&vport->phba->ndlp_lock,
52718c2ecf20Sopenharmony_ci					       iflags);
52728c2ecf20Sopenharmony_ci		}
52738c2ecf20Sopenharmony_ci	}
52748c2ecf20Sopenharmony_ci	return 0;
52758c2ecf20Sopenharmony_ci}
52768c2ecf20Sopenharmony_ci
52778c2ecf20Sopenharmony_ci/*
52788c2ecf20Sopenharmony_ci * Check to see if we can free the nlp back to the freelist.
52798c2ecf20Sopenharmony_ci * If we are in the middle of using the nlp in the discovery state
52808c2ecf20Sopenharmony_ci * machine, defer the free till we reach the end of the state machine.
52818c2ecf20Sopenharmony_ci */
52828c2ecf20Sopenharmony_cistatic void
52838c2ecf20Sopenharmony_cilpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
52848c2ecf20Sopenharmony_ci{
52858c2ecf20Sopenharmony_ci	struct lpfc_hba  *phba = vport->phba;
52868c2ecf20Sopenharmony_ci	struct lpfc_rport_data *rdata;
52878c2ecf20Sopenharmony_ci	struct fc_rport *rport;
52888c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
52898c2ecf20Sopenharmony_ci	int rc;
52908c2ecf20Sopenharmony_ci
52918c2ecf20Sopenharmony_ci	lpfc_cancel_retry_delay_tmo(vport, ndlp);
52928c2ecf20Sopenharmony_ci	if ((ndlp->nlp_flag & NLP_DEFER_RM) &&
52938c2ecf20Sopenharmony_ci	    !(ndlp->nlp_flag & NLP_REG_LOGIN_SEND) &&
52948c2ecf20Sopenharmony_ci	    !(ndlp->nlp_flag & NLP_RPI_REGISTERED) &&
52958c2ecf20Sopenharmony_ci	    phba->sli_rev != LPFC_SLI_REV4) {
52968c2ecf20Sopenharmony_ci		/* For this case we need to cleanup the default rpi
52978c2ecf20Sopenharmony_ci		 * allocated by the firmware.
52988c2ecf20Sopenharmony_ci		 */
52998c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_INFO,
53008c2ecf20Sopenharmony_ci				 LOG_NODE | LOG_DISCOVERY,
53018c2ecf20Sopenharmony_ci				 "0005 Cleanup Default rpi:x%x DID:x%x flg:x%x "
53028c2ecf20Sopenharmony_ci				 "ref %d map:x%x ndlp x%px\n",
53038c2ecf20Sopenharmony_ci				 ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag,
53048c2ecf20Sopenharmony_ci				 kref_read(&ndlp->kref),
53058c2ecf20Sopenharmony_ci				 ndlp->nlp_usg_map, ndlp);
53068c2ecf20Sopenharmony_ci		if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))
53078c2ecf20Sopenharmony_ci			!= NULL) {
53088c2ecf20Sopenharmony_ci			rc = lpfc_reg_rpi(phba, vport->vpi, ndlp->nlp_DID,
53098c2ecf20Sopenharmony_ci			    (uint8_t *) &vport->fc_sparam, mbox, ndlp->nlp_rpi);
53108c2ecf20Sopenharmony_ci			if (rc) {
53118c2ecf20Sopenharmony_ci				mempool_free(mbox, phba->mbox_mem_pool);
53128c2ecf20Sopenharmony_ci			}
53138c2ecf20Sopenharmony_ci			else {
53148c2ecf20Sopenharmony_ci				mbox->mbox_flag |= LPFC_MBX_IMED_UNREG;
53158c2ecf20Sopenharmony_ci				mbox->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;
53168c2ecf20Sopenharmony_ci				mbox->vport = vport;
53178c2ecf20Sopenharmony_ci				mbox->ctx_ndlp = ndlp;
53188c2ecf20Sopenharmony_ci				rc =lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
53198c2ecf20Sopenharmony_ci				if (rc == MBX_NOT_FINISHED) {
53208c2ecf20Sopenharmony_ci					mempool_free(mbox, phba->mbox_mem_pool);
53218c2ecf20Sopenharmony_ci				}
53228c2ecf20Sopenharmony_ci			}
53238c2ecf20Sopenharmony_ci		}
53248c2ecf20Sopenharmony_ci	}
53258c2ecf20Sopenharmony_ci	lpfc_cleanup_node(vport, ndlp);
53268c2ecf20Sopenharmony_ci
53278c2ecf20Sopenharmony_ci	/*
53288c2ecf20Sopenharmony_ci	 * ndlp->rport must be set to NULL before it reaches here
53298c2ecf20Sopenharmony_ci	 * i.e. break rport/node link before doing lpfc_nlp_put for
53308c2ecf20Sopenharmony_ci	 * registered rport and then drop the reference of rport.
53318c2ecf20Sopenharmony_ci	 */
53328c2ecf20Sopenharmony_ci	if (ndlp->rport) {
53338c2ecf20Sopenharmony_ci		/*
53348c2ecf20Sopenharmony_ci		 * extra lpfc_nlp_put dropped the reference of ndlp
53358c2ecf20Sopenharmony_ci		 * for registered rport so need to cleanup rport
53368c2ecf20Sopenharmony_ci		 */
53378c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE,
53388c2ecf20Sopenharmony_ci				"0940 removed node x%px DID x%x "
53398c2ecf20Sopenharmony_ci				"rpi %d rport not null x%px\n",
53408c2ecf20Sopenharmony_ci				 ndlp, ndlp->nlp_DID, ndlp->nlp_rpi,
53418c2ecf20Sopenharmony_ci				 ndlp->rport);
53428c2ecf20Sopenharmony_ci		rport = ndlp->rport;
53438c2ecf20Sopenharmony_ci		rdata = rport->dd_data;
53448c2ecf20Sopenharmony_ci		rdata->pnode = NULL;
53458c2ecf20Sopenharmony_ci		ndlp->rport = NULL;
53468c2ecf20Sopenharmony_ci		put_device(&rport->dev);
53478c2ecf20Sopenharmony_ci	}
53488c2ecf20Sopenharmony_ci}
53498c2ecf20Sopenharmony_ci
53508c2ecf20Sopenharmony_cistatic int
53518c2ecf20Sopenharmony_cilpfc_matchdid(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
53528c2ecf20Sopenharmony_ci	      uint32_t did)
53538c2ecf20Sopenharmony_ci{
53548c2ecf20Sopenharmony_ci	D_ID mydid, ndlpdid, matchdid;
53558c2ecf20Sopenharmony_ci
53568c2ecf20Sopenharmony_ci	if (did == Bcast_DID)
53578c2ecf20Sopenharmony_ci		return 0;
53588c2ecf20Sopenharmony_ci
53598c2ecf20Sopenharmony_ci	/* First check for Direct match */
53608c2ecf20Sopenharmony_ci	if (ndlp->nlp_DID == did)
53618c2ecf20Sopenharmony_ci		return 1;
53628c2ecf20Sopenharmony_ci
53638c2ecf20Sopenharmony_ci	/* Next check for area/domain identically equals 0 match */
53648c2ecf20Sopenharmony_ci	mydid.un.word = vport->fc_myDID;
53658c2ecf20Sopenharmony_ci	if ((mydid.un.b.domain == 0) && (mydid.un.b.area == 0)) {
53668c2ecf20Sopenharmony_ci		return 0;
53678c2ecf20Sopenharmony_ci	}
53688c2ecf20Sopenharmony_ci
53698c2ecf20Sopenharmony_ci	matchdid.un.word = did;
53708c2ecf20Sopenharmony_ci	ndlpdid.un.word = ndlp->nlp_DID;
53718c2ecf20Sopenharmony_ci	if (matchdid.un.b.id == ndlpdid.un.b.id) {
53728c2ecf20Sopenharmony_ci		if ((mydid.un.b.domain == matchdid.un.b.domain) &&
53738c2ecf20Sopenharmony_ci		    (mydid.un.b.area == matchdid.un.b.area)) {
53748c2ecf20Sopenharmony_ci			/* This code is supposed to match the ID
53758c2ecf20Sopenharmony_ci			 * for a private loop device that is
53768c2ecf20Sopenharmony_ci			 * connect to fl_port. But we need to
53778c2ecf20Sopenharmony_ci			 * check that the port did not just go
53788c2ecf20Sopenharmony_ci			 * from pt2pt to fabric or we could end
53798c2ecf20Sopenharmony_ci			 * up matching ndlp->nlp_DID 000001 to
53808c2ecf20Sopenharmony_ci			 * fabric DID 0x20101
53818c2ecf20Sopenharmony_ci			 */
53828c2ecf20Sopenharmony_ci			if ((ndlpdid.un.b.domain == 0) &&
53838c2ecf20Sopenharmony_ci			    (ndlpdid.un.b.area == 0)) {
53848c2ecf20Sopenharmony_ci				if (ndlpdid.un.b.id &&
53858c2ecf20Sopenharmony_ci				    vport->phba->fc_topology ==
53868c2ecf20Sopenharmony_ci				    LPFC_TOPOLOGY_LOOP)
53878c2ecf20Sopenharmony_ci					return 1;
53888c2ecf20Sopenharmony_ci			}
53898c2ecf20Sopenharmony_ci			return 0;
53908c2ecf20Sopenharmony_ci		}
53918c2ecf20Sopenharmony_ci
53928c2ecf20Sopenharmony_ci		matchdid.un.word = ndlp->nlp_DID;
53938c2ecf20Sopenharmony_ci		if ((mydid.un.b.domain == ndlpdid.un.b.domain) &&
53948c2ecf20Sopenharmony_ci		    (mydid.un.b.area == ndlpdid.un.b.area)) {
53958c2ecf20Sopenharmony_ci			if ((matchdid.un.b.domain == 0) &&
53968c2ecf20Sopenharmony_ci			    (matchdid.un.b.area == 0)) {
53978c2ecf20Sopenharmony_ci				if (matchdid.un.b.id)
53988c2ecf20Sopenharmony_ci					return 1;
53998c2ecf20Sopenharmony_ci			}
54008c2ecf20Sopenharmony_ci		}
54018c2ecf20Sopenharmony_ci	}
54028c2ecf20Sopenharmony_ci	return 0;
54038c2ecf20Sopenharmony_ci}
54048c2ecf20Sopenharmony_ci
54058c2ecf20Sopenharmony_ci/* Search for a nodelist entry */
54068c2ecf20Sopenharmony_cistatic struct lpfc_nodelist *
54078c2ecf20Sopenharmony_ci__lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did)
54088c2ecf20Sopenharmony_ci{
54098c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp;
54108c2ecf20Sopenharmony_ci	uint32_t data1;
54118c2ecf20Sopenharmony_ci
54128c2ecf20Sopenharmony_ci	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
54138c2ecf20Sopenharmony_ci		if (lpfc_matchdid(vport, ndlp, did)) {
54148c2ecf20Sopenharmony_ci			data1 = (((uint32_t)ndlp->nlp_state << 24) |
54158c2ecf20Sopenharmony_ci				 ((uint32_t)ndlp->nlp_xri << 16) |
54168c2ecf20Sopenharmony_ci				 ((uint32_t)ndlp->nlp_type << 8) |
54178c2ecf20Sopenharmony_ci				 ((uint32_t)ndlp->nlp_usg_map & 0xff));
54188c2ecf20Sopenharmony_ci			lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
54198c2ecf20Sopenharmony_ci					 "0929 FIND node DID "
54208c2ecf20Sopenharmony_ci					 "Data: x%px x%x x%x x%x x%x x%px\n",
54218c2ecf20Sopenharmony_ci					 ndlp, ndlp->nlp_DID,
54228c2ecf20Sopenharmony_ci					 ndlp->nlp_flag, data1, ndlp->nlp_rpi,
54238c2ecf20Sopenharmony_ci					 ndlp->active_rrqs_xri_bitmap);
54248c2ecf20Sopenharmony_ci			return ndlp;
54258c2ecf20Sopenharmony_ci		}
54268c2ecf20Sopenharmony_ci	}
54278c2ecf20Sopenharmony_ci
54288c2ecf20Sopenharmony_ci	/* FIND node did <did> NOT FOUND */
54298c2ecf20Sopenharmony_ci	lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
54308c2ecf20Sopenharmony_ci			 "0932 FIND node did x%x NOT FOUND.\n", did);
54318c2ecf20Sopenharmony_ci	return NULL;
54328c2ecf20Sopenharmony_ci}
54338c2ecf20Sopenharmony_ci
54348c2ecf20Sopenharmony_cistruct lpfc_nodelist *
54358c2ecf20Sopenharmony_cilpfc_findnode_did(struct lpfc_vport *vport, uint32_t did)
54368c2ecf20Sopenharmony_ci{
54378c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
54388c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp;
54398c2ecf20Sopenharmony_ci	unsigned long iflags;
54408c2ecf20Sopenharmony_ci
54418c2ecf20Sopenharmony_ci	spin_lock_irqsave(shost->host_lock, iflags);
54428c2ecf20Sopenharmony_ci	ndlp = __lpfc_findnode_did(vport, did);
54438c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(shost->host_lock, iflags);
54448c2ecf20Sopenharmony_ci	return ndlp;
54458c2ecf20Sopenharmony_ci}
54468c2ecf20Sopenharmony_ci
54478c2ecf20Sopenharmony_cistruct lpfc_nodelist *
54488c2ecf20Sopenharmony_cilpfc_findnode_mapped(struct lpfc_vport *vport)
54498c2ecf20Sopenharmony_ci{
54508c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
54518c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp;
54528c2ecf20Sopenharmony_ci	uint32_t data1;
54538c2ecf20Sopenharmony_ci	unsigned long iflags;
54548c2ecf20Sopenharmony_ci
54558c2ecf20Sopenharmony_ci	spin_lock_irqsave(shost->host_lock, iflags);
54568c2ecf20Sopenharmony_ci
54578c2ecf20Sopenharmony_ci	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
54588c2ecf20Sopenharmony_ci		if (ndlp->nlp_state == NLP_STE_UNMAPPED_NODE ||
54598c2ecf20Sopenharmony_ci		    ndlp->nlp_state == NLP_STE_MAPPED_NODE) {
54608c2ecf20Sopenharmony_ci			data1 = (((uint32_t)ndlp->nlp_state << 24) |
54618c2ecf20Sopenharmony_ci				 ((uint32_t)ndlp->nlp_xri << 16) |
54628c2ecf20Sopenharmony_ci				 ((uint32_t)ndlp->nlp_type << 8) |
54638c2ecf20Sopenharmony_ci				 ((uint32_t)ndlp->nlp_rpi & 0xff));
54648c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(shost->host_lock, iflags);
54658c2ecf20Sopenharmony_ci			lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
54668c2ecf20Sopenharmony_ci					 "2025 FIND node DID "
54678c2ecf20Sopenharmony_ci					 "Data: x%px x%x x%x x%x x%px\n",
54688c2ecf20Sopenharmony_ci					 ndlp, ndlp->nlp_DID,
54698c2ecf20Sopenharmony_ci					 ndlp->nlp_flag, data1,
54708c2ecf20Sopenharmony_ci					 ndlp->active_rrqs_xri_bitmap);
54718c2ecf20Sopenharmony_ci			return ndlp;
54728c2ecf20Sopenharmony_ci		}
54738c2ecf20Sopenharmony_ci	}
54748c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(shost->host_lock, iflags);
54758c2ecf20Sopenharmony_ci
54768c2ecf20Sopenharmony_ci	/* FIND node did <did> NOT FOUND */
54778c2ecf20Sopenharmony_ci	lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
54788c2ecf20Sopenharmony_ci			 "2026 FIND mapped did NOT FOUND.\n");
54798c2ecf20Sopenharmony_ci	return NULL;
54808c2ecf20Sopenharmony_ci}
54818c2ecf20Sopenharmony_ci
54828c2ecf20Sopenharmony_cistruct lpfc_nodelist *
54838c2ecf20Sopenharmony_cilpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did)
54848c2ecf20Sopenharmony_ci{
54858c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
54868c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp;
54878c2ecf20Sopenharmony_ci
54888c2ecf20Sopenharmony_ci	ndlp = lpfc_findnode_did(vport, did);
54898c2ecf20Sopenharmony_ci	if (!ndlp) {
54908c2ecf20Sopenharmony_ci		if (vport->phba->nvmet_support)
54918c2ecf20Sopenharmony_ci			return NULL;
54928c2ecf20Sopenharmony_ci		if ((vport->fc_flag & FC_RSCN_MODE) != 0 &&
54938c2ecf20Sopenharmony_ci		    lpfc_rscn_payload_check(vport, did) == 0)
54948c2ecf20Sopenharmony_ci			return NULL;
54958c2ecf20Sopenharmony_ci		ndlp = lpfc_nlp_init(vport, did);
54968c2ecf20Sopenharmony_ci		if (!ndlp)
54978c2ecf20Sopenharmony_ci			return NULL;
54988c2ecf20Sopenharmony_ci		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
54998c2ecf20Sopenharmony_ci
55008c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
55018c2ecf20Sopenharmony_ci				 "6453 Setup New Node 2B_DISC x%x "
55028c2ecf20Sopenharmony_ci				 "Data:x%x x%x x%x\n",
55038c2ecf20Sopenharmony_ci				 ndlp->nlp_DID, ndlp->nlp_flag,
55048c2ecf20Sopenharmony_ci				 ndlp->nlp_state, vport->fc_flag);
55058c2ecf20Sopenharmony_ci
55068c2ecf20Sopenharmony_ci		spin_lock_irq(shost->host_lock);
55078c2ecf20Sopenharmony_ci		ndlp->nlp_flag |= NLP_NPR_2B_DISC;
55088c2ecf20Sopenharmony_ci		spin_unlock_irq(shost->host_lock);
55098c2ecf20Sopenharmony_ci		return ndlp;
55108c2ecf20Sopenharmony_ci	} else if (!NLP_CHK_NODE_ACT(ndlp)) {
55118c2ecf20Sopenharmony_ci		if (vport->phba->nvmet_support)
55128c2ecf20Sopenharmony_ci			return NULL;
55138c2ecf20Sopenharmony_ci		ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_NPR_NODE);
55148c2ecf20Sopenharmony_ci		if (!ndlp) {
55158c2ecf20Sopenharmony_ci			lpfc_printf_vlog(vport, KERN_WARNING, LOG_SLI,
55168c2ecf20Sopenharmony_ci					 "0014 Could not enable ndlp\n");
55178c2ecf20Sopenharmony_ci			return NULL;
55188c2ecf20Sopenharmony_ci		}
55198c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
55208c2ecf20Sopenharmony_ci				 "6454 Setup Enabled Node 2B_DISC x%x "
55218c2ecf20Sopenharmony_ci				 "Data:x%x x%x x%x\n",
55228c2ecf20Sopenharmony_ci				 ndlp->nlp_DID, ndlp->nlp_flag,
55238c2ecf20Sopenharmony_ci				 ndlp->nlp_state, vport->fc_flag);
55248c2ecf20Sopenharmony_ci
55258c2ecf20Sopenharmony_ci		spin_lock_irq(shost->host_lock);
55268c2ecf20Sopenharmony_ci		ndlp->nlp_flag |= NLP_NPR_2B_DISC;
55278c2ecf20Sopenharmony_ci		spin_unlock_irq(shost->host_lock);
55288c2ecf20Sopenharmony_ci		return ndlp;
55298c2ecf20Sopenharmony_ci	}
55308c2ecf20Sopenharmony_ci
55318c2ecf20Sopenharmony_ci	/* The NVME Target does not want to actively manage an rport.
55328c2ecf20Sopenharmony_ci	 * The goal is to allow the target to reset its state and clear
55338c2ecf20Sopenharmony_ci	 * pending IO in preparation for the initiator to recover.
55348c2ecf20Sopenharmony_ci	 */
55358c2ecf20Sopenharmony_ci	if ((vport->fc_flag & FC_RSCN_MODE) &&
55368c2ecf20Sopenharmony_ci	    !(vport->fc_flag & FC_NDISC_ACTIVE)) {
55378c2ecf20Sopenharmony_ci		if (lpfc_rscn_payload_check(vport, did)) {
55388c2ecf20Sopenharmony_ci
55398c2ecf20Sopenharmony_ci			/* Since this node is marked for discovery,
55408c2ecf20Sopenharmony_ci			 * delay timeout is not needed.
55418c2ecf20Sopenharmony_ci			 */
55428c2ecf20Sopenharmony_ci			lpfc_cancel_retry_delay_tmo(vport, ndlp);
55438c2ecf20Sopenharmony_ci
55448c2ecf20Sopenharmony_ci			lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
55458c2ecf20Sopenharmony_ci					 "6455 Setup RSCN Node 2B_DISC x%x "
55468c2ecf20Sopenharmony_ci					 "Data:x%x x%x x%x\n",
55478c2ecf20Sopenharmony_ci					 ndlp->nlp_DID, ndlp->nlp_flag,
55488c2ecf20Sopenharmony_ci					 ndlp->nlp_state, vport->fc_flag);
55498c2ecf20Sopenharmony_ci
55508c2ecf20Sopenharmony_ci			/* NVME Target mode waits until rport is known to be
55518c2ecf20Sopenharmony_ci			 * impacted by the RSCN before it transitions.  No
55528c2ecf20Sopenharmony_ci			 * active management - just go to NPR provided the
55538c2ecf20Sopenharmony_ci			 * node had a valid login.
55548c2ecf20Sopenharmony_ci			 */
55558c2ecf20Sopenharmony_ci			if (vport->phba->nvmet_support)
55568c2ecf20Sopenharmony_ci				return ndlp;
55578c2ecf20Sopenharmony_ci
55588c2ecf20Sopenharmony_ci			/* If we've already received a PLOGI from this NPort
55598c2ecf20Sopenharmony_ci			 * we don't need to try to discover it again.
55608c2ecf20Sopenharmony_ci			 */
55618c2ecf20Sopenharmony_ci			if (ndlp->nlp_flag & NLP_RCV_PLOGI &&
55628c2ecf20Sopenharmony_ci			    !(ndlp->nlp_type &
55638c2ecf20Sopenharmony_ci			     (NLP_FCP_TARGET | NLP_NVME_TARGET)))
55648c2ecf20Sopenharmony_ci				return NULL;
55658c2ecf20Sopenharmony_ci
55668c2ecf20Sopenharmony_ci			ndlp->nlp_prev_state = ndlp->nlp_state;
55678c2ecf20Sopenharmony_ci			lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
55688c2ecf20Sopenharmony_ci
55698c2ecf20Sopenharmony_ci			spin_lock_irq(shost->host_lock);
55708c2ecf20Sopenharmony_ci			ndlp->nlp_flag |= NLP_NPR_2B_DISC;
55718c2ecf20Sopenharmony_ci			spin_unlock_irq(shost->host_lock);
55728c2ecf20Sopenharmony_ci		} else {
55738c2ecf20Sopenharmony_ci			lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
55748c2ecf20Sopenharmony_ci					 "6456 Skip Setup RSCN Node x%x "
55758c2ecf20Sopenharmony_ci					 "Data:x%x x%x x%x\n",
55768c2ecf20Sopenharmony_ci					 ndlp->nlp_DID, ndlp->nlp_flag,
55778c2ecf20Sopenharmony_ci					 ndlp->nlp_state, vport->fc_flag);
55788c2ecf20Sopenharmony_ci			ndlp = NULL;
55798c2ecf20Sopenharmony_ci		}
55808c2ecf20Sopenharmony_ci	} else {
55818c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
55828c2ecf20Sopenharmony_ci				 "6457 Setup Active Node 2B_DISC x%x "
55838c2ecf20Sopenharmony_ci				 "Data:x%x x%x x%x\n",
55848c2ecf20Sopenharmony_ci				 ndlp->nlp_DID, ndlp->nlp_flag,
55858c2ecf20Sopenharmony_ci				 ndlp->nlp_state, vport->fc_flag);
55868c2ecf20Sopenharmony_ci
55878c2ecf20Sopenharmony_ci		/* If the initiator received a PLOGI from this NPort or if the
55888c2ecf20Sopenharmony_ci		 * initiator is already in the process of discovery on it,
55898c2ecf20Sopenharmony_ci		 * there's no need to try to discover it again.
55908c2ecf20Sopenharmony_ci		 */
55918c2ecf20Sopenharmony_ci		if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE ||
55928c2ecf20Sopenharmony_ci		    ndlp->nlp_state == NLP_STE_PLOGI_ISSUE ||
55938c2ecf20Sopenharmony_ci		    (!vport->phba->nvmet_support &&
55948c2ecf20Sopenharmony_ci		     ndlp->nlp_flag & NLP_RCV_PLOGI))
55958c2ecf20Sopenharmony_ci			return NULL;
55968c2ecf20Sopenharmony_ci
55978c2ecf20Sopenharmony_ci		if (vport->phba->nvmet_support)
55988c2ecf20Sopenharmony_ci			return ndlp;
55998c2ecf20Sopenharmony_ci
56008c2ecf20Sopenharmony_ci		/* Moving to NPR state clears unsolicited flags and
56018c2ecf20Sopenharmony_ci		 * allows for rediscovery
56028c2ecf20Sopenharmony_ci		 */
56038c2ecf20Sopenharmony_ci		lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
56048c2ecf20Sopenharmony_ci
56058c2ecf20Sopenharmony_ci		spin_lock_irq(shost->host_lock);
56068c2ecf20Sopenharmony_ci		ndlp->nlp_flag |= NLP_NPR_2B_DISC;
56078c2ecf20Sopenharmony_ci		spin_unlock_irq(shost->host_lock);
56088c2ecf20Sopenharmony_ci	}
56098c2ecf20Sopenharmony_ci	return ndlp;
56108c2ecf20Sopenharmony_ci}
56118c2ecf20Sopenharmony_ci
56128c2ecf20Sopenharmony_ci/* Build a list of nodes to discover based on the loopmap */
56138c2ecf20Sopenharmony_civoid
56148c2ecf20Sopenharmony_cilpfc_disc_list_loopmap(struct lpfc_vport *vport)
56158c2ecf20Sopenharmony_ci{
56168c2ecf20Sopenharmony_ci	struct lpfc_hba  *phba = vport->phba;
56178c2ecf20Sopenharmony_ci	int j;
56188c2ecf20Sopenharmony_ci	uint32_t alpa, index;
56198c2ecf20Sopenharmony_ci
56208c2ecf20Sopenharmony_ci	if (!lpfc_is_link_up(phba))
56218c2ecf20Sopenharmony_ci		return;
56228c2ecf20Sopenharmony_ci
56238c2ecf20Sopenharmony_ci	if (phba->fc_topology != LPFC_TOPOLOGY_LOOP)
56248c2ecf20Sopenharmony_ci		return;
56258c2ecf20Sopenharmony_ci
56268c2ecf20Sopenharmony_ci	/* Check for loop map present or not */
56278c2ecf20Sopenharmony_ci	if (phba->alpa_map[0]) {
56288c2ecf20Sopenharmony_ci		for (j = 1; j <= phba->alpa_map[0]; j++) {
56298c2ecf20Sopenharmony_ci			alpa = phba->alpa_map[j];
56308c2ecf20Sopenharmony_ci			if (((vport->fc_myDID & 0xff) == alpa) || (alpa == 0))
56318c2ecf20Sopenharmony_ci				continue;
56328c2ecf20Sopenharmony_ci			lpfc_setup_disc_node(vport, alpa);
56338c2ecf20Sopenharmony_ci		}
56348c2ecf20Sopenharmony_ci	} else {
56358c2ecf20Sopenharmony_ci		/* No alpamap, so try all alpa's */
56368c2ecf20Sopenharmony_ci		for (j = 0; j < FC_MAXLOOP; j++) {
56378c2ecf20Sopenharmony_ci			/* If cfg_scan_down is set, start from highest
56388c2ecf20Sopenharmony_ci			 * ALPA (0xef) to lowest (0x1).
56398c2ecf20Sopenharmony_ci			 */
56408c2ecf20Sopenharmony_ci			if (vport->cfg_scan_down)
56418c2ecf20Sopenharmony_ci				index = j;
56428c2ecf20Sopenharmony_ci			else
56438c2ecf20Sopenharmony_ci				index = FC_MAXLOOP - j - 1;
56448c2ecf20Sopenharmony_ci			alpa = lpfcAlpaArray[index];
56458c2ecf20Sopenharmony_ci			if ((vport->fc_myDID & 0xff) == alpa)
56468c2ecf20Sopenharmony_ci				continue;
56478c2ecf20Sopenharmony_ci			lpfc_setup_disc_node(vport, alpa);
56488c2ecf20Sopenharmony_ci		}
56498c2ecf20Sopenharmony_ci	}
56508c2ecf20Sopenharmony_ci	return;
56518c2ecf20Sopenharmony_ci}
56528c2ecf20Sopenharmony_ci
56538c2ecf20Sopenharmony_ci/* SLI3 only */
56548c2ecf20Sopenharmony_civoid
56558c2ecf20Sopenharmony_cilpfc_issue_clear_la(struct lpfc_hba *phba, struct lpfc_vport *vport)
56568c2ecf20Sopenharmony_ci{
56578c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
56588c2ecf20Sopenharmony_ci	struct lpfc_sli *psli = &phba->sli;
56598c2ecf20Sopenharmony_ci	struct lpfc_sli_ring *extra_ring = &psli->sli3_ring[LPFC_EXTRA_RING];
56608c2ecf20Sopenharmony_ci	struct lpfc_sli_ring *fcp_ring   = &psli->sli3_ring[LPFC_FCP_RING];
56618c2ecf20Sopenharmony_ci	int  rc;
56628c2ecf20Sopenharmony_ci
56638c2ecf20Sopenharmony_ci	/*
56648c2ecf20Sopenharmony_ci	 * if it's not a physical port or if we already send
56658c2ecf20Sopenharmony_ci	 * clear_la then don't send it.
56668c2ecf20Sopenharmony_ci	 */
56678c2ecf20Sopenharmony_ci	if ((phba->link_state >= LPFC_CLEAR_LA) ||
56688c2ecf20Sopenharmony_ci	    (vport->port_type != LPFC_PHYSICAL_PORT) ||
56698c2ecf20Sopenharmony_ci		(phba->sli_rev == LPFC_SLI_REV4))
56708c2ecf20Sopenharmony_ci		return;
56718c2ecf20Sopenharmony_ci
56728c2ecf20Sopenharmony_ci			/* Link up discovery */
56738c2ecf20Sopenharmony_ci	if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL)) != NULL) {
56748c2ecf20Sopenharmony_ci		phba->link_state = LPFC_CLEAR_LA;
56758c2ecf20Sopenharmony_ci		lpfc_clear_la(phba, mbox);
56768c2ecf20Sopenharmony_ci		mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
56778c2ecf20Sopenharmony_ci		mbox->vport = vport;
56788c2ecf20Sopenharmony_ci		rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
56798c2ecf20Sopenharmony_ci		if (rc == MBX_NOT_FINISHED) {
56808c2ecf20Sopenharmony_ci			mempool_free(mbox, phba->mbox_mem_pool);
56818c2ecf20Sopenharmony_ci			lpfc_disc_flush_list(vport);
56828c2ecf20Sopenharmony_ci			extra_ring->flag &= ~LPFC_STOP_IOCB_EVENT;
56838c2ecf20Sopenharmony_ci			fcp_ring->flag &= ~LPFC_STOP_IOCB_EVENT;
56848c2ecf20Sopenharmony_ci			phba->link_state = LPFC_HBA_ERROR;
56858c2ecf20Sopenharmony_ci		}
56868c2ecf20Sopenharmony_ci	}
56878c2ecf20Sopenharmony_ci}
56888c2ecf20Sopenharmony_ci
56898c2ecf20Sopenharmony_ci/* Reg_vpi to tell firmware to resume normal operations */
56908c2ecf20Sopenharmony_civoid
56918c2ecf20Sopenharmony_cilpfc_issue_reg_vpi(struct lpfc_hba *phba, struct lpfc_vport *vport)
56928c2ecf20Sopenharmony_ci{
56938c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t *regvpimbox;
56948c2ecf20Sopenharmony_ci
56958c2ecf20Sopenharmony_ci	regvpimbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
56968c2ecf20Sopenharmony_ci	if (regvpimbox) {
56978c2ecf20Sopenharmony_ci		lpfc_reg_vpi(vport, regvpimbox);
56988c2ecf20Sopenharmony_ci		regvpimbox->mbox_cmpl = lpfc_mbx_cmpl_reg_vpi;
56998c2ecf20Sopenharmony_ci		regvpimbox->vport = vport;
57008c2ecf20Sopenharmony_ci		if (lpfc_sli_issue_mbox(phba, regvpimbox, MBX_NOWAIT)
57018c2ecf20Sopenharmony_ci					== MBX_NOT_FINISHED) {
57028c2ecf20Sopenharmony_ci			mempool_free(regvpimbox, phba->mbox_mem_pool);
57038c2ecf20Sopenharmony_ci		}
57048c2ecf20Sopenharmony_ci	}
57058c2ecf20Sopenharmony_ci}
57068c2ecf20Sopenharmony_ci
57078c2ecf20Sopenharmony_ci/* Start Link up / RSCN discovery on NPR nodes */
57088c2ecf20Sopenharmony_civoid
57098c2ecf20Sopenharmony_cilpfc_disc_start(struct lpfc_vport *vport)
57108c2ecf20Sopenharmony_ci{
57118c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
57128c2ecf20Sopenharmony_ci	struct lpfc_hba  *phba = vport->phba;
57138c2ecf20Sopenharmony_ci	uint32_t num_sent;
57148c2ecf20Sopenharmony_ci	uint32_t clear_la_pending;
57158c2ecf20Sopenharmony_ci
57168c2ecf20Sopenharmony_ci	if (!lpfc_is_link_up(phba)) {
57178c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI,
57188c2ecf20Sopenharmony_ci				 "3315 Link is not up %x\n",
57198c2ecf20Sopenharmony_ci				 phba->link_state);
57208c2ecf20Sopenharmony_ci		return;
57218c2ecf20Sopenharmony_ci	}
57228c2ecf20Sopenharmony_ci
57238c2ecf20Sopenharmony_ci	if (phba->link_state == LPFC_CLEAR_LA)
57248c2ecf20Sopenharmony_ci		clear_la_pending = 1;
57258c2ecf20Sopenharmony_ci	else
57268c2ecf20Sopenharmony_ci		clear_la_pending = 0;
57278c2ecf20Sopenharmony_ci
57288c2ecf20Sopenharmony_ci	if (vport->port_state < LPFC_VPORT_READY)
57298c2ecf20Sopenharmony_ci		vport->port_state = LPFC_DISC_AUTH;
57308c2ecf20Sopenharmony_ci
57318c2ecf20Sopenharmony_ci	lpfc_set_disctmo(vport);
57328c2ecf20Sopenharmony_ci
57338c2ecf20Sopenharmony_ci	vport->fc_prevDID = vport->fc_myDID;
57348c2ecf20Sopenharmony_ci	vport->num_disc_nodes = 0;
57358c2ecf20Sopenharmony_ci
57368c2ecf20Sopenharmony_ci	/* Start Discovery state <hba_state> */
57378c2ecf20Sopenharmony_ci	lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
57388c2ecf20Sopenharmony_ci			 "0202 Start Discovery port state x%x "
57398c2ecf20Sopenharmony_ci			 "flg x%x Data: x%x x%x x%x\n",
57408c2ecf20Sopenharmony_ci			 vport->port_state, vport->fc_flag, vport->fc_plogi_cnt,
57418c2ecf20Sopenharmony_ci			 vport->fc_adisc_cnt, vport->fc_npr_cnt);
57428c2ecf20Sopenharmony_ci
57438c2ecf20Sopenharmony_ci	/* First do ADISCs - if any */
57448c2ecf20Sopenharmony_ci	num_sent = lpfc_els_disc_adisc(vport);
57458c2ecf20Sopenharmony_ci
57468c2ecf20Sopenharmony_ci	if (num_sent)
57478c2ecf20Sopenharmony_ci		return;
57488c2ecf20Sopenharmony_ci
57498c2ecf20Sopenharmony_ci	/* Register the VPI for SLI3, NPIV only. */
57508c2ecf20Sopenharmony_ci	if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
57518c2ecf20Sopenharmony_ci	    !(vport->fc_flag & FC_PT2PT) &&
57528c2ecf20Sopenharmony_ci	    !(vport->fc_flag & FC_RSCN_MODE) &&
57538c2ecf20Sopenharmony_ci	    (phba->sli_rev < LPFC_SLI_REV4)) {
57548c2ecf20Sopenharmony_ci		lpfc_issue_clear_la(phba, vport);
57558c2ecf20Sopenharmony_ci		lpfc_issue_reg_vpi(phba, vport);
57568c2ecf20Sopenharmony_ci		return;
57578c2ecf20Sopenharmony_ci	}
57588c2ecf20Sopenharmony_ci
57598c2ecf20Sopenharmony_ci	/*
57608c2ecf20Sopenharmony_ci	 * For SLI2, we need to set port_state to READY and continue
57618c2ecf20Sopenharmony_ci	 * discovery.
57628c2ecf20Sopenharmony_ci	 */
57638c2ecf20Sopenharmony_ci	if (vport->port_state < LPFC_VPORT_READY && !clear_la_pending) {
57648c2ecf20Sopenharmony_ci		/* If we get here, there is nothing to ADISC */
57658c2ecf20Sopenharmony_ci		lpfc_issue_clear_la(phba, vport);
57668c2ecf20Sopenharmony_ci
57678c2ecf20Sopenharmony_ci		if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) {
57688c2ecf20Sopenharmony_ci			vport->num_disc_nodes = 0;
57698c2ecf20Sopenharmony_ci			/* go thru NPR nodes and issue ELS PLOGIs */
57708c2ecf20Sopenharmony_ci			if (vport->fc_npr_cnt)
57718c2ecf20Sopenharmony_ci				lpfc_els_disc_plogi(vport);
57728c2ecf20Sopenharmony_ci
57738c2ecf20Sopenharmony_ci			if (!vport->num_disc_nodes) {
57748c2ecf20Sopenharmony_ci				spin_lock_irq(shost->host_lock);
57758c2ecf20Sopenharmony_ci				vport->fc_flag &= ~FC_NDISC_ACTIVE;
57768c2ecf20Sopenharmony_ci				spin_unlock_irq(shost->host_lock);
57778c2ecf20Sopenharmony_ci				lpfc_can_disctmo(vport);
57788c2ecf20Sopenharmony_ci			}
57798c2ecf20Sopenharmony_ci		}
57808c2ecf20Sopenharmony_ci		vport->port_state = LPFC_VPORT_READY;
57818c2ecf20Sopenharmony_ci	} else {
57828c2ecf20Sopenharmony_ci		/* Next do PLOGIs - if any */
57838c2ecf20Sopenharmony_ci		num_sent = lpfc_els_disc_plogi(vport);
57848c2ecf20Sopenharmony_ci
57858c2ecf20Sopenharmony_ci		if (num_sent)
57868c2ecf20Sopenharmony_ci			return;
57878c2ecf20Sopenharmony_ci
57888c2ecf20Sopenharmony_ci		if (vport->fc_flag & FC_RSCN_MODE) {
57898c2ecf20Sopenharmony_ci			/* Check to see if more RSCNs came in while we
57908c2ecf20Sopenharmony_ci			 * were processing this one.
57918c2ecf20Sopenharmony_ci			 */
57928c2ecf20Sopenharmony_ci			if ((vport->fc_rscn_id_cnt == 0) &&
57938c2ecf20Sopenharmony_ci			    (!(vport->fc_flag & FC_RSCN_DISCOVERY))) {
57948c2ecf20Sopenharmony_ci				spin_lock_irq(shost->host_lock);
57958c2ecf20Sopenharmony_ci				vport->fc_flag &= ~FC_RSCN_MODE;
57968c2ecf20Sopenharmony_ci				spin_unlock_irq(shost->host_lock);
57978c2ecf20Sopenharmony_ci				lpfc_can_disctmo(vport);
57988c2ecf20Sopenharmony_ci			} else
57998c2ecf20Sopenharmony_ci				lpfc_els_handle_rscn(vport);
58008c2ecf20Sopenharmony_ci		}
58018c2ecf20Sopenharmony_ci	}
58028c2ecf20Sopenharmony_ci	return;
58038c2ecf20Sopenharmony_ci}
58048c2ecf20Sopenharmony_ci
58058c2ecf20Sopenharmony_ci/*
58068c2ecf20Sopenharmony_ci *  Ignore completion for all IOCBs on tx and txcmpl queue for ELS
58078c2ecf20Sopenharmony_ci *  ring the match the sppecified nodelist.
58088c2ecf20Sopenharmony_ci */
58098c2ecf20Sopenharmony_cistatic void
58108c2ecf20Sopenharmony_cilpfc_free_tx(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
58118c2ecf20Sopenharmony_ci{
58128c2ecf20Sopenharmony_ci	LIST_HEAD(completions);
58138c2ecf20Sopenharmony_ci	IOCB_t     *icmd;
58148c2ecf20Sopenharmony_ci	struct lpfc_iocbq    *iocb, *next_iocb;
58158c2ecf20Sopenharmony_ci	struct lpfc_sli_ring *pring;
58168c2ecf20Sopenharmony_ci
58178c2ecf20Sopenharmony_ci	pring = lpfc_phba_elsring(phba);
58188c2ecf20Sopenharmony_ci	if (unlikely(!pring))
58198c2ecf20Sopenharmony_ci		return;
58208c2ecf20Sopenharmony_ci
58218c2ecf20Sopenharmony_ci	/* Error matching iocb on txq or txcmplq
58228c2ecf20Sopenharmony_ci	 * First check the txq.
58238c2ecf20Sopenharmony_ci	 */
58248c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
58258c2ecf20Sopenharmony_ci	list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
58268c2ecf20Sopenharmony_ci		if (iocb->context1 != ndlp) {
58278c2ecf20Sopenharmony_ci			continue;
58288c2ecf20Sopenharmony_ci		}
58298c2ecf20Sopenharmony_ci		icmd = &iocb->iocb;
58308c2ecf20Sopenharmony_ci		if ((icmd->ulpCommand == CMD_ELS_REQUEST64_CR) ||
58318c2ecf20Sopenharmony_ci		    (icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX)) {
58328c2ecf20Sopenharmony_ci
58338c2ecf20Sopenharmony_ci			list_move_tail(&iocb->list, &completions);
58348c2ecf20Sopenharmony_ci		}
58358c2ecf20Sopenharmony_ci	}
58368c2ecf20Sopenharmony_ci
58378c2ecf20Sopenharmony_ci	/* Next check the txcmplq */
58388c2ecf20Sopenharmony_ci	list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
58398c2ecf20Sopenharmony_ci		if (iocb->context1 != ndlp) {
58408c2ecf20Sopenharmony_ci			continue;
58418c2ecf20Sopenharmony_ci		}
58428c2ecf20Sopenharmony_ci		icmd = &iocb->iocb;
58438c2ecf20Sopenharmony_ci		if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR ||
58448c2ecf20Sopenharmony_ci		    icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX) {
58458c2ecf20Sopenharmony_ci			lpfc_sli_issue_abort_iotag(phba, pring, iocb);
58468c2ecf20Sopenharmony_ci		}
58478c2ecf20Sopenharmony_ci	}
58488c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
58498c2ecf20Sopenharmony_ci
58508c2ecf20Sopenharmony_ci	/* Cancel all the IOCBs from the completions list */
58518c2ecf20Sopenharmony_ci	lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
58528c2ecf20Sopenharmony_ci			      IOERR_SLI_ABORTED);
58538c2ecf20Sopenharmony_ci}
58548c2ecf20Sopenharmony_ci
58558c2ecf20Sopenharmony_cistatic void
58568c2ecf20Sopenharmony_cilpfc_disc_flush_list(struct lpfc_vport *vport)
58578c2ecf20Sopenharmony_ci{
58588c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp, *next_ndlp;
58598c2ecf20Sopenharmony_ci	struct lpfc_hba *phba = vport->phba;
58608c2ecf20Sopenharmony_ci
58618c2ecf20Sopenharmony_ci	if (vport->fc_plogi_cnt || vport->fc_adisc_cnt) {
58628c2ecf20Sopenharmony_ci		list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
58638c2ecf20Sopenharmony_ci					 nlp_listp) {
58648c2ecf20Sopenharmony_ci			if (!NLP_CHK_NODE_ACT(ndlp))
58658c2ecf20Sopenharmony_ci				continue;
58668c2ecf20Sopenharmony_ci			if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE ||
58678c2ecf20Sopenharmony_ci			    ndlp->nlp_state == NLP_STE_ADISC_ISSUE) {
58688c2ecf20Sopenharmony_ci				lpfc_free_tx(phba, ndlp);
58698c2ecf20Sopenharmony_ci			}
58708c2ecf20Sopenharmony_ci		}
58718c2ecf20Sopenharmony_ci	}
58728c2ecf20Sopenharmony_ci}
58738c2ecf20Sopenharmony_ci
58748c2ecf20Sopenharmony_civoid
58758c2ecf20Sopenharmony_cilpfc_cleanup_discovery_resources(struct lpfc_vport *vport)
58768c2ecf20Sopenharmony_ci{
58778c2ecf20Sopenharmony_ci	lpfc_els_flush_rscn(vport);
58788c2ecf20Sopenharmony_ci	lpfc_els_flush_cmd(vport);
58798c2ecf20Sopenharmony_ci	lpfc_disc_flush_list(vport);
58808c2ecf20Sopenharmony_ci}
58818c2ecf20Sopenharmony_ci
58828c2ecf20Sopenharmony_ci/*****************************************************************************/
58838c2ecf20Sopenharmony_ci/*
58848c2ecf20Sopenharmony_ci * NAME:     lpfc_disc_timeout
58858c2ecf20Sopenharmony_ci *
58868c2ecf20Sopenharmony_ci * FUNCTION: Fibre Channel driver discovery timeout routine.
58878c2ecf20Sopenharmony_ci *
58888c2ecf20Sopenharmony_ci * EXECUTION ENVIRONMENT: interrupt only
58898c2ecf20Sopenharmony_ci *
58908c2ecf20Sopenharmony_ci * CALLED FROM:
58918c2ecf20Sopenharmony_ci *      Timer function
58928c2ecf20Sopenharmony_ci *
58938c2ecf20Sopenharmony_ci * RETURNS:
58948c2ecf20Sopenharmony_ci *      none
58958c2ecf20Sopenharmony_ci */
58968c2ecf20Sopenharmony_ci/*****************************************************************************/
58978c2ecf20Sopenharmony_civoid
58988c2ecf20Sopenharmony_cilpfc_disc_timeout(struct timer_list *t)
58998c2ecf20Sopenharmony_ci{
59008c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = from_timer(vport, t, fc_disctmo);
59018c2ecf20Sopenharmony_ci	struct lpfc_hba   *phba = vport->phba;
59028c2ecf20Sopenharmony_ci	uint32_t tmo_posted;
59038c2ecf20Sopenharmony_ci	unsigned long flags = 0;
59048c2ecf20Sopenharmony_ci
59058c2ecf20Sopenharmony_ci	if (unlikely(!phba))
59068c2ecf20Sopenharmony_ci		return;
59078c2ecf20Sopenharmony_ci
59088c2ecf20Sopenharmony_ci	spin_lock_irqsave(&vport->work_port_lock, flags);
59098c2ecf20Sopenharmony_ci	tmo_posted = vport->work_port_events & WORKER_DISC_TMO;
59108c2ecf20Sopenharmony_ci	if (!tmo_posted)
59118c2ecf20Sopenharmony_ci		vport->work_port_events |= WORKER_DISC_TMO;
59128c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&vport->work_port_lock, flags);
59138c2ecf20Sopenharmony_ci
59148c2ecf20Sopenharmony_ci	if (!tmo_posted)
59158c2ecf20Sopenharmony_ci		lpfc_worker_wake_up(phba);
59168c2ecf20Sopenharmony_ci	return;
59178c2ecf20Sopenharmony_ci}
59188c2ecf20Sopenharmony_ci
59198c2ecf20Sopenharmony_cistatic void
59208c2ecf20Sopenharmony_cilpfc_disc_timeout_handler(struct lpfc_vport *vport)
59218c2ecf20Sopenharmony_ci{
59228c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
59238c2ecf20Sopenharmony_ci	struct lpfc_hba  *phba = vport->phba;
59248c2ecf20Sopenharmony_ci	struct lpfc_sli  *psli = &phba->sli;
59258c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp, *next_ndlp;
59268c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t *initlinkmbox;
59278c2ecf20Sopenharmony_ci	int rc, clrlaerr = 0;
59288c2ecf20Sopenharmony_ci
59298c2ecf20Sopenharmony_ci	if (!(vport->fc_flag & FC_DISC_TMO))
59308c2ecf20Sopenharmony_ci		return;
59318c2ecf20Sopenharmony_ci
59328c2ecf20Sopenharmony_ci	spin_lock_irq(shost->host_lock);
59338c2ecf20Sopenharmony_ci	vport->fc_flag &= ~FC_DISC_TMO;
59348c2ecf20Sopenharmony_ci	spin_unlock_irq(shost->host_lock);
59358c2ecf20Sopenharmony_ci
59368c2ecf20Sopenharmony_ci	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
59378c2ecf20Sopenharmony_ci		"disc timeout:    state:x%x rtry:x%x flg:x%x",
59388c2ecf20Sopenharmony_ci		vport->port_state, vport->fc_ns_retry, vport->fc_flag);
59398c2ecf20Sopenharmony_ci
59408c2ecf20Sopenharmony_ci	switch (vport->port_state) {
59418c2ecf20Sopenharmony_ci
59428c2ecf20Sopenharmony_ci	case LPFC_LOCAL_CFG_LINK:
59438c2ecf20Sopenharmony_ci		/*
59448c2ecf20Sopenharmony_ci		 * port_state is identically  LPFC_LOCAL_CFG_LINK while
59458c2ecf20Sopenharmony_ci		 * waiting for FAN timeout
59468c2ecf20Sopenharmony_ci		 */
59478c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_WARNING, LOG_DISCOVERY,
59488c2ecf20Sopenharmony_ci				 "0221 FAN timeout\n");
59498c2ecf20Sopenharmony_ci
59508c2ecf20Sopenharmony_ci		/* Start discovery by sending FLOGI, clean up old rpis */
59518c2ecf20Sopenharmony_ci		list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
59528c2ecf20Sopenharmony_ci					 nlp_listp) {
59538c2ecf20Sopenharmony_ci			if (!NLP_CHK_NODE_ACT(ndlp))
59548c2ecf20Sopenharmony_ci				continue;
59558c2ecf20Sopenharmony_ci			if (ndlp->nlp_state != NLP_STE_NPR_NODE)
59568c2ecf20Sopenharmony_ci				continue;
59578c2ecf20Sopenharmony_ci			if (ndlp->nlp_type & NLP_FABRIC) {
59588c2ecf20Sopenharmony_ci				/* Clean up the ndlp on Fabric connections */
59598c2ecf20Sopenharmony_ci				lpfc_drop_node(vport, ndlp);
59608c2ecf20Sopenharmony_ci
59618c2ecf20Sopenharmony_ci			} else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
59628c2ecf20Sopenharmony_ci				/* Fail outstanding IO now since device
59638c2ecf20Sopenharmony_ci				 * is marked for PLOGI.
59648c2ecf20Sopenharmony_ci				 */
59658c2ecf20Sopenharmony_ci				lpfc_unreg_rpi(vport, ndlp);
59668c2ecf20Sopenharmony_ci			}
59678c2ecf20Sopenharmony_ci		}
59688c2ecf20Sopenharmony_ci		if (vport->port_state != LPFC_FLOGI) {
59698c2ecf20Sopenharmony_ci			if (phba->sli_rev <= LPFC_SLI_REV3)
59708c2ecf20Sopenharmony_ci				lpfc_initial_flogi(vport);
59718c2ecf20Sopenharmony_ci			else
59728c2ecf20Sopenharmony_ci				lpfc_issue_init_vfi(vport);
59738c2ecf20Sopenharmony_ci			return;
59748c2ecf20Sopenharmony_ci		}
59758c2ecf20Sopenharmony_ci		break;
59768c2ecf20Sopenharmony_ci
59778c2ecf20Sopenharmony_ci	case LPFC_FDISC:
59788c2ecf20Sopenharmony_ci	case LPFC_FLOGI:
59798c2ecf20Sopenharmony_ci	/* port_state is identically LPFC_FLOGI while waiting for FLOGI cmpl */
59808c2ecf20Sopenharmony_ci		/* Initial FLOGI timeout */
59818c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR,
59828c2ecf20Sopenharmony_ci				 LOG_TRACE_EVENT,
59838c2ecf20Sopenharmony_ci				 "0222 Initial %s timeout\n",
59848c2ecf20Sopenharmony_ci				 vport->vpi ? "FDISC" : "FLOGI");
59858c2ecf20Sopenharmony_ci
59868c2ecf20Sopenharmony_ci		/* Assume no Fabric and go on with discovery.
59878c2ecf20Sopenharmony_ci		 * Check for outstanding ELS FLOGI to abort.
59888c2ecf20Sopenharmony_ci		 */
59898c2ecf20Sopenharmony_ci
59908c2ecf20Sopenharmony_ci		/* FLOGI failed, so just use loop map to make discovery list */
59918c2ecf20Sopenharmony_ci		lpfc_disc_list_loopmap(vport);
59928c2ecf20Sopenharmony_ci
59938c2ecf20Sopenharmony_ci		/* Start discovery */
59948c2ecf20Sopenharmony_ci		lpfc_disc_start(vport);
59958c2ecf20Sopenharmony_ci		break;
59968c2ecf20Sopenharmony_ci
59978c2ecf20Sopenharmony_ci	case LPFC_FABRIC_CFG_LINK:
59988c2ecf20Sopenharmony_ci	/* hba_state is identically LPFC_FABRIC_CFG_LINK while waiting for
59998c2ecf20Sopenharmony_ci	   NameServer login */
60008c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR,
60018c2ecf20Sopenharmony_ci				 LOG_TRACE_EVENT,
60028c2ecf20Sopenharmony_ci				 "0223 Timeout while waiting for "
60038c2ecf20Sopenharmony_ci				 "NameServer login\n");
60048c2ecf20Sopenharmony_ci		/* Next look for NameServer ndlp */
60058c2ecf20Sopenharmony_ci		ndlp = lpfc_findnode_did(vport, NameServer_DID);
60068c2ecf20Sopenharmony_ci		if (ndlp && NLP_CHK_NODE_ACT(ndlp))
60078c2ecf20Sopenharmony_ci			lpfc_els_abort(phba, ndlp);
60088c2ecf20Sopenharmony_ci
60098c2ecf20Sopenharmony_ci		/* ReStart discovery */
60108c2ecf20Sopenharmony_ci		goto restart_disc;
60118c2ecf20Sopenharmony_ci
60128c2ecf20Sopenharmony_ci	case LPFC_NS_QRY:
60138c2ecf20Sopenharmony_ci	/* Check for wait for NameServer Rsp timeout */
60148c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR,
60158c2ecf20Sopenharmony_ci				 LOG_TRACE_EVENT,
60168c2ecf20Sopenharmony_ci				 "0224 NameServer Query timeout "
60178c2ecf20Sopenharmony_ci				 "Data: x%x x%x\n",
60188c2ecf20Sopenharmony_ci				 vport->fc_ns_retry, LPFC_MAX_NS_RETRY);
60198c2ecf20Sopenharmony_ci
60208c2ecf20Sopenharmony_ci		if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) {
60218c2ecf20Sopenharmony_ci			/* Try it one more time */
60228c2ecf20Sopenharmony_ci			vport->fc_ns_retry++;
60238c2ecf20Sopenharmony_ci			vport->gidft_inp = 0;
60248c2ecf20Sopenharmony_ci			rc = lpfc_issue_gidft(vport);
60258c2ecf20Sopenharmony_ci			if (rc == 0)
60268c2ecf20Sopenharmony_ci				break;
60278c2ecf20Sopenharmony_ci		}
60288c2ecf20Sopenharmony_ci		vport->fc_ns_retry = 0;
60298c2ecf20Sopenharmony_ci
60308c2ecf20Sopenharmony_cirestart_disc:
60318c2ecf20Sopenharmony_ci		/*
60328c2ecf20Sopenharmony_ci		 * Discovery is over.
60338c2ecf20Sopenharmony_ci		 * set port_state to PORT_READY if SLI2.
60348c2ecf20Sopenharmony_ci		 * cmpl_reg_vpi will set port_state to READY for SLI3.
60358c2ecf20Sopenharmony_ci		 */
60368c2ecf20Sopenharmony_ci		if (phba->sli_rev < LPFC_SLI_REV4) {
60378c2ecf20Sopenharmony_ci			if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
60388c2ecf20Sopenharmony_ci				lpfc_issue_reg_vpi(phba, vport);
60398c2ecf20Sopenharmony_ci			else  {
60408c2ecf20Sopenharmony_ci				lpfc_issue_clear_la(phba, vport);
60418c2ecf20Sopenharmony_ci				vport->port_state = LPFC_VPORT_READY;
60428c2ecf20Sopenharmony_ci			}
60438c2ecf20Sopenharmony_ci		}
60448c2ecf20Sopenharmony_ci
60458c2ecf20Sopenharmony_ci		/* Setup and issue mailbox INITIALIZE LINK command */
60468c2ecf20Sopenharmony_ci		initlinkmbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
60478c2ecf20Sopenharmony_ci		if (!initlinkmbox) {
60488c2ecf20Sopenharmony_ci			lpfc_printf_vlog(vport, KERN_ERR,
60498c2ecf20Sopenharmony_ci					 LOG_TRACE_EVENT,
60508c2ecf20Sopenharmony_ci					 "0206 Device Discovery "
60518c2ecf20Sopenharmony_ci					 "completion error\n");
60528c2ecf20Sopenharmony_ci			phba->link_state = LPFC_HBA_ERROR;
60538c2ecf20Sopenharmony_ci			break;
60548c2ecf20Sopenharmony_ci		}
60558c2ecf20Sopenharmony_ci
60568c2ecf20Sopenharmony_ci		lpfc_linkdown(phba);
60578c2ecf20Sopenharmony_ci		lpfc_init_link(phba, initlinkmbox, phba->cfg_topology,
60588c2ecf20Sopenharmony_ci			       phba->cfg_link_speed);
60598c2ecf20Sopenharmony_ci		initlinkmbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0;
60608c2ecf20Sopenharmony_ci		initlinkmbox->vport = vport;
60618c2ecf20Sopenharmony_ci		initlinkmbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
60628c2ecf20Sopenharmony_ci		rc = lpfc_sli_issue_mbox(phba, initlinkmbox, MBX_NOWAIT);
60638c2ecf20Sopenharmony_ci		lpfc_set_loopback_flag(phba);
60648c2ecf20Sopenharmony_ci		if (rc == MBX_NOT_FINISHED)
60658c2ecf20Sopenharmony_ci			mempool_free(initlinkmbox, phba->mbox_mem_pool);
60668c2ecf20Sopenharmony_ci
60678c2ecf20Sopenharmony_ci		break;
60688c2ecf20Sopenharmony_ci
60698c2ecf20Sopenharmony_ci	case LPFC_DISC_AUTH:
60708c2ecf20Sopenharmony_ci	/* Node Authentication timeout */
60718c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR,
60728c2ecf20Sopenharmony_ci				 LOG_TRACE_EVENT,
60738c2ecf20Sopenharmony_ci				 "0227 Node Authentication timeout\n");
60748c2ecf20Sopenharmony_ci		lpfc_disc_flush_list(vport);
60758c2ecf20Sopenharmony_ci
60768c2ecf20Sopenharmony_ci		/*
60778c2ecf20Sopenharmony_ci		 * set port_state to PORT_READY if SLI2.
60788c2ecf20Sopenharmony_ci		 * cmpl_reg_vpi will set port_state to READY for SLI3.
60798c2ecf20Sopenharmony_ci		 */
60808c2ecf20Sopenharmony_ci		if (phba->sli_rev < LPFC_SLI_REV4) {
60818c2ecf20Sopenharmony_ci			if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
60828c2ecf20Sopenharmony_ci				lpfc_issue_reg_vpi(phba, vport);
60838c2ecf20Sopenharmony_ci			else  {	/* NPIV Not enabled */
60848c2ecf20Sopenharmony_ci				lpfc_issue_clear_la(phba, vport);
60858c2ecf20Sopenharmony_ci				vport->port_state = LPFC_VPORT_READY;
60868c2ecf20Sopenharmony_ci			}
60878c2ecf20Sopenharmony_ci		}
60888c2ecf20Sopenharmony_ci		break;
60898c2ecf20Sopenharmony_ci
60908c2ecf20Sopenharmony_ci	case LPFC_VPORT_READY:
60918c2ecf20Sopenharmony_ci		if (vport->fc_flag & FC_RSCN_MODE) {
60928c2ecf20Sopenharmony_ci			lpfc_printf_vlog(vport, KERN_ERR,
60938c2ecf20Sopenharmony_ci					 LOG_TRACE_EVENT,
60948c2ecf20Sopenharmony_ci					 "0231 RSCN timeout Data: x%x "
60958c2ecf20Sopenharmony_ci					 "x%x\n",
60968c2ecf20Sopenharmony_ci					 vport->fc_ns_retry, LPFC_MAX_NS_RETRY);
60978c2ecf20Sopenharmony_ci
60988c2ecf20Sopenharmony_ci			/* Cleanup any outstanding ELS commands */
60998c2ecf20Sopenharmony_ci			lpfc_els_flush_cmd(vport);
61008c2ecf20Sopenharmony_ci
61018c2ecf20Sopenharmony_ci			lpfc_els_flush_rscn(vport);
61028c2ecf20Sopenharmony_ci			lpfc_disc_flush_list(vport);
61038c2ecf20Sopenharmony_ci		}
61048c2ecf20Sopenharmony_ci		break;
61058c2ecf20Sopenharmony_ci
61068c2ecf20Sopenharmony_ci	default:
61078c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR,
61088c2ecf20Sopenharmony_ci				 LOG_TRACE_EVENT,
61098c2ecf20Sopenharmony_ci				 "0273 Unexpected discovery timeout, "
61108c2ecf20Sopenharmony_ci				 "vport State x%x\n", vport->port_state);
61118c2ecf20Sopenharmony_ci		break;
61128c2ecf20Sopenharmony_ci	}
61138c2ecf20Sopenharmony_ci
61148c2ecf20Sopenharmony_ci	switch (phba->link_state) {
61158c2ecf20Sopenharmony_ci	case LPFC_CLEAR_LA:
61168c2ecf20Sopenharmony_ci				/* CLEAR LA timeout */
61178c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR,
61188c2ecf20Sopenharmony_ci				 LOG_TRACE_EVENT,
61198c2ecf20Sopenharmony_ci				 "0228 CLEAR LA timeout\n");
61208c2ecf20Sopenharmony_ci		clrlaerr = 1;
61218c2ecf20Sopenharmony_ci		break;
61228c2ecf20Sopenharmony_ci
61238c2ecf20Sopenharmony_ci	case LPFC_LINK_UP:
61248c2ecf20Sopenharmony_ci		lpfc_issue_clear_la(phba, vport);
61258c2ecf20Sopenharmony_ci		fallthrough;
61268c2ecf20Sopenharmony_ci	case LPFC_LINK_UNKNOWN:
61278c2ecf20Sopenharmony_ci	case LPFC_WARM_START:
61288c2ecf20Sopenharmony_ci	case LPFC_INIT_START:
61298c2ecf20Sopenharmony_ci	case LPFC_INIT_MBX_CMDS:
61308c2ecf20Sopenharmony_ci	case LPFC_LINK_DOWN:
61318c2ecf20Sopenharmony_ci	case LPFC_HBA_ERROR:
61328c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_ERR,
61338c2ecf20Sopenharmony_ci				 LOG_TRACE_EVENT,
61348c2ecf20Sopenharmony_ci				 "0230 Unexpected timeout, hba link "
61358c2ecf20Sopenharmony_ci				 "state x%x\n", phba->link_state);
61368c2ecf20Sopenharmony_ci		clrlaerr = 1;
61378c2ecf20Sopenharmony_ci		break;
61388c2ecf20Sopenharmony_ci
61398c2ecf20Sopenharmony_ci	case LPFC_HBA_READY:
61408c2ecf20Sopenharmony_ci		break;
61418c2ecf20Sopenharmony_ci	}
61428c2ecf20Sopenharmony_ci
61438c2ecf20Sopenharmony_ci	if (clrlaerr) {
61448c2ecf20Sopenharmony_ci		lpfc_disc_flush_list(vport);
61458c2ecf20Sopenharmony_ci		if (phba->sli_rev != LPFC_SLI_REV4) {
61468c2ecf20Sopenharmony_ci			psli->sli3_ring[(LPFC_EXTRA_RING)].flag &=
61478c2ecf20Sopenharmony_ci				~LPFC_STOP_IOCB_EVENT;
61488c2ecf20Sopenharmony_ci			psli->sli3_ring[LPFC_FCP_RING].flag &=
61498c2ecf20Sopenharmony_ci				~LPFC_STOP_IOCB_EVENT;
61508c2ecf20Sopenharmony_ci		}
61518c2ecf20Sopenharmony_ci		vport->port_state = LPFC_VPORT_READY;
61528c2ecf20Sopenharmony_ci	}
61538c2ecf20Sopenharmony_ci	return;
61548c2ecf20Sopenharmony_ci}
61558c2ecf20Sopenharmony_ci
61568c2ecf20Sopenharmony_ci/*
61578c2ecf20Sopenharmony_ci * This routine handles processing a NameServer REG_LOGIN mailbox
61588c2ecf20Sopenharmony_ci * command upon completion. It is setup in the LPFC_MBOXQ
61598c2ecf20Sopenharmony_ci * as the completion routine when the command is
61608c2ecf20Sopenharmony_ci * handed off to the SLI layer.
61618c2ecf20Sopenharmony_ci */
61628c2ecf20Sopenharmony_civoid
61638c2ecf20Sopenharmony_cilpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
61648c2ecf20Sopenharmony_ci{
61658c2ecf20Sopenharmony_ci	MAILBOX_t *mb = &pmb->u.mb;
61668c2ecf20Sopenharmony_ci	struct lpfc_dmabuf   *mp = (struct lpfc_dmabuf *)(pmb->ctx_buf);
61678c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
61688c2ecf20Sopenharmony_ci	struct lpfc_vport    *vport = pmb->vport;
61698c2ecf20Sopenharmony_ci
61708c2ecf20Sopenharmony_ci	pmb->ctx_buf = NULL;
61718c2ecf20Sopenharmony_ci	pmb->ctx_ndlp = NULL;
61728c2ecf20Sopenharmony_ci
61738c2ecf20Sopenharmony_ci	if (phba->sli_rev < LPFC_SLI_REV4)
61748c2ecf20Sopenharmony_ci		ndlp->nlp_rpi = mb->un.varWords[0];
61758c2ecf20Sopenharmony_ci	ndlp->nlp_flag |= NLP_RPI_REGISTERED;
61768c2ecf20Sopenharmony_ci	ndlp->nlp_type |= NLP_FABRIC;
61778c2ecf20Sopenharmony_ci	lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
61788c2ecf20Sopenharmony_ci	lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY,
61798c2ecf20Sopenharmony_ci			 "0004 rpi:%x DID:%x flg:%x %d map:%x x%px\n",
61808c2ecf20Sopenharmony_ci			 ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag,
61818c2ecf20Sopenharmony_ci			 kref_read(&ndlp->kref),
61828c2ecf20Sopenharmony_ci			 ndlp->nlp_usg_map, ndlp);
61838c2ecf20Sopenharmony_ci	/*
61848c2ecf20Sopenharmony_ci	 * Start issuing Fabric-Device Management Interface (FDMI) command to
61858c2ecf20Sopenharmony_ci	 * 0xfffffa (FDMI well known port).
61868c2ecf20Sopenharmony_ci	 * DHBA -> DPRT -> RHBA -> RPA  (physical port)
61878c2ecf20Sopenharmony_ci	 * DPRT -> RPRT (vports)
61888c2ecf20Sopenharmony_ci	 */
61898c2ecf20Sopenharmony_ci	if (vport->port_type == LPFC_PHYSICAL_PORT)
61908c2ecf20Sopenharmony_ci		lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0);
61918c2ecf20Sopenharmony_ci	else
61928c2ecf20Sopenharmony_ci		lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT, 0);
61938c2ecf20Sopenharmony_ci
61948c2ecf20Sopenharmony_ci
61958c2ecf20Sopenharmony_ci	/* decrement the node reference count held for this callback
61968c2ecf20Sopenharmony_ci	 * function.
61978c2ecf20Sopenharmony_ci	 */
61988c2ecf20Sopenharmony_ci	lpfc_nlp_put(ndlp);
61998c2ecf20Sopenharmony_ci	lpfc_mbuf_free(phba, mp->virt, mp->phys);
62008c2ecf20Sopenharmony_ci	kfree(mp);
62018c2ecf20Sopenharmony_ci	mempool_free(pmb, phba->mbox_mem_pool);
62028c2ecf20Sopenharmony_ci
62038c2ecf20Sopenharmony_ci	return;
62048c2ecf20Sopenharmony_ci}
62058c2ecf20Sopenharmony_ci
62068c2ecf20Sopenharmony_cistatic int
62078c2ecf20Sopenharmony_cilpfc_filter_by_rpi(struct lpfc_nodelist *ndlp, void *param)
62088c2ecf20Sopenharmony_ci{
62098c2ecf20Sopenharmony_ci	uint16_t *rpi = param;
62108c2ecf20Sopenharmony_ci
62118c2ecf20Sopenharmony_ci	/* check for active node */
62128c2ecf20Sopenharmony_ci	if (!NLP_CHK_NODE_ACT(ndlp))
62138c2ecf20Sopenharmony_ci		return 0;
62148c2ecf20Sopenharmony_ci
62158c2ecf20Sopenharmony_ci	return ndlp->nlp_rpi == *rpi;
62168c2ecf20Sopenharmony_ci}
62178c2ecf20Sopenharmony_ci
62188c2ecf20Sopenharmony_cistatic int
62198c2ecf20Sopenharmony_cilpfc_filter_by_wwpn(struct lpfc_nodelist *ndlp, void *param)
62208c2ecf20Sopenharmony_ci{
62218c2ecf20Sopenharmony_ci	return memcmp(&ndlp->nlp_portname, param,
62228c2ecf20Sopenharmony_ci		      sizeof(ndlp->nlp_portname)) == 0;
62238c2ecf20Sopenharmony_ci}
62248c2ecf20Sopenharmony_ci
62258c2ecf20Sopenharmony_cistatic struct lpfc_nodelist *
62268c2ecf20Sopenharmony_ci__lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param)
62278c2ecf20Sopenharmony_ci{
62288c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp;
62298c2ecf20Sopenharmony_ci
62308c2ecf20Sopenharmony_ci	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
62318c2ecf20Sopenharmony_ci		if (filter(ndlp, param)) {
62328c2ecf20Sopenharmony_ci			lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
62338c2ecf20Sopenharmony_ci					 "3185 FIND node filter %ps DID "
62348c2ecf20Sopenharmony_ci					 "ndlp x%px did x%x flg x%x st x%x "
62358c2ecf20Sopenharmony_ci					 "xri x%x type x%x rpi x%x\n",
62368c2ecf20Sopenharmony_ci					 filter, ndlp, ndlp->nlp_DID,
62378c2ecf20Sopenharmony_ci					 ndlp->nlp_flag, ndlp->nlp_state,
62388c2ecf20Sopenharmony_ci					 ndlp->nlp_xri, ndlp->nlp_type,
62398c2ecf20Sopenharmony_ci					 ndlp->nlp_rpi);
62408c2ecf20Sopenharmony_ci			return ndlp;
62418c2ecf20Sopenharmony_ci		}
62428c2ecf20Sopenharmony_ci	}
62438c2ecf20Sopenharmony_ci	lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
62448c2ecf20Sopenharmony_ci			 "3186 FIND node filter %ps NOT FOUND.\n", filter);
62458c2ecf20Sopenharmony_ci	return NULL;
62468c2ecf20Sopenharmony_ci}
62478c2ecf20Sopenharmony_ci
62488c2ecf20Sopenharmony_ci/*
62498c2ecf20Sopenharmony_ci * This routine looks up the ndlp lists for the given RPI. If rpi found it
62508c2ecf20Sopenharmony_ci * returns the node list element pointer else return NULL.
62518c2ecf20Sopenharmony_ci */
62528c2ecf20Sopenharmony_cistruct lpfc_nodelist *
62538c2ecf20Sopenharmony_ci__lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi)
62548c2ecf20Sopenharmony_ci{
62558c2ecf20Sopenharmony_ci	return __lpfc_find_node(vport, lpfc_filter_by_rpi, &rpi);
62568c2ecf20Sopenharmony_ci}
62578c2ecf20Sopenharmony_ci
62588c2ecf20Sopenharmony_ci/*
62598c2ecf20Sopenharmony_ci * This routine looks up the ndlp lists for the given WWPN. If WWPN found it
62608c2ecf20Sopenharmony_ci * returns the node element list pointer else return NULL.
62618c2ecf20Sopenharmony_ci */
62628c2ecf20Sopenharmony_cistruct lpfc_nodelist *
62638c2ecf20Sopenharmony_cilpfc_findnode_wwpn(struct lpfc_vport *vport, struct lpfc_name *wwpn)
62648c2ecf20Sopenharmony_ci{
62658c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
62668c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp;
62678c2ecf20Sopenharmony_ci
62688c2ecf20Sopenharmony_ci	spin_lock_irq(shost->host_lock);
62698c2ecf20Sopenharmony_ci	ndlp = __lpfc_find_node(vport, lpfc_filter_by_wwpn, wwpn);
62708c2ecf20Sopenharmony_ci	spin_unlock_irq(shost->host_lock);
62718c2ecf20Sopenharmony_ci	return ndlp;
62728c2ecf20Sopenharmony_ci}
62738c2ecf20Sopenharmony_ci
62748c2ecf20Sopenharmony_ci/*
62758c2ecf20Sopenharmony_ci * This routine looks up the ndlp lists for the given RPI. If the rpi
62768c2ecf20Sopenharmony_ci * is found, the routine returns the node element list pointer else
62778c2ecf20Sopenharmony_ci * return NULL.
62788c2ecf20Sopenharmony_ci */
62798c2ecf20Sopenharmony_cistruct lpfc_nodelist *
62808c2ecf20Sopenharmony_cilpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi)
62818c2ecf20Sopenharmony_ci{
62828c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
62838c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp;
62848c2ecf20Sopenharmony_ci	unsigned long flags;
62858c2ecf20Sopenharmony_ci
62868c2ecf20Sopenharmony_ci	spin_lock_irqsave(shost->host_lock, flags);
62878c2ecf20Sopenharmony_ci	ndlp = __lpfc_findnode_rpi(vport, rpi);
62888c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(shost->host_lock, flags);
62898c2ecf20Sopenharmony_ci	return ndlp;
62908c2ecf20Sopenharmony_ci}
62918c2ecf20Sopenharmony_ci
62928c2ecf20Sopenharmony_ci/**
62938c2ecf20Sopenharmony_ci * lpfc_find_vport_by_vpid - Find a vport on a HBA through vport identifier
62948c2ecf20Sopenharmony_ci * @phba: pointer to lpfc hba data structure.
62958c2ecf20Sopenharmony_ci * @vpi: the physical host virtual N_Port identifier.
62968c2ecf20Sopenharmony_ci *
62978c2ecf20Sopenharmony_ci * This routine finds a vport on a HBA (referred by @phba) through a
62988c2ecf20Sopenharmony_ci * @vpi. The function walks the HBA's vport list and returns the address
62998c2ecf20Sopenharmony_ci * of the vport with the matching @vpi.
63008c2ecf20Sopenharmony_ci *
63018c2ecf20Sopenharmony_ci * Return code
63028c2ecf20Sopenharmony_ci *    NULL - No vport with the matching @vpi found
63038c2ecf20Sopenharmony_ci *    Otherwise - Address to the vport with the matching @vpi.
63048c2ecf20Sopenharmony_ci **/
63058c2ecf20Sopenharmony_cistruct lpfc_vport *
63068c2ecf20Sopenharmony_cilpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi)
63078c2ecf20Sopenharmony_ci{
63088c2ecf20Sopenharmony_ci	struct lpfc_vport *vport;
63098c2ecf20Sopenharmony_ci	unsigned long flags;
63108c2ecf20Sopenharmony_ci	int i = 0;
63118c2ecf20Sopenharmony_ci
63128c2ecf20Sopenharmony_ci	/* The physical ports are always vpi 0 - translate is unnecessary. */
63138c2ecf20Sopenharmony_ci	if (vpi > 0) {
63148c2ecf20Sopenharmony_ci		/*
63158c2ecf20Sopenharmony_ci		 * Translate the physical vpi to the logical vpi.  The
63168c2ecf20Sopenharmony_ci		 * vport stores the logical vpi.
63178c2ecf20Sopenharmony_ci		 */
63188c2ecf20Sopenharmony_ci		for (i = 0; i < phba->max_vpi; i++) {
63198c2ecf20Sopenharmony_ci			if (vpi == phba->vpi_ids[i])
63208c2ecf20Sopenharmony_ci				break;
63218c2ecf20Sopenharmony_ci		}
63228c2ecf20Sopenharmony_ci
63238c2ecf20Sopenharmony_ci		if (i >= phba->max_vpi) {
63248c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
63258c2ecf20Sopenharmony_ci					"2936 Could not find Vport mapped "
63268c2ecf20Sopenharmony_ci					"to vpi %d\n", vpi);
63278c2ecf20Sopenharmony_ci			return NULL;
63288c2ecf20Sopenharmony_ci		}
63298c2ecf20Sopenharmony_ci	}
63308c2ecf20Sopenharmony_ci
63318c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->port_list_lock, flags);
63328c2ecf20Sopenharmony_ci	list_for_each_entry(vport, &phba->port_list, listentry) {
63338c2ecf20Sopenharmony_ci		if (vport->vpi == i) {
63348c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&phba->port_list_lock, flags);
63358c2ecf20Sopenharmony_ci			return vport;
63368c2ecf20Sopenharmony_ci		}
63378c2ecf20Sopenharmony_ci	}
63388c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&phba->port_list_lock, flags);
63398c2ecf20Sopenharmony_ci	return NULL;
63408c2ecf20Sopenharmony_ci}
63418c2ecf20Sopenharmony_ci
63428c2ecf20Sopenharmony_cistruct lpfc_nodelist *
63438c2ecf20Sopenharmony_cilpfc_nlp_init(struct lpfc_vport *vport, uint32_t did)
63448c2ecf20Sopenharmony_ci{
63458c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp;
63468c2ecf20Sopenharmony_ci	int rpi = LPFC_RPI_ALLOC_ERROR;
63478c2ecf20Sopenharmony_ci
63488c2ecf20Sopenharmony_ci	if (vport->phba->sli_rev == LPFC_SLI_REV4) {
63498c2ecf20Sopenharmony_ci		rpi = lpfc_sli4_alloc_rpi(vport->phba);
63508c2ecf20Sopenharmony_ci		if (rpi == LPFC_RPI_ALLOC_ERROR)
63518c2ecf20Sopenharmony_ci			return NULL;
63528c2ecf20Sopenharmony_ci	}
63538c2ecf20Sopenharmony_ci
63548c2ecf20Sopenharmony_ci	ndlp = mempool_alloc(vport->phba->nlp_mem_pool, GFP_KERNEL);
63558c2ecf20Sopenharmony_ci	if (!ndlp) {
63568c2ecf20Sopenharmony_ci		if (vport->phba->sli_rev == LPFC_SLI_REV4)
63578c2ecf20Sopenharmony_ci			lpfc_sli4_free_rpi(vport->phba, rpi);
63588c2ecf20Sopenharmony_ci		return NULL;
63598c2ecf20Sopenharmony_ci	}
63608c2ecf20Sopenharmony_ci
63618c2ecf20Sopenharmony_ci	memset(ndlp, 0, sizeof (struct lpfc_nodelist));
63628c2ecf20Sopenharmony_ci
63638c2ecf20Sopenharmony_ci	lpfc_initialize_node(vport, ndlp, did);
63648c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ndlp->nlp_listp);
63658c2ecf20Sopenharmony_ci	if (vport->phba->sli_rev == LPFC_SLI_REV4) {
63668c2ecf20Sopenharmony_ci		ndlp->nlp_rpi = rpi;
63678c2ecf20Sopenharmony_ci		lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY,
63688c2ecf20Sopenharmony_ci				 "0007 Init New ndlp x%px, rpi:x%x DID:%x "
63698c2ecf20Sopenharmony_ci				 "flg:x%x refcnt:%d map:x%x\n",
63708c2ecf20Sopenharmony_ci				 ndlp, ndlp->nlp_rpi, ndlp->nlp_DID,
63718c2ecf20Sopenharmony_ci				 ndlp->nlp_flag, kref_read(&ndlp->kref),
63728c2ecf20Sopenharmony_ci				 ndlp->nlp_usg_map);
63738c2ecf20Sopenharmony_ci
63748c2ecf20Sopenharmony_ci		ndlp->active_rrqs_xri_bitmap =
63758c2ecf20Sopenharmony_ci				mempool_alloc(vport->phba->active_rrq_pool,
63768c2ecf20Sopenharmony_ci					      GFP_KERNEL);
63778c2ecf20Sopenharmony_ci		if (ndlp->active_rrqs_xri_bitmap)
63788c2ecf20Sopenharmony_ci			memset(ndlp->active_rrqs_xri_bitmap, 0,
63798c2ecf20Sopenharmony_ci			       ndlp->phba->cfg_rrq_xri_bitmap_sz);
63808c2ecf20Sopenharmony_ci	}
63818c2ecf20Sopenharmony_ci
63828c2ecf20Sopenharmony_ci
63838c2ecf20Sopenharmony_ci
63848c2ecf20Sopenharmony_ci	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE,
63858c2ecf20Sopenharmony_ci		"node init:       did:x%x",
63868c2ecf20Sopenharmony_ci		ndlp->nlp_DID, 0, 0);
63878c2ecf20Sopenharmony_ci
63888c2ecf20Sopenharmony_ci	return ndlp;
63898c2ecf20Sopenharmony_ci}
63908c2ecf20Sopenharmony_ci
63918c2ecf20Sopenharmony_ci/* This routine releases all resources associated with a specifc NPort's ndlp
63928c2ecf20Sopenharmony_ci * and mempool_free's the nodelist.
63938c2ecf20Sopenharmony_ci */
63948c2ecf20Sopenharmony_cistatic void
63958c2ecf20Sopenharmony_cilpfc_nlp_release(struct kref *kref)
63968c2ecf20Sopenharmony_ci{
63978c2ecf20Sopenharmony_ci	struct lpfc_hba *phba;
63988c2ecf20Sopenharmony_ci	unsigned long flags;
63998c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp = container_of(kref, struct lpfc_nodelist,
64008c2ecf20Sopenharmony_ci						  kref);
64018c2ecf20Sopenharmony_ci
64028c2ecf20Sopenharmony_ci	lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE,
64038c2ecf20Sopenharmony_ci		"node release:    did:x%x flg:x%x type:x%x",
64048c2ecf20Sopenharmony_ci		ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type);
64058c2ecf20Sopenharmony_ci
64068c2ecf20Sopenharmony_ci	lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE,
64078c2ecf20Sopenharmony_ci			"0279 %s: ndlp:x%px did %x "
64088c2ecf20Sopenharmony_ci			"usgmap:x%x refcnt:%d rpi:%x\n",
64098c2ecf20Sopenharmony_ci			__func__,
64108c2ecf20Sopenharmony_ci			(void *)ndlp, ndlp->nlp_DID, ndlp->nlp_usg_map,
64118c2ecf20Sopenharmony_ci			kref_read(&ndlp->kref), ndlp->nlp_rpi);
64128c2ecf20Sopenharmony_ci
64138c2ecf20Sopenharmony_ci	/* remove ndlp from action. */
64148c2ecf20Sopenharmony_ci	lpfc_nlp_remove(ndlp->vport, ndlp);
64158c2ecf20Sopenharmony_ci
64168c2ecf20Sopenharmony_ci	/* clear the ndlp active flag for all release cases */
64178c2ecf20Sopenharmony_ci	phba = ndlp->phba;
64188c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->ndlp_lock, flags);
64198c2ecf20Sopenharmony_ci	NLP_CLR_NODE_ACT(ndlp);
64208c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&phba->ndlp_lock, flags);
64218c2ecf20Sopenharmony_ci
64228c2ecf20Sopenharmony_ci	/* free ndlp memory for final ndlp release */
64238c2ecf20Sopenharmony_ci	if (NLP_CHK_FREE_REQ(ndlp)) {
64248c2ecf20Sopenharmony_ci		kfree(ndlp->lat_data);
64258c2ecf20Sopenharmony_ci		if (phba->sli_rev == LPFC_SLI_REV4)
64268c2ecf20Sopenharmony_ci			mempool_free(ndlp->active_rrqs_xri_bitmap,
64278c2ecf20Sopenharmony_ci				     ndlp->phba->active_rrq_pool);
64288c2ecf20Sopenharmony_ci		mempool_free(ndlp, ndlp->phba->nlp_mem_pool);
64298c2ecf20Sopenharmony_ci	}
64308c2ecf20Sopenharmony_ci}
64318c2ecf20Sopenharmony_ci
64328c2ecf20Sopenharmony_ci/* This routine bumps the reference count for a ndlp structure to ensure
64338c2ecf20Sopenharmony_ci * that one discovery thread won't free a ndlp while another discovery thread
64348c2ecf20Sopenharmony_ci * is using it.
64358c2ecf20Sopenharmony_ci */
64368c2ecf20Sopenharmony_cistruct lpfc_nodelist *
64378c2ecf20Sopenharmony_cilpfc_nlp_get(struct lpfc_nodelist *ndlp)
64388c2ecf20Sopenharmony_ci{
64398c2ecf20Sopenharmony_ci	struct lpfc_hba *phba;
64408c2ecf20Sopenharmony_ci	unsigned long flags;
64418c2ecf20Sopenharmony_ci
64428c2ecf20Sopenharmony_ci	if (ndlp) {
64438c2ecf20Sopenharmony_ci		lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE,
64448c2ecf20Sopenharmony_ci			"node get:        did:x%x flg:x%x refcnt:x%x",
64458c2ecf20Sopenharmony_ci			ndlp->nlp_DID, ndlp->nlp_flag,
64468c2ecf20Sopenharmony_ci			kref_read(&ndlp->kref));
64478c2ecf20Sopenharmony_ci		/* The check of ndlp usage to prevent incrementing the
64488c2ecf20Sopenharmony_ci		 * ndlp reference count that is in the process of being
64498c2ecf20Sopenharmony_ci		 * released.
64508c2ecf20Sopenharmony_ci		 */
64518c2ecf20Sopenharmony_ci		phba = ndlp->phba;
64528c2ecf20Sopenharmony_ci		spin_lock_irqsave(&phba->ndlp_lock, flags);
64538c2ecf20Sopenharmony_ci		if (!NLP_CHK_NODE_ACT(ndlp) || NLP_CHK_FREE_ACK(ndlp)) {
64548c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&phba->ndlp_lock, flags);
64558c2ecf20Sopenharmony_ci			lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE,
64568c2ecf20Sopenharmony_ci				"0276 %s: ndlp:x%px "
64578c2ecf20Sopenharmony_ci				"usgmap:x%x refcnt:%d\n",
64588c2ecf20Sopenharmony_ci				__func__, (void *)ndlp, ndlp->nlp_usg_map,
64598c2ecf20Sopenharmony_ci				kref_read(&ndlp->kref));
64608c2ecf20Sopenharmony_ci			return NULL;
64618c2ecf20Sopenharmony_ci		} else
64628c2ecf20Sopenharmony_ci			kref_get(&ndlp->kref);
64638c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&phba->ndlp_lock, flags);
64648c2ecf20Sopenharmony_ci	}
64658c2ecf20Sopenharmony_ci	return ndlp;
64668c2ecf20Sopenharmony_ci}
64678c2ecf20Sopenharmony_ci
64688c2ecf20Sopenharmony_ci/* This routine decrements the reference count for a ndlp structure. If the
64698c2ecf20Sopenharmony_ci * count goes to 0, this indicates the the associated nodelist should be
64708c2ecf20Sopenharmony_ci * freed. Returning 1 indicates the ndlp resource has been released; on the
64718c2ecf20Sopenharmony_ci * other hand, returning 0 indicates the ndlp resource has not been released
64728c2ecf20Sopenharmony_ci * yet.
64738c2ecf20Sopenharmony_ci */
64748c2ecf20Sopenharmony_ciint
64758c2ecf20Sopenharmony_cilpfc_nlp_put(struct lpfc_nodelist *ndlp)
64768c2ecf20Sopenharmony_ci{
64778c2ecf20Sopenharmony_ci	struct lpfc_hba *phba;
64788c2ecf20Sopenharmony_ci	unsigned long flags;
64798c2ecf20Sopenharmony_ci
64808c2ecf20Sopenharmony_ci	if (!ndlp)
64818c2ecf20Sopenharmony_ci		return 1;
64828c2ecf20Sopenharmony_ci
64838c2ecf20Sopenharmony_ci	lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE,
64848c2ecf20Sopenharmony_ci			"node put:        did:x%x flg:x%x refcnt:x%x",
64858c2ecf20Sopenharmony_ci			ndlp->nlp_DID, ndlp->nlp_flag,
64868c2ecf20Sopenharmony_ci			kref_read(&ndlp->kref));
64878c2ecf20Sopenharmony_ci	phba = ndlp->phba;
64888c2ecf20Sopenharmony_ci	spin_lock_irqsave(&phba->ndlp_lock, flags);
64898c2ecf20Sopenharmony_ci	/* Check the ndlp memory free acknowledge flag to avoid the
64908c2ecf20Sopenharmony_ci	 * possible race condition that kref_put got invoked again
64918c2ecf20Sopenharmony_ci	 * after previous one has done ndlp memory free.
64928c2ecf20Sopenharmony_ci	 */
64938c2ecf20Sopenharmony_ci	if (NLP_CHK_FREE_ACK(ndlp)) {
64948c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&phba->ndlp_lock, flags);
64958c2ecf20Sopenharmony_ci		lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE,
64968c2ecf20Sopenharmony_ci				"0274 %s: ndlp:x%px "
64978c2ecf20Sopenharmony_ci				"usgmap:x%x refcnt:%d\n",
64988c2ecf20Sopenharmony_ci				__func__, (void *)ndlp, ndlp->nlp_usg_map,
64998c2ecf20Sopenharmony_ci				kref_read(&ndlp->kref));
65008c2ecf20Sopenharmony_ci		return 1;
65018c2ecf20Sopenharmony_ci	}
65028c2ecf20Sopenharmony_ci	/* Check the ndlp inactivate log flag to avoid the possible
65038c2ecf20Sopenharmony_ci	 * race condition that kref_put got invoked again after ndlp
65048c2ecf20Sopenharmony_ci	 * is already in inactivating state.
65058c2ecf20Sopenharmony_ci	 */
65068c2ecf20Sopenharmony_ci	if (NLP_CHK_IACT_REQ(ndlp)) {
65078c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&phba->ndlp_lock, flags);
65088c2ecf20Sopenharmony_ci		lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE,
65098c2ecf20Sopenharmony_ci				"0275 %s: ndlp:x%px "
65108c2ecf20Sopenharmony_ci				"usgmap:x%x refcnt:%d\n",
65118c2ecf20Sopenharmony_ci				__func__, (void *)ndlp, ndlp->nlp_usg_map,
65128c2ecf20Sopenharmony_ci				kref_read(&ndlp->kref));
65138c2ecf20Sopenharmony_ci		return 1;
65148c2ecf20Sopenharmony_ci	}
65158c2ecf20Sopenharmony_ci	/* For last put, mark the ndlp usage flags to make sure no
65168c2ecf20Sopenharmony_ci	 * other kref_get and kref_put on the same ndlp shall get
65178c2ecf20Sopenharmony_ci	 * in between the process when the final kref_put has been
65188c2ecf20Sopenharmony_ci	 * invoked on this ndlp.
65198c2ecf20Sopenharmony_ci	 */
65208c2ecf20Sopenharmony_ci	if (kref_read(&ndlp->kref) == 1) {
65218c2ecf20Sopenharmony_ci		/* Indicate ndlp is put to inactive state. */
65228c2ecf20Sopenharmony_ci		NLP_SET_IACT_REQ(ndlp);
65238c2ecf20Sopenharmony_ci		/* Acknowledge ndlp memory free has been seen. */
65248c2ecf20Sopenharmony_ci		if (NLP_CHK_FREE_REQ(ndlp))
65258c2ecf20Sopenharmony_ci			NLP_SET_FREE_ACK(ndlp);
65268c2ecf20Sopenharmony_ci	}
65278c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&phba->ndlp_lock, flags);
65288c2ecf20Sopenharmony_ci	/* Note, the kref_put returns 1 when decrementing a reference
65298c2ecf20Sopenharmony_ci	 * count that was 1, it invokes the release callback function,
65308c2ecf20Sopenharmony_ci	 * but it still left the reference count as 1 (not actually
65318c2ecf20Sopenharmony_ci	 * performs the last decrementation). Otherwise, it actually
65328c2ecf20Sopenharmony_ci	 * decrements the reference count and returns 0.
65338c2ecf20Sopenharmony_ci	 */
65348c2ecf20Sopenharmony_ci	return kref_put(&ndlp->kref, lpfc_nlp_release);
65358c2ecf20Sopenharmony_ci}
65368c2ecf20Sopenharmony_ci
65378c2ecf20Sopenharmony_ci/* This routine free's the specified nodelist if it is not in use
65388c2ecf20Sopenharmony_ci * by any other discovery thread. This routine returns 1 if the
65398c2ecf20Sopenharmony_ci * ndlp has been freed. A return value of 0 indicates the ndlp is
65408c2ecf20Sopenharmony_ci * not yet been released.
65418c2ecf20Sopenharmony_ci */
65428c2ecf20Sopenharmony_ciint
65438c2ecf20Sopenharmony_cilpfc_nlp_not_used(struct lpfc_nodelist *ndlp)
65448c2ecf20Sopenharmony_ci{
65458c2ecf20Sopenharmony_ci	lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE,
65468c2ecf20Sopenharmony_ci		"node not used:   did:x%x flg:x%x refcnt:x%x",
65478c2ecf20Sopenharmony_ci		ndlp->nlp_DID, ndlp->nlp_flag,
65488c2ecf20Sopenharmony_ci		kref_read(&ndlp->kref));
65498c2ecf20Sopenharmony_ci	if (kref_read(&ndlp->kref) == 1)
65508c2ecf20Sopenharmony_ci		if (lpfc_nlp_put(ndlp))
65518c2ecf20Sopenharmony_ci			return 1;
65528c2ecf20Sopenharmony_ci	return 0;
65538c2ecf20Sopenharmony_ci}
65548c2ecf20Sopenharmony_ci
65558c2ecf20Sopenharmony_ci/**
65568c2ecf20Sopenharmony_ci * lpfc_fcf_inuse - Check if FCF can be unregistered.
65578c2ecf20Sopenharmony_ci * @phba: Pointer to hba context object.
65588c2ecf20Sopenharmony_ci *
65598c2ecf20Sopenharmony_ci * This function iterate through all FC nodes associated
65608c2ecf20Sopenharmony_ci * will all vports to check if there is any node with
65618c2ecf20Sopenharmony_ci * fc_rports associated with it. If there is an fc_rport
65628c2ecf20Sopenharmony_ci * associated with the node, then the node is either in
65638c2ecf20Sopenharmony_ci * discovered state or its devloss_timer is pending.
65648c2ecf20Sopenharmony_ci */
65658c2ecf20Sopenharmony_cistatic int
65668c2ecf20Sopenharmony_cilpfc_fcf_inuse(struct lpfc_hba *phba)
65678c2ecf20Sopenharmony_ci{
65688c2ecf20Sopenharmony_ci	struct lpfc_vport **vports;
65698c2ecf20Sopenharmony_ci	int i, ret = 0;
65708c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp;
65718c2ecf20Sopenharmony_ci	struct Scsi_Host  *shost;
65728c2ecf20Sopenharmony_ci
65738c2ecf20Sopenharmony_ci	vports = lpfc_create_vport_work_array(phba);
65748c2ecf20Sopenharmony_ci
65758c2ecf20Sopenharmony_ci	/* If driver cannot allocate memory, indicate fcf is in use */
65768c2ecf20Sopenharmony_ci	if (!vports)
65778c2ecf20Sopenharmony_ci		return 1;
65788c2ecf20Sopenharmony_ci
65798c2ecf20Sopenharmony_ci	for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
65808c2ecf20Sopenharmony_ci		shost = lpfc_shost_from_vport(vports[i]);
65818c2ecf20Sopenharmony_ci		spin_lock_irq(shost->host_lock);
65828c2ecf20Sopenharmony_ci		/*
65838c2ecf20Sopenharmony_ci		 * IF the CVL_RCVD bit is not set then we have sent the
65848c2ecf20Sopenharmony_ci		 * flogi.
65858c2ecf20Sopenharmony_ci		 * If dev_loss fires while we are waiting we do not want to
65868c2ecf20Sopenharmony_ci		 * unreg the fcf.
65878c2ecf20Sopenharmony_ci		 */
65888c2ecf20Sopenharmony_ci		if (!(vports[i]->fc_flag & FC_VPORT_CVL_RCVD)) {
65898c2ecf20Sopenharmony_ci			spin_unlock_irq(shost->host_lock);
65908c2ecf20Sopenharmony_ci			ret =  1;
65918c2ecf20Sopenharmony_ci			goto out;
65928c2ecf20Sopenharmony_ci		}
65938c2ecf20Sopenharmony_ci		list_for_each_entry(ndlp, &vports[i]->fc_nodes, nlp_listp) {
65948c2ecf20Sopenharmony_ci			if (NLP_CHK_NODE_ACT(ndlp) && ndlp->rport &&
65958c2ecf20Sopenharmony_ci			  (ndlp->rport->roles & FC_RPORT_ROLE_FCP_TARGET)) {
65968c2ecf20Sopenharmony_ci				ret = 1;
65978c2ecf20Sopenharmony_ci				spin_unlock_irq(shost->host_lock);
65988c2ecf20Sopenharmony_ci				goto out;
65998c2ecf20Sopenharmony_ci			} else if (ndlp->nlp_flag & NLP_RPI_REGISTERED) {
66008c2ecf20Sopenharmony_ci				ret = 1;
66018c2ecf20Sopenharmony_ci				lpfc_printf_log(phba, KERN_INFO,
66028c2ecf20Sopenharmony_ci						LOG_NODE | LOG_DISCOVERY,
66038c2ecf20Sopenharmony_ci						"2624 RPI %x DID %x flag %x "
66048c2ecf20Sopenharmony_ci						"still logged in\n",
66058c2ecf20Sopenharmony_ci						ndlp->nlp_rpi, ndlp->nlp_DID,
66068c2ecf20Sopenharmony_ci						ndlp->nlp_flag);
66078c2ecf20Sopenharmony_ci			}
66088c2ecf20Sopenharmony_ci		}
66098c2ecf20Sopenharmony_ci		spin_unlock_irq(shost->host_lock);
66108c2ecf20Sopenharmony_ci	}
66118c2ecf20Sopenharmony_ciout:
66128c2ecf20Sopenharmony_ci	lpfc_destroy_vport_work_array(phba, vports);
66138c2ecf20Sopenharmony_ci	return ret;
66148c2ecf20Sopenharmony_ci}
66158c2ecf20Sopenharmony_ci
66168c2ecf20Sopenharmony_ci/**
66178c2ecf20Sopenharmony_ci * lpfc_unregister_vfi_cmpl - Completion handler for unreg vfi.
66188c2ecf20Sopenharmony_ci * @phba: Pointer to hba context object.
66198c2ecf20Sopenharmony_ci * @mboxq: Pointer to mailbox object.
66208c2ecf20Sopenharmony_ci *
66218c2ecf20Sopenharmony_ci * This function frees memory associated with the mailbox command.
66228c2ecf20Sopenharmony_ci */
66238c2ecf20Sopenharmony_civoid
66248c2ecf20Sopenharmony_cilpfc_unregister_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
66258c2ecf20Sopenharmony_ci{
66268c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = mboxq->vport;
66278c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
66288c2ecf20Sopenharmony_ci
66298c2ecf20Sopenharmony_ci	if (mboxq->u.mb.mbxStatus) {
66308c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
66318c2ecf20Sopenharmony_ci				"2555 UNREG_VFI mbxStatus error x%x "
66328c2ecf20Sopenharmony_ci				"HBA state x%x\n",
66338c2ecf20Sopenharmony_ci				mboxq->u.mb.mbxStatus, vport->port_state);
66348c2ecf20Sopenharmony_ci	}
66358c2ecf20Sopenharmony_ci	spin_lock_irq(shost->host_lock);
66368c2ecf20Sopenharmony_ci	phba->pport->fc_flag &= ~FC_VFI_REGISTERED;
66378c2ecf20Sopenharmony_ci	spin_unlock_irq(shost->host_lock);
66388c2ecf20Sopenharmony_ci	mempool_free(mboxq, phba->mbox_mem_pool);
66398c2ecf20Sopenharmony_ci	return;
66408c2ecf20Sopenharmony_ci}
66418c2ecf20Sopenharmony_ci
66428c2ecf20Sopenharmony_ci/**
66438c2ecf20Sopenharmony_ci * lpfc_unregister_fcfi_cmpl - Completion handler for unreg fcfi.
66448c2ecf20Sopenharmony_ci * @phba: Pointer to hba context object.
66458c2ecf20Sopenharmony_ci * @mboxq: Pointer to mailbox object.
66468c2ecf20Sopenharmony_ci *
66478c2ecf20Sopenharmony_ci * This function frees memory associated with the mailbox command.
66488c2ecf20Sopenharmony_ci */
66498c2ecf20Sopenharmony_cistatic void
66508c2ecf20Sopenharmony_cilpfc_unregister_fcfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
66518c2ecf20Sopenharmony_ci{
66528c2ecf20Sopenharmony_ci	struct lpfc_vport *vport = mboxq->vport;
66538c2ecf20Sopenharmony_ci
66548c2ecf20Sopenharmony_ci	if (mboxq->u.mb.mbxStatus) {
66558c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
66568c2ecf20Sopenharmony_ci				"2550 UNREG_FCFI mbxStatus error x%x "
66578c2ecf20Sopenharmony_ci				"HBA state x%x\n",
66588c2ecf20Sopenharmony_ci				mboxq->u.mb.mbxStatus, vport->port_state);
66598c2ecf20Sopenharmony_ci	}
66608c2ecf20Sopenharmony_ci	mempool_free(mboxq, phba->mbox_mem_pool);
66618c2ecf20Sopenharmony_ci	return;
66628c2ecf20Sopenharmony_ci}
66638c2ecf20Sopenharmony_ci
66648c2ecf20Sopenharmony_ci/**
66658c2ecf20Sopenharmony_ci * lpfc_unregister_fcf_prep - Unregister fcf record preparation
66668c2ecf20Sopenharmony_ci * @phba: Pointer to hba context object.
66678c2ecf20Sopenharmony_ci *
66688c2ecf20Sopenharmony_ci * This function prepare the HBA for unregistering the currently registered
66698c2ecf20Sopenharmony_ci * FCF from the HBA. It performs unregistering, in order, RPIs, VPIs, and
66708c2ecf20Sopenharmony_ci * VFIs.
66718c2ecf20Sopenharmony_ci */
66728c2ecf20Sopenharmony_ciint
66738c2ecf20Sopenharmony_cilpfc_unregister_fcf_prep(struct lpfc_hba *phba)
66748c2ecf20Sopenharmony_ci{
66758c2ecf20Sopenharmony_ci	struct lpfc_vport **vports;
66768c2ecf20Sopenharmony_ci	struct lpfc_nodelist *ndlp;
66778c2ecf20Sopenharmony_ci	struct Scsi_Host *shost;
66788c2ecf20Sopenharmony_ci	int i = 0, rc;
66798c2ecf20Sopenharmony_ci
66808c2ecf20Sopenharmony_ci	/* Unregister RPIs */
66818c2ecf20Sopenharmony_ci	if (lpfc_fcf_inuse(phba))
66828c2ecf20Sopenharmony_ci		lpfc_unreg_hba_rpis(phba);
66838c2ecf20Sopenharmony_ci
66848c2ecf20Sopenharmony_ci	/* At this point, all discovery is aborted */
66858c2ecf20Sopenharmony_ci	phba->pport->port_state = LPFC_VPORT_UNKNOWN;
66868c2ecf20Sopenharmony_ci
66878c2ecf20Sopenharmony_ci	/* Unregister VPIs */
66888c2ecf20Sopenharmony_ci	vports = lpfc_create_vport_work_array(phba);
66898c2ecf20Sopenharmony_ci	if (vports && (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED))
66908c2ecf20Sopenharmony_ci		for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
66918c2ecf20Sopenharmony_ci			/* Stop FLOGI/FDISC retries */
66928c2ecf20Sopenharmony_ci			ndlp = lpfc_findnode_did(vports[i], Fabric_DID);
66938c2ecf20Sopenharmony_ci			if (ndlp)
66948c2ecf20Sopenharmony_ci				lpfc_cancel_retry_delay_tmo(vports[i], ndlp);
66958c2ecf20Sopenharmony_ci			lpfc_cleanup_pending_mbox(vports[i]);
66968c2ecf20Sopenharmony_ci			if (phba->sli_rev == LPFC_SLI_REV4)
66978c2ecf20Sopenharmony_ci				lpfc_sli4_unreg_all_rpis(vports[i]);
66988c2ecf20Sopenharmony_ci			lpfc_mbx_unreg_vpi(vports[i]);
66998c2ecf20Sopenharmony_ci			shost = lpfc_shost_from_vport(vports[i]);
67008c2ecf20Sopenharmony_ci			spin_lock_irq(shost->host_lock);
67018c2ecf20Sopenharmony_ci			vports[i]->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
67028c2ecf20Sopenharmony_ci			vports[i]->vpi_state &= ~LPFC_VPI_REGISTERED;
67038c2ecf20Sopenharmony_ci			spin_unlock_irq(shost->host_lock);
67048c2ecf20Sopenharmony_ci		}
67058c2ecf20Sopenharmony_ci	lpfc_destroy_vport_work_array(phba, vports);
67068c2ecf20Sopenharmony_ci	if (i == 0 && (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED))) {
67078c2ecf20Sopenharmony_ci		ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
67088c2ecf20Sopenharmony_ci		if (ndlp)
67098c2ecf20Sopenharmony_ci			lpfc_cancel_retry_delay_tmo(phba->pport, ndlp);
67108c2ecf20Sopenharmony_ci		lpfc_cleanup_pending_mbox(phba->pport);
67118c2ecf20Sopenharmony_ci		if (phba->sli_rev == LPFC_SLI_REV4)
67128c2ecf20Sopenharmony_ci			lpfc_sli4_unreg_all_rpis(phba->pport);
67138c2ecf20Sopenharmony_ci		lpfc_mbx_unreg_vpi(phba->pport);
67148c2ecf20Sopenharmony_ci		shost = lpfc_shost_from_vport(phba->pport);
67158c2ecf20Sopenharmony_ci		spin_lock_irq(shost->host_lock);
67168c2ecf20Sopenharmony_ci		phba->pport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
67178c2ecf20Sopenharmony_ci		phba->pport->vpi_state &= ~LPFC_VPI_REGISTERED;
67188c2ecf20Sopenharmony_ci		spin_unlock_irq(shost->host_lock);
67198c2ecf20Sopenharmony_ci	}
67208c2ecf20Sopenharmony_ci
67218c2ecf20Sopenharmony_ci	/* Cleanup any outstanding ELS commands */
67228c2ecf20Sopenharmony_ci	lpfc_els_flush_all_cmd(phba);
67238c2ecf20Sopenharmony_ci
67248c2ecf20Sopenharmony_ci	/* Unregister the physical port VFI */
67258c2ecf20Sopenharmony_ci	rc = lpfc_issue_unreg_vfi(phba->pport);
67268c2ecf20Sopenharmony_ci	return rc;
67278c2ecf20Sopenharmony_ci}
67288c2ecf20Sopenharmony_ci
67298c2ecf20Sopenharmony_ci/**
67308c2ecf20Sopenharmony_ci * lpfc_sli4_unregister_fcf - Unregister currently registered FCF record
67318c2ecf20Sopenharmony_ci * @phba: Pointer to hba context object.
67328c2ecf20Sopenharmony_ci *
67338c2ecf20Sopenharmony_ci * This function issues synchronous unregister FCF mailbox command to HBA to
67348c2ecf20Sopenharmony_ci * unregister the currently registered FCF record. The driver does not reset
67358c2ecf20Sopenharmony_ci * the driver FCF usage state flags.
67368c2ecf20Sopenharmony_ci *
67378c2ecf20Sopenharmony_ci * Return 0 if successfully issued, none-zero otherwise.
67388c2ecf20Sopenharmony_ci */
67398c2ecf20Sopenharmony_ciint
67408c2ecf20Sopenharmony_cilpfc_sli4_unregister_fcf(struct lpfc_hba *phba)
67418c2ecf20Sopenharmony_ci{
67428c2ecf20Sopenharmony_ci	LPFC_MBOXQ_t *mbox;
67438c2ecf20Sopenharmony_ci	int rc;
67448c2ecf20Sopenharmony_ci
67458c2ecf20Sopenharmony_ci	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
67468c2ecf20Sopenharmony_ci	if (!mbox) {
67478c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
67488c2ecf20Sopenharmony_ci				"2551 UNREG_FCFI mbox allocation failed"
67498c2ecf20Sopenharmony_ci				"HBA state x%x\n", phba->pport->port_state);
67508c2ecf20Sopenharmony_ci		return -ENOMEM;
67518c2ecf20Sopenharmony_ci	}
67528c2ecf20Sopenharmony_ci	lpfc_unreg_fcfi(mbox, phba->fcf.fcfi);
67538c2ecf20Sopenharmony_ci	mbox->vport = phba->pport;
67548c2ecf20Sopenharmony_ci	mbox->mbox_cmpl = lpfc_unregister_fcfi_cmpl;
67558c2ecf20Sopenharmony_ci	rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
67568c2ecf20Sopenharmony_ci
67578c2ecf20Sopenharmony_ci	if (rc == MBX_NOT_FINISHED) {
67588c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
67598c2ecf20Sopenharmony_ci				"2552 Unregister FCFI command failed rc x%x "
67608c2ecf20Sopenharmony_ci				"HBA state x%x\n",
67618c2ecf20Sopenharmony_ci				rc, phba->pport->port_state);
67628c2ecf20Sopenharmony_ci		return -EINVAL;
67638c2ecf20Sopenharmony_ci	}
67648c2ecf20Sopenharmony_ci	return 0;
67658c2ecf20Sopenharmony_ci}
67668c2ecf20Sopenharmony_ci
67678c2ecf20Sopenharmony_ci/**
67688c2ecf20Sopenharmony_ci * lpfc_unregister_fcf_rescan - Unregister currently registered fcf and rescan
67698c2ecf20Sopenharmony_ci * @phba: Pointer to hba context object.
67708c2ecf20Sopenharmony_ci *
67718c2ecf20Sopenharmony_ci * This function unregisters the currently reigstered FCF. This function
67728c2ecf20Sopenharmony_ci * also tries to find another FCF for discovery by rescan the HBA FCF table.
67738c2ecf20Sopenharmony_ci */
67748c2ecf20Sopenharmony_civoid
67758c2ecf20Sopenharmony_cilpfc_unregister_fcf_rescan(struct lpfc_hba *phba)
67768c2ecf20Sopenharmony_ci{
67778c2ecf20Sopenharmony_ci	int rc;
67788c2ecf20Sopenharmony_ci
67798c2ecf20Sopenharmony_ci	/* Preparation for unregistering fcf */
67808c2ecf20Sopenharmony_ci	rc = lpfc_unregister_fcf_prep(phba);
67818c2ecf20Sopenharmony_ci	if (rc) {
67828c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
67838c2ecf20Sopenharmony_ci				"2748 Failed to prepare for unregistering "
67848c2ecf20Sopenharmony_ci				"HBA's FCF record: rc=%d\n", rc);
67858c2ecf20Sopenharmony_ci		return;
67868c2ecf20Sopenharmony_ci	}
67878c2ecf20Sopenharmony_ci
67888c2ecf20Sopenharmony_ci	/* Now, unregister FCF record and reset HBA FCF state */
67898c2ecf20Sopenharmony_ci	rc = lpfc_sli4_unregister_fcf(phba);
67908c2ecf20Sopenharmony_ci	if (rc)
67918c2ecf20Sopenharmony_ci		return;
67928c2ecf20Sopenharmony_ci	/* Reset HBA FCF states after successful unregister FCF */
67938c2ecf20Sopenharmony_ci	phba->fcf.fcf_flag = 0;
67948c2ecf20Sopenharmony_ci	phba->fcf.current_rec.flag = 0;
67958c2ecf20Sopenharmony_ci
67968c2ecf20Sopenharmony_ci	/*
67978c2ecf20Sopenharmony_ci	 * If driver is not unloading, check if there is any other
67988c2ecf20Sopenharmony_ci	 * FCF record that can be used for discovery.
67998c2ecf20Sopenharmony_ci	 */
68008c2ecf20Sopenharmony_ci	if ((phba->pport->load_flag & FC_UNLOADING) ||
68018c2ecf20Sopenharmony_ci	    (phba->link_state < LPFC_LINK_UP))
68028c2ecf20Sopenharmony_ci		return;
68038c2ecf20Sopenharmony_ci
68048c2ecf20Sopenharmony_ci	/* This is considered as the initial FCF discovery scan */
68058c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
68068c2ecf20Sopenharmony_ci	phba->fcf.fcf_flag |= FCF_INIT_DISC;
68078c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
68088c2ecf20Sopenharmony_ci
68098c2ecf20Sopenharmony_ci	/* Reset FCF roundrobin bmask for new discovery */
68108c2ecf20Sopenharmony_ci	lpfc_sli4_clear_fcf_rr_bmask(phba);
68118c2ecf20Sopenharmony_ci
68128c2ecf20Sopenharmony_ci	rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST);
68138c2ecf20Sopenharmony_ci
68148c2ecf20Sopenharmony_ci	if (rc) {
68158c2ecf20Sopenharmony_ci		spin_lock_irq(&phba->hbalock);
68168c2ecf20Sopenharmony_ci		phba->fcf.fcf_flag &= ~FCF_INIT_DISC;
68178c2ecf20Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
68188c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
68198c2ecf20Sopenharmony_ci				"2553 lpfc_unregister_unused_fcf failed "
68208c2ecf20Sopenharmony_ci				"to read FCF record HBA state x%x\n",
68218c2ecf20Sopenharmony_ci				phba->pport->port_state);
68228c2ecf20Sopenharmony_ci	}
68238c2ecf20Sopenharmony_ci}
68248c2ecf20Sopenharmony_ci
68258c2ecf20Sopenharmony_ci/**
68268c2ecf20Sopenharmony_ci * lpfc_unregister_fcf - Unregister the currently registered fcf record
68278c2ecf20Sopenharmony_ci * @phba: Pointer to hba context object.
68288c2ecf20Sopenharmony_ci *
68298c2ecf20Sopenharmony_ci * This function just unregisters the currently reigstered FCF. It does not
68308c2ecf20Sopenharmony_ci * try to find another FCF for discovery.
68318c2ecf20Sopenharmony_ci */
68328c2ecf20Sopenharmony_civoid
68338c2ecf20Sopenharmony_cilpfc_unregister_fcf(struct lpfc_hba *phba)
68348c2ecf20Sopenharmony_ci{
68358c2ecf20Sopenharmony_ci	int rc;
68368c2ecf20Sopenharmony_ci
68378c2ecf20Sopenharmony_ci	/* Preparation for unregistering fcf */
68388c2ecf20Sopenharmony_ci	rc = lpfc_unregister_fcf_prep(phba);
68398c2ecf20Sopenharmony_ci	if (rc) {
68408c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
68418c2ecf20Sopenharmony_ci				"2749 Failed to prepare for unregistering "
68428c2ecf20Sopenharmony_ci				"HBA's FCF record: rc=%d\n", rc);
68438c2ecf20Sopenharmony_ci		return;
68448c2ecf20Sopenharmony_ci	}
68458c2ecf20Sopenharmony_ci
68468c2ecf20Sopenharmony_ci	/* Now, unregister FCF record and reset HBA FCF state */
68478c2ecf20Sopenharmony_ci	rc = lpfc_sli4_unregister_fcf(phba);
68488c2ecf20Sopenharmony_ci	if (rc)
68498c2ecf20Sopenharmony_ci		return;
68508c2ecf20Sopenharmony_ci	/* Set proper HBA FCF states after successful unregister FCF */
68518c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
68528c2ecf20Sopenharmony_ci	phba->fcf.fcf_flag &= ~FCF_REGISTERED;
68538c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
68548c2ecf20Sopenharmony_ci}
68558c2ecf20Sopenharmony_ci
68568c2ecf20Sopenharmony_ci/**
68578c2ecf20Sopenharmony_ci * lpfc_unregister_unused_fcf - Unregister FCF if all devices are disconnected.
68588c2ecf20Sopenharmony_ci * @phba: Pointer to hba context object.
68598c2ecf20Sopenharmony_ci *
68608c2ecf20Sopenharmony_ci * This function check if there are any connected remote port for the FCF and
68618c2ecf20Sopenharmony_ci * if all the devices are disconnected, this function unregister FCFI.
68628c2ecf20Sopenharmony_ci * This function also tries to use another FCF for discovery.
68638c2ecf20Sopenharmony_ci */
68648c2ecf20Sopenharmony_civoid
68658c2ecf20Sopenharmony_cilpfc_unregister_unused_fcf(struct lpfc_hba *phba)
68668c2ecf20Sopenharmony_ci{
68678c2ecf20Sopenharmony_ci	/*
68688c2ecf20Sopenharmony_ci	 * If HBA is not running in FIP mode, if HBA does not support
68698c2ecf20Sopenharmony_ci	 * FCoE, if FCF discovery is ongoing, or if FCF has not been
68708c2ecf20Sopenharmony_ci	 * registered, do nothing.
68718c2ecf20Sopenharmony_ci	 */
68728c2ecf20Sopenharmony_ci	spin_lock_irq(&phba->hbalock);
68738c2ecf20Sopenharmony_ci	if (!(phba->hba_flag & HBA_FCOE_MODE) ||
68748c2ecf20Sopenharmony_ci	    !(phba->fcf.fcf_flag & FCF_REGISTERED) ||
68758c2ecf20Sopenharmony_ci	    !(phba->hba_flag & HBA_FIP_SUPPORT) ||
68768c2ecf20Sopenharmony_ci	    (phba->fcf.fcf_flag & FCF_DISCOVERY) ||
68778c2ecf20Sopenharmony_ci	    (phba->pport->port_state == LPFC_FLOGI)) {
68788c2ecf20Sopenharmony_ci		spin_unlock_irq(&phba->hbalock);
68798c2ecf20Sopenharmony_ci		return;
68808c2ecf20Sopenharmony_ci	}
68818c2ecf20Sopenharmony_ci	spin_unlock_irq(&phba->hbalock);
68828c2ecf20Sopenharmony_ci
68838c2ecf20Sopenharmony_ci	if (lpfc_fcf_inuse(phba))
68848c2ecf20Sopenharmony_ci		return;
68858c2ecf20Sopenharmony_ci
68868c2ecf20Sopenharmony_ci	lpfc_unregister_fcf_rescan(phba);
68878c2ecf20Sopenharmony_ci}
68888c2ecf20Sopenharmony_ci
68898c2ecf20Sopenharmony_ci/**
68908c2ecf20Sopenharmony_ci * lpfc_read_fcf_conn_tbl - Create driver FCF connection table.
68918c2ecf20Sopenharmony_ci * @phba: Pointer to hba context object.
68928c2ecf20Sopenharmony_ci * @buff: Buffer containing the FCF connection table as in the config
68938c2ecf20Sopenharmony_ci *         region.
68948c2ecf20Sopenharmony_ci * This function create driver data structure for the FCF connection
68958c2ecf20Sopenharmony_ci * record table read from config region 23.
68968c2ecf20Sopenharmony_ci */
68978c2ecf20Sopenharmony_cistatic void
68988c2ecf20Sopenharmony_cilpfc_read_fcf_conn_tbl(struct lpfc_hba *phba,
68998c2ecf20Sopenharmony_ci	uint8_t *buff)
69008c2ecf20Sopenharmony_ci{
69018c2ecf20Sopenharmony_ci	struct lpfc_fcf_conn_entry *conn_entry, *next_conn_entry;
69028c2ecf20Sopenharmony_ci	struct lpfc_fcf_conn_hdr *conn_hdr;
69038c2ecf20Sopenharmony_ci	struct lpfc_fcf_conn_rec *conn_rec;
69048c2ecf20Sopenharmony_ci	uint32_t record_count;
69058c2ecf20Sopenharmony_ci	int i;
69068c2ecf20Sopenharmony_ci
69078c2ecf20Sopenharmony_ci	/* Free the current connect table */
69088c2ecf20Sopenharmony_ci	list_for_each_entry_safe(conn_entry, next_conn_entry,
69098c2ecf20Sopenharmony_ci		&phba->fcf_conn_rec_list, list) {
69108c2ecf20Sopenharmony_ci		list_del_init(&conn_entry->list);
69118c2ecf20Sopenharmony_ci		kfree(conn_entry);
69128c2ecf20Sopenharmony_ci	}
69138c2ecf20Sopenharmony_ci
69148c2ecf20Sopenharmony_ci	conn_hdr = (struct lpfc_fcf_conn_hdr *) buff;
69158c2ecf20Sopenharmony_ci	record_count = conn_hdr->length * sizeof(uint32_t)/
69168c2ecf20Sopenharmony_ci		sizeof(struct lpfc_fcf_conn_rec);
69178c2ecf20Sopenharmony_ci
69188c2ecf20Sopenharmony_ci	conn_rec = (struct lpfc_fcf_conn_rec *)
69198c2ecf20Sopenharmony_ci		(buff + sizeof(struct lpfc_fcf_conn_hdr));
69208c2ecf20Sopenharmony_ci
69218c2ecf20Sopenharmony_ci	for (i = 0; i < record_count; i++) {
69228c2ecf20Sopenharmony_ci		if (!(conn_rec[i].flags & FCFCNCT_VALID))
69238c2ecf20Sopenharmony_ci			continue;
69248c2ecf20Sopenharmony_ci		conn_entry = kzalloc(sizeof(struct lpfc_fcf_conn_entry),
69258c2ecf20Sopenharmony_ci			GFP_KERNEL);
69268c2ecf20Sopenharmony_ci		if (!conn_entry) {
69278c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
69288c2ecf20Sopenharmony_ci					"2566 Failed to allocate connection"
69298c2ecf20Sopenharmony_ci					" table entry\n");
69308c2ecf20Sopenharmony_ci			return;
69318c2ecf20Sopenharmony_ci		}
69328c2ecf20Sopenharmony_ci
69338c2ecf20Sopenharmony_ci		memcpy(&conn_entry->conn_rec, &conn_rec[i],
69348c2ecf20Sopenharmony_ci			sizeof(struct lpfc_fcf_conn_rec));
69358c2ecf20Sopenharmony_ci		list_add_tail(&conn_entry->list,
69368c2ecf20Sopenharmony_ci			&phba->fcf_conn_rec_list);
69378c2ecf20Sopenharmony_ci	}
69388c2ecf20Sopenharmony_ci
69398c2ecf20Sopenharmony_ci	if (!list_empty(&phba->fcf_conn_rec_list)) {
69408c2ecf20Sopenharmony_ci		i = 0;
69418c2ecf20Sopenharmony_ci		list_for_each_entry(conn_entry, &phba->fcf_conn_rec_list,
69428c2ecf20Sopenharmony_ci				    list) {
69438c2ecf20Sopenharmony_ci			conn_rec = &conn_entry->conn_rec;
69448c2ecf20Sopenharmony_ci			lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
69458c2ecf20Sopenharmony_ci					"3345 FCF connection list rec[%02d]: "
69468c2ecf20Sopenharmony_ci					"flags:x%04x, vtag:x%04x, "
69478c2ecf20Sopenharmony_ci					"fabric_name:x%02x:%02x:%02x:%02x:"
69488c2ecf20Sopenharmony_ci					"%02x:%02x:%02x:%02x, "
69498c2ecf20Sopenharmony_ci					"switch_name:x%02x:%02x:%02x:%02x:"
69508c2ecf20Sopenharmony_ci					"%02x:%02x:%02x:%02x\n", i++,
69518c2ecf20Sopenharmony_ci					conn_rec->flags, conn_rec->vlan_tag,
69528c2ecf20Sopenharmony_ci					conn_rec->fabric_name[0],
69538c2ecf20Sopenharmony_ci					conn_rec->fabric_name[1],
69548c2ecf20Sopenharmony_ci					conn_rec->fabric_name[2],
69558c2ecf20Sopenharmony_ci					conn_rec->fabric_name[3],
69568c2ecf20Sopenharmony_ci					conn_rec->fabric_name[4],
69578c2ecf20Sopenharmony_ci					conn_rec->fabric_name[5],
69588c2ecf20Sopenharmony_ci					conn_rec->fabric_name[6],
69598c2ecf20Sopenharmony_ci					conn_rec->fabric_name[7],
69608c2ecf20Sopenharmony_ci					conn_rec->switch_name[0],
69618c2ecf20Sopenharmony_ci					conn_rec->switch_name[1],
69628c2ecf20Sopenharmony_ci					conn_rec->switch_name[2],
69638c2ecf20Sopenharmony_ci					conn_rec->switch_name[3],
69648c2ecf20Sopenharmony_ci					conn_rec->switch_name[4],
69658c2ecf20Sopenharmony_ci					conn_rec->switch_name[5],
69668c2ecf20Sopenharmony_ci					conn_rec->switch_name[6],
69678c2ecf20Sopenharmony_ci					conn_rec->switch_name[7]);
69688c2ecf20Sopenharmony_ci		}
69698c2ecf20Sopenharmony_ci	}
69708c2ecf20Sopenharmony_ci}
69718c2ecf20Sopenharmony_ci
69728c2ecf20Sopenharmony_ci/**
69738c2ecf20Sopenharmony_ci * lpfc_read_fcoe_param - Read FCoe parameters from conf region..
69748c2ecf20Sopenharmony_ci * @phba: Pointer to hba context object.
69758c2ecf20Sopenharmony_ci * @buff: Buffer containing the FCoE parameter data structure.
69768c2ecf20Sopenharmony_ci *
69778c2ecf20Sopenharmony_ci *  This function update driver data structure with config
69788c2ecf20Sopenharmony_ci *  parameters read from config region 23.
69798c2ecf20Sopenharmony_ci */
69808c2ecf20Sopenharmony_cistatic void
69818c2ecf20Sopenharmony_cilpfc_read_fcoe_param(struct lpfc_hba *phba,
69828c2ecf20Sopenharmony_ci			uint8_t *buff)
69838c2ecf20Sopenharmony_ci{
69848c2ecf20Sopenharmony_ci	struct lpfc_fip_param_hdr *fcoe_param_hdr;
69858c2ecf20Sopenharmony_ci	struct lpfc_fcoe_params *fcoe_param;
69868c2ecf20Sopenharmony_ci
69878c2ecf20Sopenharmony_ci	fcoe_param_hdr = (struct lpfc_fip_param_hdr *)
69888c2ecf20Sopenharmony_ci		buff;
69898c2ecf20Sopenharmony_ci	fcoe_param = (struct lpfc_fcoe_params *)
69908c2ecf20Sopenharmony_ci		(buff + sizeof(struct lpfc_fip_param_hdr));
69918c2ecf20Sopenharmony_ci
69928c2ecf20Sopenharmony_ci	if ((fcoe_param_hdr->parm_version != FIPP_VERSION) ||
69938c2ecf20Sopenharmony_ci		(fcoe_param_hdr->length != FCOE_PARAM_LENGTH))
69948c2ecf20Sopenharmony_ci		return;
69958c2ecf20Sopenharmony_ci
69968c2ecf20Sopenharmony_ci	if (fcoe_param_hdr->parm_flags & FIPP_VLAN_VALID) {
69978c2ecf20Sopenharmony_ci		phba->valid_vlan = 1;
69988c2ecf20Sopenharmony_ci		phba->vlan_id = le16_to_cpu(fcoe_param->vlan_tag) &
69998c2ecf20Sopenharmony_ci			0xFFF;
70008c2ecf20Sopenharmony_ci	}
70018c2ecf20Sopenharmony_ci
70028c2ecf20Sopenharmony_ci	phba->fc_map[0] = fcoe_param->fc_map[0];
70038c2ecf20Sopenharmony_ci	phba->fc_map[1] = fcoe_param->fc_map[1];
70048c2ecf20Sopenharmony_ci	phba->fc_map[2] = fcoe_param->fc_map[2];
70058c2ecf20Sopenharmony_ci	return;
70068c2ecf20Sopenharmony_ci}
70078c2ecf20Sopenharmony_ci
70088c2ecf20Sopenharmony_ci/**
70098c2ecf20Sopenharmony_ci * lpfc_get_rec_conf23 - Get a record type in config region data.
70108c2ecf20Sopenharmony_ci * @buff: Buffer containing config region 23 data.
70118c2ecf20Sopenharmony_ci * @size: Size of the data buffer.
70128c2ecf20Sopenharmony_ci * @rec_type: Record type to be searched.
70138c2ecf20Sopenharmony_ci *
70148c2ecf20Sopenharmony_ci * This function searches config region data to find the beginning
70158c2ecf20Sopenharmony_ci * of the record specified by record_type. If record found, this
70168c2ecf20Sopenharmony_ci * function return pointer to the record else return NULL.
70178c2ecf20Sopenharmony_ci */
70188c2ecf20Sopenharmony_cistatic uint8_t *
70198c2ecf20Sopenharmony_cilpfc_get_rec_conf23(uint8_t *buff, uint32_t size, uint8_t rec_type)
70208c2ecf20Sopenharmony_ci{
70218c2ecf20Sopenharmony_ci	uint32_t offset = 0, rec_length;
70228c2ecf20Sopenharmony_ci
70238c2ecf20Sopenharmony_ci	if ((buff[0] == LPFC_REGION23_LAST_REC) ||
70248c2ecf20Sopenharmony_ci		(size < sizeof(uint32_t)))
70258c2ecf20Sopenharmony_ci		return NULL;
70268c2ecf20Sopenharmony_ci
70278c2ecf20Sopenharmony_ci	rec_length = buff[offset + 1];
70288c2ecf20Sopenharmony_ci
70298c2ecf20Sopenharmony_ci	/*
70308c2ecf20Sopenharmony_ci	 * One TLV record has one word header and number of data words
70318c2ecf20Sopenharmony_ci	 * specified in the rec_length field of the record header.
70328c2ecf20Sopenharmony_ci	 */
70338c2ecf20Sopenharmony_ci	while ((offset + rec_length * sizeof(uint32_t) + sizeof(uint32_t))
70348c2ecf20Sopenharmony_ci		<= size) {
70358c2ecf20Sopenharmony_ci		if (buff[offset] == rec_type)
70368c2ecf20Sopenharmony_ci			return &buff[offset];
70378c2ecf20Sopenharmony_ci
70388c2ecf20Sopenharmony_ci		if (buff[offset] == LPFC_REGION23_LAST_REC)
70398c2ecf20Sopenharmony_ci			return NULL;
70408c2ecf20Sopenharmony_ci
70418c2ecf20Sopenharmony_ci		offset += rec_length * sizeof(uint32_t) + sizeof(uint32_t);
70428c2ecf20Sopenharmony_ci		rec_length = buff[offset + 1];
70438c2ecf20Sopenharmony_ci	}
70448c2ecf20Sopenharmony_ci	return NULL;
70458c2ecf20Sopenharmony_ci}
70468c2ecf20Sopenharmony_ci
70478c2ecf20Sopenharmony_ci/**
70488c2ecf20Sopenharmony_ci * lpfc_parse_fcoe_conf - Parse FCoE config data read from config region 23.
70498c2ecf20Sopenharmony_ci * @phba: Pointer to lpfc_hba data structure.
70508c2ecf20Sopenharmony_ci * @buff: Buffer containing config region 23 data.
70518c2ecf20Sopenharmony_ci * @size: Size of the data buffer.
70528c2ecf20Sopenharmony_ci *
70538c2ecf20Sopenharmony_ci * This function parses the FCoE config parameters in config region 23 and
70548c2ecf20Sopenharmony_ci * populate driver data structure with the parameters.
70558c2ecf20Sopenharmony_ci */
70568c2ecf20Sopenharmony_civoid
70578c2ecf20Sopenharmony_cilpfc_parse_fcoe_conf(struct lpfc_hba *phba,
70588c2ecf20Sopenharmony_ci		uint8_t *buff,
70598c2ecf20Sopenharmony_ci		uint32_t size)
70608c2ecf20Sopenharmony_ci{
70618c2ecf20Sopenharmony_ci	uint32_t offset = 0;
70628c2ecf20Sopenharmony_ci	uint8_t *rec_ptr;
70638c2ecf20Sopenharmony_ci
70648c2ecf20Sopenharmony_ci	/*
70658c2ecf20Sopenharmony_ci	 * If data size is less than 2 words signature and version cannot be
70668c2ecf20Sopenharmony_ci	 * verified.
70678c2ecf20Sopenharmony_ci	 */
70688c2ecf20Sopenharmony_ci	if (size < 2*sizeof(uint32_t))
70698c2ecf20Sopenharmony_ci		return;
70708c2ecf20Sopenharmony_ci
70718c2ecf20Sopenharmony_ci	/* Check the region signature first */
70728c2ecf20Sopenharmony_ci	if (memcmp(buff, LPFC_REGION23_SIGNATURE, 4)) {
70738c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
70748c2ecf20Sopenharmony_ci			"2567 Config region 23 has bad signature\n");
70758c2ecf20Sopenharmony_ci		return;
70768c2ecf20Sopenharmony_ci	}
70778c2ecf20Sopenharmony_ci
70788c2ecf20Sopenharmony_ci	offset += 4;
70798c2ecf20Sopenharmony_ci
70808c2ecf20Sopenharmony_ci	/* Check the data structure version */
70818c2ecf20Sopenharmony_ci	if (buff[offset] != LPFC_REGION23_VERSION) {
70828c2ecf20Sopenharmony_ci		lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
70838c2ecf20Sopenharmony_ci				"2568 Config region 23 has bad version\n");
70848c2ecf20Sopenharmony_ci		return;
70858c2ecf20Sopenharmony_ci	}
70868c2ecf20Sopenharmony_ci	offset += 4;
70878c2ecf20Sopenharmony_ci
70888c2ecf20Sopenharmony_ci	/* Read FCoE param record */
70898c2ecf20Sopenharmony_ci	rec_ptr = lpfc_get_rec_conf23(&buff[offset],
70908c2ecf20Sopenharmony_ci			size - offset, FCOE_PARAM_TYPE);
70918c2ecf20Sopenharmony_ci	if (rec_ptr)
70928c2ecf20Sopenharmony_ci		lpfc_read_fcoe_param(phba, rec_ptr);
70938c2ecf20Sopenharmony_ci
70948c2ecf20Sopenharmony_ci	/* Read FCF connection table */
70958c2ecf20Sopenharmony_ci	rec_ptr = lpfc_get_rec_conf23(&buff[offset],
70968c2ecf20Sopenharmony_ci		size - offset, FCOE_CONN_TBL_TYPE);
70978c2ecf20Sopenharmony_ci	if (rec_ptr)
70988c2ecf20Sopenharmony_ci		lpfc_read_fcf_conn_tbl(phba, rec_ptr);
70998c2ecf20Sopenharmony_ci
71008c2ecf20Sopenharmony_ci}
7101