xref: /linux/drivers/scsi/elx/libefc/efc_nport.c (revision 3d0fe49454652117522f60bfbefb978ba0e5300b)
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 
30 void
31 efc_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 
44 static struct efc_nport *
45 efc_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 
57 static 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 
65 struct efc_nport *
66 efc_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 
134 void
135 efc_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 
163 struct efc_nport *
164 efc_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 
176 int
177 efc_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 
212 static void
213 efc_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 
254 static void
255 efc_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 
270 static 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 
319 void
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 
343 void
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 
380 void
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 
437 void
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 
472 static void
473 efc_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 
492 void
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 
538 void
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 
575 void
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 
597 static int
598 efc_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 
620 int
621 efc_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 
642 int
643 efc_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 
680 int
681 efc_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 
719 void
720 efc_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 
734 struct efc_vport *
735 efc_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 }
778