linux/drivers/scsi/elx/efct/efct_xport.c
<<
>>
Prefs
   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};
1112