GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / scsi / elx / libefc / efc_nport.c
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 }