cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

efct_xport.c (28814B)


      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 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};