xref: /linux/drivers/scsi/elx/efct/efct_xport.c (revision 5e3992fe72748ed3892be876f09d4d990548b7af)
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 *
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 };
1112