cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

efc_nport.c (18751B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
      4 * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
      5 */
      6
      7/*
      8 * NPORT
      9 *
     10 * Port object for physical port and NPIV ports.
     11 */
     12
     13/*
     14 * NPORT REFERENCE COUNTING
     15 *
     16 * A nport reference should be taken when:
     17 * - an nport is allocated
     18 * - a vport populates associated nport
     19 * - a remote node is allocated
     20 * - a unsolicited frame is processed
     21 * The reference should be dropped when:
     22 * - the unsolicited frame processesing is done
     23 * - the remote node is removed
     24 * - the vport is removed
     25 * - the nport is removed
     26 */
     27
     28#include "efc.h"
     29
     30void
     31efc_nport_cb(void *arg, int event, void *data)
     32{
     33	struct efc *efc = arg;
     34	struct efc_nport *nport = data;
     35	unsigned long flags = 0;
     36
     37	efc_log_debug(efc, "nport event: %s\n", efc_sm_event_name(event));
     38
     39	spin_lock_irqsave(&efc->lock, flags);
     40	efc_sm_post_event(&nport->sm, event, NULL);
     41	spin_unlock_irqrestore(&efc->lock, flags);
     42}
     43
     44static struct efc_nport *
     45efc_nport_find_wwn(struct efc_domain *domain, uint64_t wwnn, uint64_t wwpn)
     46{
     47	struct efc_nport *nport = NULL;
     48
     49	/* Find a nport, given the WWNN and WWPN */
     50	list_for_each_entry(nport, &domain->nport_list, list_entry) {
     51		if (nport->wwnn == wwnn && nport->wwpn == wwpn)
     52			return nport;
     53	}
     54	return NULL;
     55}
     56
     57static void
     58_efc_nport_free(struct kref *arg)
     59{
     60	struct efc_nport *nport = container_of(arg, struct efc_nport, ref);
     61
     62	kfree(nport);
     63}
     64
     65struct efc_nport *
     66efc_nport_alloc(struct efc_domain *domain, uint64_t wwpn, uint64_t wwnn,
     67		u32 fc_id, bool enable_ini, bool enable_tgt)
     68{
     69	struct efc_nport *nport;
     70
     71	if (domain->efc->enable_ini)
     72		enable_ini = 0;
     73
     74	/* Return a failure if this nport has already been allocated */
     75	if ((wwpn != 0) || (wwnn != 0)) {
     76		nport = efc_nport_find_wwn(domain, wwnn, wwpn);
     77		if (nport) {
     78			efc_log_err(domain->efc,
     79				    "NPORT %016llX %016llX already allocated\n",
     80				    wwnn, wwpn);
     81			return NULL;
     82		}
     83	}
     84
     85	nport = kzalloc(sizeof(*nport), GFP_ATOMIC);
     86	if (!nport)
     87		return nport;
     88
     89	/* initialize refcount */
     90	kref_init(&nport->ref);
     91	nport->release = _efc_nport_free;
     92
     93	nport->efc = domain->efc;
     94	snprintf(nport->display_name, sizeof(nport->display_name), "------");
     95	nport->domain = domain;
     96	xa_init(&nport->lookup);
     97	nport->instance_index = domain->nport_count++;
     98	nport->sm.app = nport;
     99	nport->enable_ini = enable_ini;
    100	nport->enable_tgt = enable_tgt;
    101	nport->enable_rscn = (nport->enable_ini ||
    102			(nport->enable_tgt && enable_target_rscn(nport->efc)));
    103
    104	/* Copy service parameters from domain */
    105	memcpy(nport->service_params, domain->service_params,
    106	       sizeof(struct fc_els_flogi));
    107
    108	/* Update requested fc_id */
    109	nport->fc_id = fc_id;
    110
    111	/* Update the nport's service parameters for the new wwn's */
    112	nport->wwpn = wwpn;
    113	nport->wwnn = wwnn;
    114	snprintf(nport->wwnn_str, sizeof(nport->wwnn_str), "%016llX",
    115		 (unsigned long long)wwnn);
    116
    117	/*
    118	 * if this is the "first" nport of the domain,
    119	 * then make it the "phys" nport
    120	 */
    121	if (list_empty(&domain->nport_list))
    122		domain->nport = nport;
    123
    124	INIT_LIST_HEAD(&nport->list_entry);
    125	list_add_tail(&nport->list_entry, &domain->nport_list);
    126
    127	kref_get(&domain->ref);
    128
    129	efc_log_debug(domain->efc, "New Nport [%s]\n", nport->display_name);
    130
    131	return nport;
    132}
    133
    134void
    135efc_nport_free(struct efc_nport *nport)
    136{
    137	struct efc_domain *domain;
    138
    139	if (!nport)
    140		return;
    141
    142	domain = nport->domain;
    143	efc_log_debug(domain->efc, "[%s] free nport\n", nport->display_name);
    144	list_del(&nport->list_entry);
    145	/*
    146	 * if this is the physical nport,
    147	 * then clear it out of the domain
    148	 */
    149	if (nport == domain->nport)
    150		domain->nport = NULL;
    151
    152	xa_destroy(&nport->lookup);
    153	xa_erase(&domain->lookup, nport->fc_id);
    154
    155	if (list_empty(&domain->nport_list))
    156		efc_domain_post_event(domain, EFC_EVT_ALL_CHILD_NODES_FREE,
    157				      NULL);
    158
    159	kref_put(&domain->ref, domain->release);
    160	kref_put(&nport->ref, nport->release);
    161}
    162
    163struct efc_nport *
    164efc_nport_find(struct efc_domain *domain, u32 d_id)
    165{
    166	struct efc_nport *nport;
    167
    168	/* Find a nport object, given an FC_ID */
    169	nport = xa_load(&domain->lookup, d_id);
    170	if (!nport || !kref_get_unless_zero(&nport->ref))
    171		return NULL;
    172
    173	return nport;
    174}
    175
    176int
    177efc_nport_attach(struct efc_nport *nport, u32 fc_id)
    178{
    179	int rc;
    180	struct efc_node *node;
    181	struct efc *efc = nport->efc;
    182	unsigned long index;
    183
    184	/* Set our lookup */
    185	rc = xa_err(xa_store(&nport->domain->lookup, fc_id, nport, GFP_ATOMIC));
    186	if (rc) {
    187		efc_log_err(efc, "Sport lookup store failed: %d\n", rc);
    188		return rc;
    189	}
    190
    191	/* Update our display_name */
    192	efc_node_fcid_display(fc_id, nport->display_name,
    193			      sizeof(nport->display_name));
    194
    195	xa_for_each(&nport->lookup, index, node) {
    196		efc_node_update_display_name(node);
    197	}
    198
    199	efc_log_debug(nport->efc, "[%s] attach nport: fc_id x%06x\n",
    200		      nport->display_name, fc_id);
    201
    202	/* Register a nport, given an FC_ID */
    203	rc = efc_cmd_nport_attach(efc, nport, fc_id);
    204	if (rc < 0) {
    205		efc_log_err(nport->efc,
    206			    "efc_hw_port_attach failed: %d\n", rc);
    207		return -EIO;
    208	}
    209	return 0;
    210}
    211
    212static void
    213efc_nport_shutdown(struct efc_nport *nport)
    214{
    215	struct efc *efc = nport->efc;
    216	struct efc_node *node;
    217	unsigned long index;
    218
    219	xa_for_each(&nport->lookup, index, node) {
    220		if (!(node->rnode.fc_id == FC_FID_FLOGI && nport->is_vport)) {
    221			efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
    222			continue;
    223		}
    224
    225		/*
    226		 * If this is a vport, logout of the fabric
    227		 * controller so that it deletes the vport
    228		 * on the switch.
    229		 */
    230		/* if link is down, don't send logo */
    231		if (efc->link_status == EFC_LINK_STATUS_DOWN) {
    232			efc_node_post_event(node, EFC_EVT_SHUTDOWN, NULL);
    233			continue;
    234		}
    235
    236		efc_log_debug(efc, "[%s] nport shutdown vport, send logo\n",
    237			      node->display_name);
    238
    239		if (!efc_send_logo(node)) {
    240			/* sent LOGO, wait for response */
    241			efc_node_transition(node, __efc_d_wait_logo_rsp, NULL);
    242			continue;
    243		}
    244
    245		/*
    246		 * failed to send LOGO,
    247		 * go ahead and cleanup node anyways
    248		 */
    249		node_printf(node, "Failed to send LOGO\n");
    250		efc_node_post_event(node, EFC_EVT_SHUTDOWN_EXPLICIT_LOGO, NULL);
    251	}
    252}
    253
    254static void
    255efc_vport_link_down(struct efc_nport *nport)
    256{
    257	struct efc *efc = nport->efc;
    258	struct efc_vport *vport;
    259
    260	/* Clear the nport reference in the vport specification */
    261	list_for_each_entry(vport, &efc->vport_list, list_entry) {
    262		if (vport->nport == nport) {
    263			kref_put(&nport->ref, nport->release);
    264			vport->nport = NULL;
    265			break;
    266		}
    267	}
    268}
    269
    270static void
    271__efc_nport_common(const char *funcname, struct efc_sm_ctx *ctx,
    272		   enum efc_sm_event evt, void *arg)
    273{
    274	struct efc_nport *nport = ctx->app;
    275	struct efc_domain *domain = nport->domain;
    276	struct efc *efc = nport->efc;
    277
    278	switch (evt) {
    279	case EFC_EVT_ENTER:
    280	case EFC_EVT_REENTER:
    281	case EFC_EVT_EXIT:
    282	case EFC_EVT_ALL_CHILD_NODES_FREE:
    283		break;
    284	case EFC_EVT_NPORT_ATTACH_OK:
    285			efc_sm_transition(ctx, __efc_nport_attached, NULL);
    286		break;
    287	case EFC_EVT_SHUTDOWN:
    288		/* Flag this nport as shutting down */
    289		nport->shutting_down = true;
    290
    291		if (nport->is_vport)
    292			efc_vport_link_down(nport);
    293
    294		if (xa_empty(&nport->lookup)) {
    295			/* Remove the nport from the domain's lookup table */
    296			xa_erase(&domain->lookup, nport->fc_id);
    297			efc_sm_transition(ctx, __efc_nport_wait_port_free,
    298					  NULL);
    299			if (efc_cmd_nport_free(efc, nport)) {
    300				efc_log_debug(nport->efc,
    301					      "efc_hw_port_free failed\n");
    302				/* Not much we can do, free the nport anyways */
    303				efc_nport_free(nport);
    304			}
    305		} else {
    306			/* sm: node list is not empty / shutdown nodes */
    307			efc_sm_transition(ctx,
    308					  __efc_nport_wait_shutdown, NULL);
    309			efc_nport_shutdown(nport);
    310		}
    311		break;
    312	default:
    313		efc_log_debug(nport->efc, "[%s] %-20s %-20s not handled\n",
    314			      nport->display_name, funcname,
    315			      efc_sm_event_name(evt));
    316	}
    317}
    318
    319void
    320__efc_nport_allocated(struct efc_sm_ctx *ctx,
    321		      enum efc_sm_event evt, void *arg)
    322{
    323	struct efc_nport *nport = ctx->app;
    324	struct efc_domain *domain = nport->domain;
    325
    326	nport_sm_trace(nport);
    327
    328	switch (evt) {
    329	/* the physical nport is attached */
    330	case EFC_EVT_NPORT_ATTACH_OK:
    331		WARN_ON(nport != domain->nport);
    332		efc_sm_transition(ctx, __efc_nport_attached, NULL);
    333		break;
    334
    335	case EFC_EVT_NPORT_ALLOC_OK:
    336		/* ignore */
    337		break;
    338	default:
    339		__efc_nport_common(__func__, ctx, evt, arg);
    340	}
    341}
    342
    343void
    344__efc_nport_vport_init(struct efc_sm_ctx *ctx,
    345		       enum efc_sm_event evt, void *arg)
    346{
    347	struct efc_nport *nport = ctx->app;
    348	struct efc *efc = nport->efc;
    349
    350	nport_sm_trace(nport);
    351
    352	switch (evt) {
    353	case EFC_EVT_ENTER: {
    354		__be64 be_wwpn = cpu_to_be64(nport->wwpn);
    355
    356		if (nport->wwpn == 0)
    357			efc_log_debug(efc, "vport: letting f/w select WWN\n");
    358
    359		if (nport->fc_id != U32_MAX) {
    360			efc_log_debug(efc, "vport: hard coding port id: %x\n",
    361				      nport->fc_id);
    362		}
    363
    364		efc_sm_transition(ctx, __efc_nport_vport_wait_alloc, NULL);
    365		/* If wwpn is zero, then we'll let the f/w assign wwpn*/
    366		if (efc_cmd_nport_alloc(efc, nport, nport->domain,
    367					nport->wwpn == 0 ? NULL :
    368					(uint8_t *)&be_wwpn)) {
    369			efc_log_err(efc, "Can't allocate port\n");
    370			break;
    371		}
    372
    373		break;
    374	}
    375	default:
    376		__efc_nport_common(__func__, ctx, evt, arg);
    377	}
    378}
    379
    380void
    381__efc_nport_vport_wait_alloc(struct efc_sm_ctx *ctx,
    382			     enum efc_sm_event evt, void *arg)
    383{
    384	struct efc_nport *nport = ctx->app;
    385	struct efc *efc = nport->efc;
    386
    387	nport_sm_trace(nport);
    388
    389	switch (evt) {
    390	case EFC_EVT_NPORT_ALLOC_OK: {
    391		struct fc_els_flogi *sp;
    392
    393		sp = (struct fc_els_flogi *)nport->service_params;
    394
    395		if (nport->wwnn == 0) {
    396			nport->wwnn = be64_to_cpu(nport->sli_wwnn);
    397			nport->wwpn = be64_to_cpu(nport->sli_wwpn);
    398			snprintf(nport->wwnn_str, sizeof(nport->wwnn_str),
    399				 "%016llX", nport->wwpn);
    400		}
    401
    402		/* Update the nport's service parameters */
    403		sp->fl_wwpn = cpu_to_be64(nport->wwpn);
    404		sp->fl_wwnn = cpu_to_be64(nport->wwnn);
    405
    406		/*
    407		 * if nport->fc_id is uninitialized,
    408		 * then request that the fabric node use FDISC
    409		 * to find an fc_id.
    410		 * Otherwise we're restoring vports, or we're in
    411		 * fabric emulation mode, so attach the fc_id
    412		 */
    413		if (nport->fc_id == U32_MAX) {
    414			struct efc_node *fabric;
    415
    416			fabric = efc_node_alloc(nport, FC_FID_FLOGI, false,
    417						false);
    418			if (!fabric) {
    419				efc_log_err(efc, "efc_node_alloc() failed\n");
    420				return;
    421			}
    422			efc_node_transition(fabric, __efc_vport_fabric_init,
    423					    NULL);
    424		} else {
    425			snprintf(nport->wwnn_str, sizeof(nport->wwnn_str),
    426				 "%016llX", nport->wwpn);
    427			efc_nport_attach(nport, nport->fc_id);
    428		}
    429		efc_sm_transition(ctx, __efc_nport_vport_allocated, NULL);
    430		break;
    431	}
    432	default:
    433		__efc_nport_common(__func__, ctx, evt, arg);
    434	}
    435}
    436
    437void
    438__efc_nport_vport_allocated(struct efc_sm_ctx *ctx,
    439			    enum efc_sm_event evt, void *arg)
    440{
    441	struct efc_nport *nport = ctx->app;
    442	struct efc *efc = nport->efc;
    443
    444	nport_sm_trace(nport);
    445
    446	/*
    447	 * This state is entered after the nport is allocated;
    448	 * it then waits for a fabric node
    449	 * FDISC to complete, which requests a nport attach.
    450	 * The nport attach complete is handled in this state.
    451	 */
    452	switch (evt) {
    453	case EFC_EVT_NPORT_ATTACH_OK: {
    454		struct efc_node *node;
    455
    456		/* Find our fabric node, and forward this event */
    457		node = efc_node_find(nport, FC_FID_FLOGI);
    458		if (!node) {
    459			efc_log_debug(efc, "can't find node %06x\n", FC_FID_FLOGI);
    460			break;
    461		}
    462		/* sm: / forward nport attach to fabric node */
    463		efc_node_post_event(node, evt, NULL);
    464		efc_sm_transition(ctx, __efc_nport_attached, NULL);
    465		break;
    466	}
    467	default:
    468		__efc_nport_common(__func__, ctx, evt, arg);
    469	}
    470}
    471
    472static void
    473efc_vport_update_spec(struct efc_nport *nport)
    474{
    475	struct efc *efc = nport->efc;
    476	struct efc_vport *vport;
    477	unsigned long flags = 0;
    478
    479	spin_lock_irqsave(&efc->vport_lock, flags);
    480	list_for_each_entry(vport, &efc->vport_list, list_entry) {
    481		if (vport->nport == nport) {
    482			vport->wwnn = nport->wwnn;
    483			vport->wwpn = nport->wwpn;
    484			vport->tgt_data = nport->tgt_data;
    485			vport->ini_data = nport->ini_data;
    486			break;
    487		}
    488	}
    489	spin_unlock_irqrestore(&efc->vport_lock, flags);
    490}
    491
    492void
    493__efc_nport_attached(struct efc_sm_ctx *ctx,
    494		     enum efc_sm_event evt, void *arg)
    495{
    496	struct efc_nport *nport = ctx->app;
    497	struct efc *efc = nport->efc;
    498
    499	nport_sm_trace(nport);
    500
    501	switch (evt) {
    502	case EFC_EVT_ENTER: {
    503		struct efc_node *node;
    504		unsigned long index;
    505
    506		efc_log_debug(efc,
    507			      "[%s] NPORT attached WWPN %016llX WWNN %016llX\n",
    508			      nport->display_name,
    509			      nport->wwpn, nport->wwnn);
    510
    511		xa_for_each(&nport->lookup, index, node)
    512			efc_node_update_display_name(node);
    513
    514		efc->tt.new_nport(efc, nport);
    515
    516		/*
    517		 * Update the vport (if its not the physical nport)
    518		 * parameters
    519		 */
    520		if (nport->is_vport)
    521			efc_vport_update_spec(nport);
    522		break;
    523	}
    524
    525	case EFC_EVT_EXIT:
    526		efc_log_debug(efc,
    527			      "[%s] NPORT deattached WWPN %016llX WWNN %016llX\n",
    528			      nport->display_name,
    529			      nport->wwpn, nport->wwnn);
    530
    531		efc->tt.del_nport(efc, nport);
    532		break;
    533	default:
    534		__efc_nport_common(__func__, ctx, evt, arg);
    535	}
    536}
    537
    538void
    539__efc_nport_wait_shutdown(struct efc_sm_ctx *ctx,
    540			  enum efc_sm_event evt, void *arg)
    541{
    542	struct efc_nport *nport = ctx->app;
    543	struct efc_domain *domain = nport->domain;
    544	struct efc *efc = nport->efc;
    545
    546	nport_sm_trace(nport);
    547
    548	switch (evt) {
    549	case EFC_EVT_NPORT_ALLOC_OK:
    550	case EFC_EVT_NPORT_ALLOC_FAIL:
    551	case EFC_EVT_NPORT_ATTACH_OK:
    552	case EFC_EVT_NPORT_ATTACH_FAIL:
    553		/* ignore these events - just wait for the all free event */
    554		break;
    555
    556	case EFC_EVT_ALL_CHILD_NODES_FREE: {
    557		/*
    558		 * Remove the nport from the domain's
    559		 * sparse vector lookup table
    560		 */
    561		xa_erase(&domain->lookup, nport->fc_id);
    562		efc_sm_transition(ctx, __efc_nport_wait_port_free, NULL);
    563		if (efc_cmd_nport_free(efc, nport)) {
    564			efc_log_err(nport->efc, "efc_hw_port_free failed\n");
    565			/* Not much we can do, free the nport anyways */
    566			efc_nport_free(nport);
    567		}
    568		break;
    569	}
    570	default:
    571		__efc_nport_common(__func__, ctx, evt, arg);
    572	}
    573}
    574
    575void
    576__efc_nport_wait_port_free(struct efc_sm_ctx *ctx,
    577			   enum efc_sm_event evt, void *arg)
    578{
    579	struct efc_nport *nport = ctx->app;
    580
    581	nport_sm_trace(nport);
    582
    583	switch (evt) {
    584	case EFC_EVT_NPORT_ATTACH_OK:
    585		/* Ignore as we are waiting for the free CB */
    586		break;
    587	case EFC_EVT_NPORT_FREE_OK: {
    588		/* All done, free myself */
    589		efc_nport_free(nport);
    590		break;
    591	}
    592	default:
    593		__efc_nport_common(__func__, ctx, evt, arg);
    594	}
    595}
    596
    597static int
    598efc_vport_nport_alloc(struct efc_domain *domain, struct efc_vport *vport)
    599{
    600	struct efc_nport *nport;
    601
    602	lockdep_assert_held(&domain->efc->lock);
    603
    604	nport = efc_nport_alloc(domain, vport->wwpn, vport->wwnn, vport->fc_id,
    605				vport->enable_ini, vport->enable_tgt);
    606	vport->nport = nport;
    607	if (!nport)
    608		return -EIO;
    609
    610	kref_get(&nport->ref);
    611	nport->is_vport = true;
    612	nport->tgt_data = vport->tgt_data;
    613	nport->ini_data = vport->ini_data;
    614
    615	efc_sm_transition(&nport->sm, __efc_nport_vport_init, NULL);
    616
    617	return 0;
    618}
    619
    620int
    621efc_vport_start(struct efc_domain *domain)
    622{
    623	struct efc *efc = domain->efc;
    624	struct efc_vport *vport;
    625	struct efc_vport *next;
    626	int rc = 0;
    627	unsigned long flags = 0;
    628
    629	/* Use the vport spec to find the associated vports and start them */
    630	spin_lock_irqsave(&efc->vport_lock, flags);
    631	list_for_each_entry_safe(vport, next, &efc->vport_list, list_entry) {
    632		if (!vport->nport) {
    633			if (efc_vport_nport_alloc(domain, vport))
    634				rc = -EIO;
    635		}
    636	}
    637	spin_unlock_irqrestore(&efc->vport_lock, flags);
    638
    639	return rc;
    640}
    641
    642int
    643efc_nport_vport_new(struct efc_domain *domain, uint64_t wwpn, uint64_t wwnn,
    644		    u32 fc_id, bool ini, bool tgt, void *tgt_data,
    645		    void *ini_data)
    646{
    647	struct efc *efc = domain->efc;
    648	struct efc_vport *vport;
    649	int rc = 0;
    650	unsigned long flags = 0;
    651
    652	if (ini && domain->efc->enable_ini == 0) {
    653		efc_log_debug(efc, "driver initiator mode not enabled\n");
    654		return -EIO;
    655	}
    656
    657	if (tgt && domain->efc->enable_tgt == 0) {
    658		efc_log_debug(efc, "driver target mode not enabled\n");
    659		return -EIO;
    660	}
    661
    662	/*
    663	 * Create a vport spec if we need to recreate
    664	 * this vport after a link up event
    665	 */
    666	vport = efc_vport_create_spec(domain->efc, wwnn, wwpn, fc_id, ini, tgt,
    667				      tgt_data, ini_data);
    668	if (!vport) {
    669		efc_log_err(efc, "failed to create vport object entry\n");
    670		return -EIO;
    671	}
    672
    673	spin_lock_irqsave(&efc->lock, flags);
    674	rc = efc_vport_nport_alloc(domain, vport);
    675	spin_unlock_irqrestore(&efc->lock, flags);
    676
    677	return rc;
    678}
    679
    680int
    681efc_nport_vport_del(struct efc *efc, struct efc_domain *domain,
    682		    u64 wwpn, uint64_t wwnn)
    683{
    684	struct efc_nport *nport;
    685	struct efc_vport *vport;
    686	struct efc_vport *next;
    687	unsigned long flags = 0;
    688
    689	spin_lock_irqsave(&efc->vport_lock, flags);
    690	/* walk the efc_vport_list and remove from there */
    691	list_for_each_entry_safe(vport, next, &efc->vport_list, list_entry) {
    692		if (vport->wwpn == wwpn && vport->wwnn == wwnn) {
    693			list_del(&vport->list_entry);
    694			kfree(vport);
    695			break;
    696		}
    697	}
    698	spin_unlock_irqrestore(&efc->vport_lock, flags);
    699
    700	if (!domain) {
    701		/* No domain means no nport to look for */
    702		return 0;
    703	}
    704
    705	spin_lock_irqsave(&efc->lock, flags);
    706	list_for_each_entry(nport, &domain->nport_list, list_entry) {
    707		if (nport->wwpn == wwpn && nport->wwnn == wwnn) {
    708			kref_put(&nport->ref, nport->release);
    709			/* Shutdown this NPORT */
    710			efc_sm_post_event(&nport->sm, EFC_EVT_SHUTDOWN, NULL);
    711			break;
    712		}
    713	}
    714
    715	spin_unlock_irqrestore(&efc->lock, flags);
    716	return 0;
    717}
    718
    719void
    720efc_vport_del_all(struct efc *efc)
    721{
    722	struct efc_vport *vport;
    723	struct efc_vport *next;
    724	unsigned long flags = 0;
    725
    726	spin_lock_irqsave(&efc->vport_lock, flags);
    727	list_for_each_entry_safe(vport, next, &efc->vport_list, list_entry) {
    728		list_del(&vport->list_entry);
    729		kfree(vport);
    730	}
    731	spin_unlock_irqrestore(&efc->vport_lock, flags);
    732}
    733
    734struct efc_vport *
    735efc_vport_create_spec(struct efc *efc, uint64_t wwnn, uint64_t wwpn,
    736		      u32 fc_id, bool enable_ini,
    737		      bool enable_tgt, void *tgt_data, void *ini_data)
    738{
    739	struct efc_vport *vport;
    740	unsigned long flags = 0;
    741
    742	/*
    743	 * walk the efc_vport_list and return failure
    744	 * if a valid(vport with non zero WWPN and WWNN) vport entry
    745	 * is already created
    746	 */
    747	spin_lock_irqsave(&efc->vport_lock, flags);
    748	list_for_each_entry(vport, &efc->vport_list, list_entry) {
    749		if ((wwpn && vport->wwpn == wwpn) &&
    750		    (wwnn && vport->wwnn == wwnn)) {
    751			efc_log_err(efc,
    752				    "VPORT %016llX %016llX already allocated\n",
    753				    wwnn, wwpn);
    754			spin_unlock_irqrestore(&efc->vport_lock, flags);
    755			return NULL;
    756		}
    757	}
    758
    759	vport = kzalloc(sizeof(*vport), GFP_ATOMIC);
    760	if (!vport) {
    761		spin_unlock_irqrestore(&efc->vport_lock, flags);
    762		return NULL;
    763	}
    764
    765	vport->wwnn = wwnn;
    766	vport->wwpn = wwpn;
    767	vport->fc_id = fc_id;
    768	vport->enable_tgt = enable_tgt;
    769	vport->enable_ini = enable_ini;
    770	vport->tgt_data = tgt_data;
    771	vport->ini_data = ini_data;
    772
    773	INIT_LIST_HEAD(&vport->list_entry);
    774	list_add_tail(&vport->list_entry, &efc->vport_list);
    775	spin_unlock_irqrestore(&efc->vport_lock, flags);
    776	return vport;
    777}