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         uint8_t rq_threads_created = FALSE;
  201 
  202         ocs_list_init(&ocs->domain_list, ocs_domain_t, link);
  203 
  204         for (i = 0; i < SLI4_MAX_FCFI; i++) {
  205                 xport->fcfi[i].hold_frames = 1;
  206                 ocs_lock_init(ocs, &xport->fcfi[i].pend_frames_lock, "xport pend_frames[%d]", i);
  207                 ocs_list_init(&xport->fcfi[i].pend_frames, ocs_hw_sequence_t, link);
  208         }
  209 
  210         rc = ocs_hw_set_ptr(&ocs->hw, OCS_HW_WAR_VERSION, ocs->hw_war_version);
  211         if (rc) {
  212                 ocs_log_test(ocs, "can't set OCS_HW_WAR_VERSION\n");
  213                 return -1;
  214         }
  215 
  216         rc = ocs_hw_setup(&ocs->hw, ocs, SLI4_PORT_TYPE_FC);
  217         if (rc) {
  218                 ocs_log_err(ocs, "%s: Can't setup hardware\n", ocs->desc);
  219                 return -1;
  220         } else if (ocs->ctrlmask & OCS_CTRLMASK_CRASH_RESET) {
  221                 ocs_log_debug(ocs, "stopping after ocs_hw_setup\n");
  222                 return -1;
  223         }
  224 
  225         ocs_hw_set(&ocs->hw, OCS_HW_BOUNCE, ocs->hw_bounce);
  226         ocs_log_debug(ocs, "HW bounce: %d\n", ocs->hw_bounce);
  227 
  228         ocs_hw_set(&ocs->hw, OCS_HW_RQ_SELECTION_POLICY, ocs->rq_selection_policy);
  229         ocs_hw_set(&ocs->hw, OCS_HW_RR_QUANTA, ocs->rr_quanta);
  230         ocs_hw_get(&ocs->hw, OCS_HW_RQ_SELECTION_POLICY, &value);
  231         ocs_log_debug(ocs, "RQ Selection Policy: %d\n", value);
  232 
  233         ocs_hw_set_ptr(&ocs->hw, OCS_HW_FILTER_DEF, (void*) ocs->filter_def);
  234 
  235         ocs_hw_get(&ocs->hw, OCS_HW_MAX_SGL, &max_sgl);
  236         max_sgl -= SLI4_SGE_MAX_RESERVED;
  237         n_sgl = MIN(OCS_FC_MAX_SGL, max_sgl);
  238 
  239         /* EVT: For chained SGL testing */
  240         if (ocs->ctrlmask & OCS_CTRLMASK_TEST_CHAINED_SGLS) {
  241                 n_sgl = 4;
  242         }
  243 
  244         /* Note: number of SGLs must be set for ocs_node_create_pool */
  245         if (ocs_hw_set(&ocs->hw, OCS_HW_N_SGL, n_sgl) != OCS_HW_RTN_SUCCESS) {
  246                 ocs_log_err(ocs, "%s: Can't set number of SGLs\n", ocs->desc);
  247                 return -1;
  248         } else {
  249                 ocs_log_debug(ocs, "%s: Configured for %d SGLs\n", ocs->desc, n_sgl);
  250         }
  251 
  252         ocs_hw_get(&ocs->hw, OCS_HW_MAX_NODES, &max_remote_nodes);
  253 
  254         if (!ocs->max_remote_nodes)
  255                 ocs->max_remote_nodes = max_remote_nodes;
  256 
  257         rc = ocs_node_create_pool(ocs, ocs->max_remote_nodes);
  258         if (rc) {
  259                 ocs_log_err(ocs, "Can't allocate node pool\n");
  260                 goto ocs_xport_attach_cleanup;
  261         } else {
  262                 node_pool_created = TRUE;
  263         }
  264 
  265         /* EVT: if testing chained SGLs allocate OCS_FC_MAX_SGL SGE's in the IO */
  266         xport->io_pool = ocs_io_pool_create(ocs, ocs->num_scsi_ios,
  267                 (ocs->ctrlmask & OCS_CTRLMASK_TEST_CHAINED_SGLS) ? OCS_FC_MAX_SGL : n_sgl);
  268         if (xport->io_pool == NULL) {
  269                 ocs_log_err(ocs, "Can't allocate IO pool\n");
  270                 goto ocs_xport_attach_cleanup;
  271         } else {
  272                 io_pool_created = TRUE;
  273         }
  274 
  275         /*
  276          * setup the RQ processing threads
  277          */
  278         if (ocs_xport_rq_threads_create(xport, ocs->rq_threads) != 0) {
  279                 ocs_log_err(ocs, "failure creating RQ threads\n");
  280                 goto ocs_xport_attach_cleanup;
  281         }
  282         rq_threads_created = TRUE;
  283 
  284         return 0;
  285 
  286 ocs_xport_attach_cleanup:
  287         if (io_pool_created) {
  288                 ocs_io_pool_free(xport->io_pool);
  289         }
  290 
  291         if (node_pool_created) {
  292                 ocs_node_free_pool(ocs);
  293         }
  294 
  295         return -1;
  296 }
  297 
  298 /**
  299  * @brief Determines how to setup auto Xfer ready.
  300  *
  301  * @par Description
  302  * @param xport Pointer to transport object.
  303  *
  304  * @return Returns 0 on success or a non-zero value on failure.
  305  */
  306 static int32_t
  307 ocs_xport_initialize_auto_xfer_ready(ocs_xport_t *xport)
  308 {
  309         ocs_t *ocs = xport->ocs;
  310         uint32_t auto_xfer_rdy;
  311         char prop_buf[32];
  312         uint32_t ramdisc_blocksize = 512;
  313         uint8_t p_type = 0;
  314 
  315         ocs_hw_get(&ocs->hw, OCS_HW_AUTO_XFER_RDY_CAPABLE, &auto_xfer_rdy);
  316         if (!auto_xfer_rdy) {
  317                 ocs->auto_xfer_rdy_size = 0;
  318                 ocs_log_test(ocs, "Cannot enable auto xfer rdy for this port\n");
  319                 return 0;
  320         }
  321 
  322         if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_SIZE, ocs->auto_xfer_rdy_size)) {
  323                 ocs_log_test(ocs, "%s: Can't set auto xfer rdy mode\n", ocs->desc);
  324                 return -1;
  325         }
  326 
  327         /*
  328          * Determine if we are doing protection in the backend. We are looking
  329          * at the modules parameters here. The backend cannot allow a format
  330          * command to change the protection mode when using this feature,
  331          * otherwise the firmware will not do the proper thing.
  332          */
  333         if (ocs_get_property("p_type", prop_buf, sizeof(prop_buf)) == 0) {
  334                 p_type = ocs_strtoul(prop_buf, 0, 0);
  335         }
  336         if (ocs_get_property("ramdisc_blocksize", prop_buf, sizeof(prop_buf)) == 0) {
  337                 ramdisc_blocksize = ocs_strtoul(prop_buf, 0, 0);
  338         }
  339         if (ocs_get_property("external_dif", prop_buf, sizeof(prop_buf)) == 0) {
  340                 if(ocs_strlen(prop_buf)) {
  341                         if (p_type == 0) {
  342                                 p_type = 1;
  343                         }
  344                 }
  345         }
  346 
  347         if (p_type != 0) {
  348                 if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_T10_ENABLE, TRUE)) {
  349                         ocs_log_test(ocs, "%s: Can't set auto xfer rdy mode\n", ocs->desc);
  350                         return -1;
  351                 }
  352                 if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_BLK_SIZE, ramdisc_blocksize)) {
  353                         ocs_log_test(ocs, "%s: Can't set auto xfer rdy blk size\n", ocs->desc);
  354                         return -1;
  355                 }
  356                 if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_P_TYPE, p_type)) {
  357                         ocs_log_test(ocs, "%s: Can't set auto xfer rdy mode\n", ocs->desc);
  358                         return -1;
  359                 }
  360                 if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_REF_TAG_IS_LBA, TRUE)) {
  361                         ocs_log_test(ocs, "%s: Can't set auto xfer rdy ref tag\n", ocs->desc);
  362                         return -1;
  363                 }
  364                 if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_APP_TAG_VALID, FALSE)) {
  365                         ocs_log_test(ocs, "%s: Can't set auto xfer rdy app tag valid\n", ocs->desc);
  366                         return -1;
  367                 }
  368         }
  369         ocs_log_debug(ocs, "Auto xfer rdy is enabled, p_type=%d, blksize=%d\n",
  370                 p_type, ramdisc_blocksize);
  371         return 0;
  372 }
  373 
  374 /**
  375  * @brief Initializes the device.
  376  *
  377  * @par Description
  378  * Performs the functions required to make a device functional.
  379  *
  380  * @param xport Pointer to transport object.
  381  *
  382  * @return Returns 0 on success, or a non-zero value on failure.
  383  */
  384 int32_t
  385 ocs_xport_initialize(ocs_xport_t *xport)
  386 {
  387         ocs_t *ocs = xport->ocs;
  388         int32_t rc;
  389         uint32_t i;
  390         uint32_t max_hw_io;
  391         uint32_t max_sgl;
  392         uint32_t hlm;
  393         uint32_t rq_limit;
  394         uint32_t dif_capable;
  395         uint8_t dif_separate = 0;
  396         char prop_buf[32];
  397 
  398         /* booleans used for cleanup if initialization fails */
  399         uint8_t ini_device_set = FALSE;
  400         uint8_t tgt_device_set = FALSE;
  401         uint8_t hw_initialized = FALSE;
  402 
  403         ocs_hw_get(&ocs->hw, OCS_HW_MAX_IO, &max_hw_io);
  404         if (ocs_hw_set(&ocs->hw, OCS_HW_N_IO, max_hw_io) != OCS_HW_RTN_SUCCESS) {
  405                 ocs_log_err(ocs, "%s: Can't set number of IOs\n", ocs->desc);
  406                 return -1;
  407         }
  408 
  409         ocs_hw_get(&ocs->hw, OCS_HW_MAX_SGL, &max_sgl);
  410         max_sgl -= SLI4_SGE_MAX_RESERVED;
  411 
  412         if (ocs->enable_hlm) {
  413                 ocs_hw_get(&ocs->hw, OCS_HW_HIGH_LOGIN_MODE, &hlm);
  414                 if (!hlm) {
  415                         ocs->enable_hlm = FALSE;
  416                         ocs_log_err(ocs, "Cannot enable high login mode for this port\n");
  417                 } else {
  418                         ocs_log_debug(ocs, "High login mode is enabled\n");
  419                         if (ocs_hw_set(&ocs->hw, OCS_HW_HIGH_LOGIN_MODE, TRUE)) {
  420                                 ocs_log_err(ocs, "%s: Can't set high login mode\n", ocs->desc);
  421                                 return -1;
  422                         }
  423                 }
  424         }
  425 
  426         /* validate the auto xfer_rdy size */
  427         if (ocs->auto_xfer_rdy_size > 0 &&
  428             (ocs->auto_xfer_rdy_size < 2048 ||
  429              ocs->auto_xfer_rdy_size > 65536)) {
  430                 ocs_log_err(ocs, "Auto XFER_RDY size is out of range (2K-64K)\n");
  431                 return -1;
  432         }
  433 
  434         ocs_hw_get(&ocs->hw, OCS_HW_MAX_IO, &max_hw_io);
  435 
  436         if (ocs->auto_xfer_rdy_size > 0) {
  437                 if (ocs_xport_initialize_auto_xfer_ready(xport)) {
  438                         ocs_log_err(ocs, "%s: Failed auto xfer ready setup\n", ocs->desc);
  439                         return -1;
  440                 }
  441                 if (ocs->esoc){
  442                         ocs_hw_set(&ocs->hw, OCS_ESOC, TRUE);
  443                 }
  444         }
  445 
  446         if (ocs->explicit_buffer_list) {
  447                 /* Are pre-registered SGL's required? */
  448                 ocs_hw_get(&ocs->hw, OCS_HW_PREREGISTER_SGL, &i);
  449                 if (i == TRUE) {
  450                         ocs_log_err(ocs, "Explicit Buffer List not supported on this device, not enabled\n");
  451                 } else {
  452                         ocs_hw_set(&ocs->hw, OCS_HW_PREREGISTER_SGL, FALSE);
  453                 }
  454         }
  455 
  456         if (ocs_hw_set(&ocs->hw, OCS_HW_TOPOLOGY, ocs->topology) != OCS_HW_RTN_SUCCESS) {
  457                 ocs_log_err(ocs, "%s: Can't set the toplogy\n", ocs->desc);
  458                 return -1;
  459         }
  460         ocs_hw_set(&ocs->hw, OCS_HW_RQ_DEFAULT_BUFFER_SIZE, OCS_FC_RQ_SIZE_DEFAULT);
  461 
  462         if (ocs_hw_set(&ocs->hw, OCS_HW_LINK_SPEED, ocs->speed) != OCS_HW_RTN_SUCCESS) {
  463                 ocs_log_err(ocs, "%s: Can't set the link speed\n", ocs->desc);
  464                 return -1;
  465         }
  466 
  467         if (ocs_hw_set(&ocs->hw, OCS_HW_ETH_LICENSE, ocs->ethernet_license) != OCS_HW_RTN_SUCCESS) {
  468                 ocs_log_err(ocs, "%s: Can't set the ethernet license\n", ocs->desc);
  469                 return -1;
  470         }
  471 
  472         /* currently only lancer support setting the CRC seed value */
  473         if (ocs->hw.sli.asic_type == SLI4_ASIC_TYPE_LANCER) {
  474                 if (ocs_hw_set(&ocs->hw, OCS_HW_DIF_SEED, OCS_FC_DIF_SEED) != OCS_HW_RTN_SUCCESS) {
  475                         ocs_log_err(ocs, "%s: Can't set the DIF seed\n", ocs->desc);
  476                         return -1;
  477                 }
  478         }
  479 
  480         /* Set the Dif mode */
  481         if (0 == ocs_hw_get(&ocs->hw, OCS_HW_DIF_CAPABLE, &dif_capable)) {
  482                 if (dif_capable) {
  483                         if (ocs_get_property("dif_separate", prop_buf, sizeof(prop_buf)) == 0) {
  484                                 dif_separate = ocs_strtoul(prop_buf, 0, 0);
  485                         }
  486 
  487                         if ((rc = ocs_hw_set(&ocs->hw, OCS_HW_DIF_MODE,
  488                               (dif_separate == 0 ? OCS_HW_DIF_MODE_INLINE : OCS_HW_DIF_MODE_SEPARATE)))) {
  489                                 ocs_log_err(ocs, "Requested DIF MODE not supported\n");
  490                         }
  491                 }
  492         }
  493 
  494         if (ocs->target_io_timer_sec) {
  495                 ocs_log_debug(ocs, "setting target io timer=%d\n", ocs->target_io_timer_sec);
  496                 ocs_hw_set(&ocs->hw, OCS_HW_EMULATE_TARGET_WQE_TIMEOUT, TRUE);
  497         }
  498 
  499         ocs_hw_callback(&ocs->hw, OCS_HW_CB_DOMAIN, ocs_domain_cb, ocs);
  500         ocs_hw_callback(&ocs->hw, OCS_HW_CB_REMOTE_NODE, ocs_remote_node_cb, ocs);
  501         ocs_hw_callback(&ocs->hw, OCS_HW_CB_UNSOLICITED, ocs_unsolicited_cb, ocs);
  502         ocs_hw_callback(&ocs->hw, OCS_HW_CB_PORT, ocs_port_cb, ocs);
  503 
  504         ocs->fw_version = (const char*) ocs_hw_get_ptr(&ocs->hw, OCS_HW_FW_REV);
  505 
  506         /* Initialize vport list */
  507         ocs_list_init(&xport->vport_list, ocs_vport_spec_t, link);
  508         ocs_lock_init(ocs, &xport->io_pending_lock, "io_pending_lock[%d]", ocs->instance_index);
  509         ocs_list_init(&xport->io_pending_list, ocs_io_t, io_pending_link);
  510         ocs_atomic_init(&xport->io_active_count, 0);
  511         ocs_atomic_init(&xport->io_pending_count, 0);
  512         ocs_atomic_init(&xport->io_total_free, 0);
  513         ocs_atomic_init(&xport->io_total_pending, 0);
  514         ocs_atomic_init(&xport->io_alloc_failed_count, 0);
  515         ocs_atomic_init(&xport->io_pending_recursing, 0);
  516         ocs_lock_init(ocs, &ocs->hw.watchdog_lock, " Watchdog Lock[%d]", ocs_instance(ocs));
  517         rc = ocs_hw_init(&ocs->hw);
  518         if (rc) {
  519                 ocs_log_err(ocs, "ocs_hw_init failure\n");
  520                 goto ocs_xport_init_cleanup;
  521         } else {
  522                 hw_initialized = TRUE;
  523         }
  524 
  525         rq_limit = max_hw_io/2;
  526         if (ocs_hw_set(&ocs->hw, OCS_HW_RQ_PROCESS_LIMIT, rq_limit) != OCS_HW_RTN_SUCCESS) {
  527                 ocs_log_err(ocs, "%s: Can't set the RQ process limit\n", ocs->desc);
  528         }
  529 
  530         if (ocs->config_tgt) {
  531                 rc = ocs_scsi_tgt_new_device(ocs);
  532                 if (rc) {
  533                         ocs_log_err(ocs, "failed to initialize target\n");
  534                         goto ocs_xport_init_cleanup;
  535                 } else {
  536                         tgt_device_set = TRUE;
  537                 }
  538         }
  539 
  540         if (ocs->enable_ini) {
  541                 rc = ocs_scsi_ini_new_device(ocs);
  542                 if (rc) {
  543                         ocs_log_err(ocs, "failed to initialize initiator\n");
  544                         goto ocs_xport_init_cleanup;
  545                 } else {
  546                         ini_device_set = TRUE;
  547                 }
  548         }
  549 
  550         /* Add vports */
  551         if (ocs->num_vports != 0) {
  552                 uint32_t max_vports;
  553                 ocs_hw_get(&ocs->hw, OCS_HW_MAX_VPORTS, &max_vports);
  554 
  555                 if (ocs->num_vports < max_vports) {
  556                         ocs_log_debug(ocs, "Provisioning %d vports\n", ocs->num_vports);
  557                         for (i = 0; i < ocs->num_vports; i++) {
  558                                 ocs_vport_create_spec(ocs, 0, 0, UINT32_MAX, ocs->enable_ini, ocs->enable_tgt, NULL, NULL);
  559                         }
  560                 } else {
  561                         ocs_log_err(ocs, "failed to create vports. num_vports range should be (1-%d) \n", max_vports-1);
  562                         goto ocs_xport_init_cleanup;
  563                 }
  564         }
  565 
  566         return 0;
  567 
  568 ocs_xport_init_cleanup:
  569         if (ini_device_set) {
  570                 ocs_scsi_ini_del_device(ocs);
  571         }
  572 
  573         if (tgt_device_set) {
  574                 ocs_scsi_tgt_del_device(ocs);
  575         }
  576 
  577         if (hw_initialized) {
  578                 /* ocs_hw_teardown can only execute after ocs_hw_init */
  579                 ocs_hw_teardown(&ocs->hw);
  580         }
  581 
  582         return -1;
  583 }
  584 
  585 /**
  586  * @brief Detaches the transport from the device.
  587  *
  588  * @par Description
  589  * Performs the functions required to shut down a device.
  590  *
  591  * @param xport Pointer to transport object.
  592  *
  593  * @return Returns 0 on success or a non-zero value on failure.
  594  */
  595 int32_t
  596 ocs_xport_detach(ocs_xport_t *xport)
  597 {
  598         ocs_t *ocs = xport->ocs;
  599 
  600         /* free resources associated with target-server and initiator-client */
  601         if (ocs->config_tgt)
  602                 ocs_scsi_tgt_del_device(ocs);
  603 
  604         if (ocs->enable_ini) {
  605                 ocs_scsi_ini_del_device(ocs);
  606 
  607                 /*Shutdown FC Statistics timer*/
  608                 if (ocs_timer_pending(&ocs->xport->stats_timer))
  609                         ocs_del_timer(&ocs->xport->stats_timer);
  610         }
  611 
  612         ocs_hw_teardown(&ocs->hw);
  613 
  614         return 0;
  615 }
  616 
  617 /**
  618  * @brief domain list empty callback
  619  *
  620  * @par Description
  621  * Function is invoked when the device domain list goes empty. By convention
  622  * @c arg points to an ocs_sem_t instance, that is incremented.
  623  *
  624  * @param ocs Pointer to device object.
  625  * @param arg Pointer to semaphore instance.
  626  *
  627  * @return None.
  628  */
  629 
  630 static void
  631 ocs_xport_domain_list_empty_cb(ocs_t *ocs, void *arg)
  632 {
  633         ocs_sem_t *sem = arg;
  634 
  635         ocs_assert(ocs);
  636         ocs_assert(sem);
  637 
  638         ocs_sem_v(sem);
  639 }
  640 
  641 /**
  642  * @brief post node event callback
  643  *
  644  * @par Description
  645  * This function is called from the mailbox completion interrupt context to post an
  646  * event to a node object. By doing this in the interrupt context, it has
  647  * the benefit of only posting events in the interrupt context, deferring the need to
  648  * create a per event node lock.
  649  *
  650  * @param hw Pointer to HW structure.
  651  * @param status Completion status for mailbox command.
  652  * @param mqe Mailbox queue completion entry.
  653  * @param arg Callback argument.
  654  *
  655  * @return Returns 0 on success, a negative error code value on failure.
  656  */
  657 
  658 static int32_t
  659 ocs_xport_post_node_event_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
  660 {
  661         ocs_xport_post_node_event_t *payload = arg;
  662 
  663         if (payload != NULL) {
  664                 ocs_node_post_event(payload->node, payload->evt, payload->context);
  665                 ocs_sem_v(&payload->sem);
  666         }
  667 
  668         return 0;
  669 }
  670 
  671 /**
  672  * @brief Initiate force free.
  673  *
  674  * @par Description
  675  * Perform force free of OCS.
  676  *
  677  * @param xport Pointer to transport object.
  678  *
  679  * @return None.
  680  */
  681 
  682 static void
  683 ocs_xport_force_free(ocs_xport_t *xport)
  684 {
  685         ocs_t *ocs = xport->ocs;
  686         ocs_domain_t *domain;
  687         ocs_domain_t *next;
  688 
  689         ocs_log_debug(ocs, "reset required, do force shutdown\n");
  690         ocs_device_lock(ocs);
  691                 ocs_list_foreach_safe(&ocs->domain_list, domain, next) {
  692                         ocs_domain_force_free(domain);
  693                 }
  694         ocs_device_unlock(ocs);
  695 }
  696 
  697 /**
  698  * @brief Perform transport attach function.
  699  *
  700  * @par Description
  701  * Perform the attach function, which for the FC transport makes a HW call
  702  * to bring up the link.
  703  *
  704  * @param xport pointer to transport object.
  705  * @param cmd command to execute.
  706  *
  707  * ocs_xport_control(ocs_xport_t *xport, OCS_XPORT_PORT_ONLINE)
  708  * ocs_xport_control(ocs_xport_t *xport, OCS_XPORT_PORT_OFFLINE)
  709  * ocs_xport_control(ocs_xport_t *xport, OCS_XPORT_PORT_SHUTDOWN)
  710  * ocs_xport_control(ocs_xport_t *xport, OCS_XPORT_POST_NODE_EVENT, ocs_node_t *node, ocs_sm_event_t, void *context)
  711  *
  712  * @return Returns 0 on success, or a negative error code value on failure.
  713  */
  714 
  715 int32_t
  716 ocs_xport_control(ocs_xport_t *xport, ocs_xport_ctrl_e cmd, ...)
  717 {
  718         uint32_t rc = 0;
  719         ocs_t *ocs = NULL;
  720         va_list argp;
  721 
  722         ocs_assert(xport, -1);
  723         ocs_assert(xport->ocs, -1);
  724         ocs = xport->ocs;
  725 
  726         switch (cmd) {
  727         case OCS_XPORT_PORT_ONLINE: {
  728                 /* Bring the port on-line */
  729                 rc = ocs_hw_port_control(&ocs->hw, OCS_HW_PORT_INIT, 0, NULL, NULL);
  730                 if (rc) {
  731                         ocs_log_err(ocs, "%s: Can't init port\n", ocs->desc);
  732                 } else {
  733                         xport->configured_link_state = cmd;
  734                 }
  735                 break;
  736         }
  737         case OCS_XPORT_PORT_OFFLINE: {
  738                 if (ocs_hw_port_control(&ocs->hw, OCS_HW_PORT_SHUTDOWN, 0, NULL, NULL)) {
  739                         ocs_log_err(ocs, "port shutdown failed\n");
  740                 } else {
  741                         xport->configured_link_state = cmd;
  742                 }
  743                 break;
  744         }
  745 
  746         case OCS_XPORT_SHUTDOWN: {
  747                 ocs_sem_t sem;
  748                 uint32_t reset_required;
  749 
  750                 /* if a PHYSDEV reset was performed (e.g. hw dump), will affect
  751                  * all PCI functions; orderly shutdown won't work, just force free
  752                  */
  753                 /* TODO: need to poll this regularly... */
  754                 if (ocs_hw_get(&ocs->hw, OCS_HW_RESET_REQUIRED, &reset_required) != OCS_HW_RTN_SUCCESS) {
  755                         reset_required = 0;
  756                 }
  757 
  758                 if (reset_required) {
  759                         ocs_log_debug(ocs, "reset required, do force shutdown\n");
  760                         ocs_xport_force_free(xport);
  761                         break;
  762                 }
  763                 ocs_sem_init(&sem, 0, "domain_list_sem");
  764                 ocs_register_domain_list_empty_cb(ocs, ocs_xport_domain_list_empty_cb, &sem);
  765 
  766                 if (ocs_hw_port_control(&ocs->hw, OCS_HW_PORT_SHUTDOWN, 0, NULL, NULL)) {
  767                         ocs_log_debug(ocs, "port shutdown failed, do force shutdown\n");
  768                         ocs_xport_force_free(xport);
  769                 } else {
  770                         ocs_log_debug(ocs, "Waiting %d seconds for domain shutdown.\n", (OCS_FC_DOMAIN_SHUTDOWN_TIMEOUT_USEC/1000000));
  771 
  772                         rc = ocs_sem_p(&sem, OCS_FC_DOMAIN_SHUTDOWN_TIMEOUT_USEC);
  773                         if (rc) {
  774                                 ocs_log_debug(ocs, "Note: Domain shutdown timed out\n");
  775                                 ocs_xport_force_free(xport);
  776                         }
  777                 }
  778 
  779                 ocs_register_domain_list_empty_cb(ocs, NULL, NULL);
  780 
  781                 /* Free up any saved virtual ports */
  782                 ocs_vport_del_all(ocs);
  783                 break;
  784         }
  785 
  786         /*
  787          * POST_NODE_EVENT:  post an event to a node object
  788          *
  789          * This transport function is used to post an event to a node object. It does
  790          * this by submitting a NOP mailbox command to defer execution to the
  791          * interrupt context (thereby enforcing the serialized execution of event posting
  792          * to the node state machine instances)
  793          *
  794          * A counting semaphore is used to make the call synchronous (we wait until
  795          * the callback increments the semaphore before returning (or times out)
  796          */
  797         case OCS_XPORT_POST_NODE_EVENT: {
  798                 ocs_node_t *node;
  799                 ocs_sm_event_t evt;
  800                 void *context;
  801                 ocs_xport_post_node_event_t payload;
  802                 ocs_t *ocs;
  803                 ocs_hw_t *hw;
  804 
  805                 /* Retrieve arguments */
  806                 va_start(argp, cmd);
  807                 node = va_arg(argp, ocs_node_t*);
  808                 evt = va_arg(argp, ocs_sm_event_t);
  809                 context = va_arg(argp, void *);
  810                 va_end(argp);
  811 
  812                 ocs_assert(node, -1);
  813                 ocs_assert(node->ocs, -1);
  814 
  815                 ocs = node->ocs;
  816                 hw = &ocs->hw;
  817 
  818                 /* if node's state machine is disabled, don't bother continuing */
  819                 if (!node->sm.current_state) {
  820                         ocs_log_test(ocs, "node %p state machine disabled\n", node);
  821                         return -1;
  822                 }
  823 
  824                 /* Setup payload */
  825                 ocs_memset(&payload, 0, sizeof(payload));
  826                 ocs_sem_init(&payload.sem, 0, "xport_post_node_Event");
  827                 payload.node = node;
  828                 payload.evt = evt;
  829                 payload.context = context;
  830 
  831                 if (ocs_hw_async_call(hw, ocs_xport_post_node_event_cb, &payload)) {
  832                         ocs_log_test(ocs, "ocs_hw_async_call failed\n");
  833                         rc = -1;
  834                         break;
  835                 }
  836 
  837                 /* Wait for completion */
  838                 if (ocs_sem_p(&payload.sem, OCS_SEM_FOREVER)) {
  839                         ocs_log_test(ocs, "POST_NODE_EVENT: sem wait failed\n");
  840                         rc = -1;
  841                 }
  842 
  843                 break;
  844         }
  845         /*
  846          * Set wwnn for the port.  This will be used instead of the default provided by FW.
  847          */
  848         case OCS_XPORT_WWNN_SET: {
  849                 uint64_t wwnn;
  850 
  851                 /* Retrieve arguments */
  852                 va_start(argp, cmd);
  853                 wwnn = va_arg(argp, uint64_t);
  854                 va_end(argp);
  855 
  856                 ocs_log_debug(ocs, " WWNN %016" PRIx64 "\n", wwnn);
  857                 xport->req_wwnn = wwnn;
  858 
  859                 break;
  860         }
  861         /*
  862          * Set wwpn for the port.  This will be used instead of the default provided by FW.
  863          */
  864         case OCS_XPORT_WWPN_SET: {
  865                 uint64_t wwpn;
  866 
  867                 /* Retrieve arguments */
  868                 va_start(argp, cmd);
  869                 wwpn = va_arg(argp, uint64_t);
  870                 va_end(argp);
  871 
  872                 ocs_log_debug(ocs, " WWPN %016" PRIx64 "\n", wwpn);
  873                 xport->req_wwpn = wwpn;
  874 
  875                 break;
  876         }
  877 
  878         default:
  879                 break;
  880         }
  881         return rc;
  882 }
  883 
  884 /**
  885  * @brief Return status on a link.
  886  *
  887  * @par Description
  888  * Returns status information about a link.
  889  *
  890  * @param xport Pointer to transport object.
  891  * @param cmd Command to execute.
  892  * @param result Pointer to result value.
  893  *
  894  * ocs_xport_status(ocs_xport_t *xport, OCS_XPORT_PORT_STATUS)
  895  * ocs_xport_status(ocs_xport_t *xport, OCS_XPORT_LINK_SPEED, ocs_xport_stats_t *result)
  896  *      return link speed in MB/sec
  897  * ocs_xport_status(ocs_xport_t *xport, OCS_XPORT_IS_SUPPORTED_LINK_SPEED, ocs_xport_stats_t *result)
  898  *      [in] *result is speed to check in MB/s
  899  *      returns 1 if supported, 0 if not
  900  * ocs_xport_status(ocs_xport_t *xport, OCS_XPORT_LINK_STATISTICS, ocs_xport_stats_t *result)
  901  *      return link/host port stats
  902  * ocs_xport_status(ocs_xport_t *xport, OCS_XPORT_LINK_STAT_RESET, ocs_xport_stats_t *result)
  903  *      resets link/host stats
  904  *
  905  *
  906  * @return Returns 0 on success, or a negative error code value on failure.
  907  */
  908 
  909 int32_t
  910 ocs_xport_status(ocs_xport_t *xport, ocs_xport_status_e cmd, ocs_xport_stats_t *result)
  911 {
  912         uint32_t rc = 0;
  913         ocs_t *ocs = NULL;
  914         ocs_xport_stats_t value;
  915         ocs_hw_rtn_e hw_rc;
  916 
  917         ocs_assert(xport, -1);
  918         ocs_assert(xport->ocs, -1);
  919 
  920         ocs = xport->ocs;
  921 
  922         switch (cmd) {
  923         case OCS_XPORT_CONFIG_PORT_STATUS:
  924                 ocs_assert(result, -1);
  925                 if (xport->configured_link_state == 0) {
  926                         /* Initial state is offline. configured_link_state is    */
  927                         /* set to online explicitly when port is brought online. */
  928                         xport->configured_link_state = OCS_XPORT_PORT_OFFLINE;
  929                 }
  930                 result->value = xport->configured_link_state;
  931                 break;
  932 
  933         case OCS_XPORT_PORT_STATUS:
  934                 ocs_assert(result, -1);
  935                 /* Determine port status based on link speed. */
  936                 hw_rc = ocs_hw_get(&(ocs->hw), OCS_HW_LINK_SPEED, &value.value);
  937                 if (hw_rc == OCS_HW_RTN_SUCCESS) {
  938                         if (value.value == 0) {
  939                                 result->value = 0;
  940                         } else {
  941                                 result->value = 1;
  942                         }
  943                         rc = 0;
  944                 } else {
  945                         rc = -1;
  946                 }
  947                 break;
  948 
  949         case OCS_XPORT_LINK_SPEED: {
  950                 uint32_t speed;
  951 
  952                 ocs_assert(result, -1);
  953                 result->value = 0;
  954 
  955                 rc = ocs_hw_get(&ocs->hw, OCS_HW_LINK_SPEED, &speed);
  956                 if (rc == 0) {
  957                         result->value = speed;
  958                 }
  959                 break;
  960         }
  961 
  962         case OCS_XPORT_IS_SUPPORTED_LINK_SPEED: {
  963                 uint32_t speed;
  964                 uint32_t link_module_type;
  965 
  966                 ocs_assert(result, -1);
  967                 speed = result->value;
  968 
  969                 rc = ocs_hw_get(&ocs->hw, OCS_HW_LINK_MODULE_TYPE, &link_module_type);
  970                 if (rc == 0) {
  971                         switch(speed) {
  972                         case 1000:      rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_1GB) != 0; break;
  973                         case 2000:      rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_2GB) != 0; break;
  974                         case 4000:      rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_4GB) != 0; break;
  975                         case 8000:      rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_8GB) != 0; break;
  976                         case 10000:     rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_10GB) != 0; break;
  977                         case 16000:     rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_16GB) != 0; break;
  978                         case 32000:     rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_32GB) != 0; break;
  979                         default:        rc = 0; break;
  980                         }
  981                 } else {
  982                         rc = 0;
  983                 }
  984                 break;
  985         }
  986         case OCS_XPORT_LINK_STATISTICS: 
  987                 ocs_device_lock(ocs);
  988                         ocs_memcpy((void *)result, &ocs->xport->fc_xport_stats, sizeof(ocs_xport_stats_t));
  989                 ocs_device_unlock(ocs);
  990                 break;
  991         case OCS_XPORT_LINK_STAT_RESET: {
  992                 /* Create a semaphore to synchronize the stat reset process. */
  993                 ocs_sem_init(&(result->stats.semaphore), 0, "fc_stats_reset");
  994 
  995                 /* First reset the link stats */
  996                 if ((rc = ocs_hw_get_link_stats(&ocs->hw, 0, 1, 1, ocs_xport_link_stats_cb, result)) != 0) {
  997                         ocs_log_err(ocs, "%s: Failed to reset link statistics\n", __func__);
  998                         break;
  999                 }
 1000 
 1001                 /* Wait for semaphore to be signaled when the command completes */
 1002                 /* TODO:  Should there be a timeout on this?  If so, how long? */
 1003                 if (ocs_sem_p(&(result->stats.semaphore), OCS_SEM_FOREVER) != 0) {
 1004                         /* Undefined failure */
 1005                         ocs_log_test(ocs, "ocs_sem_p failed\n");
 1006                         rc = -ENXIO;
 1007                         break;
 1008                 }
 1009 
 1010                 /* Next reset the host stats */
 1011                 if ((rc = ocs_hw_get_host_stats(&ocs->hw, 1,  ocs_xport_host_stats_cb, result)) != 0) {
 1012                         ocs_log_err(ocs, "%s: Failed to reset host statistics\n", __func__);
 1013                         break;
 1014                 }
 1015 
 1016                 /* Wait for semaphore to be signaled when the command completes */
 1017                 if (ocs_sem_p(&(result->stats.semaphore), OCS_SEM_FOREVER) != 0) {
 1018                         /* Undefined failure */
 1019                         ocs_log_test(ocs, "ocs_sem_p failed\n");
 1020                         rc = -ENXIO;
 1021                         break;
 1022                 }
 1023                 break;
 1024         }
 1025         case OCS_XPORT_IS_QUIESCED:
 1026                 ocs_device_lock(ocs);
 1027                         result->value = ocs_list_empty(&ocs->domain_list);
 1028                 ocs_device_unlock(ocs);
 1029                 break;
 1030         default:
 1031                 rc = -1;
 1032                 break;
 1033         }
 1034 
 1035         return rc;
 1036 
 1037 }
 1038 
 1039 static void
 1040 ocs_xport_link_stats_cb(int32_t status, uint32_t num_counters, ocs_hw_link_stat_counts_t *counters, void *arg)
 1041 {
 1042         ocs_xport_stats_t *result = arg;
 1043 
 1044         result->stats.link_stats.link_failure_error_count = counters[OCS_HW_LINK_STAT_LINK_FAILURE_COUNT].counter;
 1045         result->stats.link_stats.loss_of_sync_error_count = counters[OCS_HW_LINK_STAT_LOSS_OF_SYNC_COUNT].counter;
 1046         result->stats.link_stats.primitive_sequence_error_count = counters[OCS_HW_LINK_STAT_PRIMITIVE_SEQ_COUNT].counter;
 1047         result->stats.link_stats.invalid_transmission_word_error_count = counters[OCS_HW_LINK_STAT_INVALID_XMIT_WORD_COUNT].counter;
 1048         result->stats.link_stats.crc_error_count = counters[OCS_HW_LINK_STAT_CRC_COUNT].counter;
 1049 
 1050         ocs_sem_v(&(result->stats.semaphore));
 1051 }
 1052 
 1053 static void
 1054 ocs_xport_host_stats_cb(int32_t status, uint32_t num_counters, ocs_hw_host_stat_counts_t *counters, void *arg)
 1055 {
 1056         ocs_xport_stats_t *result = arg;
 1057 
 1058         result->stats.host_stats.transmit_kbyte_count = counters[OCS_HW_HOST_STAT_TX_KBYTE_COUNT].counter;
 1059         result->stats.host_stats.receive_kbyte_count = counters[OCS_HW_HOST_STAT_RX_KBYTE_COUNT].counter;
 1060         result->stats.host_stats.transmit_frame_count = counters[OCS_HW_HOST_STAT_TX_FRAME_COUNT].counter;
 1061         result->stats.host_stats.receive_frame_count = counters[OCS_HW_HOST_STAT_RX_FRAME_COUNT].counter;
 1062 
 1063         ocs_sem_v(&(result->stats.semaphore));
 1064 }
 1065 
 1066 /**
 1067  * @brief Free a transport object.
 1068  *
 1069  * @par Description
 1070  * The transport object is freed.
 1071  *
 1072  * @param xport Pointer to transport object.
 1073  *
 1074  * @return None.
 1075  */
 1076 
 1077 void
 1078 ocs_xport_free(ocs_xport_t *xport)
 1079 {
 1080         ocs_t *ocs;
 1081         uint32_t i;
 1082 
 1083         if (xport) {
 1084                 ocs = xport->ocs;
 1085                 ocs_io_pool_free(xport->io_pool);
 1086                 ocs_node_free_pool(ocs);
 1087                 if(mtx_initialized(&xport->io_pending_lock.lock))
 1088                         ocs_lock_free(&xport->io_pending_lock);
 1089 
 1090                 for (i = 0; i < SLI4_MAX_FCFI; i++) {
 1091                         ocs_lock_free(&xport->fcfi[i].pend_frames_lock);
 1092                 }
 1093 
 1094                 ocs_xport_rq_threads_teardown(xport);
 1095 
 1096                 ocs_free(ocs, xport, sizeof(*xport));
 1097         }
 1098 }

Cache object: 8ff4ea8a153a02b65e6511c0f590b5a0


[ 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.