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