The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ocs_fc/ocs_xport.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2017 Broadcom. All rights reserved.
    3  * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions are met:
    7  *
    8  * 1. Redistributions of source code must retain the above copyright notice,
    9  *    this list of conditions and the following disclaimer.
   10  *
   11  * 2. Redistributions in binary form must reproduce the above copyright notice,
   12  *    this list of conditions and the following disclaimer in the documentation
   13  *    and/or other materials provided with the distribution.
   14  *
   15  * 3. Neither the name of the copyright holder nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  *
   31  * $FreeBSD$
   32  */
   33 
   34 /**
   35  * @file
   36  * FC transport API
   37  *
   38  */
   39 
   40 #include "ocs.h"
   41 #include "ocs_device.h"
   42 
   43 static void ocs_xport_link_stats_cb(int32_t status, uint32_t num_counters, ocs_hw_link_stat_counts_t *counters, void *arg);
   44 static void ocs_xport_host_stats_cb(int32_t status, uint32_t num_counters, ocs_hw_host_stat_counts_t *counters, void *arg);
   45 /**
   46  * @brief Post node event callback argument.
   47  */
   48 typedef struct {
   49         ocs_sem_t sem;
   50         ocs_node_t *node;
   51         ocs_sm_event_t evt;
   52         void *context;
   53 } ocs_xport_post_node_event_t;
   54 
   55 /**
   56  * @brief Allocate a transport object.
   57  *
   58  * @par Description
   59  * A transport object is allocated, and associated with a device instance.
   60  *
   61  * @param ocs Pointer to device instance.
   62  *
   63  * @return Returns the pointer to the allocated transport object, or NULL if failed.
   64  */
   65 ocs_xport_t *
   66 ocs_xport_alloc(ocs_t *ocs)
   67 {
   68         ocs_xport_t *xport;
   69 
   70         ocs_assert(ocs, NULL);
   71         xport = ocs_malloc(ocs, sizeof(*xport), OCS_M_ZERO);
   72         if (xport != NULL) {
   73                 xport->ocs = ocs;
   74         }
   75         return xport;
   76 }
   77 
   78 /**
   79  * @brief Create the RQ threads and the circular buffers used to pass sequences.
   80  *
   81  * @par Description
   82  * Creates the circular buffers and the servicing threads for RQ processing.
   83  *
   84  * @param xport Pointer to transport object
   85  *
   86  * @return Returns 0 on success, or a non-zero value on failure.
   87  */
   88 static void
   89 ocs_xport_rq_threads_teardown(ocs_xport_t *xport)
   90 {
   91         ocs_t *ocs = xport->ocs;
   92         uint32_t i;
   93 
   94         if (xport->num_rq_threads == 0 ||
   95             xport->rq_thread_info == NULL) {
   96                 return;
   97         }
   98 
   99         /* Abort any threads */
  100         for (i = 0; i < xport->num_rq_threads; i++) {
  101                 if (xport->rq_thread_info[i].thread_started) {
  102                         ocs_thread_terminate(&xport->rq_thread_info[i].thread);
  103                         /* wait for the thread to exit */
  104                         ocs_log_debug(ocs, "wait for thread %d to exit\n", i);
  105                         while (xport->rq_thread_info[i].thread_started) {
  106                                 ocs_udelay(10000);
  107                         }
  108                         ocs_log_debug(ocs, "thread %d to exited\n", i);
  109                 }
  110                 if (xport->rq_thread_info[i].seq_cbuf != NULL) {
  111                         ocs_cbuf_free(xport->rq_thread_info[i].seq_cbuf);
  112                         xport->rq_thread_info[i].seq_cbuf = NULL;
  113                 }
  114         }
  115 }
  116 
  117 /**
  118  * @brief Create the RQ threads and the circular buffers used to pass sequences.
  119  *
  120  * @par Description
  121  * Creates the circular buffers and the servicing threads for RQ processing.
  122  *
  123  * @param xport Pointer to transport object.
  124  * @param num_rq_threads Number of RQ processing threads that the
  125  * driver creates.
  126  *
  127  * @return Returns 0 on success, or a non-zero value on failure.
  128  */
  129 static int32_t
  130 ocs_xport_rq_threads_create(ocs_xport_t *xport, uint32_t num_rq_threads)
  131 {
  132         ocs_t *ocs = xport->ocs;
  133         int32_t rc = 0;
  134         uint32_t i;
  135 
  136         xport->num_rq_threads = num_rq_threads;
  137         ocs_log_debug(ocs, "number of RQ threads %d\n", num_rq_threads);
  138         if (num_rq_threads == 0) {
  139                 return 0;
  140         }
  141 
  142         /* Allocate the space for the thread objects */
  143         xport->rq_thread_info = ocs_malloc(ocs, sizeof(ocs_xport_rq_thread_info_t) * num_rq_threads, OCS_M_ZERO);
  144         if (xport->rq_thread_info == NULL) {
  145                 ocs_log_err(ocs, "memory allocation failure\n");
  146                 return -1;
  147         }
  148 
  149         /* Create the circular buffers and threads. */
  150         for (i = 0; i < num_rq_threads; i++) {
  151                 xport->rq_thread_info[i].ocs = ocs;
  152                 xport->rq_thread_info[i].seq_cbuf = ocs_cbuf_alloc(ocs, OCS_HW_RQ_NUM_HDR);
  153                 if (xport->rq_thread_info[i].seq_cbuf == NULL) {
  154                         goto ocs_xport_rq_threads_create_error;
  155                 }
  156 
  157                 ocs_snprintf(xport->rq_thread_info[i].thread_name,
  158                              sizeof(xport->rq_thread_info[i].thread_name),
  159                              "ocs_unsol_rq:%d:%d", ocs->instance_index, i);
  160                 rc = ocs_thread_create(ocs, &xport->rq_thread_info[i].thread, ocs_unsol_rq_thread,
  161                                        xport->rq_thread_info[i].thread_name,
  162                                        &xport->rq_thread_info[i], OCS_THREAD_RUN);
  163                 if (rc) {
  164                         ocs_log_err(ocs, "ocs_thread_create failed: %d\n", rc);
  165                         goto ocs_xport_rq_threads_create_error;
  166                 }
  167                 xport->rq_thread_info[i].thread_started = TRUE;
  168         }
  169         return 0;
  170 
  171 ocs_xport_rq_threads_create_error:
  172         ocs_xport_rq_threads_teardown(xport);
  173         return -1;
  174 }
  175 
  176 /**
  177  * @brief Do as much allocation as possible, but do not initialization the device.
  178  *
  179  * @par Description
  180  * Performs the functions required to get a device ready to run.
  181  *
  182  * @param xport Pointer to transport object.
  183  *
  184  * @return Returns 0 on success, or a non-zero value on failure.
  185  */
  186 int32_t
  187 ocs_xport_attach(ocs_xport_t *xport)
  188 {
  189         ocs_t *ocs = xport->ocs;
  190         int32_t rc;
  191         uint32_t max_sgl;
  192         uint32_t n_sgl;
  193         uint32_t i;
  194         uint32_t value;
  195         uint32_t max_remote_nodes;
  196 
  197         /* booleans used for cleanup if initialization fails */
  198         uint8_t io_pool_created = FALSE;
  199         uint8_t node_pool_created = FALSE;
  200 
  201         ocs_list_init(&ocs->domain_list, ocs_domain_t, link);
  202 
  203         for (i = 0; i < SLI4_MAX_FCFI; i++) {
  204                 xport->fcfi[i].hold_frames = 1;
  205                 ocs_lock_init(ocs, &xport->fcfi[i].pend_frames_lock, "xport pend_frames[%d]", i);
  206                 ocs_list_init(&xport->fcfi[i].pend_frames, ocs_hw_sequence_t, link);
  207         }
  208 
  209         rc = ocs_hw_set_ptr(&ocs->hw, OCS_HW_WAR_VERSION, ocs->hw_war_version);
  210         if (rc) {
  211                 ocs_log_test(ocs, "can't set OCS_HW_WAR_VERSION\n");
  212                 return -1;
  213         }
  214 
  215         rc = ocs_hw_setup(&ocs->hw, ocs, SLI4_PORT_TYPE_FC);
  216         if (rc) {
  217                 ocs_log_err(ocs, "%s: Can't setup hardware\n", ocs->desc);
  218                 return -1;
  219         } else if (ocs->ctrlmask & OCS_CTRLMASK_CRASH_RESET) {
  220                 ocs_log_debug(ocs, "stopping after ocs_hw_setup\n");
  221                 return -1;
  222         }
  223 
  224         ocs_hw_set(&ocs->hw, OCS_HW_BOUNCE, ocs->hw_bounce);
  225         ocs_log_debug(ocs, "HW bounce: %d\n", ocs->hw_bounce);
  226 
  227         ocs_hw_set(&ocs->hw, OCS_HW_RQ_SELECTION_POLICY, ocs->rq_selection_policy);
  228         ocs_hw_set(&ocs->hw, OCS_HW_RR_QUANTA, ocs->rr_quanta);
  229         ocs_hw_get(&ocs->hw, OCS_HW_RQ_SELECTION_POLICY, &value);
  230         ocs_log_debug(ocs, "RQ Selection Policy: %d\n", value);
  231 
  232         ocs_hw_set_ptr(&ocs->hw, OCS_HW_FILTER_DEF, (void*) ocs->filter_def);
  233 
  234         ocs_hw_get(&ocs->hw, OCS_HW_MAX_SGL, &max_sgl);
  235         max_sgl -= SLI4_SGE_MAX_RESERVED;
  236         n_sgl = MIN(OCS_FC_MAX_SGL, max_sgl);
  237 
  238         /* EVT: For chained SGL testing */
  239         if (ocs->ctrlmask & OCS_CTRLMASK_TEST_CHAINED_SGLS) {
  240                 n_sgl = 4;
  241         }
  242 
  243         /* Note: number of SGLs must be set for ocs_node_create_pool */
  244         if (ocs_hw_set(&ocs->hw, OCS_HW_N_SGL, n_sgl) != OCS_HW_RTN_SUCCESS) {
  245                 ocs_log_err(ocs, "%s: Can't set number of SGLs\n", ocs->desc);
  246                 return -1;
  247         } else {
  248                 ocs_log_debug(ocs, "%s: Configured for %d SGLs\n", ocs->desc, n_sgl);
  249         }
  250 
  251         ocs_hw_get(&ocs->hw, OCS_HW_MAX_NODES, &max_remote_nodes);
  252 
  253         if (!ocs->max_remote_nodes)
  254                 ocs->max_remote_nodes = max_remote_nodes;
  255 
  256         rc = ocs_node_create_pool(ocs, ocs->max_remote_nodes);
  257         if (rc) {
  258                 ocs_log_err(ocs, "Can't allocate node pool\n");
  259                 goto ocs_xport_attach_cleanup;
  260         } else {
  261                 node_pool_created = TRUE;
  262         }
  263 
  264         /* EVT: if testing chained SGLs allocate OCS_FC_MAX_SGL SGE's in the IO */
  265         xport->io_pool = ocs_io_pool_create(ocs, ocs->num_scsi_ios,
  266                 (ocs->ctrlmask & OCS_CTRLMASK_TEST_CHAINED_SGLS) ? OCS_FC_MAX_SGL : n_sgl);
  267         if (xport->io_pool == NULL) {
  268                 ocs_log_err(ocs, "Can't allocate IO pool\n");
  269                 goto ocs_xport_attach_cleanup;
  270         } else {
  271                 io_pool_created = TRUE;
  272         }
  273 
  274         /*
  275          * setup the RQ processing threads
  276          */
  277         if (ocs_xport_rq_threads_create(xport, ocs->rq_threads) != 0) {
  278                 ocs_log_err(ocs, "failure creating RQ threads\n");
  279                 goto ocs_xport_attach_cleanup;
  280         }
  281 
  282         return 0;
  283 
  284 ocs_xport_attach_cleanup:
  285         if (io_pool_created) {
  286                 ocs_io_pool_free(xport->io_pool);
  287         }
  288 
  289         if (node_pool_created) {
  290                 ocs_node_free_pool(ocs);
  291         }
  292 
  293         return -1;
  294 }
  295 
  296 /**
  297  * @brief Determines how to setup auto Xfer ready.
  298  *
  299  * @par Description
  300  * @param xport Pointer to transport object.
  301  *
  302  * @return Returns 0 on success or a non-zero value on failure.
  303  */
  304 static int32_t
  305 ocs_xport_initialize_auto_xfer_ready(ocs_xport_t *xport)
  306 {
  307         ocs_t *ocs = xport->ocs;
  308         uint32_t auto_xfer_rdy;
  309         char prop_buf[32];
  310         uint32_t ramdisc_blocksize = 512;
  311         uint8_t p_type = 0;
  312 
  313         ocs_hw_get(&ocs->hw, OCS_HW_AUTO_XFER_RDY_CAPABLE, &auto_xfer_rdy);
  314         if (!auto_xfer_rdy) {
  315                 ocs->auto_xfer_rdy_size = 0;
  316                 ocs_log_test(ocs, "Cannot enable auto xfer rdy for this port\n");
  317                 return 0;
  318         }
  319 
  320         if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_SIZE, ocs->auto_xfer_rdy_size)) {
  321                 ocs_log_test(ocs, "%s: Can't set auto xfer rdy mode\n", ocs->desc);
  322                 return -1;
  323         }
  324 
  325         /*
  326          * Determine if we are doing protection in the backend. We are looking
  327          * at the modules parameters here. The backend cannot allow a format
  328          * command to change the protection mode when using this feature,
  329          * otherwise the firmware will not do the proper thing.
  330          */
  331         if (ocs_get_property("p_type", prop_buf, sizeof(prop_buf)) == 0) {
  332                 p_type = ocs_strtoul(prop_buf, 0, 0);
  333         }
  334         if (ocs_get_property("ramdisc_blocksize", prop_buf, sizeof(prop_buf)) == 0) {
  335                 ramdisc_blocksize = ocs_strtoul(prop_buf, 0, 0);
  336         }
  337         if (ocs_get_property("external_dif", prop_buf, sizeof(prop_buf)) == 0) {
  338                 if(ocs_strlen(prop_buf)) {
  339                         if (p_type == 0) {
  340                                 p_type = 1;
  341                         }
  342                 }
  343         }
  344 
  345         if (p_type != 0) {
  346                 if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_T10_ENABLE, TRUE)) {
  347                         ocs_log_test(ocs, "%s: Can't set auto xfer rdy mode\n", ocs->desc);
  348                         return -1;
  349                 }
  350                 if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_BLK_SIZE, ramdisc_blocksize)) {
  351                         ocs_log_test(ocs, "%s: Can't set auto xfer rdy blk size\n", ocs->desc);
  352                         return -1;
  353                 }
  354                 if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_P_TYPE, p_type)) {
  355                         ocs_log_test(ocs, "%s: Can't set auto xfer rdy mode\n", ocs->desc);
  356                         return -1;
  357                 }
  358                 if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_REF_TAG_IS_LBA, TRUE)) {
  359                         ocs_log_test(ocs, "%s: Can't set auto xfer rdy ref tag\n", ocs->desc);
  360                         return -1;
  361                 }
  362                 if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_APP_TAG_VALID, FALSE)) {
  363                         ocs_log_test(ocs, "%s: Can't set auto xfer rdy app tag valid\n", ocs->desc);
  364                         return -1;
  365                 }
  366         }
  367         ocs_log_debug(ocs, "Auto xfer rdy is enabled, p_type=%d, blksize=%d\n",
  368                 p_type, ramdisc_blocksize);
  369         return 0;
  370 }
  371 
  372 /**
  373  * @brief Initialize link topology config
  374  *
  375  * @par Description
  376  * Topology can be fetched from mod-param or Persistet Topology(PT).
  377  *  a. Mod-param value is used when the value is 1(P2P) or 2(LOOP).
  378  *  a. PT is used if mod-param is not provided( i.e, default value of AUTO)
  379  * Also, if mod-param is used, update PT.
  380  *
  381  * @param ocs Pointer to ocs
  382  *
  383  * @return Returns 0 on success, or a non-zero value on failure.
  384  */
  385 static int
  386 ocs_topology_setup(ocs_t *ocs)
  387 {
  388         uint32_t topology;
  389 
  390         if (ocs->topology == OCS_HW_TOPOLOGY_AUTO) {
  391                 topology = ocs_hw_get_config_persistent_topology(&ocs->hw);
  392         }  else {
  393                 topology = ocs->topology;
  394                 /* ignore failure here. link will come-up either in auto mode
  395                  * if PT is not supported or last saved PT value */
  396                 ocs_hw_set_persistent_topology(&ocs->hw, topology, OCS_CMD_POLL);
  397         }
  398 
  399         return ocs_hw_set(&ocs->hw, OCS_HW_TOPOLOGY, topology);
  400 }
  401 
  402 /**
  403  * @brief Initializes the device.
  404  *
  405  * @par Description
  406  * Performs the functions required to make a device functional.
  407  *
  408  * @param xport Pointer to transport object.
  409  *
  410  * @return Returns 0 on success, or a non-zero value on failure.
  411  */
  412 int32_t
  413 ocs_xport_initialize(ocs_xport_t *xport)
  414 {
  415         ocs_t *ocs = xport->ocs;
  416         int32_t rc;
  417         uint32_t i;
  418         uint32_t max_hw_io;
  419         uint32_t max_sgl;
  420         uint32_t hlm;
  421         uint32_t rq_limit;
  422         uint32_t dif_capable;
  423         uint8_t dif_separate = 0;
  424         char prop_buf[32];
  425 
  426         /* booleans used for cleanup if initialization fails */
  427         uint8_t ini_device_set = FALSE;
  428         uint8_t tgt_device_set = FALSE;
  429         uint8_t hw_initialized = FALSE;
  430 
  431         ocs_hw_get(&ocs->hw, OCS_HW_MAX_IO, &max_hw_io);
  432         if (ocs_hw_set(&ocs->hw, OCS_HW_N_IO, max_hw_io) != OCS_HW_RTN_SUCCESS) {
  433                 ocs_log_err(ocs, "%s: Can't set number of IOs\n", ocs->desc);
  434                 return -1;
  435         }
  436 
  437         ocs_hw_get(&ocs->hw, OCS_HW_MAX_SGL, &max_sgl);
  438         max_sgl -= SLI4_SGE_MAX_RESERVED;
  439 
  440         if (ocs->enable_hlm) {
  441                 ocs_hw_get(&ocs->hw, OCS_HW_HIGH_LOGIN_MODE, &hlm);
  442                 if (!hlm) {
  443                         ocs->enable_hlm = FALSE;
  444                         ocs_log_err(ocs, "Cannot enable high login mode for this port\n");
  445                 } else {
  446                         ocs_log_debug(ocs, "High login mode is enabled\n");
  447                         if (ocs_hw_set(&ocs->hw, OCS_HW_HIGH_LOGIN_MODE, TRUE)) {
  448                                 ocs_log_err(ocs, "%s: Can't set high login mode\n", ocs->desc);
  449                                 return -1;
  450                         }
  451                 }
  452         }
  453 
  454         /* validate the auto xfer_rdy size */
  455         if (ocs->auto_xfer_rdy_size > 0 &&
  456             (ocs->auto_xfer_rdy_size < 2048 ||
  457              ocs->auto_xfer_rdy_size > 65536)) {
  458                 ocs_log_err(ocs, "Auto XFER_RDY size is out of range (2K-64K)\n");
  459                 return -1;
  460         }
  461 
  462         ocs_hw_get(&ocs->hw, OCS_HW_MAX_IO, &max_hw_io);
  463 
  464         if (ocs->auto_xfer_rdy_size > 0) {
  465                 if (ocs_xport_initialize_auto_xfer_ready(xport)) {
  466                         ocs_log_err(ocs, "%s: Failed auto xfer ready setup\n", ocs->desc);
  467                         return -1;
  468                 }
  469                 if (ocs->esoc){
  470                         ocs_hw_set(&ocs->hw, OCS_ESOC, TRUE);
  471                 }
  472         }
  473 
  474         if (ocs->explicit_buffer_list) {
  475                 /* Are pre-registered SGL's required? */
  476                 ocs_hw_get(&ocs->hw, OCS_HW_PREREGISTER_SGL, &i);
  477                 if (i == TRUE) {
  478                         ocs_log_err(ocs, "Explicit Buffer List not supported on this device, not enabled\n");
  479                 } else {
  480                         ocs_hw_set(&ocs->hw, OCS_HW_PREREGISTER_SGL, FALSE);
  481                 }
  482         }
  483 
  484          /* Setup persistent topology based on topology mod-param value */
  485         rc = ocs_topology_setup(ocs);
  486         if (rc) {
  487                 ocs_log_err(ocs, "%s: Can't set the toplogy\n", ocs->desc);
  488                 return -1;
  489         }
  490 
  491         if (ocs_hw_set(&ocs->hw, OCS_HW_TOPOLOGY, ocs->topology) != OCS_HW_RTN_SUCCESS) {
  492                 ocs_log_err(ocs, "%s: Can't set the toplogy\n", ocs->desc);
  493                 return -1;
  494         }
  495         ocs_hw_set(&ocs->hw, OCS_HW_RQ_DEFAULT_BUFFER_SIZE, OCS_FC_RQ_SIZE_DEFAULT);
  496 
  497         if (ocs_hw_set(&ocs->hw, OCS_HW_LINK_SPEED, ocs->speed) != OCS_HW_RTN_SUCCESS) {
  498                 ocs_log_err(ocs, "%s: Can't set the link speed\n", ocs->desc);
  499                 return -1;
  500         }
  501 
  502         if (ocs_hw_set(&ocs->hw, OCS_HW_ETH_LICENSE, ocs->ethernet_license) != OCS_HW_RTN_SUCCESS) {
  503                 ocs_log_err(ocs, "%s: Can't set the ethernet license\n", ocs->desc);
  504                 return -1;
  505         }
  506 
  507         /* currently only lancer support setting the CRC seed value */
  508         if (ocs->hw.sli.asic_type == SLI4_ASIC_TYPE_LANCER) {
  509                 if (ocs_hw_set(&ocs->hw, OCS_HW_DIF_SEED, OCS_FC_DIF_SEED) != OCS_HW_RTN_SUCCESS) {
  510                         ocs_log_err(ocs, "%s: Can't set the DIF seed\n", ocs->desc);
  511                         return -1;
  512                 }
  513         }
  514 
  515         /* Set the Dif mode */
  516         if (0 == ocs_hw_get(&ocs->hw, OCS_HW_DIF_CAPABLE, &dif_capable)) {
  517                 if (dif_capable) {
  518                         if (ocs_get_property("dif_separate", prop_buf, sizeof(prop_buf)) == 0) {
  519                                 dif_separate = ocs_strtoul(prop_buf, 0, 0);
  520                         }
  521 
  522                         if ((rc = ocs_hw_set(&ocs->hw, OCS_HW_DIF_MODE,
  523                               (dif_separate == 0 ? OCS_HW_DIF_MODE_INLINE : OCS_HW_DIF_MODE_SEPARATE)))) {
  524                                 ocs_log_err(ocs, "Requested DIF MODE not supported\n");
  525                         }
  526                 }
  527         }
  528 
  529         if (ocs->target_io_timer_sec) {
  530                 ocs_log_debug(ocs, "setting target io timer=%d\n", ocs->target_io_timer_sec);
  531                 ocs_hw_set(&ocs->hw, OCS_HW_EMULATE_TARGET_WQE_TIMEOUT, TRUE);
  532         }
  533 
  534         ocs_hw_callback(&ocs->hw, OCS_HW_CB_DOMAIN, ocs_domain_cb, ocs);
  535         ocs_hw_callback(&ocs->hw, OCS_HW_CB_REMOTE_NODE, ocs_remote_node_cb, ocs);
  536         ocs_hw_callback(&ocs->hw, OCS_HW_CB_UNSOLICITED, ocs_unsolicited_cb, ocs);
  537         ocs_hw_callback(&ocs->hw, OCS_HW_CB_PORT, ocs_port_cb, ocs);
  538 
  539         ocs->fw_version = (const char*) ocs_hw_get_ptr(&ocs->hw, OCS_HW_FW_REV);
  540 
  541         /* Initialize vport list */
  542         ocs_list_init(&xport->vport_list, ocs_vport_spec_t, link);
  543         ocs_lock_init(ocs, &xport->io_pending_lock, "io_pending_lock[%d]", ocs->instance_index);
  544         ocs_list_init(&xport->io_pending_list, ocs_io_t, io_pending_link);
  545         ocs_atomic_init(&xport->io_active_count, 0);
  546         ocs_atomic_init(&xport->io_pending_count, 0);
  547         ocs_atomic_init(&xport->io_total_free, 0);
  548         ocs_atomic_init(&xport->io_total_pending, 0);
  549         ocs_atomic_init(&xport->io_alloc_failed_count, 0);
  550         ocs_atomic_init(&xport->io_pending_recursing, 0);
  551         ocs_lock_init(ocs, &ocs->hw.watchdog_lock, " Watchdog Lock[%d]", ocs_instance(ocs));
  552         rc = ocs_hw_init(&ocs->hw);
  553         if (rc) {
  554                 ocs_log_err(ocs, "ocs_hw_init failure\n");
  555                 goto ocs_xport_init_cleanup;
  556         } else {
  557                 hw_initialized = TRUE;
  558         }
  559 
  560         rq_limit = max_hw_io/2;
  561         if (ocs_hw_set(&ocs->hw, OCS_HW_RQ_PROCESS_LIMIT, rq_limit) != OCS_HW_RTN_SUCCESS) {
  562                 ocs_log_err(ocs, "%s: Can't set the RQ process limit\n", ocs->desc);
  563         }
  564 
  565         if (ocs->config_tgt) {
  566                 rc = ocs_scsi_tgt_new_device(ocs);
  567                 if (rc) {
  568                         ocs_log_err(ocs, "failed to initialize target\n");
  569                         goto ocs_xport_init_cleanup;
  570                 } else {
  571                         tgt_device_set = TRUE;
  572                 }
  573         }
  574 
  575         if (ocs->enable_ini) {
  576                 rc = ocs_scsi_ini_new_device(ocs);
  577                 if (rc) {
  578                         ocs_log_err(ocs, "failed to initialize initiator\n");
  579                         goto ocs_xport_init_cleanup;
  580                 } else {
  581                         ini_device_set = TRUE;
  582                 }
  583         }
  584 
  585         /* Add vports */
  586         if (ocs->num_vports != 0) {
  587                 uint32_t max_vports;
  588                 ocs_hw_get(&ocs->hw, OCS_HW_MAX_VPORTS, &max_vports);
  589 
  590                 if (ocs->num_vports < max_vports) {
  591                         ocs_log_debug(ocs, "Provisioning %d vports\n", ocs->num_vports);
  592                         for (i = 0; i < ocs->num_vports; i++) {
  593                                 ocs_vport_create_spec(ocs, 0, 0, UINT32_MAX, ocs->enable_ini, ocs->enable_tgt, NULL, NULL);
  594                         }
  595                 } else {
  596                         ocs_log_err(ocs, "failed to create vports. num_vports range should be (1-%d) \n", max_vports-1);
  597                         goto ocs_xport_init_cleanup;
  598                 }
  599         }
  600 
  601         return 0;
  602 
  603 ocs_xport_init_cleanup:
  604         if (ini_device_set) {
  605                 ocs_scsi_ini_del_device(ocs);
  606         }
  607 
  608         if (tgt_device_set) {
  609                 ocs_scsi_tgt_del_device(ocs);
  610         }
  611 
  612         if (hw_initialized) {
  613                 /* ocs_hw_teardown can only execute after ocs_hw_init */
  614                 ocs_hw_teardown(&ocs->hw);
  615         }
  616 
  617         return -1;
  618 }
  619 
  620 /**
  621  * @brief Detaches the transport from the device.
  622  *
  623  * @par Description
  624  * Performs the functions required to shut down a device.
  625  *
  626  * @param xport Pointer to transport object.
  627  *
  628  * @return Returns 0 on success or a non-zero value on failure.
  629  */
  630 int32_t
  631 ocs_xport_detach(ocs_xport_t *xport)
  632 {
  633         ocs_t *ocs = xport->ocs;
  634 
  635         /* free resources associated with target-server and initiator-client */
  636         if (ocs->config_tgt)
  637                 ocs_scsi_tgt_del_device(ocs);
  638 
  639         if (ocs->enable_ini) {
  640                 ocs_scsi_ini_del_device(ocs);
  641 
  642                 /*Shutdown FC Statistics timer*/
  643                 if (ocs_timer_pending(&ocs->xport->stats_timer))
  644                         ocs_del_timer(&ocs->xport->stats_timer);
  645         }
  646 
  647         ocs_hw_teardown(&ocs->hw);
  648 
  649         return 0;
  650 }
  651 
  652 /**
  653  * @brief domain list empty callback
  654  *
  655  * @par Description
  656  * Function is invoked when the device domain list goes empty. By convention
  657  * @c arg points to an ocs_sem_t instance, that is incremented.
  658  *
  659  * @param ocs Pointer to device object.
  660  * @param arg Pointer to semaphore instance.
  661  *
  662  * @return None.
  663  */
  664 
  665 static void
  666 ocs_xport_domain_list_empty_cb(ocs_t *ocs, void *arg)
  667 {
  668         ocs_sem_t *sem = arg;
  669 
  670         ocs_assert(ocs);
  671         ocs_assert(sem);
  672 
  673         ocs_sem_v(sem);
  674 }
  675 
  676 /**
  677  * @brief post node event callback
  678  *
  679  * @par Description
  680  * This function is called from the mailbox completion interrupt context to post an
  681  * event to a node object. By doing this in the interrupt context, it has
  682  * the benefit of only posting events in the interrupt context, deferring the need to
  683  * create a per event node lock.
  684  *
  685  * @param hw Pointer to HW structure.
  686  * @param status Completion status for mailbox command.
  687  * @param mqe Mailbox queue completion entry.
  688  * @param arg Callback argument.
  689  *
  690  * @return Returns 0 on success, a negative error code value on failure.
  691  */
  692 
  693 static int32_t
  694 ocs_xport_post_node_event_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
  695 {
  696         ocs_xport_post_node_event_t *payload = arg;
  697 
  698         if (payload != NULL) {
  699                 ocs_node_post_event(payload->node, payload->evt, payload->context);
  700                 ocs_sem_v(&payload->sem);
  701         }
  702 
  703         return 0;
  704 }
  705 
  706 /**
  707  * @brief Initiate force free.
  708  *
  709  * @par Description
  710  * Perform force free of OCS.
  711  *
  712  * @param xport Pointer to transport object.
  713  *
  714  * @return None.
  715  */
  716 
  717 static void
  718 ocs_xport_force_free(ocs_xport_t *xport)
  719 {
  720         ocs_t *ocs = xport->ocs;
  721         ocs_domain_t *domain;
  722         ocs_domain_t *next;
  723 
  724         ocs_log_debug(ocs, "reset required, do force shutdown\n");
  725         ocs_device_lock(ocs);
  726                 ocs_list_foreach_safe(&ocs->domain_list, domain, next) {
  727                         ocs_domain_force_free(domain);
  728                 }
  729         ocs_device_unlock(ocs);
  730 }
  731 
  732 /**
  733  * @brief Perform transport attach function.
  734  *
  735  * @par Description
  736  * Perform the attach function, which for the FC transport makes a HW call
  737  * to bring up the link.
  738  *
  739  * @param xport pointer to transport object.
  740  * @param cmd command to execute.
  741  *
  742  * ocs_xport_control(ocs_xport_t *xport, OCS_XPORT_PORT_ONLINE)
  743  * ocs_xport_control(ocs_xport_t *xport, OCS_XPORT_PORT_OFFLINE)
  744  * ocs_xport_control(ocs_xport_t *xport, OCS_XPORT_PORT_SHUTDOWN)
  745  * ocs_xport_control(ocs_xport_t *xport, OCS_XPORT_POST_NODE_EVENT, ocs_node_t *node, ocs_sm_event_t, void *context)
  746  *
  747  * @return Returns 0 on success, or a negative error code value on failure.
  748  */
  749 
  750 int32_t
  751 ocs_xport_control(ocs_xport_t *xport, ocs_xport_ctrl_e cmd, ...)
  752 {
  753         uint32_t rc = 0;
  754         ocs_t *ocs = NULL;
  755         va_list argp;
  756 
  757         ocs_assert(xport, -1);
  758         ocs_assert(xport->ocs, -1);
  759         ocs = xport->ocs;
  760 
  761         switch (cmd) {
  762         case OCS_XPORT_PORT_ONLINE: {
  763                 /* Bring the port on-line */
  764                 rc = ocs_hw_port_control(&ocs->hw, OCS_HW_PORT_INIT, 0, NULL, NULL);
  765                 if (rc) {
  766                         ocs_log_err(ocs, "%s: Can't init port\n", ocs->desc);
  767                 } else {
  768                         xport->configured_link_state = cmd;
  769                 }
  770                 break;
  771         }
  772         case OCS_XPORT_PORT_OFFLINE: {
  773                 if (ocs_hw_port_control(&ocs->hw, OCS_HW_PORT_SHUTDOWN, 0, NULL, NULL)) {
  774                         ocs_log_err(ocs, "port shutdown failed\n");
  775                 } else {
  776                         xport->configured_link_state = cmd;
  777                 }
  778                 break;
  779         }
  780 
  781         case OCS_XPORT_SHUTDOWN: {
  782                 ocs_sem_t sem;
  783                 uint32_t reset_required;
  784 
  785                 /* if a PHYSDEV reset was performed (e.g. hw dump), will affect
  786                  * all PCI functions; orderly shutdown won't work, just force free
  787                  */
  788                 /* TODO: need to poll this regularly... */
  789                 if (ocs_hw_get(&ocs->hw, OCS_HW_RESET_REQUIRED, &reset_required) != OCS_HW_RTN_SUCCESS) {
  790                         reset_required = 0;
  791                 }
  792 
  793                 if (reset_required) {
  794                         ocs_log_debug(ocs, "reset required, do force shutdown\n");
  795                         ocs_xport_force_free(xport);
  796                         break;
  797                 }
  798                 ocs_sem_init(&sem, 0, "domain_list_sem");
  799                 ocs_register_domain_list_empty_cb(ocs, ocs_xport_domain_list_empty_cb, &sem);
  800 
  801                 if (ocs_hw_port_control(&ocs->hw, OCS_HW_PORT_SHUTDOWN, 0, NULL, NULL)) {
  802                         ocs_log_debug(ocs, "port shutdown failed, do force shutdown\n");
  803                         ocs_xport_force_free(xport);
  804                 } else {
  805                         ocs_log_debug(ocs, "Waiting %d seconds for domain shutdown.\n", (OCS_FC_DOMAIN_SHUTDOWN_TIMEOUT_USEC/1000000));
  806 
  807                         rc = ocs_sem_p(&sem, OCS_FC_DOMAIN_SHUTDOWN_TIMEOUT_USEC);
  808                         if (rc) {
  809                                 ocs_log_debug(ocs, "Note: Domain shutdown timed out\n");
  810                                 ocs_xport_force_free(xport);
  811                         }
  812                 }
  813 
  814                 ocs_register_domain_list_empty_cb(ocs, NULL, NULL);
  815 
  816                 /* Free up any saved virtual ports */
  817                 ocs_vport_del_all(ocs);
  818                 break;
  819         }
  820 
  821         /*
  822          * POST_NODE_EVENT:  post an event to a node object
  823          *
  824          * This transport function is used to post an event to a node object. It does
  825          * this by submitting a NOP mailbox command to defer execution to the
  826          * interrupt context (thereby enforcing the serialized execution of event posting
  827          * to the node state machine instances)
  828          *
  829          * A counting semaphore is used to make the call synchronous (we wait until
  830          * the callback increments the semaphore before returning (or times out)
  831          */
  832         case OCS_XPORT_POST_NODE_EVENT: {
  833                 ocs_node_t *node;
  834                 ocs_sm_event_t evt;
  835                 void *context;
  836                 ocs_xport_post_node_event_t payload;
  837                 ocs_t *ocs;
  838                 ocs_hw_t *hw;
  839 
  840                 /* Retrieve arguments */
  841                 va_start(argp, cmd);
  842                 node = va_arg(argp, ocs_node_t*);
  843                 evt = va_arg(argp, ocs_sm_event_t);
  844                 context = va_arg(argp, void *);
  845                 va_end(argp);
  846 
  847                 ocs_assert(node, -1);
  848                 ocs_assert(node->ocs, -1);
  849 
  850                 ocs = node->ocs;
  851                 hw = &ocs->hw;
  852 
  853                 /* if node's state machine is disabled, don't bother continuing */
  854                 if (!node->sm.current_state) {
  855                         ocs_log_test(ocs, "node %p state machine disabled\n", node);
  856                         return -1;
  857                 }
  858 
  859                 /* Setup payload */
  860                 ocs_memset(&payload, 0, sizeof(payload));
  861                 ocs_sem_init(&payload.sem, 0, "xport_post_node_Event");
  862                 payload.node = node;
  863                 payload.evt = evt;
  864                 payload.context = context;
  865 
  866                 if (ocs_hw_async_call(hw, ocs_xport_post_node_event_cb, &payload)) {
  867                         ocs_log_test(ocs, "ocs_hw_async_call failed\n");
  868                         rc = -1;
  869                         break;
  870                 }
  871 
  872                 /* Wait for completion */
  873                 if (ocs_sem_p(&payload.sem, OCS_SEM_FOREVER)) {
  874                         ocs_log_test(ocs, "POST_NODE_EVENT: sem wait failed\n");
  875                         rc = -1;
  876                 }
  877 
  878                 break;
  879         }
  880         /*
  881          * Set wwnn for the port.  This will be used instead of the default provided by FW.
  882          */
  883         case OCS_XPORT_WWNN_SET: {
  884                 uint64_t wwnn;
  885 
  886                 /* Retrieve arguments */
  887                 va_start(argp, cmd);
  888                 wwnn = va_arg(argp, uint64_t);
  889                 va_end(argp);
  890 
  891                 ocs_log_debug(ocs, " WWNN %016" PRIx64 "\n", wwnn);
  892                 xport->req_wwnn = wwnn;
  893 
  894                 break;
  895         }
  896         /*
  897          * Set wwpn for the port.  This will be used instead of the default provided by FW.
  898          */
  899         case OCS_XPORT_WWPN_SET: {
  900                 uint64_t wwpn;
  901 
  902                 /* Retrieve arguments */
  903                 va_start(argp, cmd);
  904                 wwpn = va_arg(argp, uint64_t);
  905                 va_end(argp);
  906 
  907                 ocs_log_debug(ocs, " WWPN %016" PRIx64 "\n", wwpn);
  908                 xport->req_wwpn = wwpn;
  909 
  910                 break;
  911         }
  912 
  913         default:
  914                 break;
  915         }
  916         return rc;
  917 }
  918 
  919 /**
  920  * @brief Return status on a link.
  921  *
  922  * @par Description
  923  * Returns status information about a link.
  924  *
  925  * @param xport Pointer to transport object.
  926  * @param cmd Command to execute.
  927  * @param result Pointer to result value.
  928  *
  929  * ocs_xport_status(ocs_xport_t *xport, OCS_XPORT_PORT_STATUS)
  930  * ocs_xport_status(ocs_xport_t *xport, OCS_XPORT_LINK_SPEED, ocs_xport_stats_t *result)
  931  *      return link speed in MB/sec
  932  * ocs_xport_status(ocs_xport_t *xport, OCS_XPORT_IS_SUPPORTED_LINK_SPEED, ocs_xport_stats_t *result)
  933  *      [in] *result is speed to check in MB/s
  934  *      returns 1 if supported, 0 if not
  935  * ocs_xport_status(ocs_xport_t *xport, OCS_XPORT_LINK_STATISTICS, ocs_xport_stats_t *result)
  936  *      return link/host port stats
  937  * ocs_xport_status(ocs_xport_t *xport, OCS_XPORT_LINK_STAT_RESET, ocs_xport_stats_t *result)
  938  *      resets link/host stats
  939  *
  940  *
  941  * @return Returns 0 on success, or a negative error code value on failure.
  942  */
  943 
  944 int32_t
  945 ocs_xport_status(ocs_xport_t *xport, ocs_xport_status_e cmd, ocs_xport_stats_t *result)
  946 {
  947         uint32_t rc = 0;
  948         ocs_t *ocs = NULL;
  949         ocs_xport_stats_t value;
  950         ocs_hw_rtn_e hw_rc;
  951 
  952         ocs_assert(xport, -1);
  953         ocs_assert(xport->ocs, -1);
  954 
  955         ocs = xport->ocs;
  956 
  957         switch (cmd) {
  958         case OCS_XPORT_CONFIG_PORT_STATUS:
  959                 ocs_assert(result, -1);
  960                 if (xport->configured_link_state == 0) {
  961                         /* Initial state is offline. configured_link_state is    */
  962                         /* set to online explicitly when port is brought online. */
  963                         xport->configured_link_state = OCS_XPORT_PORT_OFFLINE;
  964                 }
  965                 result->value = xport->configured_link_state;
  966                 break;
  967 
  968         case OCS_XPORT_PORT_STATUS:
  969                 ocs_assert(result, -1);
  970                 /* Determine port status based on link speed. */
  971                 hw_rc = ocs_hw_get(&(ocs->hw), OCS_HW_LINK_SPEED, &value.value);
  972                 if (hw_rc == OCS_HW_RTN_SUCCESS) {
  973                         if (value.value == 0) {
  974                                 result->value = 0;
  975                         } else {
  976                                 result->value = 1;
  977                         }
  978                         rc = 0;
  979                 } else {
  980                         rc = -1;
  981                 }
  982                 break;
  983 
  984         case OCS_XPORT_LINK_SPEED: {
  985                 uint32_t speed;
  986 
  987                 ocs_assert(result, -1);
  988                 result->value = 0;
  989 
  990                 rc = ocs_hw_get(&ocs->hw, OCS_HW_LINK_SPEED, &speed);
  991                 if (rc == 0) {
  992                         result->value = speed;
  993                 }
  994                 break;
  995         }
  996 
  997         case OCS_XPORT_IS_SUPPORTED_LINK_SPEED: {
  998                 uint32_t speed;
  999                 uint32_t link_module_type;
 1000 
 1001                 ocs_assert(result, -1);
 1002                 speed = result->value;
 1003 
 1004                 rc = ocs_hw_get(&ocs->hw, OCS_HW_LINK_MODULE_TYPE, &link_module_type);
 1005                 if (rc == 0) {
 1006                         switch(speed) {
 1007                         case 1000:      rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_1GB) != 0; break;
 1008                         case 2000:      rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_2GB) != 0; break;
 1009                         case 4000:      rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_4GB) != 0; break;
 1010                         case 8000:      rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_8GB) != 0; break;
 1011                         case 10000:     rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_10GB) != 0; break;
 1012                         case 16000:     rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_16GB) != 0; break;
 1013                         case 32000:     rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_32GB) != 0; break;
 1014                         default:        rc = 0; break;
 1015                         }
 1016                 } else {
 1017                         rc = 0;
 1018                 }
 1019                 break;
 1020         }
 1021         case OCS_XPORT_LINK_STATISTICS: 
 1022                 ocs_device_lock(ocs);
 1023                         ocs_memcpy((void *)result, &ocs->xport->fc_xport_stats, sizeof(ocs_xport_stats_t));
 1024                 ocs_device_unlock(ocs);
 1025                 break;
 1026         case OCS_XPORT_LINK_STAT_RESET: {
 1027                 /* Create a semaphore to synchronize the stat reset process. */
 1028                 ocs_sem_init(&(result->stats.semaphore), 0, "fc_stats_reset");
 1029 
 1030                 /* First reset the link stats */
 1031                 if ((rc = ocs_hw_get_link_stats(&ocs->hw, 0, 1, 1, ocs_xport_link_stats_cb, result)) != 0) {
 1032                         ocs_log_err(ocs, "%s: Failed to reset link statistics\n", __func__);
 1033                         break;
 1034                 }
 1035 
 1036                 /* Wait for semaphore to be signaled when the command completes */
 1037                 /* TODO:  Should there be a timeout on this?  If so, how long? */
 1038                 if (ocs_sem_p(&(result->stats.semaphore), OCS_SEM_FOREVER) != 0) {
 1039                         /* Undefined failure */
 1040                         ocs_log_test(ocs, "ocs_sem_p failed\n");
 1041                         rc = -ENXIO;
 1042                         break;
 1043                 }
 1044 
 1045                 /* Next reset the host stats */
 1046                 if ((rc = ocs_hw_get_host_stats(&ocs->hw, 1,  ocs_xport_host_stats_cb, result)) != 0) {
 1047                         ocs_log_err(ocs, "%s: Failed to reset host statistics\n", __func__);
 1048                         break;
 1049                 }
 1050 
 1051                 /* Wait for semaphore to be signaled when the command completes */
 1052                 if (ocs_sem_p(&(result->stats.semaphore), OCS_SEM_FOREVER) != 0) {
 1053                         /* Undefined failure */
 1054                         ocs_log_test(ocs, "ocs_sem_p failed\n");
 1055                         rc = -ENXIO;
 1056                         break;
 1057                 }
 1058                 break;
 1059         }
 1060         case OCS_XPORT_IS_QUIESCED:
 1061                 ocs_device_lock(ocs);
 1062                         result->value = ocs_list_empty(&ocs->domain_list);
 1063                 ocs_device_unlock(ocs);
 1064                 break;
 1065         default:
 1066                 rc = -1;
 1067                 break;
 1068         }
 1069 
 1070         return rc;
 1071 
 1072 }
 1073 
 1074 static void
 1075 ocs_xport_link_stats_cb(int32_t status, uint32_t num_counters, ocs_hw_link_stat_counts_t *counters, void *arg)
 1076 {
 1077         ocs_xport_stats_t *result = arg;
 1078 
 1079         result->stats.link_stats.link_failure_error_count = counters[OCS_HW_LINK_STAT_LINK_FAILURE_COUNT].counter;
 1080         result->stats.link_stats.loss_of_sync_error_count = counters[OCS_HW_LINK_STAT_LOSS_OF_SYNC_COUNT].counter;
 1081         result->stats.link_stats.primitive_sequence_error_count = counters[OCS_HW_LINK_STAT_PRIMITIVE_SEQ_COUNT].counter;
 1082         result->stats.link_stats.invalid_transmission_word_error_count = counters[OCS_HW_LINK_STAT_INVALID_XMIT_WORD_COUNT].counter;
 1083         result->stats.link_stats.crc_error_count = counters[OCS_HW_LINK_STAT_CRC_COUNT].counter;
 1084 
 1085         ocs_sem_v(&(result->stats.semaphore));
 1086 }
 1087 
 1088 static void
 1089 ocs_xport_host_stats_cb(int32_t status, uint32_t num_counters, ocs_hw_host_stat_counts_t *counters, void *arg)
 1090 {
 1091         ocs_xport_stats_t *result = arg;
 1092 
 1093         result->stats.host_stats.transmit_kbyte_count = counters[OCS_HW_HOST_STAT_TX_KBYTE_COUNT].counter;
 1094         result->stats.host_stats.receive_kbyte_count = counters[OCS_HW_HOST_STAT_RX_KBYTE_COUNT].counter;
 1095         result->stats.host_stats.transmit_frame_count = counters[OCS_HW_HOST_STAT_TX_FRAME_COUNT].counter;
 1096         result->stats.host_stats.receive_frame_count = counters[OCS_HW_HOST_STAT_RX_FRAME_COUNT].counter;
 1097 
 1098         ocs_sem_v(&(result->stats.semaphore));
 1099 }
 1100 
 1101 /**
 1102  * @brief Free a transport object.
 1103  *
 1104  * @par Description
 1105  * The transport object is freed.
 1106  *
 1107  * @param xport Pointer to transport object.
 1108  *
 1109  * @return None.
 1110  */
 1111 
 1112 void
 1113 ocs_xport_free(ocs_xport_t *xport)
 1114 {
 1115         ocs_t *ocs;
 1116         uint32_t i;
 1117 
 1118         if (xport) {
 1119                 ocs = xport->ocs;
 1120                 ocs_io_pool_free(xport->io_pool);
 1121                 ocs_node_free_pool(ocs);
 1122                 if(mtx_initialized(&xport->io_pending_lock.lock))
 1123                         ocs_lock_free(&xport->io_pending_lock);
 1124 
 1125                 for (i = 0; i < SLI4_MAX_FCFI; i++) {
 1126                         ocs_lock_free(&xport->fcfi[i].pend_frames_lock);
 1127                 }
 1128 
 1129                 ocs_xport_rq_threads_teardown(xport);
 1130 
 1131                 ocs_free(ocs, xport, sizeof(*xport));
 1132         }
 1133 }

Cache object: 7b59e9a4d8ca0003ecd83cc549e705cf


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.