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 const 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 *
efct_xport_alloc(struct efct * efct)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
efct_xport_init_debugfs(struct efct * efct)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
efct_xport_delete_debugfs(struct efct * efct)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
efct_xport_attach(struct efct_xport * xport)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
efct_xport_link_stats_cb(int status,u32 num_counters,struct efct_hw_link_stat_counts * counters,void * arg)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
efct_xport_host_stats_cb(int status,u32 num_counters,struct efct_hw_host_stat_counts * counters,void * arg)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
efct_xport_async_link_stats_cb(int status,u32 num_counters,struct efct_hw_link_stat_counts * counters,void * arg)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
efct_xport_async_host_stats_cb(int status,u32 num_counters,struct efct_hw_host_stat_counts * counters,void * arg)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
efct_xport_stats_timer_cb(struct timer_list * t)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
efct_xport_config_stats_timer(struct efct * efct)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
efct_xport_initialize(struct efct_xport * xport)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
efct_xport_status(struct efct_xport * xport,enum efct_xport_status cmd,union efct_xport_stats_u * result)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
efct_get_link_supported_speeds(struct efct * efct)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
efct_scsi_new_device(struct efct * efct)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 *
efct_attach_fc_transport(void)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 *
efct_attach_vport_fc_transport(void)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
efct_scsi_reg_fc_transport(void)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
efct_scsi_release_fc_transport(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
efct_xport_detach(struct efct_xport * xport)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
efct_xport_domain_free_cb(struct efc * efc,void * arg)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
efct_xport_control(struct efct_xport * xport,enum efct_xport_ctrl cmd,...)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
efct_xport_free(struct efct_xport * xport)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
efct_release_fc_transport(struct scsi_transport_template * transport_template)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
efct_xport_remove_host(struct Scsi_Host * shost)658 efct_xport_remove_host(struct Scsi_Host *shost)
659 {
660 fc_remove_host(shost);
661 }
662
663 void
efct_scsi_del_device(struct efct * efct)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
efct_get_host_port_id(struct Scsi_Host * shost)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
efct_get_host_port_type(struct Scsi_Host * shost)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
efct_get_host_vport_type(struct Scsi_Host * shost)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
efct_get_host_port_state(struct Scsi_Host * shost)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
efct_get_host_speed(struct Scsi_Host * shost)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
efct_get_host_fabric_name(struct Scsi_Host * shost)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 *
efct_get_stats(struct Scsi_Host * shost)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
efct_reset_stats(struct Scsi_Host * shost)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
efct_issue_lip(struct Scsi_Host * shost)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 *
efct_scsi_new_vport(struct efct * efct,struct device * dev)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
efct_scsi_del_vport(struct efct * efct,struct Scsi_Host * shost)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
efct_vport_create(struct fc_vport * fc_vport,bool disable)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
efct_vport_delete(struct fc_vport * fc_vport)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
efct_vport_disable(struct fc_vport * fc_vport,bool disable)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 };
1112