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
10static struct dentry *efct_debugfs_root;
11static atomic_t efct_debugfs_count;
12
13static 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 */
20static struct fc_function_template efct_xport_functions;
21static struct fc_function_template efct_vport_functions;
22
23static struct scsi_transport_template *efct_xport_fc_tt;
24static struct scsi_transport_template *efct_vport_fc_tt;
25
26struct efct_xport *
27efct_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
39static int
40efct_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
62debugfs_fail:
63	return -EIO;
64}
65
66static 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
80int
81efct_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
103static void
104efct_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
123static void
124efct_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
141static void
142efct_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
160static void
161efct_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
177static void
178efct_xport_config_stats_timer(struct efct *efct);
179
180static void
181efct_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
189static void
190efct_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
213int
214efct_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
254tgt_dev_out:
255	efct_scsi_tgt_del_device(efct);
256
257hw_init_out:
258	efct_hw_teardown(&efct->hw);
259out:
260	return rc;
261}
262
263int
264efct_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
344static int
345efct_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
374int
375efct_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
440struct scsi_transport_template *
441efct_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
453struct scsi_transport_template *
454efct_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
466int
467efct_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
487void
488efct_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
499void
500efct_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
518static void
519efct_xport_domain_free_cb(struct efc *efc, void *arg)
520{
521	struct completion *done = arg;
522
523	complete(done);
524}
525
526int
527efct_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
637void
638efct_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
647void
648efct_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
657static void
658efct_xport_remove_host(struct Scsi_Host *shost)
659{
660	fc_remove_host(shost);
661}
662
663void
664efct_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
677static void
678efct_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
691static void
692efct_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
718static void
719efct_get_host_vport_type(struct Scsi_Host *shost)
720{
721	fc_host_port_type(shost) = FC_PORTTYPE_NPIV;
722}
723
724static void
725efct_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
739static void
740efct_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
790static void
791efct_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
806static struct fc_host_statistics *
807efct_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
856static void
857efct_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
870static int
871efct_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
898struct efct_vport *
899efct_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
951int 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
965static int
966efct_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
993fail:
994	return -EIO;
995}
996
997static int
998efct_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
1013static int
1014efct_vport_disable(struct fc_vport *fc_vport, bool disable)
1015{
1016	return 0;
1017}
1018
1019static 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
1068static 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