brintos

brintos / linux-shallow public Read only

0
0
Text · 28.1 KiB · cf4dced Raw
1112 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2021 Broadcom. All Rights Reserved. The term4 * “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 int40efct_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 80int81efct_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 void104efct_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 void124efct_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 void142efct_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 void161efct_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 void178efct_xport_config_stats_timer(struct efct *efct);179 180static void181efct_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 void190efct_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 213int214efct_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 263int264efct_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 is278			 * set to online explicitly when port is brought online279			 */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		else291			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 int345efct_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 374int375efct_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 maximum396	 * 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've406	 * pre-registered407	 */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 466int467efct_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 487void488efct_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 499void500efct_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 void519efct_xport_domain_free_cb(struct efc *efc, void *arg)520{521	struct completion *done = arg;522 523	complete(done);524}525 526int527efct_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		else544			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		else552			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 affect561		 * all PCI functions; orderly shutdown won't work,562		 * just force free563		 */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 default598	 * 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 default615	 * 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 637void638efct_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 647void648efct_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 void658efct_xport_remove_host(struct Scsi_Host *shost)659{660	fc_remove_host(shost);661}662 663void664efct_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 void678efct_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 void692efct_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			else712				type = FC_PORTTYPE_NPORT;713		}714	}715	fc_host_port_type(shost) = type;716}717 718static void719efct_get_host_vport_type(struct Scsi_Host *shost)720{721	fc_host_port_type(shost) = FC_PORTTYPE_NPIV;722}723 724static void725efct_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	else736		fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;737}738 739static void740efct_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 void791efct_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 void857efct_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 int871efct_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 as886	 * 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 int966efct_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 int998efct_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 int1014efct_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