GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / scsi / elx / efct / efct_xport.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 #include "efct_driver.h"
8 #include "efct_unsol.h"
9
10 static struct dentry *efct_debugfs_root;
11 static atomic_t efct_debugfs_count;
12
13 static struct scsi_host_template efct_template = {
14         .module                 = THIS_MODULE,
15         .name                   = EFCT_DRIVER_NAME,
16         .supported_mode         = MODE_TARGET,
17 };
18
19 /* globals */
20 static struct fc_function_template efct_xport_functions;
21 static struct fc_function_template efct_vport_functions;
22
23 static struct scsi_transport_template *efct_xport_fc_tt;
24 static struct scsi_transport_template *efct_vport_fc_tt;
25
26 struct efct_xport *
27 efct_xport_alloc(struct efct *efct)
28 {
29         struct efct_xport *xport;
30
31         xport = kzalloc(sizeof(*xport), GFP_KERNEL);
32         if (!xport)
33                 return xport;
34
35         xport->efct = efct;
36         return xport;
37 }
38
39 static int
40 efct_xport_init_debugfs(struct efct *efct)
41 {
42         /* Setup efct debugfs root directory */
43         if (!efct_debugfs_root) {
44                 efct_debugfs_root = debugfs_create_dir("efct", NULL);
45                 atomic_set(&efct_debugfs_count, 0);
46         }
47
48         /* Create a directory for sessions in root */
49         if (!efct->sess_debugfs_dir) {
50                 efct->sess_debugfs_dir = debugfs_create_dir("sessions",
51                                                         efct_debugfs_root);
52                 if (IS_ERR(efct->sess_debugfs_dir)) {
53                         efc_log_err(efct,
54                                     "failed to create debugfs entry for sessions\n");
55                         goto debugfs_fail;
56                 }
57                 atomic_inc(&efct_debugfs_count);
58         }
59
60         return 0;
61
62 debugfs_fail:
63         return -EIO;
64 }
65
66 static void efct_xport_delete_debugfs(struct efct *efct)
67 {
68         /* Remove session debugfs directory */
69         debugfs_remove(efct->sess_debugfs_dir);
70         efct->sess_debugfs_dir = NULL;
71         atomic_dec(&efct_debugfs_count);
72
73         if (atomic_read(&efct_debugfs_count) == 0) {
74                 /* remove root debugfs directory */
75                 debugfs_remove(efct_debugfs_root);
76                 efct_debugfs_root = NULL;
77         }
78 }
79
80 int
81 efct_xport_attach(struct efct_xport *xport)
82 {
83         struct efct *efct = xport->efct;
84         int rc;
85
86         rc = efct_hw_setup(&efct->hw, efct, efct->pci);
87         if (rc) {
88                 efc_log_err(efct, "%s: Can't setup hardware\n", efct->desc);
89                 return rc;
90         }
91
92         efct_hw_parse_filter(&efct->hw, (void *)efct->filter_def);
93
94         xport->io_pool = efct_io_pool_create(efct, efct->hw.config.n_sgl);
95         if (!xport->io_pool) {
96                 efc_log_err(efct, "Can't allocate IO pool\n");
97                 return -ENOMEM;
98         }
99
100         return 0;
101 }
102
103 static void
104 efct_xport_link_stats_cb(int status, u32 num_counters,
105                          struct efct_hw_link_stat_counts *counters, void *arg)
106 {
107         union efct_xport_stats_u *result = arg;
108
109         result->stats.link_stats.link_failure_error_count =
110                 counters[EFCT_HW_LINK_STAT_LINK_FAILURE_COUNT].counter;
111         result->stats.link_stats.loss_of_sync_error_count =
112                 counters[EFCT_HW_LINK_STAT_LOSS_OF_SYNC_COUNT].counter;
113         result->stats.link_stats.primitive_sequence_error_count =
114                 counters[EFCT_HW_LINK_STAT_PRIMITIVE_SEQ_COUNT].counter;
115         result->stats.link_stats.invalid_transmission_word_error_count =
116                 counters[EFCT_HW_LINK_STAT_INVALID_XMIT_WORD_COUNT].counter;
117         result->stats.link_stats.crc_error_count =
118                 counters[EFCT_HW_LINK_STAT_CRC_COUNT].counter;
119
120         complete(&result->stats.done);
121 }
122
123 static void
124 efct_xport_host_stats_cb(int status, u32 num_counters,
125                          struct efct_hw_host_stat_counts *counters, void *arg)
126 {
127         union efct_xport_stats_u *result = arg;
128
129         result->stats.host_stats.transmit_kbyte_count =
130                 counters[EFCT_HW_HOST_STAT_TX_KBYTE_COUNT].counter;
131         result->stats.host_stats.receive_kbyte_count =
132                 counters[EFCT_HW_HOST_STAT_RX_KBYTE_COUNT].counter;
133         result->stats.host_stats.transmit_frame_count =
134                 counters[EFCT_HW_HOST_STAT_TX_FRAME_COUNT].counter;
135         result->stats.host_stats.receive_frame_count =
136                 counters[EFCT_HW_HOST_STAT_RX_FRAME_COUNT].counter;
137
138         complete(&result->stats.done);
139 }
140
141 static void
142 efct_xport_async_link_stats_cb(int status, u32 num_counters,
143                                struct efct_hw_link_stat_counts *counters,
144                                void *arg)
145 {
146         union efct_xport_stats_u *result = arg;
147
148         result->stats.link_stats.link_failure_error_count =
149                 counters[EFCT_HW_LINK_STAT_LINK_FAILURE_COUNT].counter;
150         result->stats.link_stats.loss_of_sync_error_count =
151                 counters[EFCT_HW_LINK_STAT_LOSS_OF_SYNC_COUNT].counter;
152         result->stats.link_stats.primitive_sequence_error_count =
153                 counters[EFCT_HW_LINK_STAT_PRIMITIVE_SEQ_COUNT].counter;
154         result->stats.link_stats.invalid_transmission_word_error_count =
155                 counters[EFCT_HW_LINK_STAT_INVALID_XMIT_WORD_COUNT].counter;
156         result->stats.link_stats.crc_error_count =
157                 counters[EFCT_HW_LINK_STAT_CRC_COUNT].counter;
158 }
159
160 static void
161 efct_xport_async_host_stats_cb(int status, u32 num_counters,
162                                struct efct_hw_host_stat_counts *counters,
163                                void *arg)
164 {
165         union efct_xport_stats_u *result = arg;
166
167         result->stats.host_stats.transmit_kbyte_count =
168                 counters[EFCT_HW_HOST_STAT_TX_KBYTE_COUNT].counter;
169         result->stats.host_stats.receive_kbyte_count =
170                 counters[EFCT_HW_HOST_STAT_RX_KBYTE_COUNT].counter;
171         result->stats.host_stats.transmit_frame_count =
172                 counters[EFCT_HW_HOST_STAT_TX_FRAME_COUNT].counter;
173         result->stats.host_stats.receive_frame_count =
174                 counters[EFCT_HW_HOST_STAT_RX_FRAME_COUNT].counter;
175 }
176
177 static void
178 efct_xport_config_stats_timer(struct efct *efct);
179
180 static void
181 efct_xport_stats_timer_cb(struct timer_list *t)
182 {
183         struct efct_xport *xport = from_timer(xport, t, stats_timer);
184         struct efct *efct = xport->efct;
185
186         efct_xport_config_stats_timer(efct);
187 }
188
189 static void
190 efct_xport_config_stats_timer(struct efct *efct)
191 {
192         u32 timeout = 3 * 1000;
193         struct efct_xport *xport = NULL;
194
195         if (!efct) {
196                 pr_err("%s: failed to locate EFCT device\n", __func__);
197                 return;
198         }
199
200         xport = efct->xport;
201         efct_hw_get_link_stats(&efct->hw, 0, 0, 0,
202                                efct_xport_async_link_stats_cb,
203                                &xport->fc_xport_stats);
204         efct_hw_get_host_stats(&efct->hw, 0, efct_xport_async_host_stats_cb,
205                                &xport->fc_xport_stats);
206
207         timer_setup(&xport->stats_timer,
208                     &efct_xport_stats_timer_cb, 0);
209         mod_timer(&xport->stats_timer,
210                   jiffies + msecs_to_jiffies(timeout));
211 }
212
213 int
214 efct_xport_initialize(struct efct_xport *xport)
215 {
216         struct efct *efct = xport->efct;
217         int rc = 0;
218
219         /* Initialize io lists */
220         spin_lock_init(&xport->io_pending_lock);
221         INIT_LIST_HEAD(&xport->io_pending_list);
222         atomic_set(&xport->io_active_count, 0);
223         atomic_set(&xport->io_pending_count, 0);
224         atomic_set(&xport->io_total_free, 0);
225         atomic_set(&xport->io_total_pending, 0);
226         atomic_set(&xport->io_alloc_failed_count, 0);
227         atomic_set(&xport->io_pending_recursing, 0);
228
229         rc = efct_hw_init(&efct->hw);
230         if (rc) {
231                 efc_log_err(efct, "efct_hw_init failure\n");
232                 goto out;
233         }
234
235         rc = efct_scsi_tgt_new_device(efct);
236         if (rc) {
237                 efc_log_err(efct, "failed to initialize target\n");
238                 goto hw_init_out;
239         }
240
241         rc = efct_scsi_new_device(efct);
242         if (rc) {
243                 efc_log_err(efct, "failed to initialize initiator\n");
244                 goto tgt_dev_out;
245         }
246
247         /* Get FC link and host statistics perodically*/
248         efct_xport_config_stats_timer(efct);
249
250         efct_xport_init_debugfs(efct);
251
252         return rc;
253
254 tgt_dev_out:
255         efct_scsi_tgt_del_device(efct);
256
257 hw_init_out:
258         efct_hw_teardown(&efct->hw);
259 out:
260         return rc;
261 }
262
263 int
264 efct_xport_status(struct efct_xport *xport, enum efct_xport_status cmd,
265                   union efct_xport_stats_u *result)
266 {
267         int rc = 0;
268         struct efct *efct = NULL;
269         union efct_xport_stats_u value;
270
271         efct = xport->efct;
272
273         switch (cmd) {
274         case EFCT_XPORT_CONFIG_PORT_STATUS:
275                 if (xport->configured_link_state == 0) {
276                         /*
277                          * Initial state is offline. configured_link_state is
278                          * set to online explicitly when port is brought online
279                          */
280                         xport->configured_link_state = EFCT_XPORT_PORT_OFFLINE;
281                 }
282                 result->value = xport->configured_link_state;
283                 break;
284
285         case EFCT_XPORT_PORT_STATUS:
286                 /* Determine port status based on link speed. */
287                 value.value = efct_hw_get_link_speed(&efct->hw);
288                 if (value.value == 0)
289                         result->value = EFCT_XPORT_PORT_OFFLINE;
290                 else
291                         result->value = EFCT_XPORT_PORT_ONLINE;
292                 break;
293
294         case EFCT_XPORT_LINK_SPEED:
295                 result->value = efct_hw_get_link_speed(&efct->hw);
296                 break;
297
298         case EFCT_XPORT_LINK_STATISTICS:
299                 memcpy((void *)result, &efct->xport->fc_xport_stats,
300                        sizeof(union efct_xport_stats_u));
301                 break;
302         case EFCT_XPORT_LINK_STAT_RESET: {
303                 /* Create a completion to synchronize the stat reset process */
304                 init_completion(&result->stats.done);
305
306                 /* First reset the link stats */
307                 rc = efct_hw_get_link_stats(&efct->hw, 0, 1, 1,
308                                             efct_xport_link_stats_cb, result);
309                 if (rc)
310                         break;
311
312                 /* Wait for completion to be signaled when the cmd completes */
313                 if (wait_for_completion_interruptible(&result->stats.done)) {
314                         /* Undefined failure */
315                         efc_log_debug(efct, "sem wait failed\n");
316                         rc = -EIO;
317                         break;
318                 }
319
320                 /* Next reset the host stats */
321                 rc = efct_hw_get_host_stats(&efct->hw, 1,
322                                             efct_xport_host_stats_cb, result);
323
324                 if (rc)
325                         break;
326
327                 /* Wait for completion to be signaled when the cmd completes */
328                 if (wait_for_completion_interruptible(&result->stats.done)) {
329                         /* Undefined failure */
330                         efc_log_debug(efct, "sem wait failed\n");
331                         rc = -EIO;
332                         break;
333                 }
334                 break;
335         }
336         default:
337                 rc = -EIO;
338                 break;
339         }
340
341         return rc;
342 }
343
344 static int
345 efct_get_link_supported_speeds(struct efct *efct)
346 {
347         u32 supported_speeds = 0;
348         u32 link_module_type, i;
349         struct {
350                 u32 lmt_speed;
351                 u32 speed;
352         } supported_speed_list[] = {
353                 {SLI4_LINK_MODULE_TYPE_1GB, FC_PORTSPEED_1GBIT},
354                 {SLI4_LINK_MODULE_TYPE_2GB, FC_PORTSPEED_2GBIT},
355                 {SLI4_LINK_MODULE_TYPE_4GB, FC_PORTSPEED_4GBIT},
356                 {SLI4_LINK_MODULE_TYPE_8GB, FC_PORTSPEED_8GBIT},
357                 {SLI4_LINK_MODULE_TYPE_16GB, FC_PORTSPEED_16GBIT},
358                 {SLI4_LINK_MODULE_TYPE_32GB, FC_PORTSPEED_32GBIT},
359                 {SLI4_LINK_MODULE_TYPE_64GB, FC_PORTSPEED_64GBIT},
360                 {SLI4_LINK_MODULE_TYPE_128GB, FC_PORTSPEED_128GBIT},
361         };
362
363         link_module_type = sli_get_lmt(&efct->hw.sli);
364
365         /* populate link supported speeds */
366         for (i = 0; i < ARRAY_SIZE(supported_speed_list); i++) {
367                 if (link_module_type & supported_speed_list[i].lmt_speed)
368                         supported_speeds |= supported_speed_list[i].speed;
369         }
370
371         return supported_speeds;
372 }
373
374 int
375 efct_scsi_new_device(struct efct *efct)
376 {
377         struct Scsi_Host *shost = NULL;
378         int error = 0;
379         struct efct_vport *vport = NULL;
380
381         shost = scsi_host_alloc(&efct_template, sizeof(*vport));
382         if (!shost) {
383                 efc_log_err(efct, "failed to allocate Scsi_Host struct\n");
384                 return -ENOMEM;
385         }
386
387         /* save shost to initiator-client context */
388         efct->shost = shost;
389
390         /* save efct information to shost LLD-specific space */
391         vport = (struct efct_vport *)shost->hostdata;
392         vport->efct = efct;
393
394         /*
395          * Set initial can_queue value to the max SCSI IOs. This is the maximum
396          * global queue depth (as opposed to the per-LUN queue depth --
397          * .cmd_per_lun This may need to be adjusted for I+T mode.
398          */
399         shost->can_queue = efct->hw.config.n_io;
400         shost->max_cmd_len = 16; /* 16-byte CDBs */
401         shost->max_id = 0xffff;
402         shost->max_lun = 0xffffffff;
403
404         /*
405          * can only accept (from mid-layer) as many SGEs as we've
406          * pre-registered
407          */
408         shost->sg_tablesize = sli_get_max_sgl(&efct->hw.sli);
409
410         /* attach FC Transport template to shost */
411         shost->transportt = efct_xport_fc_tt;
412         efc_log_debug(efct, "transport template=%p\n", efct_xport_fc_tt);
413
414         /* get pci_dev structure and add host to SCSI ML */
415         error = scsi_add_host_with_dma(shost, &efct->pci->dev,
416                                        &efct->pci->dev);
417         if (error) {
418                 efc_log_debug(efct, "failed scsi_add_host_with_dma\n");
419                 return -EIO;
420         }
421
422         /* Set symbolic name for host port */
423         snprintf(fc_host_symbolic_name(shost),
424                  sizeof(fc_host_symbolic_name(shost)),
425                      "Emulex %s FV%s DV%s", efct->model,
426                      efct->hw.sli.fw_name[0], EFCT_DRIVER_VERSION);
427
428         /* Set host port supported classes */
429         fc_host_supported_classes(shost) = FC_COS_CLASS3;
430
431         fc_host_supported_speeds(shost) = efct_get_link_supported_speeds(efct);
432
433         fc_host_node_name(shost) = efct_get_wwnn(&efct->hw);
434         fc_host_port_name(shost) = efct_get_wwpn(&efct->hw);
435         fc_host_max_npiv_vports(shost) = 128;
436
437         return 0;
438 }
439
440 struct scsi_transport_template *
441 efct_attach_fc_transport(void)
442 {
443         struct scsi_transport_template *efct_fc_template = NULL;
444
445         efct_fc_template = fc_attach_transport(&efct_xport_functions);
446
447         if (!efct_fc_template)
448                 pr_err("failed to attach EFCT with fc transport\n");
449
450         return efct_fc_template;
451 }
452
453 struct scsi_transport_template *
454 efct_attach_vport_fc_transport(void)
455 {
456         struct scsi_transport_template *efct_fc_template = NULL;
457
458         efct_fc_template = fc_attach_transport(&efct_vport_functions);
459
460         if (!efct_fc_template)
461                 pr_err("failed to attach EFCT with fc transport\n");
462
463         return efct_fc_template;
464 }
465
466 int
467 efct_scsi_reg_fc_transport(void)
468 {
469         /* attach to appropriate scsi_tranport_* module */
470         efct_xport_fc_tt = efct_attach_fc_transport();
471         if (!efct_xport_fc_tt) {
472                 pr_err("%s: failed to attach to scsi_transport_*", __func__);
473                 return -EIO;
474         }
475
476         efct_vport_fc_tt = efct_attach_vport_fc_transport();
477         if (!efct_vport_fc_tt) {
478                 pr_err("%s: failed to attach to scsi_transport_*", __func__);
479                 efct_release_fc_transport(efct_xport_fc_tt);
480                 efct_xport_fc_tt = NULL;
481                 return -EIO;
482         }
483
484         return 0;
485 }
486
487 void
488 efct_scsi_release_fc_transport(void)
489 {
490         /* detach from scsi_transport_* */
491         efct_release_fc_transport(efct_xport_fc_tt);
492         efct_xport_fc_tt = NULL;
493         if (efct_vport_fc_tt)
494                 efct_release_fc_transport(efct_vport_fc_tt);
495
496         efct_vport_fc_tt = NULL;
497 }
498
499 void
500 efct_xport_detach(struct efct_xport *xport)
501 {
502         struct efct *efct = xport->efct;
503
504         /* free resources associated with target-server and initiator-client */
505         efct_scsi_tgt_del_device(efct);
506
507         efct_scsi_del_device(efct);
508
509         /*Shutdown FC Statistics timer*/
510         if (timer_pending(&xport->stats_timer))
511                 del_timer(&xport->stats_timer);
512
513         efct_hw_teardown(&efct->hw);
514
515         efct_xport_delete_debugfs(efct);
516 }
517
518 static void
519 efct_xport_domain_free_cb(struct efc *efc, void *arg)
520 {
521         struct completion *done = arg;
522
523         complete(done);
524 }
525
526 int
527 efct_xport_control(struct efct_xport *xport, enum efct_xport_ctrl cmd, ...)
528 {
529         u32 rc = 0;
530         struct efct *efct = NULL;
531         va_list argp;
532
533         efct = xport->efct;
534
535         switch (cmd) {
536         case EFCT_XPORT_PORT_ONLINE: {
537                 /* Bring the port on-line */
538                 rc = efct_hw_port_control(&efct->hw, EFCT_HW_PORT_INIT, 0,
539                                           NULL, NULL);
540                 if (rc)
541                         efc_log_err(efct,
542                                     "%s: Can't init port\n", efct->desc);
543                 else
544                         xport->configured_link_state = cmd;
545                 break;
546         }
547         case EFCT_XPORT_PORT_OFFLINE: {
548                 if (efct_hw_port_control(&efct->hw, EFCT_HW_PORT_SHUTDOWN, 0,
549                                          NULL, NULL))
550                         efc_log_err(efct, "port shutdown failed\n");
551                 else
552                         xport->configured_link_state = cmd;
553                 break;
554         }
555
556         case EFCT_XPORT_SHUTDOWN: {
557                 struct completion done;
558                 unsigned long timeout;
559
560                 /* if a PHYSDEV reset was performed (e.g. hw dump), will affect
561                  * all PCI functions; orderly shutdown won't work,
562                  * just force free
563                  */
564                 if (sli_reset_required(&efct->hw.sli)) {
565                         struct efc_domain *domain = efct->efcport->domain;
566
567                         if (domain)
568                                 efc_domain_cb(efct->efcport, EFC_HW_DOMAIN_LOST,
569                                               domain);
570                 } else {
571                         efct_hw_port_control(&efct->hw, EFCT_HW_PORT_SHUTDOWN,
572                                              0, NULL, NULL);
573                 }
574
575                 init_completion(&done);
576
577                 efc_register_domain_free_cb(efct->efcport,
578                                             efct_xport_domain_free_cb, &done);
579
580                 efc_log_debug(efct, "Waiting %d seconds for domain shutdown\n",
581                               (EFC_SHUTDOWN_TIMEOUT_USEC / 1000000));
582
583                 timeout = usecs_to_jiffies(EFC_SHUTDOWN_TIMEOUT_USEC);
584                 if (!wait_for_completion_timeout(&done, timeout)) {
585                         efc_log_err(efct, "Domain shutdown timed out!!\n");
586                         WARN_ON(1);
587                 }
588
589                 efc_register_domain_free_cb(efct->efcport, NULL, NULL);
590
591                 /* Free up any saved virtual ports */
592                 efc_vport_del_all(efct->efcport);
593                 break;
594         }
595
596         /*
597          * Set wwnn for the port. This will be used instead of the default
598          * provided by FW.
599          */
600         case EFCT_XPORT_WWNN_SET: {
601                 u64 wwnn;
602
603                 /* Retrieve arguments */
604                 va_start(argp, cmd);
605                 wwnn = va_arg(argp, uint64_t);
606                 va_end(argp);
607
608                 efc_log_debug(efct, " WWNN %016llx\n", wwnn);
609                 xport->req_wwnn = wwnn;
610
611                 break;
612         }
613         /*
614          * Set wwpn for the port. This will be used instead of the default
615          * provided by FW.
616          */
617         case EFCT_XPORT_WWPN_SET: {
618                 u64 wwpn;
619
620                 /* Retrieve arguments */
621                 va_start(argp, cmd);
622                 wwpn = va_arg(argp, uint64_t);
623                 va_end(argp);
624
625                 efc_log_debug(efct, " WWPN %016llx\n", wwpn);
626                 xport->req_wwpn = wwpn;
627
628                 break;
629         }
630
631         default:
632                 break;
633         }
634         return rc;
635 }
636
637 void
638 efct_xport_free(struct efct_xport *xport)
639 {
640         if (xport) {
641                 efct_io_pool_free(xport->io_pool);
642
643                 kfree(xport);
644         }
645 }
646
647 void
648 efct_release_fc_transport(struct scsi_transport_template *transport_template)
649 {
650         if (transport_template)
651                 pr_err("releasing transport layer\n");
652
653         /* Releasing FC transport */
654         fc_release_transport(transport_template);
655 }
656
657 static void
658 efct_xport_remove_host(struct Scsi_Host *shost)
659 {
660         fc_remove_host(shost);
661 }
662
663 void
664 efct_scsi_del_device(struct efct *efct)
665 {
666         if (!efct->shost)
667                 return;
668
669         efc_log_debug(efct, "Unregistering with Transport Layer\n");
670         efct_xport_remove_host(efct->shost);
671         efc_log_debug(efct, "Unregistering with SCSI Midlayer\n");
672         scsi_remove_host(efct->shost);
673         scsi_host_put(efct->shost);
674         efct->shost = NULL;
675 }
676
677 static void
678 efct_get_host_port_id(struct Scsi_Host *shost)
679 {
680         struct efct_vport *vport = (struct efct_vport *)shost->hostdata;
681         struct efct *efct = vport->efct;
682         struct efc *efc = efct->efcport;
683         struct efc_nport *nport;
684
685         if (efc->domain && efc->domain->nport) {
686                 nport = efc->domain->nport;
687                 fc_host_port_id(shost) = nport->fc_id;
688         }
689 }
690
691 static void
692 efct_get_host_port_type(struct Scsi_Host *shost)
693 {
694         struct efct_vport *vport = (struct efct_vport *)shost->hostdata;
695         struct efct *efct = vport->efct;
696         struct efc *efc = efct->efcport;
697         int type = FC_PORTTYPE_UNKNOWN;
698
699         if (efc->domain && efc->domain->nport) {
700                 if (efc->domain->is_loop) {
701                         type = FC_PORTTYPE_LPORT;
702                 } else {
703                         struct efc_nport *nport = efc->domain->nport;
704
705                         if (nport->is_vport)
706                                 type = FC_PORTTYPE_NPIV;
707                         else if (nport->topology == EFC_NPORT_TOPO_P2P)
708                                 type = FC_PORTTYPE_PTP;
709                         else if (nport->topology == EFC_NPORT_TOPO_UNKNOWN)
710                                 type = FC_PORTTYPE_UNKNOWN;
711                         else
712                                 type = FC_PORTTYPE_NPORT;
713                 }
714         }
715         fc_host_port_type(shost) = type;
716 }
717
718 static void
719 efct_get_host_vport_type(struct Scsi_Host *shost)
720 {
721         fc_host_port_type(shost) = FC_PORTTYPE_NPIV;
722 }
723
724 static void
725 efct_get_host_port_state(struct Scsi_Host *shost)
726 {
727         struct efct_vport *vport = (struct efct_vport *)shost->hostdata;
728         struct efct *efct = vport->efct;
729         union efct_xport_stats_u status;
730         int rc;
731
732         rc = efct_xport_status(efct->xport, EFCT_XPORT_PORT_STATUS, &status);
733         if ((!rc) && (status.value == EFCT_XPORT_PORT_ONLINE))
734                 fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;
735         else
736                 fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
737 }
738
739 static void
740 efct_get_host_speed(struct Scsi_Host *shost)
741 {
742         struct efct_vport *vport = (struct efct_vport *)shost->hostdata;
743         struct efct *efct = vport->efct;
744         struct efc *efc = efct->efcport;
745         union efct_xport_stats_u speed;
746         u32 fc_speed = FC_PORTSPEED_UNKNOWN;
747         int rc;
748
749         if (!efc->domain || !efc->domain->nport) {
750                 fc_host_speed(shost) = fc_speed;
751                 return;
752         }
753
754         rc = efct_xport_status(efct->xport, EFCT_XPORT_LINK_SPEED, &speed);
755         if (!rc) {
756                 switch (speed.value) {
757                 case 1000:
758                         fc_speed = FC_PORTSPEED_1GBIT;
759                         break;
760                 case 2000:
761                         fc_speed = FC_PORTSPEED_2GBIT;
762                         break;
763                 case 4000:
764                         fc_speed = FC_PORTSPEED_4GBIT;
765                         break;
766                 case 8000:
767                         fc_speed = FC_PORTSPEED_8GBIT;
768                         break;
769                 case 10000:
770                         fc_speed = FC_PORTSPEED_10GBIT;
771                         break;
772                 case 16000:
773                         fc_speed = FC_PORTSPEED_16GBIT;
774                         break;
775                 case 32000:
776                         fc_speed = FC_PORTSPEED_32GBIT;
777                         break;
778                 case 64000:
779                         fc_speed = FC_PORTSPEED_64GBIT;
780                         break;
781                 case 128000:
782                         fc_speed = FC_PORTSPEED_128GBIT;
783                         break;
784                 }
785         }
786
787         fc_host_speed(shost) = fc_speed;
788 }
789
790 static void
791 efct_get_host_fabric_name(struct Scsi_Host *shost)
792 {
793         struct efct_vport *vport = (struct efct_vport *)shost->hostdata;
794         struct efct *efct = vport->efct;
795         struct efc *efc = efct->efcport;
796
797         if (efc->domain) {
798                 struct fc_els_flogi  *sp =
799                         (struct fc_els_flogi  *)
800                                 efc->domain->flogi_service_params;
801
802                 fc_host_fabric_name(shost) = be64_to_cpu(sp->fl_wwnn);
803         }
804 }
805
806 static struct fc_host_statistics *
807 efct_get_stats(struct Scsi_Host *shost)
808 {
809         struct efct_vport *vport = (struct efct_vport *)shost->hostdata;
810         struct efct *efct = vport->efct;
811         union efct_xport_stats_u stats;
812         struct efct_xport *xport = efct->xport;
813         int rc = 0;
814
815         rc = efct_xport_status(xport, EFCT_XPORT_LINK_STATISTICS, &stats);
816         if (rc) {
817                 pr_err("efct_xport_status returned non 0 - %d\n", rc);
818                 return NULL;
819         }
820
821         vport->fc_host_stats.loss_of_sync_count =
822                 stats.stats.link_stats.loss_of_sync_error_count;
823         vport->fc_host_stats.link_failure_count =
824                 stats.stats.link_stats.link_failure_error_count;
825         vport->fc_host_stats.prim_seq_protocol_err_count =
826                 stats.stats.link_stats.primitive_sequence_error_count;
827         vport->fc_host_stats.invalid_tx_word_count =
828                 stats.stats.link_stats.invalid_transmission_word_error_count;
829         vport->fc_host_stats.invalid_crc_count =
830                 stats.stats.link_stats.crc_error_count;
831         /* mbox returns kbyte count so we need to convert to words */
832         vport->fc_host_stats.tx_words =
833                 stats.stats.host_stats.transmit_kbyte_count * 256;
834         /* mbox returns kbyte count so we need to convert to words */
835         vport->fc_host_stats.rx_words =
836                 stats.stats.host_stats.receive_kbyte_count * 256;
837         vport->fc_host_stats.tx_frames =
838                 stats.stats.host_stats.transmit_frame_count;
839         vport->fc_host_stats.rx_frames =
840                 stats.stats.host_stats.receive_frame_count;
841
842         vport->fc_host_stats.fcp_input_requests =
843                         xport->fcp_stats.input_requests;
844         vport->fc_host_stats.fcp_output_requests =
845                         xport->fcp_stats.output_requests;
846         vport->fc_host_stats.fcp_output_megabytes =
847                         xport->fcp_stats.output_bytes >> 20;
848         vport->fc_host_stats.fcp_input_megabytes =
849                         xport->fcp_stats.input_bytes >> 20;
850         vport->fc_host_stats.fcp_control_requests =
851                         xport->fcp_stats.control_requests;
852
853         return &vport->fc_host_stats;
854 }
855
856 static void
857 efct_reset_stats(struct Scsi_Host *shost)
858 {
859         struct efct_vport *vport = (struct efct_vport *)shost->hostdata;
860         struct efct *efct = vport->efct;
861         /* argument has no purpose for this action */
862         union efct_xport_stats_u dummy;
863         int rc;
864
865         rc = efct_xport_status(efct->xport, EFCT_XPORT_LINK_STAT_RESET, &dummy);
866         if (rc)
867                 pr_err("efct_xport_status returned non 0 - %d\n", rc);
868 }
869
870 static int
871 efct_issue_lip(struct Scsi_Host *shost)
872 {
873         struct efct_vport *vport =
874                         shost ? (struct efct_vport *)shost->hostdata : NULL;
875         struct efct *efct = vport ? vport->efct : NULL;
876
877         if (!shost || !vport || !efct) {
878                 pr_err("%s: shost=%p vport=%p efct=%p\n", __func__,
879                        shost, vport, efct);
880                 return -EPERM;
881         }
882
883         /*
884          * Bring the link down gracefully then re-init the link.
885          * The firmware will re-initialize the Fibre Channel interface as
886          * required. It does not issue a LIP.
887          */
888
889         if (efct_xport_control(efct->xport, EFCT_XPORT_PORT_OFFLINE))
890                 efc_log_debug(efct, "EFCT_XPORT_PORT_OFFLINE failed\n");
891
892         if (efct_xport_control(efct->xport, EFCT_XPORT_PORT_ONLINE))
893                 efc_log_debug(efct, "EFCT_XPORT_PORT_ONLINE failed\n");
894
895         return 0;
896 }
897
898 struct efct_vport *
899 efct_scsi_new_vport(struct efct *efct, struct device *dev)
900 {
901         struct Scsi_Host *shost = NULL;
902         int error = 0;
903         struct efct_vport *vport = NULL;
904
905         shost = scsi_host_alloc(&efct_template, sizeof(*vport));
906         if (!shost) {
907                 efc_log_err(efct, "failed to allocate Scsi_Host struct\n");
908                 return NULL;
909         }
910
911         /* save efct information to shost LLD-specific space */
912         vport = (struct efct_vport *)shost->hostdata;
913         vport->efct = efct;
914         vport->is_vport = true;
915
916         shost->can_queue = efct->hw.config.n_io;
917         shost->max_cmd_len = 16; /* 16-byte CDBs */
918         shost->max_id = 0xffff;
919         shost->max_lun = 0xffffffff;
920
921         /* can only accept (from mid-layer) as many SGEs as we've pre-regited*/
922         shost->sg_tablesize = sli_get_max_sgl(&efct->hw.sli);
923
924         /* attach FC Transport template to shost */
925         shost->transportt = efct_vport_fc_tt;
926         efc_log_debug(efct, "vport transport template=%p\n",
927                       efct_vport_fc_tt);
928
929         /* get pci_dev structure and add host to SCSI ML */
930         error = scsi_add_host_with_dma(shost, dev, &efct->pci->dev);
931         if (error) {
932                 efc_log_debug(efct, "failed scsi_add_host_with_dma\n");
933                 return NULL;
934         }
935
936         /* Set symbolic name for host port */
937         snprintf(fc_host_symbolic_name(shost),
938                  sizeof(fc_host_symbolic_name(shost)),
939                  "Emulex %s FV%s DV%s", efct->model, efct->hw.sli.fw_name[0],
940                  EFCT_DRIVER_VERSION);
941
942         /* Set host port supported classes */
943         fc_host_supported_classes(shost) = FC_COS_CLASS3;
944
945         fc_host_supported_speeds(shost) = efct_get_link_supported_speeds(efct);
946         vport->shost = shost;
947
948         return vport;
949 }
950
951 int efct_scsi_del_vport(struct efct *efct, struct Scsi_Host *shost)
952 {
953         if (shost) {
954                 efc_log_debug(efct,
955                               "Unregistering vport with Transport Layer\n");
956                 efct_xport_remove_host(shost);
957                 efc_log_debug(efct, "Unregistering vport with SCSI Midlayer\n");
958                 scsi_remove_host(shost);
959                 scsi_host_put(shost);
960                 return 0;
961         }
962         return -EIO;
963 }
964
965 static int
966 efct_vport_create(struct fc_vport *fc_vport, bool disable)
967 {
968         struct Scsi_Host *shost = fc_vport ? fc_vport->shost : NULL;
969         struct efct_vport *pport = shost ?
970                                         (struct efct_vport *)shost->hostdata :
971                                         NULL;
972         struct efct *efct = pport ? pport->efct : NULL;
973         struct efct_vport *vport = NULL;
974
975         if (!fc_vport || !shost || !efct)
976                 goto fail;
977
978         vport = efct_scsi_new_vport(efct, &fc_vport->dev);
979         if (!vport) {
980                 efc_log_err(efct, "failed to create vport\n");
981                 goto fail;
982         }
983
984         vport->fc_vport = fc_vport;
985         vport->npiv_wwpn = fc_vport->port_name;
986         vport->npiv_wwnn = fc_vport->node_name;
987         fc_host_node_name(vport->shost) = vport->npiv_wwnn;
988         fc_host_port_name(vport->shost) = vport->npiv_wwpn;
989         *(struct efct_vport **)fc_vport->dd_data = vport;
990
991         return 0;
992
993 fail:
994         return -EIO;
995 }
996
997 static int
998 efct_vport_delete(struct fc_vport *fc_vport)
999 {
1000         struct efct_vport *vport = *(struct efct_vport **)fc_vport->dd_data;
1001         struct Scsi_Host *shost = vport ? vport->shost : NULL;
1002         struct efct *efct = vport ? vport->efct : NULL;
1003         int rc;
1004
1005         rc = efct_scsi_del_vport(efct, shost);
1006
1007         if (rc)
1008                 pr_err("%s: vport delete failed\n", __func__);
1009
1010         return rc;
1011 }
1012
1013 static int
1014 efct_vport_disable(struct fc_vport *fc_vport, bool disable)
1015 {
1016         return 0;
1017 }
1018
1019 static struct fc_function_template efct_xport_functions = {
1020         .get_host_port_id = efct_get_host_port_id,
1021         .get_host_port_type = efct_get_host_port_type,
1022         .get_host_port_state = efct_get_host_port_state,
1023         .get_host_speed = efct_get_host_speed,
1024         .get_host_fabric_name = efct_get_host_fabric_name,
1025
1026         .get_fc_host_stats = efct_get_stats,
1027         .reset_fc_host_stats = efct_reset_stats,
1028
1029         .issue_fc_host_lip = efct_issue_lip,
1030
1031         .vport_disable = efct_vport_disable,
1032
1033         /* allocation lengths for host-specific data */
1034         .dd_fcrport_size = sizeof(struct efct_rport_data),
1035         .dd_fcvport_size = 128, /* should be sizeof(...) */
1036
1037         /* remote port fixed attributes */
1038         .show_rport_maxframe_size = 1,
1039         .show_rport_supported_classes = 1,
1040         .show_rport_dev_loss_tmo = 1,
1041
1042         /* target dynamic attributes */
1043         .show_starget_node_name = 1,
1044         .show_starget_port_name = 1,
1045         .show_starget_port_id = 1,
1046
1047         /* host fixed attributes */
1048         .show_host_node_name = 1,
1049         .show_host_port_name = 1,
1050         .show_host_supported_classes = 1,
1051         .show_host_supported_fc4s = 1,
1052         .show_host_supported_speeds = 1,
1053         .show_host_maxframe_size = 1,
1054
1055         /* host dynamic attributes */
1056         .show_host_port_id = 1,
1057         .show_host_port_type = 1,
1058         .show_host_port_state = 1,
1059         /* active_fc4s is shown but doesn't change (thus no get function) */
1060         .show_host_active_fc4s = 1,
1061         .show_host_speed = 1,
1062         .show_host_fabric_name = 1,
1063         .show_host_symbolic_name = 1,
1064         .vport_create = efct_vport_create,
1065         .vport_delete = efct_vport_delete,
1066 };
1067
1068 static struct fc_function_template efct_vport_functions = {
1069         .get_host_port_id = efct_get_host_port_id,
1070         .get_host_port_type = efct_get_host_vport_type,
1071         .get_host_port_state = efct_get_host_port_state,
1072         .get_host_speed = efct_get_host_speed,
1073         .get_host_fabric_name = efct_get_host_fabric_name,
1074
1075         .get_fc_host_stats = efct_get_stats,
1076         .reset_fc_host_stats = efct_reset_stats,
1077
1078         .issue_fc_host_lip = efct_issue_lip,
1079
1080         /* allocation lengths for host-specific data */
1081         .dd_fcrport_size = sizeof(struct efct_rport_data),
1082         .dd_fcvport_size = 128, /* should be sizeof(...) */
1083
1084         /* remote port fixed attributes */
1085         .show_rport_maxframe_size = 1,
1086         .show_rport_supported_classes = 1,
1087         .show_rport_dev_loss_tmo = 1,
1088
1089         /* target dynamic attributes */
1090         .show_starget_node_name = 1,
1091         .show_starget_port_name = 1,
1092         .show_starget_port_id = 1,
1093
1094         /* host fixed attributes */
1095         .show_host_node_name = 1,
1096         .show_host_port_name = 1,
1097         .show_host_supported_classes = 1,
1098         .show_host_supported_fc4s = 1,
1099         .show_host_supported_speeds = 1,
1100         .show_host_maxframe_size = 1,
1101
1102         /* host dynamic attributes */
1103         .show_host_port_id = 1,
1104         .show_host_port_type = 1,
1105         .show_host_port_state = 1,
1106         /* active_fc4s is shown but doesn't change (thus no get function) */
1107         .show_host_active_fc4s = 1,
1108         .show_host_speed = 1,
1109         .show_host_fabric_name = 1,
1110         .show_host_symbolic_name = 1,
1111 };