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