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