Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
0004  * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
0005  */
0006 
0007 #include "efct_driver.h"
0008 #include "efct_unsol.h"
0009 
0010 static struct dentry *efct_debugfs_root;
0011 static atomic_t efct_debugfs_count;
0012 
0013 static struct scsi_host_template efct_template = {
0014     .module         = THIS_MODULE,
0015     .name           = EFCT_DRIVER_NAME,
0016     .supported_mode     = MODE_TARGET,
0017 };
0018 
0019 /* globals */
0020 static struct fc_function_template efct_xport_functions;
0021 static struct fc_function_template efct_vport_functions;
0022 
0023 static struct scsi_transport_template *efct_xport_fc_tt;
0024 static struct scsi_transport_template *efct_vport_fc_tt;
0025 
0026 struct efct_xport *
0027 efct_xport_alloc(struct efct *efct)
0028 {
0029     struct efct_xport *xport;
0030 
0031     xport = kzalloc(sizeof(*xport), GFP_KERNEL);
0032     if (!xport)
0033         return xport;
0034 
0035     xport->efct = efct;
0036     return xport;
0037 }
0038 
0039 static int
0040 efct_xport_init_debugfs(struct efct *efct)
0041 {
0042     /* Setup efct debugfs root directory */
0043     if (!efct_debugfs_root) {
0044         efct_debugfs_root = debugfs_create_dir("efct", NULL);
0045         atomic_set(&efct_debugfs_count, 0);
0046     }
0047 
0048     /* Create a directory for sessions in root */
0049     if (!efct->sess_debugfs_dir) {
0050         efct->sess_debugfs_dir = debugfs_create_dir("sessions",
0051                             efct_debugfs_root);
0052         if (IS_ERR(efct->sess_debugfs_dir)) {
0053             efc_log_err(efct,
0054                     "failed to create debugfs entry for sessions\n");
0055             goto debugfs_fail;
0056         }
0057         atomic_inc(&efct_debugfs_count);
0058     }
0059 
0060     return 0;
0061 
0062 debugfs_fail:
0063     return -EIO;
0064 }
0065 
0066 static void efct_xport_delete_debugfs(struct efct *efct)
0067 {
0068     /* Remove session debugfs directory */
0069     debugfs_remove(efct->sess_debugfs_dir);
0070     efct->sess_debugfs_dir = NULL;
0071     atomic_dec(&efct_debugfs_count);
0072 
0073     if (atomic_read(&efct_debugfs_count) == 0) {
0074         /* remove root debugfs directory */
0075         debugfs_remove(efct_debugfs_root);
0076         efct_debugfs_root = NULL;
0077     }
0078 }
0079 
0080 int
0081 efct_xport_attach(struct efct_xport *xport)
0082 {
0083     struct efct *efct = xport->efct;
0084     int rc;
0085 
0086     rc = efct_hw_setup(&efct->hw, efct, efct->pci);
0087     if (rc) {
0088         efc_log_err(efct, "%s: Can't setup hardware\n", efct->desc);
0089         return rc;
0090     }
0091 
0092     efct_hw_parse_filter(&efct->hw, (void *)efct->filter_def);
0093 
0094     xport->io_pool = efct_io_pool_create(efct, efct->hw.config.n_sgl);
0095     if (!xport->io_pool) {
0096         efc_log_err(efct, "Can't allocate IO pool\n");
0097         return -ENOMEM;
0098     }
0099 
0100     return 0;
0101 }
0102 
0103 static void
0104 efct_xport_link_stats_cb(int status, u32 num_counters,
0105              struct efct_hw_link_stat_counts *counters, void *arg)
0106 {
0107     union efct_xport_stats_u *result = arg;
0108 
0109     result->stats.link_stats.link_failure_error_count =
0110         counters[EFCT_HW_LINK_STAT_LINK_FAILURE_COUNT].counter;
0111     result->stats.link_stats.loss_of_sync_error_count =
0112         counters[EFCT_HW_LINK_STAT_LOSS_OF_SYNC_COUNT].counter;
0113     result->stats.link_stats.primitive_sequence_error_count =
0114         counters[EFCT_HW_LINK_STAT_PRIMITIVE_SEQ_COUNT].counter;
0115     result->stats.link_stats.invalid_transmission_word_error_count =
0116         counters[EFCT_HW_LINK_STAT_INVALID_XMIT_WORD_COUNT].counter;
0117     result->stats.link_stats.crc_error_count =
0118         counters[EFCT_HW_LINK_STAT_CRC_COUNT].counter;
0119 
0120     complete(&result->stats.done);
0121 }
0122 
0123 static void
0124 efct_xport_host_stats_cb(int status, u32 num_counters,
0125              struct efct_hw_host_stat_counts *counters, void *arg)
0126 {
0127     union efct_xport_stats_u *result = arg;
0128 
0129     result->stats.host_stats.transmit_kbyte_count =
0130         counters[EFCT_HW_HOST_STAT_TX_KBYTE_COUNT].counter;
0131     result->stats.host_stats.receive_kbyte_count =
0132         counters[EFCT_HW_HOST_STAT_RX_KBYTE_COUNT].counter;
0133     result->stats.host_stats.transmit_frame_count =
0134         counters[EFCT_HW_HOST_STAT_TX_FRAME_COUNT].counter;
0135     result->stats.host_stats.receive_frame_count =
0136         counters[EFCT_HW_HOST_STAT_RX_FRAME_COUNT].counter;
0137 
0138     complete(&result->stats.done);
0139 }
0140 
0141 static void
0142 efct_xport_async_link_stats_cb(int status, u32 num_counters,
0143                    struct efct_hw_link_stat_counts *counters,
0144                    void *arg)
0145 {
0146     union efct_xport_stats_u *result = arg;
0147 
0148     result->stats.link_stats.link_failure_error_count =
0149         counters[EFCT_HW_LINK_STAT_LINK_FAILURE_COUNT].counter;
0150     result->stats.link_stats.loss_of_sync_error_count =
0151         counters[EFCT_HW_LINK_STAT_LOSS_OF_SYNC_COUNT].counter;
0152     result->stats.link_stats.primitive_sequence_error_count =
0153         counters[EFCT_HW_LINK_STAT_PRIMITIVE_SEQ_COUNT].counter;
0154     result->stats.link_stats.invalid_transmission_word_error_count =
0155         counters[EFCT_HW_LINK_STAT_INVALID_XMIT_WORD_COUNT].counter;
0156     result->stats.link_stats.crc_error_count =
0157         counters[EFCT_HW_LINK_STAT_CRC_COUNT].counter;
0158 }
0159 
0160 static void
0161 efct_xport_async_host_stats_cb(int status, u32 num_counters,
0162                    struct efct_hw_host_stat_counts *counters,
0163                    void *arg)
0164 {
0165     union efct_xport_stats_u *result = arg;
0166 
0167     result->stats.host_stats.transmit_kbyte_count =
0168         counters[EFCT_HW_HOST_STAT_TX_KBYTE_COUNT].counter;
0169     result->stats.host_stats.receive_kbyte_count =
0170         counters[EFCT_HW_HOST_STAT_RX_KBYTE_COUNT].counter;
0171     result->stats.host_stats.transmit_frame_count =
0172         counters[EFCT_HW_HOST_STAT_TX_FRAME_COUNT].counter;
0173     result->stats.host_stats.receive_frame_count =
0174         counters[EFCT_HW_HOST_STAT_RX_FRAME_COUNT].counter;
0175 }
0176 
0177 static void
0178 efct_xport_config_stats_timer(struct efct *efct);
0179 
0180 static void
0181 efct_xport_stats_timer_cb(struct timer_list *t)
0182 {
0183     struct efct_xport *xport = from_timer(xport, t, stats_timer);
0184     struct efct *efct = xport->efct;
0185 
0186     efct_xport_config_stats_timer(efct);
0187 }
0188 
0189 static void
0190 efct_xport_config_stats_timer(struct efct *efct)
0191 {
0192     u32 timeout = 3 * 1000;
0193     struct efct_xport *xport = NULL;
0194 
0195     if (!efct) {
0196         pr_err("%s: failed to locate EFCT device\n", __func__);
0197         return;
0198     }
0199 
0200     xport = efct->xport;
0201     efct_hw_get_link_stats(&efct->hw, 0, 0, 0,
0202                    efct_xport_async_link_stats_cb,
0203                    &xport->fc_xport_stats);
0204     efct_hw_get_host_stats(&efct->hw, 0, efct_xport_async_host_stats_cb,
0205                    &xport->fc_xport_stats);
0206 
0207     timer_setup(&xport->stats_timer,
0208             &efct_xport_stats_timer_cb, 0);
0209     mod_timer(&xport->stats_timer,
0210           jiffies + msecs_to_jiffies(timeout));
0211 }
0212 
0213 int
0214 efct_xport_initialize(struct efct_xport *xport)
0215 {
0216     struct efct *efct = xport->efct;
0217     int rc = 0;
0218 
0219     /* Initialize io lists */
0220     spin_lock_init(&xport->io_pending_lock);
0221     INIT_LIST_HEAD(&xport->io_pending_list);
0222     atomic_set(&xport->io_active_count, 0);
0223     atomic_set(&xport->io_pending_count, 0);
0224     atomic_set(&xport->io_total_free, 0);
0225     atomic_set(&xport->io_total_pending, 0);
0226     atomic_set(&xport->io_alloc_failed_count, 0);
0227     atomic_set(&xport->io_pending_recursing, 0);
0228 
0229     rc = efct_hw_init(&efct->hw);
0230     if (rc) {
0231         efc_log_err(efct, "efct_hw_init failure\n");
0232         goto out;
0233     }
0234 
0235     rc = efct_scsi_tgt_new_device(efct);
0236     if (rc) {
0237         efc_log_err(efct, "failed to initialize target\n");
0238         goto hw_init_out;
0239     }
0240 
0241     rc = efct_scsi_new_device(efct);
0242     if (rc) {
0243         efc_log_err(efct, "failed to initialize initiator\n");
0244         goto tgt_dev_out;
0245     }
0246 
0247     /* Get FC link and host statistics perodically*/
0248     efct_xport_config_stats_timer(efct);
0249 
0250     efct_xport_init_debugfs(efct);
0251 
0252     return rc;
0253 
0254 tgt_dev_out:
0255     efct_scsi_tgt_del_device(efct);
0256 
0257 hw_init_out:
0258     efct_hw_teardown(&efct->hw);
0259 out:
0260     return rc;
0261 }
0262 
0263 int
0264 efct_xport_status(struct efct_xport *xport, enum efct_xport_status cmd,
0265           union efct_xport_stats_u *result)
0266 {
0267     int rc = 0;
0268     struct efct *efct = NULL;
0269     union efct_xport_stats_u value;
0270 
0271     efct = xport->efct;
0272 
0273     switch (cmd) {
0274     case EFCT_XPORT_CONFIG_PORT_STATUS:
0275         if (xport->configured_link_state == 0) {
0276             /*
0277              * Initial state is offline. configured_link_state is
0278              * set to online explicitly when port is brought online
0279              */
0280             xport->configured_link_state = EFCT_XPORT_PORT_OFFLINE;
0281         }
0282         result->value = xport->configured_link_state;
0283         break;
0284 
0285     case EFCT_XPORT_PORT_STATUS:
0286         /* Determine port status based on link speed. */
0287         value.value = efct_hw_get_link_speed(&efct->hw);
0288         if (value.value == 0)
0289             result->value = EFCT_XPORT_PORT_OFFLINE;
0290         else
0291             result->value = EFCT_XPORT_PORT_ONLINE;
0292         break;
0293 
0294     case EFCT_XPORT_LINK_SPEED:
0295         result->value = efct_hw_get_link_speed(&efct->hw);
0296         break;
0297 
0298     case EFCT_XPORT_LINK_STATISTICS:
0299         memcpy((void *)result, &efct->xport->fc_xport_stats,
0300                sizeof(union efct_xport_stats_u));
0301         break;
0302     case EFCT_XPORT_LINK_STAT_RESET: {
0303         /* Create a completion to synchronize the stat reset process */
0304         init_completion(&result->stats.done);
0305 
0306         /* First reset the link stats */
0307         rc = efct_hw_get_link_stats(&efct->hw, 0, 1, 1,
0308                         efct_xport_link_stats_cb, result);
0309         if (rc)
0310             break;
0311 
0312         /* Wait for completion to be signaled when the cmd completes */
0313         if (wait_for_completion_interruptible(&result->stats.done)) {
0314             /* Undefined failure */
0315             efc_log_debug(efct, "sem wait failed\n");
0316             rc = -EIO;
0317             break;
0318         }
0319 
0320         /* Next reset the host stats */
0321         rc = efct_hw_get_host_stats(&efct->hw, 1,
0322                         efct_xport_host_stats_cb, result);
0323 
0324         if (rc)
0325             break;
0326 
0327         /* Wait for completion to be signaled when the cmd completes */
0328         if (wait_for_completion_interruptible(&result->stats.done)) {
0329             /* Undefined failure */
0330             efc_log_debug(efct, "sem wait failed\n");
0331             rc = -EIO;
0332             break;
0333         }
0334         break;
0335     }
0336     default:
0337         rc = -EIO;
0338         break;
0339     }
0340 
0341     return rc;
0342 }
0343 
0344 static int
0345 efct_get_link_supported_speeds(struct efct *efct)
0346 {
0347     u32 supported_speeds = 0;
0348     u32 link_module_type, i;
0349     struct {
0350         u32 lmt_speed;
0351         u32 speed;
0352     } supported_speed_list[] = {
0353         {SLI4_LINK_MODULE_TYPE_1GB, FC_PORTSPEED_1GBIT},
0354         {SLI4_LINK_MODULE_TYPE_2GB, FC_PORTSPEED_2GBIT},
0355         {SLI4_LINK_MODULE_TYPE_4GB, FC_PORTSPEED_4GBIT},
0356         {SLI4_LINK_MODULE_TYPE_8GB, FC_PORTSPEED_8GBIT},
0357         {SLI4_LINK_MODULE_TYPE_16GB, FC_PORTSPEED_16GBIT},
0358         {SLI4_LINK_MODULE_TYPE_32GB, FC_PORTSPEED_32GBIT},
0359         {SLI4_LINK_MODULE_TYPE_64GB, FC_PORTSPEED_64GBIT},
0360         {SLI4_LINK_MODULE_TYPE_128GB, FC_PORTSPEED_128GBIT},
0361     };
0362 
0363     link_module_type = sli_get_lmt(&efct->hw.sli);
0364 
0365     /* populate link supported speeds */
0366     for (i = 0; i < ARRAY_SIZE(supported_speed_list); i++) {
0367         if (link_module_type & supported_speed_list[i].lmt_speed)
0368             supported_speeds |= supported_speed_list[i].speed;
0369     }
0370 
0371     return supported_speeds;
0372 }
0373 
0374 int
0375 efct_scsi_new_device(struct efct *efct)
0376 {
0377     struct Scsi_Host *shost = NULL;
0378     int error = 0;
0379     struct efct_vport *vport = NULL;
0380 
0381     shost = scsi_host_alloc(&efct_template, sizeof(*vport));
0382     if (!shost) {
0383         efc_log_err(efct, "failed to allocate Scsi_Host struct\n");
0384         return -ENOMEM;
0385     }
0386 
0387     /* save shost to initiator-client context */
0388     efct->shost = shost;
0389 
0390     /* save efct information to shost LLD-specific space */
0391     vport = (struct efct_vport *)shost->hostdata;
0392     vport->efct = efct;
0393 
0394     /*
0395      * Set initial can_queue value to the max SCSI IOs. This is the maximum
0396      * global queue depth (as opposed to the per-LUN queue depth --
0397      * .cmd_per_lun This may need to be adjusted for I+T mode.
0398      */
0399     shost->can_queue = efct->hw.config.n_io;
0400     shost->max_cmd_len = 16; /* 16-byte CDBs */
0401     shost->max_id = 0xffff;
0402     shost->max_lun = 0xffffffff;
0403 
0404     /*
0405      * can only accept (from mid-layer) as many SGEs as we've
0406      * pre-registered
0407      */
0408     shost->sg_tablesize = sli_get_max_sgl(&efct->hw.sli);
0409 
0410     /* attach FC Transport template to shost */
0411     shost->transportt = efct_xport_fc_tt;
0412     efc_log_debug(efct, "transport template=%p\n", efct_xport_fc_tt);
0413 
0414     /* get pci_dev structure and add host to SCSI ML */
0415     error = scsi_add_host_with_dma(shost, &efct->pci->dev,
0416                        &efct->pci->dev);
0417     if (error) {
0418         efc_log_debug(efct, "failed scsi_add_host_with_dma\n");
0419         return -EIO;
0420     }
0421 
0422     /* Set symbolic name for host port */
0423     snprintf(fc_host_symbolic_name(shost),
0424          sizeof(fc_host_symbolic_name(shost)),
0425              "Emulex %s FV%s DV%s", efct->model,
0426              efct->hw.sli.fw_name[0], EFCT_DRIVER_VERSION);
0427 
0428     /* Set host port supported classes */
0429     fc_host_supported_classes(shost) = FC_COS_CLASS3;
0430 
0431     fc_host_supported_speeds(shost) = efct_get_link_supported_speeds(efct);
0432 
0433     fc_host_node_name(shost) = efct_get_wwnn(&efct->hw);
0434     fc_host_port_name(shost) = efct_get_wwpn(&efct->hw);
0435     fc_host_max_npiv_vports(shost) = 128;
0436 
0437     return 0;
0438 }
0439 
0440 struct scsi_transport_template *
0441 efct_attach_fc_transport(void)
0442 {
0443     struct scsi_transport_template *efct_fc_template = NULL;
0444 
0445     efct_fc_template = fc_attach_transport(&efct_xport_functions);
0446 
0447     if (!efct_fc_template)
0448         pr_err("failed to attach EFCT with fc transport\n");
0449 
0450     return efct_fc_template;
0451 }
0452 
0453 struct scsi_transport_template *
0454 efct_attach_vport_fc_transport(void)
0455 {
0456     struct scsi_transport_template *efct_fc_template = NULL;
0457 
0458     efct_fc_template = fc_attach_transport(&efct_vport_functions);
0459 
0460     if (!efct_fc_template)
0461         pr_err("failed to attach EFCT with fc transport\n");
0462 
0463     return efct_fc_template;
0464 }
0465 
0466 int
0467 efct_scsi_reg_fc_transport(void)
0468 {
0469     /* attach to appropriate scsi_tranport_* module */
0470     efct_xport_fc_tt = efct_attach_fc_transport();
0471     if (!efct_xport_fc_tt) {
0472         pr_err("%s: failed to attach to scsi_transport_*", __func__);
0473         return -EIO;
0474     }
0475 
0476     efct_vport_fc_tt = efct_attach_vport_fc_transport();
0477     if (!efct_vport_fc_tt) {
0478         pr_err("%s: failed to attach to scsi_transport_*", __func__);
0479         efct_release_fc_transport(efct_xport_fc_tt);
0480         efct_xport_fc_tt = NULL;
0481         return -EIO;
0482     }
0483 
0484     return 0;
0485 }
0486 
0487 void
0488 efct_scsi_release_fc_transport(void)
0489 {
0490     /* detach from scsi_transport_* */
0491     efct_release_fc_transport(efct_xport_fc_tt);
0492     efct_xport_fc_tt = NULL;
0493     if (efct_vport_fc_tt)
0494         efct_release_fc_transport(efct_vport_fc_tt);
0495 
0496     efct_vport_fc_tt = NULL;
0497 }
0498 
0499 void
0500 efct_xport_detach(struct efct_xport *xport)
0501 {
0502     struct efct *efct = xport->efct;
0503 
0504     /* free resources associated with target-server and initiator-client */
0505     efct_scsi_tgt_del_device(efct);
0506 
0507     efct_scsi_del_device(efct);
0508 
0509     /*Shutdown FC Statistics timer*/
0510     if (timer_pending(&xport->stats_timer))
0511         del_timer(&xport->stats_timer);
0512 
0513     efct_hw_teardown(&efct->hw);
0514 
0515     efct_xport_delete_debugfs(efct);
0516 }
0517 
0518 static void
0519 efct_xport_domain_free_cb(struct efc *efc, void *arg)
0520 {
0521     struct completion *done = arg;
0522 
0523     complete(done);
0524 }
0525 
0526 int
0527 efct_xport_control(struct efct_xport *xport, enum efct_xport_ctrl cmd, ...)
0528 {
0529     u32 rc = 0;
0530     struct efct *efct = NULL;
0531     va_list argp;
0532 
0533     efct = xport->efct;
0534 
0535     switch (cmd) {
0536     case EFCT_XPORT_PORT_ONLINE: {
0537         /* Bring the port on-line */
0538         rc = efct_hw_port_control(&efct->hw, EFCT_HW_PORT_INIT, 0,
0539                       NULL, NULL);
0540         if (rc)
0541             efc_log_err(efct,
0542                     "%s: Can't init port\n", efct->desc);
0543         else
0544             xport->configured_link_state = cmd;
0545         break;
0546     }
0547     case EFCT_XPORT_PORT_OFFLINE: {
0548         if (efct_hw_port_control(&efct->hw, EFCT_HW_PORT_SHUTDOWN, 0,
0549                      NULL, NULL))
0550             efc_log_err(efct, "port shutdown failed\n");
0551         else
0552             xport->configured_link_state = cmd;
0553         break;
0554     }
0555 
0556     case EFCT_XPORT_SHUTDOWN: {
0557         struct completion done;
0558         unsigned long timeout;
0559 
0560         /* if a PHYSDEV reset was performed (e.g. hw dump), will affect
0561          * all PCI functions; orderly shutdown won't work,
0562          * just force free
0563          */
0564         if (sli_reset_required(&efct->hw.sli)) {
0565             struct efc_domain *domain = efct->efcport->domain;
0566 
0567             if (domain)
0568                 efc_domain_cb(efct->efcport, EFC_HW_DOMAIN_LOST,
0569                           domain);
0570         } else {
0571             efct_hw_port_control(&efct->hw, EFCT_HW_PORT_SHUTDOWN,
0572                          0, NULL, NULL);
0573         }
0574 
0575         init_completion(&done);
0576 
0577         efc_register_domain_free_cb(efct->efcport,
0578                         efct_xport_domain_free_cb, &done);
0579 
0580         efc_log_debug(efct, "Waiting %d seconds for domain shutdown\n",
0581                   (EFC_SHUTDOWN_TIMEOUT_USEC / 1000000));
0582 
0583         timeout = usecs_to_jiffies(EFC_SHUTDOWN_TIMEOUT_USEC);
0584         if (!wait_for_completion_timeout(&done, timeout)) {
0585             efc_log_err(efct, "Domain shutdown timed out!!\n");
0586             WARN_ON(1);
0587         }
0588 
0589         efc_register_domain_free_cb(efct->efcport, NULL, NULL);
0590 
0591         /* Free up any saved virtual ports */
0592         efc_vport_del_all(efct->efcport);
0593         break;
0594     }
0595 
0596     /*
0597      * Set wwnn for the port. This will be used instead of the default
0598      * provided by FW.
0599      */
0600     case EFCT_XPORT_WWNN_SET: {
0601         u64 wwnn;
0602 
0603         /* Retrieve arguments */
0604         va_start(argp, cmd);
0605         wwnn = va_arg(argp, uint64_t);
0606         va_end(argp);
0607 
0608         efc_log_debug(efct, " WWNN %016llx\n", wwnn);
0609         xport->req_wwnn = wwnn;
0610 
0611         break;
0612     }
0613     /*
0614      * Set wwpn for the port. This will be used instead of the default
0615      * provided by FW.
0616      */
0617     case EFCT_XPORT_WWPN_SET: {
0618         u64 wwpn;
0619 
0620         /* Retrieve arguments */
0621         va_start(argp, cmd);
0622         wwpn = va_arg(argp, uint64_t);
0623         va_end(argp);
0624 
0625         efc_log_debug(efct, " WWPN %016llx\n", wwpn);
0626         xport->req_wwpn = wwpn;
0627 
0628         break;
0629     }
0630 
0631     default:
0632         break;
0633     }
0634     return rc;
0635 }
0636 
0637 void
0638 efct_xport_free(struct efct_xport *xport)
0639 {
0640     if (xport) {
0641         efct_io_pool_free(xport->io_pool);
0642 
0643         kfree(xport);
0644     }
0645 }
0646 
0647 void
0648 efct_release_fc_transport(struct scsi_transport_template *transport_template)
0649 {
0650     if (transport_template)
0651         pr_err("releasing transport layer\n");
0652 
0653     /* Releasing FC transport */
0654     fc_release_transport(transport_template);
0655 }
0656 
0657 static void
0658 efct_xport_remove_host(struct Scsi_Host *shost)
0659 {
0660     fc_remove_host(shost);
0661 }
0662 
0663 void
0664 efct_scsi_del_device(struct efct *efct)
0665 {
0666     if (!efct->shost)
0667         return;
0668 
0669     efc_log_debug(efct, "Unregistering with Transport Layer\n");
0670     efct_xport_remove_host(efct->shost);
0671     efc_log_debug(efct, "Unregistering with SCSI Midlayer\n");
0672     scsi_remove_host(efct->shost);
0673     scsi_host_put(efct->shost);
0674     efct->shost = NULL;
0675 }
0676 
0677 static void
0678 efct_get_host_port_id(struct Scsi_Host *shost)
0679 {
0680     struct efct_vport *vport = (struct efct_vport *)shost->hostdata;
0681     struct efct *efct = vport->efct;
0682     struct efc *efc = efct->efcport;
0683     struct efc_nport *nport;
0684 
0685     if (efc->domain && efc->domain->nport) {
0686         nport = efc->domain->nport;
0687         fc_host_port_id(shost) = nport->fc_id;
0688     }
0689 }
0690 
0691 static void
0692 efct_get_host_port_type(struct Scsi_Host *shost)
0693 {
0694     struct efct_vport *vport = (struct efct_vport *)shost->hostdata;
0695     struct efct *efct = vport->efct;
0696     struct efc *efc = efct->efcport;
0697     int type = FC_PORTTYPE_UNKNOWN;
0698 
0699     if (efc->domain && efc->domain->nport) {
0700         if (efc->domain->is_loop) {
0701             type = FC_PORTTYPE_LPORT;
0702         } else {
0703             struct efc_nport *nport = efc->domain->nport;
0704 
0705             if (nport->is_vport)
0706                 type = FC_PORTTYPE_NPIV;
0707             else if (nport->topology == EFC_NPORT_TOPO_P2P)
0708                 type = FC_PORTTYPE_PTP;
0709             else if (nport->topology == EFC_NPORT_TOPO_UNKNOWN)
0710                 type = FC_PORTTYPE_UNKNOWN;
0711             else
0712                 type = FC_PORTTYPE_NPORT;
0713         }
0714     }
0715     fc_host_port_type(shost) = type;
0716 }
0717 
0718 static void
0719 efct_get_host_vport_type(struct Scsi_Host *shost)
0720 {
0721     fc_host_port_type(shost) = FC_PORTTYPE_NPIV;
0722 }
0723 
0724 static void
0725 efct_get_host_port_state(struct Scsi_Host *shost)
0726 {
0727     struct efct_vport *vport = (struct efct_vport *)shost->hostdata;
0728     struct efct *efct = vport->efct;
0729     union efct_xport_stats_u status;
0730     int rc;
0731 
0732     rc = efct_xport_status(efct->xport, EFCT_XPORT_PORT_STATUS, &status);
0733     if ((!rc) && (status.value == EFCT_XPORT_PORT_ONLINE))
0734         fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;
0735     else
0736         fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
0737 }
0738 
0739 static void
0740 efct_get_host_speed(struct Scsi_Host *shost)
0741 {
0742     struct efct_vport *vport = (struct efct_vport *)shost->hostdata;
0743     struct efct *efct = vport->efct;
0744     struct efc *efc = efct->efcport;
0745     union efct_xport_stats_u speed;
0746     u32 fc_speed = FC_PORTSPEED_UNKNOWN;
0747     int rc;
0748 
0749     if (!efc->domain || !efc->domain->nport) {
0750         fc_host_speed(shost) = fc_speed;
0751         return;
0752     }
0753 
0754     rc = efct_xport_status(efct->xport, EFCT_XPORT_LINK_SPEED, &speed);
0755     if (!rc) {
0756         switch (speed.value) {
0757         case 1000:
0758             fc_speed = FC_PORTSPEED_1GBIT;
0759             break;
0760         case 2000:
0761             fc_speed = FC_PORTSPEED_2GBIT;
0762             break;
0763         case 4000:
0764             fc_speed = FC_PORTSPEED_4GBIT;
0765             break;
0766         case 8000:
0767             fc_speed = FC_PORTSPEED_8GBIT;
0768             break;
0769         case 10000:
0770             fc_speed = FC_PORTSPEED_10GBIT;
0771             break;
0772         case 16000:
0773             fc_speed = FC_PORTSPEED_16GBIT;
0774             break;
0775         case 32000:
0776             fc_speed = FC_PORTSPEED_32GBIT;
0777             break;
0778         case 64000:
0779             fc_speed = FC_PORTSPEED_64GBIT;
0780             break;
0781         case 128000:
0782             fc_speed = FC_PORTSPEED_128GBIT;
0783             break;
0784         }
0785     }
0786 
0787     fc_host_speed(shost) = fc_speed;
0788 }
0789 
0790 static void
0791 efct_get_host_fabric_name(struct Scsi_Host *shost)
0792 {
0793     struct efct_vport *vport = (struct efct_vport *)shost->hostdata;
0794     struct efct *efct = vport->efct;
0795     struct efc *efc = efct->efcport;
0796 
0797     if (efc->domain) {
0798         struct fc_els_flogi  *sp =
0799             (struct fc_els_flogi  *)
0800                 efc->domain->flogi_service_params;
0801 
0802         fc_host_fabric_name(shost) = be64_to_cpu(sp->fl_wwnn);
0803     }
0804 }
0805 
0806 static struct fc_host_statistics *
0807 efct_get_stats(struct Scsi_Host *shost)
0808 {
0809     struct efct_vport *vport = (struct efct_vport *)shost->hostdata;
0810     struct efct *efct = vport->efct;
0811     union efct_xport_stats_u stats;
0812     struct efct_xport *xport = efct->xport;
0813     int rc = 0;
0814 
0815     rc = efct_xport_status(xport, EFCT_XPORT_LINK_STATISTICS, &stats);
0816     if (rc) {
0817         pr_err("efct_xport_status returned non 0 - %d\n", rc);
0818         return NULL;
0819     }
0820 
0821     vport->fc_host_stats.loss_of_sync_count =
0822         stats.stats.link_stats.loss_of_sync_error_count;
0823     vport->fc_host_stats.link_failure_count =
0824         stats.stats.link_stats.link_failure_error_count;
0825     vport->fc_host_stats.prim_seq_protocol_err_count =
0826         stats.stats.link_stats.primitive_sequence_error_count;
0827     vport->fc_host_stats.invalid_tx_word_count =
0828         stats.stats.link_stats.invalid_transmission_word_error_count;
0829     vport->fc_host_stats.invalid_crc_count =
0830         stats.stats.link_stats.crc_error_count;
0831     /* mbox returns kbyte count so we need to convert to words */
0832     vport->fc_host_stats.tx_words =
0833         stats.stats.host_stats.transmit_kbyte_count * 256;
0834     /* mbox returns kbyte count so we need to convert to words */
0835     vport->fc_host_stats.rx_words =
0836         stats.stats.host_stats.receive_kbyte_count * 256;
0837     vport->fc_host_stats.tx_frames =
0838         stats.stats.host_stats.transmit_frame_count;
0839     vport->fc_host_stats.rx_frames =
0840         stats.stats.host_stats.receive_frame_count;
0841 
0842     vport->fc_host_stats.fcp_input_requests =
0843             xport->fcp_stats.input_requests;
0844     vport->fc_host_stats.fcp_output_requests =
0845             xport->fcp_stats.output_requests;
0846     vport->fc_host_stats.fcp_output_megabytes =
0847             xport->fcp_stats.output_bytes >> 20;
0848     vport->fc_host_stats.fcp_input_megabytes =
0849             xport->fcp_stats.input_bytes >> 20;
0850     vport->fc_host_stats.fcp_control_requests =
0851             xport->fcp_stats.control_requests;
0852 
0853     return &vport->fc_host_stats;
0854 }
0855 
0856 static void
0857 efct_reset_stats(struct Scsi_Host *shost)
0858 {
0859     struct efct_vport *vport = (struct efct_vport *)shost->hostdata;
0860     struct efct *efct = vport->efct;
0861     /* argument has no purpose for this action */
0862     union efct_xport_stats_u dummy;
0863     int rc;
0864 
0865     rc = efct_xport_status(efct->xport, EFCT_XPORT_LINK_STAT_RESET, &dummy);
0866     if (rc)
0867         pr_err("efct_xport_status returned non 0 - %d\n", rc);
0868 }
0869 
0870 static int
0871 efct_issue_lip(struct Scsi_Host *shost)
0872 {
0873     struct efct_vport *vport =
0874             shost ? (struct efct_vport *)shost->hostdata : NULL;
0875     struct efct *efct = vport ? vport->efct : NULL;
0876 
0877     if (!shost || !vport || !efct) {
0878         pr_err("%s: shost=%p vport=%p efct=%p\n", __func__,
0879                shost, vport, efct);
0880         return -EPERM;
0881     }
0882 
0883     /*
0884      * Bring the link down gracefully then re-init the link.
0885      * The firmware will re-initialize the Fibre Channel interface as
0886      * required. It does not issue a LIP.
0887      */
0888 
0889     if (efct_xport_control(efct->xport, EFCT_XPORT_PORT_OFFLINE))
0890         efc_log_debug(efct, "EFCT_XPORT_PORT_OFFLINE failed\n");
0891 
0892     if (efct_xport_control(efct->xport, EFCT_XPORT_PORT_ONLINE))
0893         efc_log_debug(efct, "EFCT_XPORT_PORT_ONLINE failed\n");
0894 
0895     return 0;
0896 }
0897 
0898 struct efct_vport *
0899 efct_scsi_new_vport(struct efct *efct, struct device *dev)
0900 {
0901     struct Scsi_Host *shost = NULL;
0902     int error = 0;
0903     struct efct_vport *vport = NULL;
0904 
0905     shost = scsi_host_alloc(&efct_template, sizeof(*vport));
0906     if (!shost) {
0907         efc_log_err(efct, "failed to allocate Scsi_Host struct\n");
0908         return NULL;
0909     }
0910 
0911     /* save efct information to shost LLD-specific space */
0912     vport = (struct efct_vport *)shost->hostdata;
0913     vport->efct = efct;
0914     vport->is_vport = true;
0915 
0916     shost->can_queue = efct->hw.config.n_io;
0917     shost->max_cmd_len = 16; /* 16-byte CDBs */
0918     shost->max_id = 0xffff;
0919     shost->max_lun = 0xffffffff;
0920 
0921     /* can only accept (from mid-layer) as many SGEs as we've pre-regited*/
0922     shost->sg_tablesize = sli_get_max_sgl(&efct->hw.sli);
0923 
0924     /* attach FC Transport template to shost */
0925     shost->transportt = efct_vport_fc_tt;
0926     efc_log_debug(efct, "vport transport template=%p\n",
0927               efct_vport_fc_tt);
0928 
0929     /* get pci_dev structure and add host to SCSI ML */
0930     error = scsi_add_host_with_dma(shost, dev, &efct->pci->dev);
0931     if (error) {
0932         efc_log_debug(efct, "failed scsi_add_host_with_dma\n");
0933         return NULL;
0934     }
0935 
0936     /* Set symbolic name for host port */
0937     snprintf(fc_host_symbolic_name(shost),
0938          sizeof(fc_host_symbolic_name(shost)),
0939          "Emulex %s FV%s DV%s", efct->model, efct->hw.sli.fw_name[0],
0940          EFCT_DRIVER_VERSION);
0941 
0942     /* Set host port supported classes */
0943     fc_host_supported_classes(shost) = FC_COS_CLASS3;
0944 
0945     fc_host_supported_speeds(shost) = efct_get_link_supported_speeds(efct);
0946     vport->shost = shost;
0947 
0948     return vport;
0949 }
0950 
0951 int efct_scsi_del_vport(struct efct *efct, struct Scsi_Host *shost)
0952 {
0953     if (shost) {
0954         efc_log_debug(efct,
0955                   "Unregistering vport with Transport Layer\n");
0956         efct_xport_remove_host(shost);
0957         efc_log_debug(efct, "Unregistering vport with SCSI Midlayer\n");
0958         scsi_remove_host(shost);
0959         scsi_host_put(shost);
0960         return 0;
0961     }
0962     return -EIO;
0963 }
0964 
0965 static int
0966 efct_vport_create(struct fc_vport *fc_vport, bool disable)
0967 {
0968     struct Scsi_Host *shost = fc_vport ? fc_vport->shost : NULL;
0969     struct efct_vport *pport = shost ?
0970                     (struct efct_vport *)shost->hostdata :
0971                     NULL;
0972     struct efct *efct = pport ? pport->efct : NULL;
0973     struct efct_vport *vport = NULL;
0974 
0975     if (!fc_vport || !shost || !efct)
0976         goto fail;
0977 
0978     vport = efct_scsi_new_vport(efct, &fc_vport->dev);
0979     if (!vport) {
0980         efc_log_err(efct, "failed to create vport\n");
0981         goto fail;
0982     }
0983 
0984     vport->fc_vport = fc_vport;
0985     vport->npiv_wwpn = fc_vport->port_name;
0986     vport->npiv_wwnn = fc_vport->node_name;
0987     fc_host_node_name(vport->shost) = vport->npiv_wwnn;
0988     fc_host_port_name(vport->shost) = vport->npiv_wwpn;
0989     *(struct efct_vport **)fc_vport->dd_data = vport;
0990 
0991     return 0;
0992 
0993 fail:
0994     return -EIO;
0995 }
0996 
0997 static int
0998 efct_vport_delete(struct fc_vport *fc_vport)
0999 {
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 
1013 static int
1014 efct_vport_disable(struct fc_vport *fc_vport, bool disable)
1015 {
1016     return 0;
1017 }
1018 
1019 static 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 
1068 static 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 };