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_hw.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  * Defines and implements the Hardware Abstraction Layer (HW).
   37  * All interaction with the hardware is performed through the HW, which abstracts
   38  * the details of the underlying SLI-4 implementation.
   39  */
   40 
   41 /**
   42  * @defgroup devInitShutdown Device Initialization and Shutdown
   43  * @defgroup domain Domain Functions
   44  * @defgroup port Port Functions
   45  * @defgroup node Remote Node Functions
   46  * @defgroup io IO Functions
   47  * @defgroup interrupt Interrupt handling
   48  * @defgroup os OS Required Functions
   49  */
   50 
   51 #include "ocs.h"
   52 #include "ocs_os.h"
   53 #include "ocs_hw.h"
   54 #include "ocs_hw_queues.h"
   55 
   56 #define OCS_HW_MQ_DEPTH 128
   57 #define OCS_HW_READ_FCF_SIZE    4096
   58 #define OCS_HW_DEFAULT_AUTO_XFER_RDY_IOS        256
   59 #define OCS_HW_WQ_TIMER_PERIOD_MS       500
   60 
   61 /* values used for setting the auto xfer rdy parameters */
   62 #define OCS_HW_AUTO_XFER_RDY_BLK_SIZE_DEFAULT           0 /* 512 bytes */
   63 #define OCS_HW_AUTO_XFER_RDY_REF_TAG_IS_LBA_DEFAULT     TRUE
   64 #define OCS_HW_AUTO_XFER_RDY_APP_TAG_VALID_DEFAULT      FALSE
   65 #define OCS_HW_AUTO_XFER_RDY_APP_TAG_VALUE_DEFAULT      0
   66 #define OCS_HW_REQUE_XRI_REGTAG                 65534
   67 /* max command and response buffer lengths -- arbitrary at the moment */
   68 #define OCS_HW_DMTF_CLP_CMD_MAX 256
   69 #define OCS_HW_DMTF_CLP_RSP_MAX 256
   70 
   71 /* HW global data */
   72 ocs_hw_global_t hw_global;
   73 
   74 static void ocs_hw_queue_hash_add(ocs_queue_hash_t *, uint16_t, uint16_t);
   75 static void ocs_hw_adjust_wqs(ocs_hw_t *hw);
   76 static uint32_t ocs_hw_get_num_chutes(ocs_hw_t *hw);
   77 static int32_t ocs_hw_cb_link(void *, void *);
   78 static int32_t ocs_hw_cb_fip(void *, void *);
   79 static int32_t ocs_hw_command_process(ocs_hw_t *, int32_t, uint8_t *, size_t);
   80 static int32_t ocs_hw_mq_process(ocs_hw_t *, int32_t, sli4_queue_t *);
   81 static int32_t ocs_hw_cb_read_fcf(ocs_hw_t *, int32_t, uint8_t *, void *);
   82 static int32_t ocs_hw_cb_node_attach(ocs_hw_t *, int32_t, uint8_t *, void *);
   83 static int32_t ocs_hw_cb_node_free(ocs_hw_t *, int32_t, uint8_t *, void *);
   84 static int32_t ocs_hw_cb_node_free_all(ocs_hw_t *, int32_t, uint8_t *, void *);
   85 static ocs_hw_rtn_e ocs_hw_setup_io(ocs_hw_t *);
   86 static ocs_hw_rtn_e ocs_hw_init_io(ocs_hw_t *);
   87 static int32_t ocs_hw_flush(ocs_hw_t *);
   88 static int32_t ocs_hw_command_cancel(ocs_hw_t *);
   89 static int32_t ocs_hw_io_cancel(ocs_hw_t *);
   90 static void ocs_hw_io_quarantine(ocs_hw_t *hw, hw_wq_t *wq, ocs_hw_io_t *io);
   91 static void ocs_hw_io_restore_sgl(ocs_hw_t *, ocs_hw_io_t *);
   92 static int32_t ocs_hw_io_ini_sge(ocs_hw_t *, ocs_hw_io_t *, ocs_dma_t *, uint32_t, ocs_dma_t *);
   93 static ocs_hw_rtn_e ocs_hw_firmware_write_lancer(ocs_hw_t *hw, ocs_dma_t *dma, uint32_t size, uint32_t offset, int last, ocs_hw_fw_cb_t cb, void *arg);
   94 static int32_t ocs_hw_cb_fw_write(ocs_hw_t *, int32_t, uint8_t *, void  *);
   95 static int32_t ocs_hw_cb_sfp(ocs_hw_t *, int32_t, uint8_t *, void  *);
   96 static int32_t ocs_hw_cb_temp(ocs_hw_t *, int32_t, uint8_t *, void  *);
   97 static int32_t ocs_hw_cb_link_stat(ocs_hw_t *, int32_t, uint8_t *, void  *);
   98 static int32_t ocs_hw_cb_host_stat(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void  *arg);
   99 static void ocs_hw_dmtf_clp_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void  *arg);
  100 static int32_t ocs_hw_clp_resp_get_value(ocs_hw_t *hw, const char *keyword, char *value, uint32_t value_len, const char *resp, uint32_t resp_len);
  101 typedef void (*ocs_hw_dmtf_clp_cb_t)(ocs_hw_t *hw, int32_t status, uint32_t result_len, void *arg);
  102 static ocs_hw_rtn_e ocs_hw_exec_dmtf_clp_cmd(ocs_hw_t *hw, ocs_dma_t *dma_cmd, ocs_dma_t *dma_resp, uint32_t opts, ocs_hw_dmtf_clp_cb_t cb, void *arg);
  103 static void ocs_hw_linkcfg_dmtf_clp_cb(ocs_hw_t *hw, int32_t status, uint32_t result_len, void *arg);
  104 
  105 static int32_t __ocs_read_topology_cb(ocs_hw_t *, int32_t, uint8_t *, void *);
  106 static ocs_hw_rtn_e ocs_hw_get_linkcfg(ocs_hw_t *, uint32_t, ocs_hw_port_control_cb_t, void *);
  107 static ocs_hw_rtn_e ocs_hw_get_linkcfg_lancer(ocs_hw_t *, uint32_t, ocs_hw_port_control_cb_t, void *);
  108 static ocs_hw_rtn_e ocs_hw_get_linkcfg_skyhawk(ocs_hw_t *, uint32_t, ocs_hw_port_control_cb_t, void *);
  109 static ocs_hw_rtn_e ocs_hw_set_linkcfg(ocs_hw_t *, ocs_hw_linkcfg_e, uint32_t, ocs_hw_port_control_cb_t, void *);
  110 static ocs_hw_rtn_e ocs_hw_set_linkcfg_lancer(ocs_hw_t *, ocs_hw_linkcfg_e, uint32_t, ocs_hw_port_control_cb_t, void *);
  111 static ocs_hw_rtn_e ocs_hw_set_linkcfg_skyhawk(ocs_hw_t *, ocs_hw_linkcfg_e, uint32_t, ocs_hw_port_control_cb_t, void *);
  112 static void ocs_hw_init_linkcfg_cb(int32_t status, uintptr_t value, void *arg);
  113 static ocs_hw_rtn_e ocs_hw_set_eth_license(ocs_hw_t *hw, uint32_t license);
  114 static ocs_hw_rtn_e ocs_hw_set_dif_seed(ocs_hw_t *hw);
  115 static ocs_hw_rtn_e ocs_hw_set_dif_mode(ocs_hw_t *hw);
  116 static void ocs_hw_io_free_internal(void *arg);
  117 static void ocs_hw_io_free_port_owned(void *arg);
  118 static ocs_hw_rtn_e ocs_hw_config_auto_xfer_rdy_t10pi(ocs_hw_t *hw, uint8_t *buf);
  119 static ocs_hw_rtn_e ocs_hw_config_set_fdt_xfer_hint(ocs_hw_t *hw, uint32_t fdt_xfer_hint);
  120 static void ocs_hw_wq_process_abort(void *arg, uint8_t *cqe, int32_t status);
  121 static int32_t ocs_hw_config_mrq(ocs_hw_t *hw, uint8_t, uint16_t, uint16_t);
  122 static ocs_hw_rtn_e ocs_hw_config_watchdog_timer(ocs_hw_t *hw);
  123 static ocs_hw_rtn_e ocs_hw_config_sli_port_health_check(ocs_hw_t *hw, uint8_t query, uint8_t enable);
  124 
  125 /* HW domain database operations */
  126 static int32_t ocs_hw_domain_add(ocs_hw_t *, ocs_domain_t *);
  127 static int32_t ocs_hw_domain_del(ocs_hw_t *, ocs_domain_t *);
  128 
  129 /* Port state machine */
  130 static void *__ocs_hw_port_alloc_init(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
  131 static void *__ocs_hw_port_alloc_read_sparm64(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
  132 static void *__ocs_hw_port_alloc_init_vpi(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
  133 static void *__ocs_hw_port_done(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
  134 static void *__ocs_hw_port_free_unreg_vpi(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
  135 
  136 /* Domain state machine */
  137 static void *__ocs_hw_domain_init(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
  138 static void *__ocs_hw_domain_alloc_reg_fcfi(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
  139 static void * __ocs_hw_domain_alloc_init_vfi(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
  140 static void *__ocs_hw_domain_free_unreg_vfi(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
  141 static void *__ocs_hw_domain_free_unreg_fcfi(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data);
  142 static int32_t __ocs_hw_domain_cb(ocs_hw_t *, int32_t, uint8_t *, void *);
  143 static int32_t __ocs_hw_port_cb(ocs_hw_t *, int32_t, uint8_t *, void *);
  144 static int32_t __ocs_hw_port_realloc_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg);
  145 
  146 /* BZ 161832 */
  147 static void ocs_hw_check_sec_hio_list(ocs_hw_t *hw);
  148 
  149 /* WQE timeouts */
  150 static void target_wqe_timer_cb(void *arg);
  151 static void shutdown_target_wqe_timer(ocs_hw_t *hw);
  152 
  153 static inline void
  154 ocs_hw_add_io_timed_wqe(ocs_hw_t *hw, ocs_hw_io_t *io)
  155 {
  156         if (hw->config.emulate_tgt_wqe_timeout && io->tgt_wqe_timeout) {
  157                 /*
  158                  * Active WQE list currently only used for
  159                  * target WQE timeouts.
  160                  */
  161                 ocs_lock(&hw->io_lock);
  162                         ocs_list_add_tail(&hw->io_timed_wqe, io);
  163                         io->submit_ticks = ocs_get_os_ticks();
  164                 ocs_unlock(&hw->io_lock);
  165         }
  166 }
  167 
  168 static inline void
  169 ocs_hw_remove_io_timed_wqe(ocs_hw_t *hw, ocs_hw_io_t *io)
  170 {
  171         if (hw->config.emulate_tgt_wqe_timeout) {
  172                 /*
  173                  * If target wqe timeouts are enabled,
  174                  * remove from active wqe list.
  175                  */
  176                 ocs_lock(&hw->io_lock);
  177                         if (ocs_list_on_list(&io->wqe_link)) {
  178                                 ocs_list_remove(&hw->io_timed_wqe, io);
  179                         }
  180                 ocs_unlock(&hw->io_lock);
  181         }
  182 }
  183 
  184 static uint8_t ocs_hw_iotype_is_originator(uint16_t io_type)
  185 {
  186         switch (io_type) {
  187         case OCS_HW_IO_INITIATOR_READ:
  188         case OCS_HW_IO_INITIATOR_WRITE:
  189         case OCS_HW_IO_INITIATOR_NODATA:
  190         case OCS_HW_FC_CT:
  191         case OCS_HW_ELS_REQ:
  192                 return 1;
  193         default:
  194                 return 0;
  195         }
  196 }
  197 
  198 static uint8_t ocs_hw_wcqe_abort_needed(uint16_t status, uint8_t ext, uint8_t xb)
  199 {
  200         /* if exchange not active, nothing to abort */
  201         if (!xb) {
  202                 return FALSE;
  203         }
  204         if (status == SLI4_FC_WCQE_STATUS_LOCAL_REJECT) {
  205                 switch (ext) {
  206                 /* exceptions where abort is not needed */
  207                 case SLI4_FC_LOCAL_REJECT_INVALID_RPI: /* lancer returns this after unreg_rpi */
  208                 case SLI4_FC_LOCAL_REJECT_ABORT_REQUESTED: /* abort already in progress */
  209                         return FALSE;
  210                 default:
  211                         break;
  212                 }
  213         }
  214         return TRUE;
  215 }
  216 
  217 /**
  218  * @brief Determine the number of chutes on the device.
  219  *
  220  * @par Description
  221  * Some devices require queue resources allocated per protocol processor
  222  * (chute). This function returns the number of chutes on this device.
  223  *
  224  * @param hw Hardware context allocated by the caller.
  225  *
  226  * @return Returns the number of chutes on the device for protocol.
  227  */
  228 static uint32_t
  229 ocs_hw_get_num_chutes(ocs_hw_t *hw)
  230 {
  231         uint32_t num_chutes = 1;
  232 
  233         if (sli_get_is_dual_ulp_capable(&hw->sli) &&
  234             sli_get_is_ulp_enabled(&hw->sli, 0) &&
  235             sli_get_is_ulp_enabled(&hw->sli, 1)) {
  236                 num_chutes = 2;
  237         }
  238         return num_chutes;
  239 }
  240 
  241 static ocs_hw_rtn_e
  242 ocs_hw_link_event_init(ocs_hw_t *hw)
  243 {
  244         ocs_hw_assert(hw);
  245 
  246         hw->link.status = SLI_LINK_STATUS_MAX;
  247         hw->link.topology = SLI_LINK_TOPO_NONE;
  248         hw->link.medium = SLI_LINK_MEDIUM_MAX;
  249         hw->link.speed = 0;
  250         hw->link.loop_map = NULL;
  251         hw->link.fc_id = UINT32_MAX;
  252 
  253         return OCS_HW_RTN_SUCCESS;
  254 }
  255 
  256 /**
  257  * @ingroup devInitShutdown
  258  * @brief If this is physical port 0, then read the max dump size.
  259  *
  260  * @par Description
  261  * Queries the FW for the maximum dump size
  262  *
  263  * @param hw Hardware context allocated by the caller.
  264  *
  265  * @return Returns 0 on success, or a non-zero value on failure.
  266  */
  267 static ocs_hw_rtn_e
  268 ocs_hw_read_max_dump_size(ocs_hw_t *hw)
  269 {
  270         uint8_t buf[SLI4_BMBX_SIZE];
  271         uint8_t bus, dev, func;
  272         int     rc;
  273 
  274         /* lancer only */
  275         if (SLI4_IF_TYPE_LANCER_FC_ETH != sli_get_if_type(&hw->sli)) {
  276                 ocs_log_debug(hw->os, "Function only supported for I/F type 2\n");
  277                 return OCS_HW_RTN_ERROR;
  278         }
  279 
  280         /*
  281          * Make sure the FW is new enough to support this command. If the FW
  282          * is too old, the FW will UE.
  283          */
  284         if (hw->workaround.disable_dump_loc) {
  285                 ocs_log_test(hw->os, "FW version is too old for this feature\n");
  286                 return OCS_HW_RTN_ERROR;
  287         }
  288 
  289         /* attempt to detemine the dump size for function 0 only. */
  290         ocs_get_bus_dev_func(hw->os, &bus, &dev, &func);
  291         if (func == 0) {
  292                 if (sli_cmd_common_set_dump_location(&hw->sli, buf,
  293                                                         SLI4_BMBX_SIZE, 1, 0, NULL, 0)) {
  294                         sli4_res_common_set_dump_location_t *rsp =
  295                                 (sli4_res_common_set_dump_location_t *)
  296                                 (buf + offsetof(sli4_cmd_sli_config_t,
  297                                                 payload.embed));
  298 
  299                         rc = ocs_hw_command(hw, buf, OCS_CMD_POLL, NULL, NULL);
  300                         if (rc != OCS_HW_RTN_SUCCESS) {
  301                                 ocs_log_test(hw->os, "set dump location command failed\n");
  302                                 return rc;
  303                         } else {
  304                                 hw->dump_size = rsp->buffer_length;
  305                                 ocs_log_debug(hw->os, "Dump size %x\n", rsp->buffer_length);
  306                         }
  307                 }
  308         }
  309         return OCS_HW_RTN_SUCCESS;
  310 }
  311 
  312 /**
  313  * @ingroup devInitShutdown
  314  * @brief Set up the Hardware Abstraction Layer module.
  315  *
  316  * @par Description
  317  * Calls set up to configure the hardware.
  318  *
  319  * @param hw Hardware context allocated by the caller.
  320  * @param os Device abstraction.
  321  * @param port_type Protocol type of port, such as FC and NIC.
  322  *
  323  * @todo Why is port_type a parameter?
  324  *
  325  * @return Returns 0 on success, or a non-zero value on failure.
  326  */
  327 ocs_hw_rtn_e
  328 ocs_hw_setup(ocs_hw_t *hw, ocs_os_handle_t os, sli4_port_type_e port_type)
  329 {
  330         uint32_t i;
  331         char prop_buf[32];
  332 
  333         if (hw == NULL) {
  334                 ocs_log_err(os, "bad parameter(s) hw=%p\n", hw);
  335                 return OCS_HW_RTN_ERROR;
  336         }
  337 
  338         if (hw->hw_setup_called) {
  339                 /* Setup run-time workarounds.
  340                  * Call for each setup, to allow for hw_war_version
  341                  */
  342                 ocs_hw_workaround_setup(hw);
  343                 return OCS_HW_RTN_SUCCESS;
  344         }
  345 
  346         /*
  347          * ocs_hw_init() relies on NULL pointers indicating that a structure
  348          * needs allocation. If a structure is non-NULL, ocs_hw_init() won't
  349          * free/realloc that memory
  350          */
  351         ocs_memset(hw, 0, sizeof(ocs_hw_t));
  352 
  353         hw->hw_setup_called = TRUE;
  354 
  355         hw->os = os;
  356 
  357         ocs_lock_init(hw->os, &hw->cmd_lock, "HW_cmd_lock[%d]", ocs_instance(hw->os));
  358         ocs_list_init(&hw->cmd_head, ocs_command_ctx_t, link);
  359         ocs_list_init(&hw->cmd_pending, ocs_command_ctx_t, link);
  360         hw->cmd_head_count = 0;
  361 
  362         ocs_lock_init(hw->os, &hw->io_lock, "HW_io_lock[%d]", ocs_instance(hw->os));
  363         ocs_lock_init(hw->os, &hw->io_abort_lock, "HW_io_abort_lock[%d]", ocs_instance(hw->os));
  364 
  365         ocs_atomic_init(&hw->io_alloc_failed_count, 0);
  366 
  367         hw->config.speed = FC_LINK_SPEED_AUTO_16_8_4;
  368         hw->config.dif_seed = 0;
  369         hw->config.auto_xfer_rdy_blk_size_chip = OCS_HW_AUTO_XFER_RDY_BLK_SIZE_DEFAULT;
  370         hw->config.auto_xfer_rdy_ref_tag_is_lba = OCS_HW_AUTO_XFER_RDY_REF_TAG_IS_LBA_DEFAULT;
  371         hw->config.auto_xfer_rdy_app_tag_valid =  OCS_HW_AUTO_XFER_RDY_APP_TAG_VALID_DEFAULT;
  372         hw->config.auto_xfer_rdy_app_tag_value = OCS_HW_AUTO_XFER_RDY_APP_TAG_VALUE_DEFAULT;
  373 
  374         if (sli_setup(&hw->sli, hw->os, port_type)) {
  375                 ocs_log_err(hw->os, "SLI setup failed\n");
  376                 return OCS_HW_RTN_ERROR;
  377         }
  378 
  379         ocs_memset(hw->domains, 0, sizeof(hw->domains));
  380 
  381         ocs_memset(hw->fcf_index_fcfi, 0, sizeof(hw->fcf_index_fcfi));
  382 
  383         ocs_hw_link_event_init(hw);
  384 
  385         sli_callback(&hw->sli, SLI4_CB_LINK, ocs_hw_cb_link, hw);
  386         sli_callback(&hw->sli, SLI4_CB_FIP, ocs_hw_cb_fip, hw);
  387 
  388         /*
  389          * Set all the queue sizes to the maximum allowed. These values may
  390          * be changes later by the adjust and workaround functions.
  391          */
  392         for (i = 0; i < ARRAY_SIZE(hw->num_qentries); i++) {
  393                 hw->num_qentries[i] = sli_get_max_qentries(&hw->sli, i);
  394         }
  395 
  396         /*
  397          * The RQ assignment for RQ pair mode.
  398          */
  399         hw->config.rq_default_buffer_size = OCS_HW_RQ_SIZE_PAYLOAD;
  400         hw->config.n_io = sli_get_max_rsrc(&hw->sli, SLI_RSRC_FCOE_XRI);
  401         if (ocs_get_property("auto_xfer_rdy_xri_cnt", prop_buf, sizeof(prop_buf)) == 0) {
  402                 hw->config.auto_xfer_rdy_xri_cnt = ocs_strtoul(prop_buf, 0, 0);
  403         }
  404 
  405         /* by default, enable initiator-only auto-ABTS emulation */
  406         hw->config.i_only_aab = TRUE;
  407 
  408         /* Setup run-time workarounds */
  409         ocs_hw_workaround_setup(hw);
  410 
  411         /* HW_WORKAROUND_OVERRIDE_FCFI_IN_SRB */
  412         if (hw->workaround.override_fcfi) {
  413                 hw->first_domain_idx = -1;
  414         }
  415 
  416         /* Must be done after the workaround setup */
  417         if (SLI4_IF_TYPE_LANCER_FC_ETH == sli_get_if_type(&hw->sli)) {
  418                 (void)ocs_hw_read_max_dump_size(hw);
  419         }
  420 
  421         /* calculate the number of WQs required. */
  422         ocs_hw_adjust_wqs(hw);
  423 
  424         /* Set the default dif mode */
  425         if (! sli_is_dif_inline_capable(&hw->sli)) {
  426                 ocs_log_test(hw->os, "not inline capable, setting mode to separate\n");
  427                 hw->config.dif_mode = OCS_HW_DIF_MODE_SEPARATE;
  428         }
  429         /* Workaround: BZ 161832 */
  430         if (hw->workaround.use_dif_sec_xri) {
  431                 ocs_list_init(&hw->sec_hio_wait_list, ocs_hw_io_t, link);
  432         }
  433 
  434         /*
  435          * Figure out the starting and max ULP to spread the WQs across the
  436          * ULPs.
  437          */
  438         if (sli_get_is_dual_ulp_capable(&hw->sli)) {
  439                 if (sli_get_is_ulp_enabled(&hw->sli, 0) &&
  440                     sli_get_is_ulp_enabled(&hw->sli, 1)) {
  441                         hw->ulp_start = 0;
  442                         hw->ulp_max   = 1;
  443                 } else if (sli_get_is_ulp_enabled(&hw->sli, 0)) {
  444                         hw->ulp_start = 0;
  445                         hw->ulp_max   = 0;
  446                 } else {
  447                         hw->ulp_start = 1;
  448                         hw->ulp_max   = 1;
  449                 }
  450         } else {
  451                 if (sli_get_is_ulp_enabled(&hw->sli, 0)) {
  452                         hw->ulp_start = 0;
  453                         hw->ulp_max   = 0;
  454                 } else {
  455                         hw->ulp_start = 1;
  456                         hw->ulp_max   = 1;
  457                 }
  458         }
  459         ocs_log_debug(hw->os, "ulp_start %d, ulp_max %d\n",
  460                 hw->ulp_start, hw->ulp_max);
  461         hw->config.queue_topology = hw_global.queue_topology_string;
  462 
  463         hw->qtop = ocs_hw_qtop_parse(hw, hw->config.queue_topology);
  464 
  465         hw->config.n_eq = hw->qtop->entry_counts[QTOP_EQ];
  466         hw->config.n_cq = hw->qtop->entry_counts[QTOP_CQ];
  467         hw->config.n_rq = hw->qtop->entry_counts[QTOP_RQ];
  468         hw->config.n_wq = hw->qtop->entry_counts[QTOP_WQ];
  469         hw->config.n_mq = hw->qtop->entry_counts[QTOP_MQ];
  470 
  471         /* Verify qtop configuration against driver supported configuration */
  472         if (hw->config.n_rq > OCE_HW_MAX_NUM_MRQ_PAIRS) {
  473                 ocs_log_crit(hw->os, "Max supported MRQ pairs = %d\n",
  474                                 OCE_HW_MAX_NUM_MRQ_PAIRS);
  475                 return OCS_HW_RTN_ERROR;
  476         }
  477 
  478         if (hw->config.n_eq > OCS_HW_MAX_NUM_EQ) {
  479                 ocs_log_crit(hw->os, "Max supported EQs = %d\n",
  480                                 OCS_HW_MAX_NUM_EQ);
  481                 return OCS_HW_RTN_ERROR;
  482         }
  483 
  484         if (hw->config.n_cq > OCS_HW_MAX_NUM_CQ) {
  485                 ocs_log_crit(hw->os, "Max supported CQs = %d\n",
  486                                 OCS_HW_MAX_NUM_CQ);
  487                 return OCS_HW_RTN_ERROR;
  488         }
  489 
  490         if (hw->config.n_wq > OCS_HW_MAX_NUM_WQ) {
  491                 ocs_log_crit(hw->os, "Max supported WQs = %d\n",
  492                                 OCS_HW_MAX_NUM_WQ);
  493                 return OCS_HW_RTN_ERROR;
  494         }
  495 
  496         if (hw->config.n_mq > OCS_HW_MAX_NUM_MQ) {
  497                 ocs_log_crit(hw->os, "Max supported MQs = %d\n",
  498                                 OCS_HW_MAX_NUM_MQ);
  499                 return OCS_HW_RTN_ERROR;
  500         }
  501 
  502         return OCS_HW_RTN_SUCCESS;
  503 }
  504 
  505 /**
  506  * @ingroup devInitShutdown
  507  * @brief Allocate memory structures to prepare for the device operation.
  508  *
  509  * @par Description
  510  * Allocates memory structures needed by the device and prepares the device
  511  * for operation.
  512  * @n @n @b Note: This function may be called more than once (for example, at
  513  * initialization and then after a reset), but the size of the internal resources
  514  * may not be changed without tearing down the HW (ocs_hw_teardown()).
  515  *
  516  * @param hw Hardware context allocated by the caller.
  517  *
  518  * @return Returns 0 on success, or a non-zero value on failure.
  519  */
  520 ocs_hw_rtn_e
  521 ocs_hw_init(ocs_hw_t *hw)
  522 {
  523         ocs_hw_rtn_e    rc;
  524         uint32_t        i = 0;
  525         uint8_t         buf[SLI4_BMBX_SIZE];
  526         uint32_t        max_rpi;
  527         int             rem_count;
  528         int             written_size = 0;
  529         uint32_t        count;
  530         char            prop_buf[32];
  531         uint32_t ramdisc_blocksize = 512;
  532         uint32_t q_count = 0;
  533         /*
  534          * Make sure the command lists are empty. If this is start-of-day,
  535          * they'll be empty since they were just initialized in ocs_hw_setup.
  536          * If we've just gone through a reset, the command and command pending
  537          * lists should have been cleaned up as part of the reset (ocs_hw_reset()).
  538          */
  539         ocs_lock(&hw->cmd_lock);
  540                 if (!ocs_list_empty(&hw->cmd_head)) {
  541                         ocs_log_test(hw->os, "command found on cmd list\n");
  542                         ocs_unlock(&hw->cmd_lock);
  543                         return OCS_HW_RTN_ERROR;
  544                 }
  545                 if (!ocs_list_empty(&hw->cmd_pending)) {
  546                         ocs_log_test(hw->os, "command found on pending list\n");
  547                         ocs_unlock(&hw->cmd_lock);
  548                         return OCS_HW_RTN_ERROR;
  549                 }
  550         ocs_unlock(&hw->cmd_lock);
  551 
  552         /* Free RQ buffers if prevously allocated */
  553         ocs_hw_rx_free(hw);
  554 
  555         /*
  556          * The IO queues must be initialized here for the reset case. The
  557          * ocs_hw_init_io() function will re-add the IOs to the free list.
  558          * The cmd_head list should be OK since we free all entries in
  559          * ocs_hw_command_cancel() that is called in the ocs_hw_reset().
  560          */
  561 
  562         /* If we are in this function due to a reset, there may be stale items
  563          * on lists that need to be removed.  Clean them up.
  564          */
  565         rem_count=0;
  566         if (ocs_list_valid(&hw->io_wait_free)) {
  567                 while ((!ocs_list_empty(&hw->io_wait_free))) {
  568                         rem_count++;
  569                         ocs_list_remove_head(&hw->io_wait_free);
  570                 }
  571                 if (rem_count > 0) {
  572                         ocs_log_debug(hw->os, "removed %d items from io_wait_free list\n", rem_count);
  573                 }
  574         }
  575         rem_count=0;
  576         if (ocs_list_valid(&hw->io_inuse)) {
  577                 while ((!ocs_list_empty(&hw->io_inuse))) {
  578                         rem_count++;
  579                         ocs_list_remove_head(&hw->io_inuse);
  580                 }
  581                 if (rem_count > 0) {
  582                         ocs_log_debug(hw->os, "removed %d items from io_inuse list\n", rem_count);
  583                 }
  584         }
  585         rem_count=0;
  586         if (ocs_list_valid(&hw->io_free)) {
  587                 while ((!ocs_list_empty(&hw->io_free))) {
  588                         rem_count++;
  589                         ocs_list_remove_head(&hw->io_free);
  590                 }
  591                 if (rem_count > 0) {
  592                         ocs_log_debug(hw->os, "removed %d items from io_free list\n", rem_count);
  593                 }
  594         }
  595         if (ocs_list_valid(&hw->io_port_owned)) {
  596                 while ((!ocs_list_empty(&hw->io_port_owned))) {
  597                         ocs_list_remove_head(&hw->io_port_owned);
  598                 }
  599         }
  600         ocs_list_init(&hw->io_inuse, ocs_hw_io_t, link);
  601         ocs_list_init(&hw->io_free, ocs_hw_io_t, link);
  602         ocs_list_init(&hw->io_port_owned, ocs_hw_io_t, link);
  603         ocs_list_init(&hw->io_wait_free, ocs_hw_io_t, link);
  604         ocs_list_init(&hw->io_timed_wqe, ocs_hw_io_t, wqe_link);
  605         ocs_list_init(&hw->io_port_dnrx, ocs_hw_io_t, dnrx_link);
  606 
  607         /* If MRQ not required, Make sure we dont request feature. */
  608         if (hw->config.n_rq == 1) {
  609                 hw->sli.config.features.flag.mrqp = FALSE;
  610         }
  611 
  612         if (sli_init(&hw->sli)) {
  613                 ocs_log_err(hw->os, "SLI failed to initialize\n");
  614                 return OCS_HW_RTN_ERROR;
  615         }
  616 
  617         /*
  618          * Enable the auto xfer rdy feature if requested.
  619          */
  620         hw->auto_xfer_rdy_enabled = FALSE;
  621         if (sli_get_auto_xfer_rdy_capable(&hw->sli) &&
  622             hw->config.auto_xfer_rdy_size > 0) {
  623                 if (hw->config.esoc){
  624                         if (ocs_get_property("ramdisc_blocksize", prop_buf, sizeof(prop_buf)) == 0) {
  625                                 ramdisc_blocksize = ocs_strtoul(prop_buf, 0, 0);
  626                         }
  627                         written_size = sli_cmd_config_auto_xfer_rdy_hp(&hw->sli, buf, SLI4_BMBX_SIZE, hw->config.auto_xfer_rdy_size, 1, ramdisc_blocksize);
  628                 } else {
  629                         written_size = sli_cmd_config_auto_xfer_rdy(&hw->sli, buf, SLI4_BMBX_SIZE, hw->config.auto_xfer_rdy_size);
  630                 }
  631                 if (written_size) {
  632                         rc = ocs_hw_command(hw, buf, OCS_CMD_POLL, NULL, NULL);
  633                         if (rc != OCS_HW_RTN_SUCCESS) {
  634                                 ocs_log_err(hw->os, "config auto xfer rdy failed\n");
  635                                 return rc;
  636                         }
  637                 }
  638                 hw->auto_xfer_rdy_enabled = TRUE;
  639 
  640                 if (hw->config.auto_xfer_rdy_t10_enable) {
  641                         rc = ocs_hw_config_auto_xfer_rdy_t10pi(hw, buf);
  642                         if (rc != OCS_HW_RTN_SUCCESS) {
  643                                 ocs_log_err(hw->os, "set parameters auto xfer rdy T10 PI failed\n");
  644                                 return rc;
  645                         }
  646                 }
  647         }
  648 
  649         if(hw->sliport_healthcheck) {
  650                 rc = ocs_hw_config_sli_port_health_check(hw, 0, 1);
  651                 if (rc != OCS_HW_RTN_SUCCESS) {
  652                         ocs_log_err(hw->os, "Enabling Sliport Health check failed \n");
  653                         return rc;
  654                 }
  655         }
  656 
  657         /*
  658          * Set FDT transfer hint, only works on Lancer
  659          */
  660         if ((hw->sli.if_type == SLI4_IF_TYPE_LANCER_FC_ETH) && (OCS_HW_FDT_XFER_HINT != 0)) {
  661                 /*
  662                  * Non-fatal error. In particular, we can disregard failure to set OCS_HW_FDT_XFER_HINT on
  663                  * devices with legacy firmware that do not support OCS_HW_FDT_XFER_HINT feature.
  664                  */
  665                 ocs_hw_config_set_fdt_xfer_hint(hw, OCS_HW_FDT_XFER_HINT);
  666         }
  667 
  668         /*
  669          * Verify that we have not exceeded any queue sizes
  670          */
  671         q_count = MIN(sli_get_max_queue(&hw->sli, SLI_QTYPE_EQ),
  672                                         OCS_HW_MAX_NUM_EQ);
  673         if (hw->config.n_eq > q_count) {
  674                 ocs_log_err(hw->os, "requested %d EQ but %d allowed\n",
  675                             hw->config.n_eq, q_count);
  676                 return OCS_HW_RTN_ERROR;
  677         }
  678 
  679         q_count = MIN(sli_get_max_queue(&hw->sli, SLI_QTYPE_CQ),
  680                                         OCS_HW_MAX_NUM_CQ);
  681         if (hw->config.n_cq > q_count) {
  682                 ocs_log_err(hw->os, "requested %d CQ but %d allowed\n",
  683                             hw->config.n_cq, q_count);
  684                 return OCS_HW_RTN_ERROR;
  685         }
  686 
  687         q_count = MIN(sli_get_max_queue(&hw->sli, SLI_QTYPE_MQ),
  688                                         OCS_HW_MAX_NUM_MQ);
  689         if (hw->config.n_mq > q_count) {
  690                 ocs_log_err(hw->os, "requested %d MQ but %d allowed\n",
  691                             hw->config.n_mq, q_count);
  692                 return OCS_HW_RTN_ERROR;
  693         }
  694 
  695         q_count = MIN(sli_get_max_queue(&hw->sli, SLI_QTYPE_RQ),
  696                                         OCS_HW_MAX_NUM_RQ);
  697         if (hw->config.n_rq > q_count) {
  698                 ocs_log_err(hw->os, "requested %d RQ but %d allowed\n",
  699                             hw->config.n_rq, q_count);
  700                 return OCS_HW_RTN_ERROR;
  701         }
  702 
  703         q_count = MIN(sli_get_max_queue(&hw->sli, SLI_QTYPE_WQ),
  704                                         OCS_HW_MAX_NUM_WQ);
  705         if (hw->config.n_wq > q_count) {
  706                 ocs_log_err(hw->os, "requested %d WQ but %d allowed\n",
  707                             hw->config.n_wq, q_count);
  708                 return OCS_HW_RTN_ERROR;
  709         }
  710 
  711         /* zero the hashes */
  712         ocs_memset(hw->cq_hash, 0, sizeof(hw->cq_hash));
  713         ocs_log_debug(hw->os, "Max CQs %d, hash size = %d\n",
  714                         OCS_HW_MAX_NUM_CQ, OCS_HW_Q_HASH_SIZE);
  715 
  716         ocs_memset(hw->rq_hash, 0, sizeof(hw->rq_hash));
  717         ocs_log_debug(hw->os, "Max RQs %d, hash size = %d\n",
  718                         OCS_HW_MAX_NUM_RQ, OCS_HW_Q_HASH_SIZE);
  719 
  720         ocs_memset(hw->wq_hash, 0, sizeof(hw->wq_hash));
  721         ocs_log_debug(hw->os, "Max WQs %d, hash size = %d\n",
  722                         OCS_HW_MAX_NUM_WQ, OCS_HW_Q_HASH_SIZE);
  723 
  724         rc = ocs_hw_init_queues(hw, hw->qtop);
  725         if (rc != OCS_HW_RTN_SUCCESS) {
  726                 return rc;
  727         }
  728 
  729         max_rpi = sli_get_max_rsrc(&hw->sli, SLI_RSRC_FCOE_RPI);
  730         i = sli_fc_get_rpi_requirements(&hw->sli, max_rpi);
  731         if (i) {
  732                 ocs_dma_t payload_memory;
  733 
  734                 rc = OCS_HW_RTN_ERROR;
  735 
  736                 if (hw->rnode_mem.size) {
  737                         ocs_dma_free(hw->os, &hw->rnode_mem);
  738                 }
  739 
  740                 if (ocs_dma_alloc(hw->os, &hw->rnode_mem, i, 4096)) {
  741                         ocs_log_err(hw->os, "remote node memory allocation fail\n");
  742                         return OCS_HW_RTN_NO_MEMORY;
  743                 }
  744 
  745                 payload_memory.size = 0;
  746                 if (sli_cmd_fcoe_post_hdr_templates(&hw->sli, buf, SLI4_BMBX_SIZE,
  747                                         &hw->rnode_mem, UINT16_MAX, &payload_memory)) {
  748                         rc = ocs_hw_command(hw, buf, OCS_CMD_POLL, NULL, NULL);
  749 
  750                         if (payload_memory.size != 0) {
  751                                 /* The command was non-embedded - need to free the dma buffer */
  752                                 ocs_dma_free(hw->os, &payload_memory);
  753                         }
  754                 }
  755 
  756                 if (rc != OCS_HW_RTN_SUCCESS) {
  757                         ocs_log_err(hw->os, "header template registration failed\n");
  758                         return rc;
  759                 }
  760         }
  761 
  762         /* Allocate and post RQ buffers */
  763         rc = ocs_hw_rx_allocate(hw);
  764         if (rc) {
  765                 ocs_log_err(hw->os, "rx_allocate failed\n");
  766                 return rc;
  767         }
  768 
  769         /* Populate hw->seq_free_list */
  770         if (hw->seq_pool == NULL) {
  771                 uint32_t count = 0;
  772                 uint32_t i;
  773 
  774                 /* Sum up the total number of RQ entries, to use to allocate the sequence object pool */
  775                 for (i = 0; i < hw->hw_rq_count; i++) {
  776                         count += hw->hw_rq[i]->entry_count;
  777                 }
  778 
  779                 hw->seq_pool = ocs_array_alloc(hw->os, sizeof(ocs_hw_sequence_t), count);
  780                 if (hw->seq_pool == NULL) {
  781                         ocs_log_err(hw->os, "malloc seq_pool failed\n");
  782                         return OCS_HW_RTN_NO_MEMORY;
  783                 }
  784         }
  785 
  786         if(ocs_hw_rx_post(hw)) {
  787                 ocs_log_err(hw->os, "WARNING - error posting RQ buffers\n");
  788         }
  789 
  790         /* Allocate rpi_ref if not previously allocated */
  791         if (hw->rpi_ref == NULL) {
  792                 hw->rpi_ref = ocs_malloc(hw->os, max_rpi * sizeof(*hw->rpi_ref),
  793                                           OCS_M_ZERO | OCS_M_NOWAIT);
  794                 if (hw->rpi_ref == NULL) {
  795                         ocs_log_err(hw->os, "rpi_ref allocation failure (%d)\n", i);
  796                         return OCS_HW_RTN_NO_MEMORY;
  797                 }
  798         }
  799 
  800         for (i = 0; i < max_rpi; i ++) {
  801                 ocs_atomic_init(&hw->rpi_ref[i].rpi_count, 0);
  802                 ocs_atomic_init(&hw->rpi_ref[i].rpi_attached, 0);
  803         }
  804 
  805         ocs_memset(hw->domains, 0, sizeof(hw->domains));
  806 
  807         /* HW_WORKAROUND_OVERRIDE_FCFI_IN_SRB */
  808         if (hw->workaround.override_fcfi) {
  809                 hw->first_domain_idx = -1;
  810         }
  811 
  812         ocs_memset(hw->fcf_index_fcfi, 0, sizeof(hw->fcf_index_fcfi));
  813 
  814         /* Register a FCFI to allow unsolicited frames to be routed to the driver */
  815         if (sli_get_medium(&hw->sli) == SLI_LINK_MEDIUM_FC) {
  816                 if (hw->hw_mrq_count) {
  817                         ocs_log_debug(hw->os, "using REG_FCFI MRQ\n");
  818 
  819                         rc = ocs_hw_config_mrq(hw, SLI4_CMD_REG_FCFI_SET_FCFI_MODE, 0, 0);
  820                         if (rc != OCS_HW_RTN_SUCCESS) {
  821                                 ocs_log_err(hw->os, "REG_FCFI_MRQ FCFI registration failed\n");
  822                                 return rc;
  823                         }
  824 
  825                         rc = ocs_hw_config_mrq(hw, SLI4_CMD_REG_FCFI_SET_MRQ_MODE, 0, 0);
  826                         if (rc != OCS_HW_RTN_SUCCESS) {
  827                                 ocs_log_err(hw->os, "REG_FCFI_MRQ MRQ registration failed\n");
  828                                 return rc;
  829                         }
  830                 } else {
  831                         sli4_cmd_rq_cfg_t rq_cfg[SLI4_CMD_REG_FCFI_NUM_RQ_CFG];
  832 
  833                         ocs_log_debug(hw->os, "using REG_FCFI standard\n");
  834 
  835                         /* Set the filter match/mask values from hw's filter_def values */
  836                         for (i = 0; i < SLI4_CMD_REG_FCFI_NUM_RQ_CFG; i++) {
  837                                 rq_cfg[i].rq_id = 0xffff;
  838                                 rq_cfg[i].r_ctl_mask =  (uint8_t)  hw->config.filter_def[i];
  839                                 rq_cfg[i].r_ctl_match = (uint8_t) (hw->config.filter_def[i] >> 8);
  840                                 rq_cfg[i].type_mask =   (uint8_t) (hw->config.filter_def[i] >> 16);
  841                                 rq_cfg[i].type_match =  (uint8_t) (hw->config.filter_def[i] >> 24);
  842                         }
  843 
  844                         /*
  845                          * Update the rq_id's of the FCF configuration (don't update more than the number
  846                          * of rq_cfg elements)
  847                          */
  848                         for (i = 0; i < OCS_MIN(hw->hw_rq_count, SLI4_CMD_REG_FCFI_NUM_RQ_CFG); i++) {
  849                                 hw_rq_t *rq = hw->hw_rq[i];
  850                                 uint32_t j;
  851                                 for (j = 0; j < SLI4_CMD_REG_FCFI_NUM_RQ_CFG; j++) {
  852                                         uint32_t mask = (rq->filter_mask != 0) ? rq->filter_mask : 1;
  853                                         if (mask & (1U << j)) {
  854                                                 rq_cfg[j].rq_id = rq->hdr->id;
  855                                                 ocs_log_debug(hw->os, "REG_FCFI: filter[%d] %08X -> RQ[%d] id=%d\n",
  856                                                         j, hw->config.filter_def[j], i, rq->hdr->id);
  857                                         }
  858                                 }
  859                         }
  860 
  861                         rc = OCS_HW_RTN_ERROR;
  862 
  863                         if (sli_cmd_reg_fcfi(&hw->sli, buf, SLI4_BMBX_SIZE, 0, rq_cfg, 0)) {
  864                                 rc = ocs_hw_command(hw, buf, OCS_CMD_POLL, NULL, NULL);
  865                         }
  866 
  867                         if (rc != OCS_HW_RTN_SUCCESS) {
  868                                 ocs_log_err(hw->os, "FCFI registration failed\n");
  869                                 return rc;
  870                         }
  871                         hw->fcf_indicator = ((sli4_cmd_reg_fcfi_t *)buf)->fcfi;
  872                 }
  873         }
  874 
  875         /*
  876          * Allocate the WQ request tag pool, if not previously allocated (the request tag value is 16 bits,
  877          * thus the pool allocation size of 64k)
  878          */
  879         rc = ocs_hw_reqtag_init(hw);
  880         if (rc) {
  881                 ocs_log_err(hw->os, "ocs_pool_alloc hw_wq_callback_t failed: %d\n", rc);
  882                 return rc;
  883         }
  884 
  885         rc = ocs_hw_setup_io(hw);
  886         if (rc) {
  887                 ocs_log_err(hw->os, "IO allocation failure\n");
  888                 return rc;
  889         }
  890 
  891         rc = ocs_hw_init_io(hw);
  892         if (rc) {
  893                 ocs_log_err(hw->os, "IO initialization failure\n");
  894                 return rc;
  895         }
  896 
  897         ocs_queue_history_init(hw->os, &hw->q_hist);
  898 
  899         /* get hw link config; polling, so callback will be called immediately */
  900         hw->linkcfg = OCS_HW_LINKCFG_NA;
  901         ocs_hw_get_linkcfg(hw, OCS_CMD_POLL, ocs_hw_init_linkcfg_cb, hw);
  902 
  903         /* if lancer ethernet, ethernet ports need to be enabled */
  904         if ((hw->sli.if_type == SLI4_IF_TYPE_LANCER_FC_ETH) &&
  905             (sli_get_medium(&hw->sli) == SLI_LINK_MEDIUM_ETHERNET)) {
  906                 if (ocs_hw_set_eth_license(hw, hw->eth_license)) {
  907                         /* log warning but continue */
  908                         ocs_log_err(hw->os, "Failed to set ethernet license\n");
  909                 }
  910         }
  911 
  912         /* Set the DIF seed - only for lancer right now */
  913         if (SLI4_IF_TYPE_LANCER_FC_ETH == sli_get_if_type(&hw->sli) &&
  914             ocs_hw_set_dif_seed(hw) != OCS_HW_RTN_SUCCESS) {
  915                 ocs_log_err(hw->os, "Failed to set DIF seed value\n");
  916                 return rc;
  917         }
  918 
  919         /* Set the DIF mode - skyhawk only */
  920         if (SLI4_IF_TYPE_BE3_SKH_PF == sli_get_if_type(&hw->sli) &&
  921             sli_get_dif_capable(&hw->sli)) {
  922                 rc = ocs_hw_set_dif_mode(hw);
  923                 if (rc != OCS_HW_RTN_SUCCESS) {
  924                         ocs_log_err(hw->os, "Failed to set DIF mode value\n");
  925                         return rc;
  926                 }
  927         }
  928 
  929         /*
  930          * Arming the EQ allows (e.g.) interrupts when CQ completions write EQ entries
  931          */
  932         for (i = 0; i < hw->eq_count; i++) {
  933                 sli_queue_arm(&hw->sli, &hw->eq[i], TRUE);
  934         }
  935 
  936         /*
  937          * Initialize RQ hash
  938          */
  939         for (i = 0; i < hw->rq_count; i++) {
  940                 ocs_hw_queue_hash_add(hw->rq_hash, hw->rq[i].id, i);
  941         }
  942 
  943         /*
  944          * Initialize WQ hash
  945          */
  946         for (i = 0; i < hw->wq_count; i++) {
  947                 ocs_hw_queue_hash_add(hw->wq_hash, hw->wq[i].id, i);
  948         }
  949 
  950         /*
  951          * Arming the CQ allows (e.g.) MQ completions to write CQ entries
  952          */
  953         for (i = 0; i < hw->cq_count; i++) {
  954                 ocs_hw_queue_hash_add(hw->cq_hash, hw->cq[i].id, i);
  955                 sli_queue_arm(&hw->sli, &hw->cq[i], TRUE);
  956         }
  957 
  958         /* record the fact that the queues are functional */
  959         hw->state = OCS_HW_STATE_ACTIVE;
  960 
  961         /* Note: Must be after the IOs are setup and the state is active*/
  962         if (ocs_hw_rqpair_init(hw)) {
  963                 ocs_log_err(hw->os, "WARNING - error initializing RQ pair\n");
  964         }
  965 
  966         /* finally kick off periodic timer to check for timed out target WQEs */
  967         if (hw->config.emulate_tgt_wqe_timeout) {
  968                 ocs_setup_timer(hw->os, &hw->wqe_timer, target_wqe_timer_cb, hw,
  969                                 OCS_HW_WQ_TIMER_PERIOD_MS);
  970         }
  971 
  972         /*
  973          * Allocate a HW IOs for send frame.  Allocate one for each Class 1 WQ, or if there
  974          * are none of those, allocate one for WQ[0]
  975          */
  976         if ((count = ocs_varray_get_count(hw->wq_class_array[1])) > 0) {
  977                 for (i = 0; i < count; i++) {
  978                         hw_wq_t *wq = ocs_varray_iter_next(hw->wq_class_array[1]);
  979                         wq->send_frame_io = ocs_hw_io_alloc(hw);
  980                         if (wq->send_frame_io == NULL) {
  981                                 ocs_log_err(hw->os, "ocs_hw_io_alloc for send_frame_io failed\n");
  982                         }
  983                 }
  984         } else {
  985                 hw->hw_wq[0]->send_frame_io = ocs_hw_io_alloc(hw);
  986                 if (hw->hw_wq[0]->send_frame_io == NULL) {
  987                         ocs_log_err(hw->os, "ocs_hw_io_alloc for send_frame_io failed\n");
  988                 }
  989         }
  990 
  991         /* Initialize send frame frame sequence id */
  992         ocs_atomic_init(&hw->send_frame_seq_id, 0);
  993 
  994         /* Initialize watchdog timer if enabled by user */
  995         hw->expiration_logged = 0;
  996         if(hw->watchdog_timeout) {
  997                 if((hw->watchdog_timeout < 1) || (hw->watchdog_timeout > 65534)) {
  998                         ocs_log_err(hw->os, "watchdog_timeout out of range: Valid range is 1 - 65534\n");
  999                 }else if(!ocs_hw_config_watchdog_timer(hw)) {
 1000                         ocs_log_info(hw->os, "watchdog timer configured with timeout = %d seconds \n", hw->watchdog_timeout); 
 1001                 }
 1002         }
 1003 
 1004         if (ocs_dma_alloc(hw->os, &hw->domain_dmem, 112, 4)) {
 1005            ocs_log_err(hw->os, "domain node memory allocation fail\n");
 1006            return OCS_HW_RTN_NO_MEMORY;
 1007         }
 1008 
 1009         if (ocs_dma_alloc(hw->os, &hw->fcf_dmem, OCS_HW_READ_FCF_SIZE, OCS_HW_READ_FCF_SIZE)) {
 1010            ocs_log_err(hw->os, "domain fcf memory allocation fail\n");
 1011            return OCS_HW_RTN_NO_MEMORY;
 1012         }
 1013 
 1014         if ((0 == hw->loop_map.size) && ocs_dma_alloc(hw->os, &hw->loop_map,
 1015                                 SLI4_MIN_LOOP_MAP_BYTES, 4)) {
 1016                 ocs_log_err(hw->os, "Loop dma alloc failed size:%d \n", hw->loop_map.size);
 1017         }
 1018 
 1019         return OCS_HW_RTN_SUCCESS;
 1020 }
 1021 
 1022 /**
 1023  * @brief Configure Multi-RQ
 1024  *
 1025  * @param hw    Hardware context allocated by the caller.
 1026  * @param mode  1 to set MRQ filters and 0 to set FCFI index
 1027  * @param vlanid    valid in mode 0
 1028  * @param fcf_index valid in mode 0
 1029  *
 1030  * @return Returns 0 on success, or a non-zero value on failure.
 1031  */
 1032 static int32_t
 1033 ocs_hw_config_mrq(ocs_hw_t *hw, uint8_t mode, uint16_t vlanid, uint16_t fcf_index)
 1034 {
 1035         uint8_t buf[SLI4_BMBX_SIZE], mrq_bitmask = 0;
 1036         hw_rq_t *rq;
 1037         sli4_cmd_reg_fcfi_mrq_t *rsp = NULL;
 1038         uint32_t i, j;
 1039         sli4_cmd_rq_cfg_t rq_filter[SLI4_CMD_REG_FCFI_MRQ_NUM_RQ_CFG];
 1040         int32_t rc;
 1041 
 1042         if (mode == SLI4_CMD_REG_FCFI_SET_FCFI_MODE) {
 1043                 goto issue_cmd;
 1044         }
 1045 
 1046         /* Set the filter match/mask values from hw's filter_def values */
 1047         for (i = 0; i < SLI4_CMD_REG_FCFI_NUM_RQ_CFG; i++) {
 1048                 rq_filter[i].rq_id = 0xffff;
 1049                 rq_filter[i].r_ctl_mask  = (uint8_t)  hw->config.filter_def[i];
 1050                 rq_filter[i].r_ctl_match = (uint8_t) (hw->config.filter_def[i] >> 8);
 1051                 rq_filter[i].type_mask   = (uint8_t) (hw->config.filter_def[i] >> 16);
 1052                 rq_filter[i].type_match  = (uint8_t) (hw->config.filter_def[i] >> 24);
 1053         }
 1054 
 1055         /* Accumulate counts for each filter type used, build rq_ids[] list */
 1056         for (i = 0; i < hw->hw_rq_count; i++) {
 1057                 rq = hw->hw_rq[i];
 1058                 for (j = 0; j < SLI4_CMD_REG_FCFI_MRQ_NUM_RQ_CFG; j++) {
 1059                         if (rq->filter_mask & (1U << j)) {
 1060                                 if (rq_filter[j].rq_id != 0xffff) {
 1061                                         /* Already used. Bailout ifts not RQset case */
 1062                                         if (!rq->is_mrq || (rq_filter[j].rq_id != rq->base_mrq_id)) {
 1063                                                 ocs_log_err(hw->os, "Wrong queue topology.\n");
 1064                                                 return OCS_HW_RTN_ERROR;
 1065                                         }
 1066                                         continue;
 1067                                 }
 1068 
 1069                                 if (rq->is_mrq) {
 1070                                         rq_filter[j].rq_id = rq->base_mrq_id;
 1071                                         mrq_bitmask |= (1U << j);
 1072                                 } else {
 1073                                         rq_filter[j].rq_id = rq->hdr->id;
 1074                                 }
 1075                         }
 1076                 }
 1077         }
 1078 
 1079 issue_cmd:
 1080         /* Invoke REG_FCFI_MRQ */
 1081         rc = sli_cmd_reg_fcfi_mrq(&hw->sli,
 1082                                  buf,                                   /* buf */
 1083                                  SLI4_BMBX_SIZE,                        /* size */
 1084                                  mode,                                  /* mode 1 */
 1085                                  fcf_index,                             /* fcf_index */
 1086                                  vlanid,                                /* vlan_id */
 1087                                  hw->config.rq_selection_policy,        /* RQ selection policy*/
 1088                                  mrq_bitmask,                           /* MRQ bitmask */
 1089                                  hw->hw_mrq_count,                      /* num_mrqs */
 1090                                  rq_filter);                            /* RQ filter */
 1091         if (rc == 0) {
 1092                 ocs_log_err(hw->os, "sli_cmd_reg_fcfi_mrq() failed: %d\n", rc);
 1093                 return OCS_HW_RTN_ERROR;
 1094         }
 1095 
 1096         rc = ocs_hw_command(hw, buf, OCS_CMD_POLL, NULL, NULL);
 1097 
 1098         rsp = (sli4_cmd_reg_fcfi_mrq_t *)buf;
 1099 
 1100         if ((rc != OCS_HW_RTN_SUCCESS) || (rsp->hdr.status)) {
 1101                 ocs_log_err(hw->os, "FCFI MRQ registration failed. cmd = %x status = %x\n",
 1102                             rsp->hdr.command, rsp->hdr.status);
 1103                 return OCS_HW_RTN_ERROR;
 1104         }
 1105 
 1106         if (mode == SLI4_CMD_REG_FCFI_SET_FCFI_MODE) {
 1107                 hw->fcf_indicator = rsp->fcfi;
 1108         }
 1109         return 0;
 1110 }
 1111 
 1112 /**
 1113  * @brief Callback function for getting linkcfg during HW initialization.
 1114  *
 1115  * @param status Status of the linkcfg get operation.
 1116  * @param value Link configuration enum to which the link configuration is set.
 1117  * @param arg Callback argument (ocs_hw_t *).
 1118  *
 1119  * @return None.
 1120  */
 1121 static void
 1122 ocs_hw_init_linkcfg_cb(int32_t status, uintptr_t value, void *arg)
 1123 {
 1124         ocs_hw_t *hw = (ocs_hw_t *)arg;
 1125         if (status == 0) {
 1126                 hw->linkcfg = (ocs_hw_linkcfg_e)value;
 1127         } else {
 1128                 hw->linkcfg = OCS_HW_LINKCFG_NA;
 1129         }
 1130         ocs_log_debug(hw->os, "linkcfg=%d\n", hw->linkcfg);
 1131 }
 1132 
 1133 /**
 1134  * @ingroup devInitShutdown
 1135  * @brief Tear down the Hardware Abstraction Layer module.
 1136  *
 1137  * @par Description
 1138  * Frees memory structures needed by the device, and shuts down the device. Does
 1139  * not free the HW context memory (which is done by the caller).
 1140  *
 1141  * @param hw Hardware context allocated by the caller.
 1142  *
 1143  * @return Returns 0 on success, or a non-zero value on failure.
 1144  */
 1145 ocs_hw_rtn_e
 1146 ocs_hw_teardown(ocs_hw_t *hw)
 1147 {
 1148         uint32_t        i = 0;
 1149         uint32_t        iters = 10;/*XXX*/
 1150         uint32_t        max_rpi;
 1151         uint32_t destroy_queues;
 1152         uint32_t free_memory;
 1153 
 1154         if (!hw) {
 1155                 ocs_log_err(NULL, "bad parameter(s) hw=%p\n", hw);
 1156                 return OCS_HW_RTN_ERROR;
 1157         }
 1158 
 1159         destroy_queues = (hw->state == OCS_HW_STATE_ACTIVE);
 1160         free_memory = (hw->state != OCS_HW_STATE_UNINITIALIZED);
 1161 
 1162         /* shutdown target wqe timer */
 1163         shutdown_target_wqe_timer(hw);
 1164 
 1165         /* Cancel watchdog timer if enabled */
 1166         if(hw->watchdog_timeout) {
 1167                 hw->watchdog_timeout = 0;
 1168                 ocs_hw_config_watchdog_timer(hw);
 1169         }
 1170 
 1171         /* Cancel Sliport Healthcheck */
 1172         if(hw->sliport_healthcheck) {
 1173                 hw->sliport_healthcheck = 0;
 1174                 ocs_hw_config_sli_port_health_check(hw, 0, 0);
 1175         }
 1176 
 1177         if (hw->state != OCS_HW_STATE_QUEUES_ALLOCATED) {
 1178                 hw->state = OCS_HW_STATE_TEARDOWN_IN_PROGRESS;
 1179 
 1180                 ocs_hw_flush(hw);
 1181 
 1182                 /* If there are outstanding commands, wait for them to complete */
 1183                 while (!ocs_list_empty(&hw->cmd_head) && iters) {
 1184                         ocs_udelay(10000);
 1185                         ocs_hw_flush(hw);
 1186                         iters--;
 1187                 }
 1188 
 1189                 if (ocs_list_empty(&hw->cmd_head)) {
 1190                         ocs_log_debug(hw->os, "All commands completed on MQ queue\n");
 1191                 } else {
 1192                         ocs_log_debug(hw->os, "Some commands still pending on MQ queue\n");
 1193                 }
 1194 
 1195                 /* Cancel any remaining commands */
 1196                 ocs_hw_command_cancel(hw);
 1197         } else {
 1198                 hw->state = OCS_HW_STATE_TEARDOWN_IN_PROGRESS;
 1199         }
 1200 
 1201         ocs_lock_free(&hw->cmd_lock);
 1202 
 1203         /* Free unregistered RPI if workaround is in force */
 1204         if (hw->workaround.use_unregistered_rpi) {
 1205                 sli_resource_free(&hw->sli, SLI_RSRC_FCOE_RPI, hw->workaround.unregistered_rid);
 1206         }
 1207 
 1208         max_rpi = sli_get_max_rsrc(&hw->sli, SLI_RSRC_FCOE_RPI);
 1209         if (hw->rpi_ref) {
 1210                 for (i = 0; i < max_rpi; i++) {
 1211                         if (ocs_atomic_read(&hw->rpi_ref[i].rpi_count)) {
 1212                                 ocs_log_debug(hw->os, "non-zero ref [%d]=%d\n",
 1213                                                 i, ocs_atomic_read(&hw->rpi_ref[i].rpi_count));
 1214                         }
 1215                 }
 1216                 ocs_free(hw->os, hw->rpi_ref, max_rpi * sizeof(*hw->rpi_ref));
 1217                 hw->rpi_ref = NULL;
 1218         }
 1219 
 1220         ocs_dma_free(hw->os, &hw->rnode_mem);
 1221 
 1222         if (hw->io) {
 1223                 for (i = 0; i < hw->config.n_io; i++) {
 1224                         if (hw->io[i] && (hw->io[i]->sgl != NULL) &&
 1225                             (hw->io[i]->sgl->virt != NULL)) {
 1226                                 if(hw->io[i]->is_port_owned) {
 1227                                         ocs_lock_free(&hw->io[i]->axr_lock);
 1228                                 }
 1229                                 ocs_dma_free(hw->os, hw->io[i]->sgl);
 1230                         }
 1231                         ocs_free(hw->os, hw->io[i], sizeof(ocs_hw_io_t));
 1232                         hw->io[i] = NULL;
 1233                 }
 1234                 ocs_free(hw->os, hw->wqe_buffs, hw->config.n_io * hw->sli.config.wqe_size);
 1235                 hw->wqe_buffs = NULL;
 1236                 ocs_free(hw->os, hw->io, hw->config.n_io * sizeof(ocs_hw_io_t *));
 1237                 hw->io = NULL;
 1238         }
 1239 
 1240         ocs_dma_free(hw->os, &hw->xfer_rdy);
 1241         ocs_dma_free(hw->os, &hw->dump_sges);
 1242         ocs_dma_free(hw->os, &hw->loop_map);
 1243 
 1244         ocs_lock_free(&hw->io_lock);
 1245         ocs_lock_free(&hw->io_abort_lock);
 1246 
 1247         for (i = 0; i < hw->wq_count; i++) {
 1248                 sli_queue_free(&hw->sli, &hw->wq[i], destroy_queues, free_memory);
 1249         }
 1250 
 1251         for (i = 0; i < hw->rq_count; i++) {
 1252                 sli_queue_free(&hw->sli, &hw->rq[i], destroy_queues, free_memory);
 1253         }
 1254 
 1255         for (i = 0; i < hw->mq_count; i++) {
 1256                 sli_queue_free(&hw->sli, &hw->mq[i], destroy_queues, free_memory);
 1257         }
 1258 
 1259         for (i = 0; i < hw->cq_count; i++) {
 1260                 sli_queue_free(&hw->sli, &hw->cq[i], destroy_queues, free_memory);
 1261         }
 1262 
 1263         for (i = 0; i < hw->eq_count; i++) {
 1264                 sli_queue_free(&hw->sli, &hw->eq[i], destroy_queues, free_memory);
 1265         }
 1266 
 1267         ocs_hw_qtop_free(hw->qtop);
 1268 
 1269         /* Free rq buffers */
 1270         ocs_hw_rx_free(hw);
 1271 
 1272         hw_queue_teardown(hw);
 1273 
 1274         ocs_hw_rqpair_teardown(hw);
 1275 
 1276         if (sli_teardown(&hw->sli)) {
 1277                 ocs_log_err(hw->os, "SLI teardown failed\n");
 1278         }
 1279 
 1280         ocs_queue_history_free(&hw->q_hist);
 1281 
 1282         /* record the fact that the queues are non-functional */
 1283         hw->state = OCS_HW_STATE_UNINITIALIZED;
 1284 
 1285         /* free sequence free pool */
 1286         ocs_array_free(hw->seq_pool);
 1287         hw->seq_pool = NULL;
 1288 
 1289         /* free hw_wq_callback pool */
 1290         ocs_pool_free(hw->wq_reqtag_pool);
 1291 
 1292         ocs_dma_free(hw->os, &hw->domain_dmem);
 1293         ocs_dma_free(hw->os, &hw->fcf_dmem);
 1294         /* Mark HW setup as not having been called */
 1295         hw->hw_setup_called = FALSE;
 1296 
 1297         return OCS_HW_RTN_SUCCESS;
 1298 }
 1299 
 1300 ocs_hw_rtn_e
 1301 ocs_hw_reset(ocs_hw_t *hw, ocs_hw_reset_e reset)
 1302 {
 1303         uint32_t        i;
 1304         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 1305         uint32_t        iters;
 1306         ocs_hw_state_e prev_state = hw->state;
 1307 
 1308         if (hw->state != OCS_HW_STATE_ACTIVE) {
 1309                 ocs_log_test(hw->os, "HW state %d is not active\n", hw->state);
 1310         }
 1311 
 1312         hw->state = OCS_HW_STATE_RESET_IN_PROGRESS;
 1313 
 1314         /* shutdown target wqe timer */
 1315         shutdown_target_wqe_timer(hw);
 1316 
 1317         ocs_hw_flush(hw);
 1318 
 1319         /*
 1320          * If an mailbox command requiring a DMA is outstanding (i.e. SFP/DDM),
 1321          * then the FW will UE when the reset is issued. So attempt to complete
 1322          * all mailbox commands.
 1323          */
 1324         iters = 10;
 1325         while (!ocs_list_empty(&hw->cmd_head) && iters) {
 1326                 ocs_udelay(10000);
 1327                 ocs_hw_flush(hw);
 1328                 iters--;
 1329         }
 1330 
 1331         if (ocs_list_empty(&hw->cmd_head)) {
 1332                 ocs_log_debug(hw->os, "All commands completed on MQ queue\n");
 1333         } else {
 1334                 ocs_log_debug(hw->os, "Some commands still pending on MQ queue\n");
 1335         }
 1336 
 1337         /* Reset the chip */
 1338         switch(reset) {
 1339         case OCS_HW_RESET_FUNCTION:
 1340                 ocs_log_debug(hw->os, "issuing function level reset\n");
 1341                 if (sli_reset(&hw->sli)) {
 1342                         ocs_log_err(hw->os, "sli_reset failed\n");
 1343                         rc = OCS_HW_RTN_ERROR;
 1344                 }
 1345                 break;
 1346         case OCS_HW_RESET_FIRMWARE:
 1347                 ocs_log_debug(hw->os, "issuing firmware reset\n");
 1348                 if (sli_fw_reset(&hw->sli)) {
 1349                         ocs_log_err(hw->os, "sli_soft_reset failed\n");
 1350                         rc = OCS_HW_RTN_ERROR;
 1351                 }
 1352                 /*
 1353                  * Because the FW reset leaves the FW in a non-running state,
 1354                  * follow that with a regular reset.
 1355                  */
 1356                 ocs_log_debug(hw->os, "issuing function level reset\n");
 1357                 if (sli_reset(&hw->sli)) {
 1358                         ocs_log_err(hw->os, "sli_reset failed\n");
 1359                         rc = OCS_HW_RTN_ERROR;
 1360                 }
 1361                 break;
 1362         default:
 1363                 ocs_log_test(hw->os, "unknown reset type - no reset performed\n");
 1364                 hw->state = prev_state;
 1365                 return OCS_HW_RTN_ERROR;
 1366         }
 1367 
 1368         /* Not safe to walk command/io lists unless they've been initialized */
 1369         if (prev_state != OCS_HW_STATE_UNINITIALIZED) {
 1370                 ocs_hw_command_cancel(hw);
 1371 
 1372                 /* Clean up the inuse list, the free list and the wait free list */
 1373                 ocs_hw_io_cancel(hw);
 1374 
 1375                 ocs_memset(hw->domains, 0, sizeof(hw->domains));
 1376                 ocs_memset(hw->fcf_index_fcfi, 0, sizeof(hw->fcf_index_fcfi));
 1377 
 1378                 ocs_hw_link_event_init(hw);
 1379 
 1380                 ocs_lock(&hw->io_lock);
 1381                         /* The io lists should be empty, but remove any that didn't get cleaned up. */
 1382                         while (!ocs_list_empty(&hw->io_timed_wqe)) {
 1383                                 ocs_list_remove_head(&hw->io_timed_wqe);
 1384                         }
 1385                         /* Don't clean up the io_inuse list, the backend will do that when it finishes the IO */
 1386 
 1387                         while (!ocs_list_empty(&hw->io_free)) {
 1388                                 ocs_list_remove_head(&hw->io_free);
 1389                         }
 1390                         while (!ocs_list_empty(&hw->io_wait_free)) {
 1391                                 ocs_list_remove_head(&hw->io_wait_free);
 1392                         }
 1393 
 1394                         /* Reset the request tag pool, the HW IO request tags are reassigned in ocs_hw_setup_io() */
 1395                         ocs_hw_reqtag_reset(hw);
 1396 
 1397                 ocs_unlock(&hw->io_lock);
 1398         }
 1399 
 1400         if (prev_state != OCS_HW_STATE_UNINITIALIZED) {
 1401                 for (i = 0; i < hw->wq_count; i++) {
 1402                         sli_queue_reset(&hw->sli, &hw->wq[i]);
 1403                 }
 1404 
 1405                 for (i = 0; i < hw->rq_count; i++) {
 1406                         sli_queue_reset(&hw->sli, &hw->rq[i]);
 1407                 }
 1408 
 1409                 for (i = 0; i < hw->hw_rq_count; i++) {
 1410                         hw_rq_t *rq = hw->hw_rq[i];
 1411                         if (rq->rq_tracker != NULL) {
 1412                                 uint32_t j;
 1413 
 1414                                 for (j = 0; j < rq->entry_count; j++) {
 1415                                         rq->rq_tracker[j] = NULL;
 1416                                 }
 1417                         }
 1418                 }
 1419 
 1420                 for (i = 0; i < hw->mq_count; i++) {
 1421                         sli_queue_reset(&hw->sli, &hw->mq[i]);
 1422                 }
 1423 
 1424                 for (i = 0; i < hw->cq_count; i++) {
 1425                         sli_queue_reset(&hw->sli, &hw->cq[i]);
 1426                 }
 1427 
 1428                 for (i = 0; i < hw->eq_count; i++) {
 1429                         sli_queue_reset(&hw->sli, &hw->eq[i]);
 1430                 }
 1431 
 1432                 /* Free rq buffers */
 1433                 ocs_hw_rx_free(hw);
 1434 
 1435                 /* Teardown the HW queue topology */
 1436                 hw_queue_teardown(hw);
 1437         } else {
 1438                 /* Free rq buffers */
 1439                 ocs_hw_rx_free(hw);
 1440         }
 1441 
 1442         /*
 1443          * Re-apply the run-time workarounds after clearing the SLI config
 1444          * fields in sli_reset.
 1445          */
 1446         ocs_hw_workaround_setup(hw);
 1447         hw->state = OCS_HW_STATE_QUEUES_ALLOCATED;
 1448 
 1449         return rc;
 1450 }
 1451 
 1452 int32_t
 1453 ocs_hw_get_num_eq(ocs_hw_t *hw)
 1454 {
 1455         return hw->eq_count;
 1456 }
 1457 
 1458 static int32_t
 1459 ocs_hw_get_fw_timed_out(ocs_hw_t *hw)
 1460 {
 1461         /* The error values below are taken from LOWLEVEL_SET_WATCHDOG_TIMER_rev1.pdf
 1462         * No further explanation is given in the document.
 1463         * */
 1464         return (sli_reg_read(&hw->sli, SLI4_REG_SLIPORT_ERROR1) == 0x2 &&
 1465                 sli_reg_read(&hw->sli, SLI4_REG_SLIPORT_ERROR2) == 0x10);
 1466 }
 1467 
 1468 ocs_hw_rtn_e
 1469 ocs_hw_get(ocs_hw_t *hw, ocs_hw_property_e prop, uint32_t *value)
 1470 {
 1471         ocs_hw_rtn_e            rc = OCS_HW_RTN_SUCCESS;
 1472         int32_t                 tmp;
 1473 
 1474         if (!value) {
 1475                 return OCS_HW_RTN_ERROR;
 1476         }
 1477 
 1478         *value = 0;
 1479 
 1480         switch (prop) {
 1481         case OCS_HW_N_IO:
 1482                 *value = hw->config.n_io;
 1483                 break;
 1484         case OCS_HW_N_SGL:
 1485                 *value = (hw->config.n_sgl - SLI4_SGE_MAX_RESERVED);
 1486                 break;
 1487         case OCS_HW_MAX_IO:
 1488                 *value = sli_get_max_rsrc(&hw->sli, SLI_RSRC_FCOE_XRI);
 1489                 break;
 1490         case OCS_HW_MAX_NODES:
 1491                 *value = sli_get_max_rsrc(&hw->sli, SLI_RSRC_FCOE_RPI);
 1492                 break;
 1493         case OCS_HW_MAX_RQ_ENTRIES:
 1494                 *value = hw->num_qentries[SLI_QTYPE_RQ];
 1495                 break;
 1496         case OCS_HW_RQ_DEFAULT_BUFFER_SIZE:
 1497                 *value = hw->config.rq_default_buffer_size;
 1498                 break;
 1499         case OCS_HW_AUTO_XFER_RDY_CAPABLE:
 1500                 *value = sli_get_auto_xfer_rdy_capable(&hw->sli);
 1501                 break;
 1502         case OCS_HW_AUTO_XFER_RDY_XRI_CNT:
 1503                 *value = hw->config.auto_xfer_rdy_xri_cnt;
 1504                 break;
 1505         case OCS_HW_AUTO_XFER_RDY_SIZE:
 1506                 *value = hw->config.auto_xfer_rdy_size;
 1507                 break;
 1508         case OCS_HW_AUTO_XFER_RDY_BLK_SIZE:
 1509                 switch (hw->config.auto_xfer_rdy_blk_size_chip) {
 1510                 case 0:
 1511                         *value = 512;
 1512                         break;
 1513                 case 1:
 1514                         *value = 1024;
 1515                         break;
 1516                 case 2:
 1517                         *value = 2048;
 1518                         break;
 1519                 case 3:
 1520                         *value = 4096;
 1521                         break;
 1522                 case 4:
 1523                         *value = 520;
 1524                         break;
 1525                 default:
 1526                         *value = 0;
 1527                         rc = OCS_HW_RTN_ERROR;
 1528                         break;
 1529                 }
 1530                 break;
 1531         case OCS_HW_AUTO_XFER_RDY_T10_ENABLE:
 1532                 *value = hw->config.auto_xfer_rdy_t10_enable;
 1533                 break;
 1534         case OCS_HW_AUTO_XFER_RDY_P_TYPE:
 1535                 *value = hw->config.auto_xfer_rdy_p_type;
 1536                 break;
 1537         case OCS_HW_AUTO_XFER_RDY_REF_TAG_IS_LBA:
 1538                 *value = hw->config.auto_xfer_rdy_ref_tag_is_lba;
 1539                 break;
 1540         case OCS_HW_AUTO_XFER_RDY_APP_TAG_VALID:
 1541                 *value = hw->config.auto_xfer_rdy_app_tag_valid;
 1542                 break;
 1543         case OCS_HW_AUTO_XFER_RDY_APP_TAG_VALUE:
 1544                 *value = hw->config.auto_xfer_rdy_app_tag_value;
 1545                 break;
 1546         case OCS_HW_MAX_SGE:
 1547                 *value = sli_get_max_sge(&hw->sli);
 1548                 break;
 1549         case OCS_HW_MAX_SGL:
 1550                 *value = sli_get_max_sgl(&hw->sli);
 1551                 break;
 1552         case OCS_HW_TOPOLOGY:
 1553                 /*
 1554                  * Infer link.status based on link.speed.
 1555                  * Report OCS_HW_TOPOLOGY_NONE if the link is down.
 1556                  */
 1557                 if (hw->link.speed == 0) {
 1558                         *value = OCS_HW_TOPOLOGY_NONE;
 1559                         break;
 1560                 }
 1561                 switch (hw->link.topology) {
 1562                 case SLI_LINK_TOPO_NPORT:
 1563                         *value = OCS_HW_TOPOLOGY_NPORT;
 1564                         break;
 1565                 case SLI_LINK_TOPO_LOOP:
 1566                         *value = OCS_HW_TOPOLOGY_LOOP;
 1567                         break;
 1568                 case SLI_LINK_TOPO_NONE:
 1569                         *value = OCS_HW_TOPOLOGY_NONE;
 1570                         break;
 1571                 default:
 1572                         ocs_log_test(hw->os, "unsupported topology %#x\n", hw->link.topology);
 1573                         rc = OCS_HW_RTN_ERROR;
 1574                         break;
 1575                 }
 1576                 break;
 1577         case OCS_HW_CONFIG_TOPOLOGY:
 1578                 *value = hw->config.topology;
 1579                 break;
 1580         case OCS_HW_LINK_SPEED:
 1581                 *value = hw->link.speed;
 1582                 break;
 1583         case OCS_HW_LINK_CONFIG_SPEED:
 1584                 switch (hw->config.speed) {
 1585                 case FC_LINK_SPEED_10G:
 1586                         *value = 10000;
 1587                         break;
 1588                 case FC_LINK_SPEED_AUTO_16_8_4:
 1589                         *value = 0;
 1590                         break;
 1591                 case FC_LINK_SPEED_2G:
 1592                         *value = 2000;
 1593                         break;
 1594                 case FC_LINK_SPEED_4G:
 1595                         *value = 4000;
 1596                         break;
 1597                 case FC_LINK_SPEED_8G:
 1598                         *value = 8000;
 1599                         break;
 1600                 case FC_LINK_SPEED_16G:
 1601                         *value = 16000;
 1602                         break;
 1603                 case FC_LINK_SPEED_32G:
 1604                         *value = 32000;
 1605                         break;
 1606                 default:
 1607                         ocs_log_test(hw->os, "unsupported speed %#x\n", hw->config.speed);
 1608                         rc = OCS_HW_RTN_ERROR;
 1609                         break;
 1610                 }
 1611                 break;
 1612         case OCS_HW_IF_TYPE:
 1613                 *value = sli_get_if_type(&hw->sli);
 1614                 break;
 1615         case OCS_HW_SLI_REV:
 1616                 *value = sli_get_sli_rev(&hw->sli);
 1617                 break;
 1618         case OCS_HW_SLI_FAMILY:
 1619                 *value = sli_get_sli_family(&hw->sli);
 1620                 break;
 1621         case OCS_HW_DIF_CAPABLE:
 1622                 *value = sli_get_dif_capable(&hw->sli);
 1623                 break;
 1624         case OCS_HW_DIF_SEED:
 1625                 *value = hw->config.dif_seed;
 1626                 break;
 1627         case OCS_HW_DIF_MODE:
 1628                 *value = hw->config.dif_mode;
 1629                 break;
 1630         case OCS_HW_DIF_MULTI_SEPARATE:
 1631                 /* Lancer supports multiple DIF separates */
 1632                 if (hw->sli.if_type == SLI4_IF_TYPE_LANCER_FC_ETH) {
 1633                         *value = TRUE;
 1634                 } else {
 1635                         *value = FALSE;
 1636                 }
 1637                 break;
 1638         case OCS_HW_DUMP_MAX_SIZE:
 1639                 *value = hw->dump_size;
 1640                 break;
 1641         case OCS_HW_DUMP_READY:
 1642                 *value = sli_dump_is_ready(&hw->sli);
 1643                 break;
 1644         case OCS_HW_DUMP_PRESENT:
 1645                 *value = sli_dump_is_present(&hw->sli);
 1646                 break;
 1647         case OCS_HW_RESET_REQUIRED:
 1648                 tmp = sli_reset_required(&hw->sli);
 1649                 if(tmp < 0) {
 1650                         rc = OCS_HW_RTN_ERROR;
 1651                 } else {
 1652                         *value = tmp;
 1653                 }
 1654                 break;
 1655         case OCS_HW_FW_ERROR:
 1656                 *value = sli_fw_error_status(&hw->sli);
 1657                 break;
 1658         case OCS_HW_FW_READY:
 1659                 *value = sli_fw_ready(&hw->sli);
 1660                 break;
 1661         case OCS_HW_FW_TIMED_OUT:
 1662                 *value = ocs_hw_get_fw_timed_out(hw);
 1663                 break;
 1664         case OCS_HW_HIGH_LOGIN_MODE:
 1665                 *value = sli_get_hlm_capable(&hw->sli);
 1666                 break;
 1667         case OCS_HW_PREREGISTER_SGL:
 1668                 *value = sli_get_sgl_preregister_required(&hw->sli);
 1669                 break;
 1670         case OCS_HW_HW_REV1:
 1671                 *value = sli_get_hw_revision(&hw->sli, 0);
 1672                 break;
 1673         case OCS_HW_HW_REV2:
 1674                 *value = sli_get_hw_revision(&hw->sli, 1);
 1675                 break;
 1676         case OCS_HW_HW_REV3:
 1677                 *value = sli_get_hw_revision(&hw->sli, 2);
 1678                 break;
 1679         case OCS_HW_LINKCFG:
 1680                 *value = hw->linkcfg;
 1681                 break;
 1682         case OCS_HW_ETH_LICENSE:
 1683                 *value = hw->eth_license;
 1684                 break;
 1685         case OCS_HW_LINK_MODULE_TYPE:
 1686                 *value = sli_get_link_module_type(&hw->sli);
 1687                 break;
 1688         case OCS_HW_NUM_CHUTES:
 1689                 *value = ocs_hw_get_num_chutes(hw);
 1690                 break;
 1691         case OCS_HW_DISABLE_AR_TGT_DIF:
 1692                 *value = hw->workaround.disable_ar_tgt_dif;
 1693                 break;
 1694         case OCS_HW_EMULATE_I_ONLY_AAB:
 1695                 *value = hw->config.i_only_aab;
 1696                 break;
 1697         case OCS_HW_EMULATE_TARGET_WQE_TIMEOUT:
 1698                 *value = hw->config.emulate_tgt_wqe_timeout;
 1699                 break;
 1700         case OCS_HW_VPD_LEN:
 1701                 *value = sli_get_vpd_len(&hw->sli);
 1702                 break;
 1703         case OCS_HW_SGL_CHAINING_CAPABLE:
 1704                 *value = sli_get_is_sgl_chaining_capable(&hw->sli) || hw->workaround.sglc_misreported;
 1705                 break;
 1706         case OCS_HW_SGL_CHAINING_ALLOWED:
 1707                 /*
 1708                  * SGL Chaining is allowed in the following cases:
 1709                  *   1. Lancer with host SGL Lists
 1710                  *   2. Skyhawk with pre-registered SGL Lists
 1711                  */
 1712                 *value = FALSE;
 1713                 if ((sli_get_is_sgl_chaining_capable(&hw->sli) || hw->workaround.sglc_misreported) &&
 1714                     !sli_get_sgl_preregister(&hw->sli) &&
 1715                     SLI4_IF_TYPE_LANCER_FC_ETH  == sli_get_if_type(&hw->sli)) {
 1716                         *value = TRUE;
 1717                 }
 1718 
 1719                 if ((sli_get_is_sgl_chaining_capable(&hw->sli) || hw->workaround.sglc_misreported) &&
 1720                     sli_get_sgl_preregister(&hw->sli) &&
 1721                     ((SLI4_IF_TYPE_BE3_SKH_PF == sli_get_if_type(&hw->sli)) ||
 1722                         (SLI4_IF_TYPE_BE3_SKH_VF == sli_get_if_type(&hw->sli)))) {
 1723                         *value = TRUE;
 1724                 }
 1725                 break;
 1726         case OCS_HW_SGL_CHAINING_HOST_ALLOCATED:
 1727                 /* Only lancer supports host allocated SGL Chaining buffers. */
 1728                 *value = ((sli_get_is_sgl_chaining_capable(&hw->sli) || hw->workaround.sglc_misreported) &&
 1729                           (SLI4_IF_TYPE_LANCER_FC_ETH  == sli_get_if_type(&hw->sli)));
 1730                 break;
 1731         case OCS_HW_SEND_FRAME_CAPABLE:
 1732                 if (hw->workaround.ignore_send_frame) {
 1733                         *value = 0;
 1734                 } else {
 1735                         /* Only lancer is capable */
 1736                         *value = sli_get_if_type(&hw->sli) == SLI4_IF_TYPE_LANCER_FC_ETH;
 1737                 }
 1738                 break;
 1739         case OCS_HW_RQ_SELECTION_POLICY:
 1740                 *value = hw->config.rq_selection_policy;
 1741                 break;
 1742         case OCS_HW_RR_QUANTA:
 1743                 *value = hw->config.rr_quanta;
 1744                 break;
 1745         case OCS_HW_MAX_VPORTS:
 1746                 *value = sli_get_max_rsrc(&hw->sli, SLI_RSRC_FCOE_VPI);
 1747                 break;
 1748         default:
 1749                 ocs_log_test(hw->os, "unsupported property %#x\n", prop);
 1750                 rc = OCS_HW_RTN_ERROR;
 1751         }
 1752 
 1753         return rc;
 1754 }
 1755 
 1756 void *
 1757 ocs_hw_get_ptr(ocs_hw_t *hw, ocs_hw_property_e prop)
 1758 {
 1759         void    *rc = NULL;
 1760 
 1761         switch (prop) {
 1762         case OCS_HW_WWN_NODE:
 1763                 rc = sli_get_wwn_node(&hw->sli);
 1764                 break;
 1765         case OCS_HW_WWN_PORT:
 1766                 rc = sli_get_wwn_port(&hw->sli);
 1767                 break;
 1768         case OCS_HW_VPD:
 1769                 /* make sure VPD length is non-zero */
 1770                 if (sli_get_vpd_len(&hw->sli)) {
 1771                         rc = sli_get_vpd(&hw->sli);
 1772                 }
 1773                 break;
 1774         case OCS_HW_FW_REV:
 1775                 rc = sli_get_fw_name(&hw->sli, 0);
 1776                 break;
 1777         case OCS_HW_FW_REV2:
 1778                 rc = sli_get_fw_name(&hw->sli, 1);
 1779                 break;
 1780         case OCS_HW_IPL:
 1781                 rc = sli_get_ipl_name(&hw->sli);
 1782                 break;
 1783         case OCS_HW_PORTNUM:
 1784                 rc = sli_get_portnum(&hw->sli);
 1785                 break;
 1786         case OCS_HW_BIOS_VERSION_STRING:
 1787                 rc = sli_get_bios_version_string(&hw->sli);
 1788                 break;
 1789         default:
 1790                 ocs_log_test(hw->os, "unsupported property %#x\n", prop);
 1791         }
 1792 
 1793         return rc;
 1794 }
 1795 
 1796 ocs_hw_rtn_e
 1797 ocs_hw_set(ocs_hw_t *hw, ocs_hw_property_e prop, uint32_t value)
 1798 {
 1799         ocs_hw_rtn_e            rc = OCS_HW_RTN_SUCCESS;
 1800 
 1801         switch (prop) {
 1802         case OCS_HW_N_IO:
 1803                 if (value > sli_get_max_rsrc(&hw->sli, SLI_RSRC_FCOE_XRI) ||
 1804                     value == 0) {
 1805                         ocs_log_test(hw->os, "IO value out of range %d vs %d\n",
 1806                                         value, sli_get_max_rsrc(&hw->sli, SLI_RSRC_FCOE_XRI));
 1807                         rc = OCS_HW_RTN_ERROR;
 1808                 } else {
 1809                         hw->config.n_io = value;
 1810                 }
 1811                 break;
 1812         case OCS_HW_N_SGL:
 1813                 value += SLI4_SGE_MAX_RESERVED;
 1814                 if (value > sli_get_max_sgl(&hw->sli)) {
 1815                         ocs_log_test(hw->os, "SGL value out of range %d vs %d\n",
 1816                                         value, sli_get_max_sgl(&hw->sli));
 1817                         rc = OCS_HW_RTN_ERROR;
 1818                 } else {
 1819                         hw->config.n_sgl = value;
 1820                 }
 1821                 break;
 1822         case OCS_HW_TOPOLOGY:
 1823                 if ((sli_get_medium(&hw->sli) != SLI_LINK_MEDIUM_FC) &&
 1824                                 (value != OCS_HW_TOPOLOGY_AUTO)) {
 1825                         ocs_log_test(hw->os, "unsupported topology=%#x medium=%#x\n",
 1826                                         value, sli_get_medium(&hw->sli));
 1827                         rc = OCS_HW_RTN_ERROR;
 1828                         break;
 1829                 }
 1830 
 1831                 switch (value) {
 1832                 case OCS_HW_TOPOLOGY_AUTO:
 1833                         if (sli_get_medium(&hw->sli) == SLI_LINK_MEDIUM_FC) {
 1834                                 sli_set_topology(&hw->sli, SLI4_READ_CFG_TOPO_FC);
 1835                         } else {
 1836                                 sli_set_topology(&hw->sli, SLI4_READ_CFG_TOPO_FCOE);
 1837                         }
 1838                         break;
 1839                 case OCS_HW_TOPOLOGY_NPORT:
 1840                         sli_set_topology(&hw->sli, SLI4_READ_CFG_TOPO_FC_DA);
 1841                         break;
 1842                 case OCS_HW_TOPOLOGY_LOOP:
 1843                         sli_set_topology(&hw->sli, SLI4_READ_CFG_TOPO_FC_AL);
 1844                         break;
 1845                 default:
 1846                         ocs_log_test(hw->os, "unsupported topology %#x\n", value);
 1847                         rc = OCS_HW_RTN_ERROR;
 1848                 }
 1849                 hw->config.topology = value;
 1850                 break;
 1851         case OCS_HW_LINK_SPEED:
 1852                 if (sli_get_medium(&hw->sli) != SLI_LINK_MEDIUM_FC) {
 1853                         switch (value) {
 1854                         case 0:         /* Auto-speed negotiation */
 1855                         case 10000:     /* FCoE speed */
 1856                                 hw->config.speed = FC_LINK_SPEED_10G;
 1857                                 break;
 1858                         default:
 1859                                 ocs_log_test(hw->os, "unsupported speed=%#x medium=%#x\n",
 1860                                                 value, sli_get_medium(&hw->sli));
 1861                                 rc = OCS_HW_RTN_ERROR;
 1862                         }
 1863                         break;
 1864                 }
 1865 
 1866                 switch (value) {
 1867                 case 0:         /* Auto-speed negotiation */
 1868                         hw->config.speed = FC_LINK_SPEED_AUTO_16_8_4;
 1869                         break;
 1870                 case 2000:      /* FC speeds */
 1871                         hw->config.speed = FC_LINK_SPEED_2G;
 1872                         break;
 1873                 case 4000:
 1874                         hw->config.speed = FC_LINK_SPEED_4G;
 1875                         break;
 1876                 case 8000:
 1877                         hw->config.speed = FC_LINK_SPEED_8G;
 1878                         break;
 1879                 case 16000:
 1880                         hw->config.speed = FC_LINK_SPEED_16G;
 1881                         break;
 1882                 case 32000:
 1883                         hw->config.speed = FC_LINK_SPEED_32G;
 1884                         break;
 1885                 default:
 1886                         ocs_log_test(hw->os, "unsupported speed %d\n", value);
 1887                         rc = OCS_HW_RTN_ERROR;
 1888                 }
 1889                 break;
 1890         case OCS_HW_DIF_SEED:
 1891                 /* Set the DIF seed - only for lancer right now */
 1892                 if (SLI4_IF_TYPE_LANCER_FC_ETH != sli_get_if_type(&hw->sli)) {
 1893                         ocs_log_test(hw->os, "DIF seed not supported for this device\n");
 1894                         rc = OCS_HW_RTN_ERROR;
 1895                 } else {
 1896                         hw->config.dif_seed = value;
 1897                 }
 1898                 break;
 1899         case OCS_HW_DIF_MODE:
 1900                 switch (value) {
 1901                 case OCS_HW_DIF_MODE_INLINE:
 1902                         /*
 1903                          *  Make sure we support inline DIF.
 1904                          *
 1905                          * Note: Having both bits clear means that we have old
 1906                          *      FW that doesn't set the bits.
 1907                          */
 1908                         if (sli_is_dif_inline_capable(&hw->sli)) {
 1909                                 hw->config.dif_mode = value;
 1910                         } else {
 1911                                 ocs_log_test(hw->os, "chip does not support DIF inline\n");
 1912                                 rc = OCS_HW_RTN_ERROR;
 1913                         }
 1914                         break;
 1915                 case OCS_HW_DIF_MODE_SEPARATE:
 1916                         /* Make sure we support DIF separates. */
 1917                         if (sli_is_dif_separate_capable(&hw->sli)) {
 1918                                 hw->config.dif_mode = value;
 1919                         } else {
 1920                                 ocs_log_test(hw->os, "chip does not support DIF separate\n");
 1921                                 rc = OCS_HW_RTN_ERROR;
 1922                         }
 1923                 }
 1924                 break;
 1925         case OCS_HW_RQ_PROCESS_LIMIT: {
 1926                 hw_rq_t *rq;
 1927                 uint32_t i;
 1928 
 1929                 /* For each hw_rq object, set its parent CQ limit value */
 1930                 for (i = 0; i < hw->hw_rq_count; i++) {
 1931                         rq = hw->hw_rq[i];
 1932                         hw->cq[rq->cq->instance].proc_limit = value;
 1933                 }
 1934                 break;
 1935         }
 1936         case OCS_HW_RQ_DEFAULT_BUFFER_SIZE:
 1937                 hw->config.rq_default_buffer_size = value;
 1938                 break;
 1939         case OCS_HW_AUTO_XFER_RDY_XRI_CNT:
 1940                 hw->config.auto_xfer_rdy_xri_cnt = value;
 1941                 break;
 1942         case OCS_HW_AUTO_XFER_RDY_SIZE:
 1943                 hw->config.auto_xfer_rdy_size = value;
 1944                 break;
 1945         case OCS_HW_AUTO_XFER_RDY_BLK_SIZE:
 1946                 switch (value) {
 1947                 case 512:
 1948                         hw->config.auto_xfer_rdy_blk_size_chip = 0;
 1949                         break;
 1950                 case 1024:
 1951                         hw->config.auto_xfer_rdy_blk_size_chip = 1;
 1952                         break;
 1953                 case 2048:
 1954                         hw->config.auto_xfer_rdy_blk_size_chip = 2;
 1955                         break;
 1956                 case 4096:
 1957                         hw->config.auto_xfer_rdy_blk_size_chip = 3;
 1958                         break;
 1959                 case 520:
 1960                         hw->config.auto_xfer_rdy_blk_size_chip = 4;
 1961                         break;
 1962                 default:
 1963                         ocs_log_err(hw->os, "Invalid block size %d\n",
 1964                                     value);
 1965                         rc = OCS_HW_RTN_ERROR;
 1966                 }
 1967                 break;
 1968         case OCS_HW_AUTO_XFER_RDY_T10_ENABLE:
 1969                 hw->config.auto_xfer_rdy_t10_enable = value;
 1970                 break;
 1971         case OCS_HW_AUTO_XFER_RDY_P_TYPE:
 1972                 hw->config.auto_xfer_rdy_p_type = value;
 1973                 break;
 1974         case OCS_HW_AUTO_XFER_RDY_REF_TAG_IS_LBA:
 1975                 hw->config.auto_xfer_rdy_ref_tag_is_lba = value;
 1976                 break;
 1977         case OCS_HW_AUTO_XFER_RDY_APP_TAG_VALID:
 1978                 hw->config.auto_xfer_rdy_app_tag_valid = value;
 1979                 break;
 1980         case OCS_HW_AUTO_XFER_RDY_APP_TAG_VALUE:
 1981                 hw->config.auto_xfer_rdy_app_tag_value = value;
 1982                 break;
 1983         case OCS_ESOC:
 1984                 hw->config.esoc = value;
 1985                 break;
 1986         case OCS_HW_HIGH_LOGIN_MODE:
 1987                 rc = sli_set_hlm(&hw->sli, value);
 1988                 break;
 1989         case OCS_HW_PREREGISTER_SGL:
 1990                 rc = sli_set_sgl_preregister(&hw->sli, value);
 1991                 break;
 1992         case OCS_HW_ETH_LICENSE:
 1993                 hw->eth_license = value;
 1994                 break;
 1995         case OCS_HW_EMULATE_I_ONLY_AAB:
 1996                 hw->config.i_only_aab = value;
 1997                 break;
 1998         case OCS_HW_EMULATE_TARGET_WQE_TIMEOUT:
 1999                 hw->config.emulate_tgt_wqe_timeout = value;
 2000                 break;
 2001         case OCS_HW_BOUNCE:
 2002                 hw->config.bounce = value;
 2003                 break;
 2004         case OCS_HW_RQ_SELECTION_POLICY:
 2005                 hw->config.rq_selection_policy = value;
 2006                 break;
 2007         case OCS_HW_RR_QUANTA:
 2008                 hw->config.rr_quanta = value;
 2009                 break;
 2010         default:
 2011                 ocs_log_test(hw->os, "unsupported property %#x\n", prop);
 2012                 rc = OCS_HW_RTN_ERROR;
 2013         }
 2014 
 2015         return rc;
 2016 }
 2017 
 2018 ocs_hw_rtn_e
 2019 ocs_hw_set_ptr(ocs_hw_t *hw, ocs_hw_property_e prop, void *value)
 2020 {
 2021         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 2022 
 2023         switch (prop) {
 2024         case OCS_HW_WAR_VERSION:
 2025                 hw->hw_war_version = value;
 2026                 break;
 2027         case OCS_HW_FILTER_DEF: {
 2028                 char *p = value;
 2029                 uint32_t idx = 0;
 2030 
 2031                 for (idx = 0; idx < ARRAY_SIZE(hw->config.filter_def); idx++) {
 2032                         hw->config.filter_def[idx] = 0;
 2033                 }
 2034 
 2035                 for (idx = 0; (idx < ARRAY_SIZE(hw->config.filter_def)) && (p != NULL) && *p; ) {
 2036                         hw->config.filter_def[idx++] = ocs_strtoul(p, 0, 0);
 2037                         p = ocs_strchr(p, ',');
 2038                         if (p != NULL) {
 2039                                 p++;
 2040                         }
 2041                 }
 2042 
 2043                 break;
 2044         }
 2045         default:
 2046                 ocs_log_test(hw->os, "unsupported property %#x\n", prop);
 2047                 rc = OCS_HW_RTN_ERROR;
 2048                 break;
 2049         }
 2050         return rc;
 2051 }
 2052 /**
 2053  * @ingroup interrupt
 2054  * @brief Check for the events associated with the interrupt vector.
 2055  *
 2056  * @param hw Hardware context.
 2057  * @param vector Zero-based interrupt vector number.
 2058  *
 2059  * @return Returns 0 on success, or a non-zero value on failure.
 2060  */
 2061 int32_t
 2062 ocs_hw_event_check(ocs_hw_t *hw, uint32_t vector)
 2063 {
 2064         int32_t rc = 0;
 2065 
 2066         if (!hw) {
 2067                 ocs_log_err(NULL, "HW context NULL?!?\n");
 2068                 return -1;
 2069         }
 2070 
 2071         if (vector > hw->eq_count) {
 2072                 ocs_log_err(hw->os, "vector %d. max %d\n",
 2073                                 vector, hw->eq_count);
 2074                 return -1;
 2075         }
 2076 
 2077         /*
 2078          * The caller should disable interrupts if they wish to prevent us
 2079          * from processing during a shutdown. The following states are defined:
 2080          *   OCS_HW_STATE_UNINITIALIZED - No queues allocated
 2081          *   OCS_HW_STATE_QUEUES_ALLOCATED - The state after a chip reset,
 2082          *                                    queues are cleared.
 2083          *   OCS_HW_STATE_ACTIVE - Chip and queues are operational
 2084          *   OCS_HW_STATE_RESET_IN_PROGRESS - reset, we still want completions
 2085          *   OCS_HW_STATE_TEARDOWN_IN_PROGRESS - We still want mailbox
 2086          *                                        completions.
 2087          */
 2088         if (hw->state != OCS_HW_STATE_UNINITIALIZED) {
 2089                 rc = sli_queue_is_empty(&hw->sli, &hw->eq[vector]);
 2090 
 2091                 /* Re-arm queue if there are no entries */
 2092                 if (rc != 0) {
 2093                         sli_queue_arm(&hw->sli, &hw->eq[vector], TRUE);
 2094                 }
 2095         }
 2096         return rc;
 2097 }
 2098 
 2099 void
 2100 ocs_hw_unsol_process_bounce(void *arg)
 2101 {
 2102         ocs_hw_sequence_t *seq = arg;
 2103         ocs_hw_t *hw = seq->hw;
 2104 
 2105         ocs_hw_assert(hw != NULL);
 2106         ocs_hw_assert(hw->callback.unsolicited != NULL);
 2107 
 2108         hw->callback.unsolicited(hw->args.unsolicited, seq);
 2109 }
 2110 
 2111 int32_t
 2112 ocs_hw_process(ocs_hw_t *hw, uint32_t vector, uint32_t max_isr_time_msec)
 2113 {
 2114         hw_eq_t *eq;
 2115         int32_t rc = 0;
 2116 
 2117         CPUTRACE("");
 2118 
 2119         /*
 2120          * The caller should disable interrupts if they wish to prevent us
 2121          * from processing during a shutdown. The following states are defined:
 2122          *   OCS_HW_STATE_UNINITIALIZED - No queues allocated
 2123          *   OCS_HW_STATE_QUEUES_ALLOCATED - The state after a chip reset,
 2124          *                                    queues are cleared.
 2125          *   OCS_HW_STATE_ACTIVE - Chip and queues are operational
 2126          *   OCS_HW_STATE_RESET_IN_PROGRESS - reset, we still want completions
 2127          *   OCS_HW_STATE_TEARDOWN_IN_PROGRESS - We still want mailbox
 2128          *                                        completions.
 2129          */
 2130         if (hw->state == OCS_HW_STATE_UNINITIALIZED) {
 2131                 return 0;
 2132         }
 2133 
 2134         /* Get pointer to hw_eq_t */
 2135         eq = hw->hw_eq[vector];
 2136 
 2137         OCS_STAT(eq->use_count++);
 2138 
 2139         rc = ocs_hw_eq_process(hw, eq, max_isr_time_msec);
 2140 
 2141         return rc;
 2142 }
 2143 
 2144 /**
 2145  * @ingroup interrupt
 2146  * @brief Process events associated with an EQ.
 2147  *
 2148  * @par Description
 2149  * Loop termination:
 2150  * @n @n Without a mechanism to terminate the completion processing loop, it
 2151  * is possible under some workload conditions for the loop to never terminate
 2152  * (or at least take longer than the OS is happy to have an interrupt handler
 2153  * or kernel thread context hold a CPU without yielding).
 2154  * @n @n The approach taken here is to periodically check how much time
 2155  * we have been in this
 2156  * processing loop, and if we exceed a predetermined time (multiple seconds), the
 2157  * loop is terminated, and ocs_hw_process() returns.
 2158  *
 2159  * @param hw Hardware context.
 2160  * @param eq Pointer to HW EQ object.
 2161  * @param max_isr_time_msec Maximum time in msec to stay in this function.
 2162  *
 2163  * @return Returns 0 on success, or a non-zero value on failure.
 2164  */
 2165 int32_t
 2166 ocs_hw_eq_process(ocs_hw_t *hw, hw_eq_t *eq, uint32_t max_isr_time_msec)
 2167 {
 2168         uint8_t         eqe[sizeof(sli4_eqe_t)] = { 0 };
 2169         uint32_t        done = FALSE;
 2170         uint32_t        tcheck_count;
 2171         time_t          tstart;
 2172         time_t          telapsed;
 2173 
 2174         tcheck_count = OCS_HW_TIMECHECK_ITERATIONS;
 2175         tstart = ocs_msectime();
 2176 
 2177         CPUTRACE("");
 2178 
 2179         while (!done && !sli_queue_read(&hw->sli, eq->queue, eqe)) {
 2180                 uint16_t        cq_id = 0;
 2181                 int32_t         rc;
 2182 
 2183                 rc = sli_eq_parse(&hw->sli, eqe, &cq_id);
 2184                 if (unlikely(rc)) {
 2185                         if (rc > 0) {
 2186                                 uint32_t i;
 2187 
 2188                                 /*
 2189                                  * Received a sentinel EQE indicating the EQ is full.
 2190                                  * Process all CQs
 2191                                  */
 2192                                 for (i = 0; i < hw->cq_count; i++) {
 2193                                         ocs_hw_cq_process(hw, hw->hw_cq[i]);
 2194                                 }
 2195                                 continue;
 2196                         } else {
 2197                                 return rc;
 2198                         }
 2199                 } else {
 2200                         int32_t index = ocs_hw_queue_hash_find(hw->cq_hash, cq_id);
 2201                         if (likely(index >= 0)) {
 2202                                 ocs_hw_cq_process(hw, hw->hw_cq[index]);
 2203                         } else {
 2204                                 ocs_log_err(hw->os, "bad CQ_ID %#06x\n", cq_id);
 2205                         }
 2206                 }
 2207 
 2208                 if (eq->queue->n_posted > (eq->queue->posted_limit)) {
 2209                         sli_queue_arm(&hw->sli, eq->queue, FALSE);
 2210                 }
 2211 
 2212                 if (tcheck_count && (--tcheck_count == 0)) {
 2213                         tcheck_count = OCS_HW_TIMECHECK_ITERATIONS;
 2214                         telapsed = ocs_msectime() - tstart;
 2215                         if (telapsed >= max_isr_time_msec) {
 2216                                 done = TRUE;
 2217                         }
 2218                 }
 2219         }
 2220         sli_queue_eq_arm(&hw->sli, eq->queue, TRUE);
 2221 
 2222         return 0;
 2223 }
 2224 
 2225 /**
 2226  * @brief Submit queued (pending) mbx commands.
 2227  *
 2228  * @par Description
 2229  * Submit queued mailbox commands.
 2230  * --- Assumes that hw->cmd_lock is held ---
 2231  *
 2232  * @param hw Hardware context.
 2233  *
 2234  * @return Returns 0 on success, or a negative error code value on failure.
 2235  */
 2236 static int32_t
 2237 ocs_hw_cmd_submit_pending(ocs_hw_t *hw)
 2238 {
 2239         ocs_command_ctx_t *ctx;
 2240         int32_t rc = 0;
 2241 
 2242         /* Assumes lock held */
 2243 
 2244         /* Only submit MQE if there's room */
 2245         while (hw->cmd_head_count < (OCS_HW_MQ_DEPTH - 1)) {
 2246                 ctx = ocs_list_remove_head(&hw->cmd_pending);
 2247                 if (ctx == NULL) {
 2248                         break;
 2249                 }
 2250                 ocs_list_add_tail(&hw->cmd_head, ctx);
 2251                 hw->cmd_head_count++;
 2252                 if (sli_queue_write(&hw->sli, hw->mq, ctx->buf) < 0) {
 2253                         ocs_log_test(hw->os, "sli_queue_write failed: %d\n", rc);
 2254                         rc = -1;
 2255                         break;
 2256                 }
 2257         }
 2258         return rc;
 2259 }
 2260 
 2261 /**
 2262  * @ingroup io
 2263  * @brief Issue a SLI command.
 2264  *
 2265  * @par Description
 2266  * Send a mailbox command to the hardware, and either wait for a completion
 2267  * (OCS_CMD_POLL) or get an optional asynchronous completion (OCS_CMD_NOWAIT).
 2268  *
 2269  * @param hw Hardware context.
 2270  * @param cmd Buffer containing a formatted command and results.
 2271  * @param opts Command options:
 2272  *  - OCS_CMD_POLL - Command executes synchronously and busy-waits for the completion.
 2273  *  - OCS_CMD_NOWAIT - Command executes asynchronously. Uses callback.
 2274  * @param cb Function callback used for asynchronous mode. May be NULL.
 2275  * @n Prototype is <tt>(*cb)(void *arg, uint8_t *cmd)</tt>.
 2276  * @n @n @b Note: If the
 2277  * callback function pointer is NULL, the results of the command are silently
 2278  * discarded, allowing this pointer to exist solely on the stack.
 2279  * @param arg Argument passed to an asynchronous callback.
 2280  *
 2281  * @return Returns 0 on success, or a non-zero value on failure.
 2282  */
 2283 ocs_hw_rtn_e
 2284 ocs_hw_command(ocs_hw_t *hw, uint8_t *cmd, uint32_t opts, void *cb, void *arg)
 2285 {
 2286         ocs_hw_rtn_e rc = OCS_HW_RTN_ERROR;
 2287 
 2288         /*
 2289          * If the chip is in an error state (UE'd) then reject this mailbox
 2290          *  command.
 2291          */
 2292         if (sli_fw_error_status(&hw->sli) > 0) {
 2293                 uint32_t err1 = sli_reg_read(&hw->sli, SLI4_REG_SLIPORT_ERROR1);
 2294                 uint32_t err2 = sli_reg_read(&hw->sli, SLI4_REG_SLIPORT_ERROR2);
 2295                 if (hw->expiration_logged == 0 && err1 == 0x2 && err2 == 0x10) {
 2296                         hw->expiration_logged = 1;
 2297                         ocs_log_crit(hw->os,"Emulex: Heartbeat expired after %d seconds\n",
 2298                                         hw->watchdog_timeout);
 2299                 }
 2300                 ocs_log_crit(hw->os, "Chip is in an error state - reset needed\n");
 2301                 ocs_log_crit(hw->os, "status=%#x error1=%#x error2=%#x\n",
 2302                         sli_reg_read(&hw->sli, SLI4_REG_SLIPORT_STATUS),
 2303                         err1, err2);
 2304 
 2305                 return OCS_HW_RTN_ERROR;
 2306         }
 2307 
 2308         if (OCS_CMD_POLL == opts) {
 2309                 ocs_lock(&hw->cmd_lock);
 2310                 if (hw->mq->length && !sli_queue_is_empty(&hw->sli, hw->mq)) {
 2311                         /*
 2312                          * Can't issue Boot-strap mailbox command with other
 2313                          * mail-queue commands pending as this interaction is
 2314                          * undefined
 2315                          */
 2316                         rc = OCS_HW_RTN_ERROR;
 2317                 } else {
 2318                         void *bmbx = hw->sli.bmbx.virt;
 2319 
 2320                         ocs_memset(bmbx, 0, SLI4_BMBX_SIZE);
 2321                         ocs_memcpy(bmbx, cmd, SLI4_BMBX_SIZE);
 2322 
 2323                         if (sli_bmbx_command(&hw->sli) == 0) {
 2324                                 rc = OCS_HW_RTN_SUCCESS;
 2325                                 ocs_memcpy(cmd, bmbx, SLI4_BMBX_SIZE);
 2326                         }
 2327                 }
 2328                 ocs_unlock(&hw->cmd_lock);
 2329         } else if (OCS_CMD_NOWAIT == opts) {
 2330                 ocs_command_ctx_t       *ctx = NULL;
 2331 
 2332                 ctx = ocs_malloc(hw->os, sizeof(ocs_command_ctx_t), OCS_M_ZERO | OCS_M_NOWAIT);
 2333                 if (!ctx) {
 2334                         ocs_log_err(hw->os, "can't allocate command context\n");
 2335                         return OCS_HW_RTN_NO_RESOURCES;
 2336                 }
 2337 
 2338                 if (hw->state != OCS_HW_STATE_ACTIVE) {
 2339                         ocs_log_err(hw->os, "Can't send command, HW state=%d\n", hw->state);
 2340                         ocs_free(hw->os, ctx, sizeof(*ctx));
 2341                         return OCS_HW_RTN_ERROR;
 2342                 }
 2343 
 2344                 if (cb) {
 2345                         ctx->cb = cb;
 2346                         ctx->arg = arg;
 2347                 }
 2348                 ctx->buf = cmd;
 2349                 ctx->ctx = hw;
 2350 
 2351                 ocs_lock(&hw->cmd_lock);
 2352 
 2353                         /* Add to pending list */
 2354                         ocs_list_add_tail(&hw->cmd_pending, ctx);
 2355 
 2356                         /* Submit as much of the pending list as we can */
 2357                         if (ocs_hw_cmd_submit_pending(hw) == 0) {
 2358                                 rc = OCS_HW_RTN_SUCCESS;
 2359                         }
 2360 
 2361                 ocs_unlock(&hw->cmd_lock);
 2362         }
 2363 
 2364         return rc;
 2365 }
 2366 
 2367 /**
 2368  * @ingroup devInitShutdown
 2369  * @brief Register a callback for the given event.
 2370  *
 2371  * @param hw Hardware context.
 2372  * @param which Event of interest.
 2373  * @param func Function to call when the event occurs.
 2374  * @param arg Argument passed to the callback function.
 2375  *
 2376  * @return Returns 0 on success, or a non-zero value on failure.
 2377  */
 2378 ocs_hw_rtn_e
 2379 ocs_hw_callback(ocs_hw_t *hw, ocs_hw_callback_e which, void *func, void *arg)
 2380 {
 2381 
 2382         if (!hw || !func || (which >= OCS_HW_CB_MAX)) {
 2383                 ocs_log_err(NULL, "bad parameter hw=%p which=%#x func=%p\n",
 2384                             hw, which, func);
 2385                 return OCS_HW_RTN_ERROR;
 2386         }
 2387 
 2388         switch (which) {
 2389         case OCS_HW_CB_DOMAIN:
 2390                 hw->callback.domain = func;
 2391                 hw->args.domain = arg;
 2392                 break;
 2393         case OCS_HW_CB_PORT:
 2394                 hw->callback.port = func;
 2395                 hw->args.port = arg;
 2396                 break;
 2397         case OCS_HW_CB_UNSOLICITED:
 2398                 hw->callback.unsolicited = func;
 2399                 hw->args.unsolicited = arg;
 2400                 break;
 2401         case OCS_HW_CB_REMOTE_NODE:
 2402                 hw->callback.rnode = func;
 2403                 hw->args.rnode = arg;
 2404                 break;
 2405         case OCS_HW_CB_BOUNCE:
 2406                 hw->callback.bounce = func;
 2407                 hw->args.bounce = arg;
 2408                 break;
 2409         default:
 2410                 ocs_log_test(hw->os, "unknown callback %#x\n", which);
 2411                 return OCS_HW_RTN_ERROR;
 2412         }
 2413 
 2414         return OCS_HW_RTN_SUCCESS;
 2415 }
 2416 
 2417 /**
 2418  * @ingroup port
 2419  * @brief Allocate a port object.
 2420  *
 2421  * @par Description
 2422  * This function allocates a VPI object for the port and stores it in the
 2423  * indicator field of the port object.
 2424  *
 2425  * @param hw Hardware context.
 2426  * @param sport SLI port object used to connect to the domain.
 2427  * @param domain Domain object associated with this port (may be NULL).
 2428  * @param wwpn Port's WWPN in big-endian order, or NULL to use default.
 2429  *
 2430  * @return Returns 0 on success, or a non-zero value on failure.
 2431  */
 2432 ocs_hw_rtn_e
 2433 ocs_hw_port_alloc(ocs_hw_t *hw, ocs_sli_port_t *sport, ocs_domain_t *domain,
 2434                 uint8_t *wwpn)
 2435 {
 2436         uint8_t *cmd = NULL;
 2437         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 2438         uint32_t index;
 2439 
 2440         sport->indicator = UINT32_MAX;
 2441         sport->hw = hw;
 2442         sport->ctx.app = sport;
 2443         sport->sm_free_req_pending = 0;
 2444 
 2445         /*
 2446          * Check if the chip is in an error state (UE'd) before proceeding.
 2447          */
 2448         if (sli_fw_error_status(&hw->sli) > 0) {
 2449                 ocs_log_crit(hw->os, "Chip is in an error state - reset needed\n");
 2450                 return OCS_HW_RTN_ERROR;
 2451         }
 2452 
 2453         if (wwpn) {
 2454                 ocs_memcpy(&sport->sli_wwpn, wwpn, sizeof(sport->sli_wwpn));
 2455         }
 2456 
 2457         if (sli_resource_alloc(&hw->sli, SLI_RSRC_FCOE_VPI, &sport->indicator, &index)) {
 2458                 ocs_log_err(hw->os, "FCOE_VPI allocation failure\n");
 2459                 return OCS_HW_RTN_ERROR;
 2460         }
 2461 
 2462         if (domain != NULL) {
 2463                 ocs_sm_function_t       next = NULL;
 2464 
 2465                 cmd = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
 2466                 if (!cmd) {
 2467                         ocs_log_err(hw->os, "command memory allocation failed\n");
 2468                         rc = OCS_HW_RTN_NO_MEMORY;
 2469                         goto ocs_hw_port_alloc_out;
 2470                 }
 2471 
 2472                 /* If the WWPN is NULL, fetch the default WWPN and WWNN before
 2473                  * initializing the VPI
 2474                  */
 2475                 if (!wwpn) {
 2476                         next = __ocs_hw_port_alloc_read_sparm64;
 2477                 } else {
 2478                         next = __ocs_hw_port_alloc_init_vpi;
 2479                 }
 2480 
 2481                 ocs_sm_transition(&sport->ctx, next, cmd);
 2482         } else if (!wwpn) {
 2483                 /* This is the convention for the HW, not SLI */
 2484                 ocs_log_test(hw->os, "need WWN for physical port\n");
 2485                 rc = OCS_HW_RTN_ERROR;
 2486         } else {
 2487                 /* domain NULL and wwpn non-NULL */
 2488                 ocs_sm_transition(&sport->ctx, __ocs_hw_port_alloc_init, NULL);
 2489         }
 2490 
 2491 ocs_hw_port_alloc_out:
 2492         if (rc != OCS_HW_RTN_SUCCESS) {
 2493                 ocs_free(hw->os, cmd, SLI4_BMBX_SIZE);
 2494 
 2495                 sli_resource_free(&hw->sli, SLI_RSRC_FCOE_VPI, sport->indicator);
 2496         }
 2497 
 2498         return rc;
 2499 }
 2500 
 2501 /**
 2502  * @ingroup port
 2503  * @brief Attach a physical/virtual SLI port to a domain.
 2504  *
 2505  * @par Description
 2506  * This function registers a previously-allocated VPI with the
 2507  * device.
 2508  *
 2509  * @param hw Hardware context.
 2510  * @param sport Pointer to the SLI port object.
 2511  * @param fc_id Fibre Channel ID to associate with this port.
 2512  *
 2513  * @return Returns OCS_HW_RTN_SUCCESS on success, or an error code on failure.
 2514  */
 2515 ocs_hw_rtn_e
 2516 ocs_hw_port_attach(ocs_hw_t *hw, ocs_sli_port_t *sport, uint32_t fc_id)
 2517 {
 2518         uint8_t *buf = NULL;
 2519         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 2520 
 2521         if (!hw || !sport) {
 2522                 ocs_log_err(hw ? hw->os : NULL,
 2523                         "bad parameter(s) hw=%p sport=%p\n", hw,
 2524                         sport);
 2525                 return OCS_HW_RTN_ERROR;
 2526         }
 2527 
 2528         /*
 2529          * Check if the chip is in an error state (UE'd) before proceeding.
 2530          */
 2531         if (sli_fw_error_status(&hw->sli) > 0) {
 2532                 ocs_log_crit(hw->os, "Chip is in an error state - reset needed\n");
 2533                 return OCS_HW_RTN_ERROR;
 2534         }
 2535 
 2536         buf = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
 2537         if (!buf) {
 2538                 ocs_log_err(hw->os, "no buffer for command\n");
 2539                 return OCS_HW_RTN_NO_MEMORY;
 2540         }
 2541 
 2542         sport->fc_id = fc_id;
 2543         ocs_sm_post_event(&sport->ctx, OCS_EVT_HW_PORT_REQ_ATTACH, buf);
 2544         return rc;
 2545 }
 2546 
 2547 /**
 2548  * @brief Called when the port control command completes.
 2549  *
 2550  * @par Description
 2551  * We only need to free the mailbox command buffer.
 2552  *
 2553  * @param hw Hardware context.
 2554  * @param status Status field from the mbox completion.
 2555  * @param mqe Mailbox response structure.
 2556  * @param arg Pointer to a callback function that signals the caller that the command is done.
 2557  *
 2558  * @return Returns 0.
 2559  */
 2560 static int32_t
 2561 ocs_hw_cb_port_control(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void  *arg)
 2562 {
 2563         ocs_free(hw->os, mqe, SLI4_BMBX_SIZE);
 2564         return 0;
 2565 }
 2566 
 2567 /**
 2568  * @ingroup port
 2569  * @brief Control a port (initialize, shutdown, or set link configuration).
 2570  *
 2571  * @par Description
 2572  * This function controls a port depending on the @c ctrl parameter:
 2573  * - @b OCS_HW_PORT_INIT -
 2574  * Issues the CONFIG_LINK and INIT_LINK commands for the specified port.
 2575  * The HW generates an OCS_HW_DOMAIN_FOUND event when the link comes up.
 2576  * .
 2577  * - @b OCS_HW_PORT_SHUTDOWN -
 2578  * Issues the DOWN_LINK command for the specified port.
 2579  * The HW generates an OCS_HW_DOMAIN_LOST event when the link is down.
 2580  * .
 2581  * - @b OCS_HW_PORT_SET_LINK_CONFIG -
 2582  * Sets the link configuration.
 2583  *
 2584  * @param hw Hardware context.
 2585  * @param ctrl Specifies the operation:
 2586  * - OCS_HW_PORT_INIT
 2587  * - OCS_HW_PORT_SHUTDOWN
 2588  * - OCS_HW_PORT_SET_LINK_CONFIG
 2589  *
 2590  * @param value Operation-specific value.
 2591  * - OCS_HW_PORT_INIT - Selective reset AL_PA
 2592  * - OCS_HW_PORT_SHUTDOWN - N/A
 2593  * - OCS_HW_PORT_SET_LINK_CONFIG - An enum #ocs_hw_linkcfg_e value.
 2594  *
 2595  * @param cb Callback function to invoke the following operation.
 2596  * - OCS_HW_PORT_INIT/OCS_HW_PORT_SHUTDOWN - NULL (link events
 2597  * are handled by the OCS_HW_CB_DOMAIN callbacks).
 2598  * - OCS_HW_PORT_SET_LINK_CONFIG - Invoked after linkcfg mailbox command
 2599  * completes.
 2600  *
 2601  * @param arg Callback argument invoked after the command completes.
 2602  * - OCS_HW_PORT_INIT/OCS_HW_PORT_SHUTDOWN - NULL (link events
 2603  * are handled by the OCS_HW_CB_DOMAIN callbacks).
 2604  * - OCS_HW_PORT_SET_LINK_CONFIG - Invoked after linkcfg mailbox command
 2605  * completes.
 2606  *
 2607  * @return Returns 0 on success, or a non-zero value on failure.
 2608  */
 2609 ocs_hw_rtn_e
 2610 ocs_hw_port_control(ocs_hw_t *hw, ocs_hw_port_e ctrl, uintptr_t value, ocs_hw_port_control_cb_t cb, void *arg)
 2611 {
 2612         ocs_hw_rtn_e rc = OCS_HW_RTN_ERROR;
 2613 
 2614         switch (ctrl) {
 2615         case OCS_HW_PORT_INIT:
 2616         {
 2617                 uint8_t *init_link;
 2618                 uint32_t speed = 0;
 2619                 uint8_t reset_alpa = 0;
 2620 
 2621                 if (SLI_LINK_MEDIUM_FC == sli_get_medium(&hw->sli)) {
 2622                         uint8_t *cfg_link;
 2623 
 2624                         cfg_link = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
 2625                         if (cfg_link == NULL) {
 2626                                 ocs_log_err(hw->os, "no buffer for command\n");
 2627                                 return OCS_HW_RTN_NO_MEMORY;
 2628                         }
 2629 
 2630                         if (sli_cmd_config_link(&hw->sli, cfg_link, SLI4_BMBX_SIZE)) {
 2631                                 rc = ocs_hw_command(hw, cfg_link, OCS_CMD_NOWAIT,
 2632                                                         ocs_hw_cb_port_control, NULL);
 2633                         }
 2634 
 2635                         if (rc != OCS_HW_RTN_SUCCESS) {
 2636                                 ocs_free(hw->os, cfg_link, SLI4_BMBX_SIZE);
 2637                                 ocs_log_err(hw->os, "CONFIG_LINK failed\n");
 2638                                 break;
 2639                         }
 2640                         speed = hw->config.speed;
 2641                         reset_alpa = (uint8_t)(value & 0xff);
 2642                 } else {
 2643                         speed = FC_LINK_SPEED_10G;
 2644                 }
 2645 
 2646                 /*
 2647                  * Bring link up, unless FW version is not supported
 2648                  */
 2649                 if (hw->workaround.fw_version_too_low) {
 2650                         if (SLI4_IF_TYPE_LANCER_FC_ETH == hw->sli.if_type) {
 2651                                 ocs_log_err(hw->os, "Cannot bring up link.  Please update firmware to %s or later (current version is %s)\n",
 2652                                         OCS_FW_VER_STR(OCS_MIN_FW_VER_LANCER), (char *) sli_get_fw_name(&hw->sli,0));
 2653                         } else {
 2654                                 ocs_log_err(hw->os, "Cannot bring up link.  Please update firmware to %s or later (current version is %s)\n",
 2655                                         OCS_FW_VER_STR(OCS_MIN_FW_VER_SKYHAWK), (char *) sli_get_fw_name(&hw->sli, 0));
 2656                         }
 2657 
 2658                         return OCS_HW_RTN_ERROR;
 2659                 }
 2660 
 2661                 rc = OCS_HW_RTN_ERROR;
 2662 
 2663                 /* Allocate a new buffer for the init_link command */
 2664                 init_link = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
 2665                 if (init_link == NULL) {
 2666                         ocs_log_err(hw->os, "no buffer for command\n");
 2667                         return OCS_HW_RTN_NO_MEMORY;
 2668                 }
 2669 
 2670                 if (sli_cmd_init_link(&hw->sli, init_link, SLI4_BMBX_SIZE, speed, reset_alpa)) {
 2671                         rc = ocs_hw_command(hw, init_link, OCS_CMD_NOWAIT,
 2672                                                 ocs_hw_cb_port_control, NULL);
 2673                 }
 2674                 /* Free buffer on error, since no callback is coming */
 2675                 if (rc != OCS_HW_RTN_SUCCESS) {
 2676                         ocs_free(hw->os, init_link, SLI4_BMBX_SIZE);
 2677                         ocs_log_err(hw->os, "INIT_LINK failed\n");
 2678                 }
 2679                 break;
 2680         }
 2681         case OCS_HW_PORT_SHUTDOWN:
 2682         {
 2683                 uint8_t *down_link;
 2684 
 2685                 down_link = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
 2686                 if (down_link == NULL) {
 2687                         ocs_log_err(hw->os, "no buffer for command\n");
 2688                         return OCS_HW_RTN_NO_MEMORY;
 2689                 }
 2690                 if (sli_cmd_down_link(&hw->sli, down_link, SLI4_BMBX_SIZE)) {
 2691                         rc = ocs_hw_command(hw, down_link, OCS_CMD_NOWAIT,
 2692                                                 ocs_hw_cb_port_control, NULL);
 2693                 }
 2694                 /* Free buffer on error, since no callback is coming */
 2695                 if (rc != OCS_HW_RTN_SUCCESS) {
 2696                         ocs_free(hw->os, down_link, SLI4_BMBX_SIZE);
 2697                         ocs_log_err(hw->os, "DOWN_LINK failed\n");
 2698                 }
 2699                 break;
 2700         }
 2701         case OCS_HW_PORT_SET_LINK_CONFIG:
 2702                 rc = ocs_hw_set_linkcfg(hw, (ocs_hw_linkcfg_e)value, OCS_CMD_NOWAIT, cb, arg);
 2703                 break;
 2704         default:
 2705                 ocs_log_test(hw->os, "unhandled control %#x\n", ctrl);
 2706                 break;
 2707         }
 2708 
 2709         return rc;
 2710 }
 2711 
 2712 /**
 2713  * @ingroup port
 2714  * @brief Free port resources.
 2715  *
 2716  * @par Description
 2717  * Issue the UNREG_VPI command to free the assigned VPI context.
 2718  *
 2719  * @param hw Hardware context.
 2720  * @param sport SLI port object used to connect to the domain.
 2721  *
 2722  * @return Returns 0 on success, or a non-zero value on failure.
 2723  */
 2724 ocs_hw_rtn_e
 2725 ocs_hw_port_free(ocs_hw_t *hw, ocs_sli_port_t *sport)
 2726 {
 2727         ocs_hw_rtn_e    rc = OCS_HW_RTN_SUCCESS;
 2728 
 2729         if (!hw || !sport) {
 2730                 ocs_log_err(hw ? hw->os : NULL,
 2731                         "bad parameter(s) hw=%p sport=%p\n", hw,
 2732                         sport);
 2733                 return OCS_HW_RTN_ERROR;
 2734         }
 2735 
 2736         /*
 2737          * Check if the chip is in an error state (UE'd) before proceeding.
 2738          */
 2739         if (sli_fw_error_status(&hw->sli) > 0) {
 2740                 ocs_log_crit(hw->os, "Chip is in an error state - reset needed\n");
 2741                 return OCS_HW_RTN_ERROR;
 2742         }
 2743 
 2744         ocs_sm_post_event(&sport->ctx, OCS_EVT_HW_PORT_REQ_FREE, NULL);
 2745         return rc;
 2746 }
 2747 
 2748 /**
 2749  * @ingroup domain
 2750  * @brief Allocate a fabric domain object.
 2751  *
 2752  * @par Description
 2753  * This function starts a series of commands needed to connect to the domain, including
 2754  *   - REG_FCFI
 2755  *   - INIT_VFI
 2756  *   - READ_SPARMS
 2757  *   .
 2758  * @b Note: Not all SLI interface types use all of the above commands.
 2759  * @n @n Upon successful allocation, the HW generates a OCS_HW_DOMAIN_ALLOC_OK
 2760  * event. On failure, it generates a OCS_HW_DOMAIN_ALLOC_FAIL event.
 2761  *
 2762  * @param hw Hardware context.
 2763  * @param domain Pointer to the domain object.
 2764  * @param fcf FCF index.
 2765  * @param vlan VLAN ID.
 2766  *
 2767  * @return Returns 0 on success, or a non-zero value on failure.
 2768  */
 2769 ocs_hw_rtn_e
 2770 ocs_hw_domain_alloc(ocs_hw_t *hw, ocs_domain_t *domain, uint32_t fcf, uint32_t vlan)
 2771 {
 2772         uint8_t         *cmd = NULL;
 2773         uint32_t        index;
 2774 
 2775         if (!hw || !domain || !domain->sport) {
 2776                 ocs_log_err(NULL, "bad parameter(s) hw=%p domain=%p sport=%p\n",
 2777                                 hw, domain, domain ? domain->sport : NULL);
 2778                 return OCS_HW_RTN_ERROR;
 2779         }
 2780 
 2781         /*
 2782          * Check if the chip is in an error state (UE'd) before proceeding.
 2783          */
 2784         if (sli_fw_error_status(&hw->sli) > 0) {
 2785                 ocs_log_crit(hw->os, "Chip is in an error state - reset needed\n");
 2786                 return OCS_HW_RTN_ERROR;
 2787         }
 2788 
 2789         cmd = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
 2790         if (!cmd) {
 2791                 ocs_log_err(hw->os, "command memory allocation failed\n");
 2792                 return OCS_HW_RTN_NO_MEMORY;
 2793         }
 2794 
 2795         domain->dma = hw->domain_dmem;
 2796 
 2797         domain->hw = hw;
 2798         domain->sm.app = domain;
 2799         domain->fcf = fcf;
 2800         domain->fcf_indicator = UINT32_MAX;
 2801         domain->vlan_id = vlan;
 2802         domain->indicator = UINT32_MAX;
 2803 
 2804         if (sli_resource_alloc(&hw->sli, SLI_RSRC_FCOE_VFI, &domain->indicator, &index)) {
 2805                 ocs_log_err(hw->os, "FCOE_VFI allocation failure\n");
 2806 
 2807                 ocs_free(hw->os, cmd, SLI4_BMBX_SIZE);
 2808 
 2809                 return OCS_HW_RTN_ERROR;
 2810         }
 2811 
 2812         ocs_sm_transition(&domain->sm, __ocs_hw_domain_init, cmd);
 2813         return OCS_HW_RTN_SUCCESS;
 2814 }
 2815 
 2816 /**
 2817  * @ingroup domain
 2818  * @brief Attach a SLI port to a domain.
 2819  *
 2820  * @param hw Hardware context.
 2821  * @param domain Pointer to the domain object.
 2822  * @param fc_id Fibre Channel ID to associate with this port.
 2823  *
 2824  * @return Returns 0 on success, or a non-zero value on failure.
 2825  */
 2826 ocs_hw_rtn_e
 2827 ocs_hw_domain_attach(ocs_hw_t *hw, ocs_domain_t *domain, uint32_t fc_id)
 2828 {
 2829         uint8_t *buf = NULL;
 2830         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 2831 
 2832         if (!hw || !domain) {
 2833                 ocs_log_err(hw ? hw->os : NULL,
 2834                         "bad parameter(s) hw=%p domain=%p\n",
 2835                         hw, domain);
 2836                 return OCS_HW_RTN_ERROR;
 2837         }
 2838 
 2839         /*
 2840          * Check if the chip is in an error state (UE'd) before proceeding.
 2841          */
 2842         if (sli_fw_error_status(&hw->sli) > 0) {
 2843                 ocs_log_crit(hw->os, "Chip is in an error state - reset needed\n");
 2844                 return OCS_HW_RTN_ERROR;
 2845         }
 2846 
 2847         buf = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
 2848         if (!buf) {
 2849                 ocs_log_err(hw->os, "no buffer for command\n");
 2850                 return OCS_HW_RTN_NO_MEMORY;
 2851         }
 2852 
 2853         domain->sport->fc_id = fc_id;
 2854         ocs_sm_post_event(&domain->sm, OCS_EVT_HW_DOMAIN_REQ_ATTACH, buf);
 2855         return rc;
 2856 }
 2857 
 2858 /**
 2859  * @ingroup domain
 2860  * @brief Free a fabric domain object.
 2861  *
 2862  * @par Description
 2863  * Free both the driver and SLI port resources associated with the domain.
 2864  *
 2865  * @param hw Hardware context.
 2866  * @param domain Pointer to the domain object.
 2867  *
 2868  * @return Returns 0 on success, or a non-zero value on failure.
 2869  */
 2870 ocs_hw_rtn_e
 2871 ocs_hw_domain_free(ocs_hw_t *hw, ocs_domain_t *domain)
 2872 {
 2873         ocs_hw_rtn_e    rc = OCS_HW_RTN_SUCCESS;
 2874 
 2875         if (!hw || !domain) {
 2876                 ocs_log_err(hw ? hw->os : NULL,
 2877                         "bad parameter(s) hw=%p domain=%p\n",
 2878                         hw, domain);
 2879                 return OCS_HW_RTN_ERROR;
 2880         }
 2881 
 2882         /*
 2883          * Check if the chip is in an error state (UE'd) before proceeding.
 2884          */
 2885         if (sli_fw_error_status(&hw->sli) > 0) {
 2886                 ocs_log_crit(hw->os, "Chip is in an error state - reset needed\n");
 2887                 return OCS_HW_RTN_ERROR;
 2888         }
 2889 
 2890         ocs_sm_post_event(&domain->sm, OCS_EVT_HW_DOMAIN_REQ_FREE, NULL);
 2891         return rc;
 2892 }
 2893 
 2894 /**
 2895  * @ingroup domain
 2896  * @brief Free a fabric domain object.
 2897  *
 2898  * @par Description
 2899  * Free the driver resources associated with the domain. The difference between
 2900  * this call and ocs_hw_domain_free() is that this call assumes resources no longer
 2901  * exist on the SLI port, due to a reset or after some error conditions.
 2902  *
 2903  * @param hw Hardware context.
 2904  * @param domain Pointer to the domain object.
 2905  *
 2906  * @return Returns 0 on success, or a non-zero value on failure.
 2907  */
 2908 ocs_hw_rtn_e
 2909 ocs_hw_domain_force_free(ocs_hw_t *hw, ocs_domain_t *domain)
 2910 {
 2911         if (!hw || !domain) {
 2912                 ocs_log_err(NULL, "bad parameter(s) hw=%p domain=%p\n", hw, domain);
 2913                 return OCS_HW_RTN_ERROR;
 2914         }
 2915 
 2916         sli_resource_free(&hw->sli, SLI_RSRC_FCOE_VFI, domain->indicator);
 2917 
 2918         return OCS_HW_RTN_SUCCESS;
 2919 }
 2920 
 2921 /**
 2922  * @ingroup node
 2923  * @brief Allocate a remote node object.
 2924  *
 2925  * @param hw Hardware context.
 2926  * @param rnode Allocated remote node object to initialize.
 2927  * @param fc_addr FC address of the remote node.
 2928  * @param sport SLI port used to connect to remote node.
 2929  *
 2930  * @return Returns 0 on success, or a non-zero value on failure.
 2931  */
 2932 ocs_hw_rtn_e
 2933 ocs_hw_node_alloc(ocs_hw_t *hw, ocs_remote_node_t *rnode, uint32_t fc_addr,
 2934                 ocs_sli_port_t *sport)
 2935 {
 2936         /* Check for invalid indicator */
 2937         if (UINT32_MAX != rnode->indicator) {
 2938                 ocs_log_err(hw->os, "FCOE_RPI allocation failure addr=%#x rpi=%#x\n",
 2939                                 fc_addr, rnode->indicator);
 2940                 return OCS_HW_RTN_ERROR;
 2941         }
 2942 
 2943         /*
 2944          * Check if the chip is in an error state (UE'd) before proceeding.
 2945          */
 2946         if (sli_fw_error_status(&hw->sli) > 0) {
 2947                 ocs_log_crit(hw->os, "Chip is in an error state - reset needed\n");
 2948                 return OCS_HW_RTN_ERROR;
 2949         }
 2950 
 2951         /* NULL SLI port indicates an unallocated remote node */
 2952         rnode->sport = NULL;
 2953 
 2954         if (sli_resource_alloc(&hw->sli, SLI_RSRC_FCOE_RPI, &rnode->indicator, &rnode->index)) {
 2955                 ocs_log_err(hw->os, "FCOE_RPI allocation failure addr=%#x\n",
 2956                                 fc_addr);
 2957                 return OCS_HW_RTN_ERROR;
 2958         }
 2959 
 2960         rnode->fc_id = fc_addr;
 2961         rnode->sport = sport;
 2962 
 2963         return OCS_HW_RTN_SUCCESS;
 2964 }
 2965 
 2966 /**
 2967  * @ingroup node
 2968  * @brief Update a remote node object with the remote port's service parameters.
 2969  *
 2970  * @param hw Hardware context.
 2971  * @param rnode Allocated remote node object to initialize.
 2972  * @param sparms DMA buffer containing the remote port's service parameters.
 2973  *
 2974  * @return Returns 0 on success, or a non-zero value on failure.
 2975  */
 2976 ocs_hw_rtn_e
 2977 ocs_hw_node_attach(ocs_hw_t *hw, ocs_remote_node_t *rnode, ocs_dma_t *sparms)
 2978 {
 2979         ocs_hw_rtn_e    rc = OCS_HW_RTN_ERROR;
 2980         uint8_t         *buf = NULL;
 2981         uint32_t        count = 0;
 2982 
 2983         if (!hw || !rnode || !sparms) {
 2984                 ocs_log_err(NULL, "bad parameter(s) hw=%p rnode=%p sparms=%p\n",
 2985                             hw, rnode, sparms);
 2986                 return OCS_HW_RTN_ERROR;
 2987         }
 2988 
 2989         /*
 2990          * Check if the chip is in an error state (UE'd) before proceeding.
 2991          */
 2992         if (sli_fw_error_status(&hw->sli) > 0) {
 2993                 ocs_log_crit(hw->os, "Chip is in an error state - reset needed\n");
 2994                 return OCS_HW_RTN_ERROR;
 2995         }
 2996 
 2997         buf = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
 2998         if (!buf) {
 2999                 ocs_log_err(hw->os, "no buffer for command\n");
 3000                 return OCS_HW_RTN_NO_MEMORY;
 3001         }
 3002 
 3003         /*
 3004          * If the attach count is non-zero, this RPI has already been registered.
 3005          * Otherwise, register the RPI
 3006          */
 3007         if (rnode->index == UINT32_MAX) {
 3008                 ocs_log_err(NULL, "bad parameter rnode->index invalid\n");
 3009                 ocs_free(hw->os, buf, SLI4_BMBX_SIZE);
 3010                 return OCS_HW_RTN_ERROR;
 3011         }
 3012         count = ocs_atomic_add_return(&hw->rpi_ref[rnode->index].rpi_count, 1);
 3013         if (count) {
 3014                 /*
 3015                  * Can't attach multiple FC_ID's to a node unless High Login
 3016                  * Mode is enabled
 3017                  */
 3018                 if (sli_get_hlm(&hw->sli) == FALSE) {
 3019                         ocs_log_test(hw->os, "attach to already attached node HLM=%d count=%d\n",
 3020                                         sli_get_hlm(&hw->sli), count);
 3021                         rc = OCS_HW_RTN_SUCCESS;
 3022                 } else {
 3023                         rnode->node_group = TRUE;
 3024                         rnode->attached = ocs_atomic_read(&hw->rpi_ref[rnode->index].rpi_attached);
 3025                         rc = rnode->attached  ? OCS_HW_RTN_SUCCESS_SYNC : OCS_HW_RTN_SUCCESS;
 3026                 }
 3027         } else {
 3028                 rnode->node_group = FALSE;
 3029 
 3030                 ocs_display_sparams("", "reg rpi", 0, NULL, sparms->virt);
 3031                 if (sli_cmd_reg_rpi(&hw->sli, buf, SLI4_BMBX_SIZE, rnode->fc_id,
 3032                                         rnode->indicator, rnode->sport->indicator,
 3033                                         sparms, 0, (hw->auto_xfer_rdy_enabled && hw->config.auto_xfer_rdy_t10_enable))) {
 3034                         rc = ocs_hw_command(hw, buf, OCS_CMD_NOWAIT,
 3035                                         ocs_hw_cb_node_attach, rnode);
 3036                 }
 3037         }
 3038 
 3039         if (count || rc) {
 3040                 if (rc < OCS_HW_RTN_SUCCESS) {
 3041                         ocs_atomic_sub_return(&hw->rpi_ref[rnode->index].rpi_count, 1);
 3042                         ocs_log_err(hw->os, "%s error\n", count ? "HLM" : "REG_RPI");
 3043                 }
 3044                 ocs_free(hw->os, buf, SLI4_BMBX_SIZE);
 3045         }
 3046 
 3047         return rc;
 3048 }
 3049 
 3050 /**
 3051  * @ingroup node
 3052  * @brief Free a remote node resource.
 3053  *
 3054  * @param hw Hardware context.
 3055  * @param rnode Remote node object to free.
 3056  *
 3057  * @return Returns 0 on success, or a non-zero value on failure.
 3058  */
 3059 ocs_hw_rtn_e
 3060 ocs_hw_node_free_resources(ocs_hw_t *hw, ocs_remote_node_t *rnode)
 3061 {
 3062         ocs_hw_rtn_e    rc = OCS_HW_RTN_SUCCESS;
 3063 
 3064         if (!hw || !rnode) {
 3065                 ocs_log_err(NULL, "bad parameter(s) hw=%p rnode=%p\n",
 3066                             hw, rnode);
 3067                 return OCS_HW_RTN_ERROR;
 3068         }
 3069 
 3070         if (rnode->sport) {
 3071                 if (!rnode->attached) {
 3072                         if (rnode->indicator != UINT32_MAX) {
 3073                                 if (sli_resource_free(&hw->sli, SLI_RSRC_FCOE_RPI, rnode->indicator)) {
 3074                                         ocs_log_err(hw->os, "FCOE_RPI free failure RPI %d addr=%#x\n",
 3075                                                     rnode->indicator, rnode->fc_id);
 3076                                         rc = OCS_HW_RTN_ERROR;
 3077                                 } else {
 3078                                         rnode->node_group = FALSE;
 3079                                         rnode->indicator = UINT32_MAX;
 3080                                         rnode->index = UINT32_MAX;
 3081                                         rnode->free_group = FALSE;
 3082                                 }
 3083                         }
 3084                 } else {
 3085                         ocs_log_err(hw->os, "Error: rnode is still attached\n");
 3086                         rc = OCS_HW_RTN_ERROR;
 3087                 }
 3088         }
 3089 
 3090         return rc;
 3091 }
 3092 
 3093 /**
 3094  * @ingroup node
 3095  * @brief Free a remote node object.
 3096  *
 3097  * @param hw Hardware context.
 3098  * @param rnode Remote node object to free.
 3099  *
 3100  * @return Returns 0 on success, or a non-zero value on failure.
 3101  */
 3102 ocs_hw_rtn_e
 3103 ocs_hw_node_detach(ocs_hw_t *hw, ocs_remote_node_t *rnode)
 3104 {
 3105         uint8_t *buf = NULL;
 3106         ocs_hw_rtn_e    rc = OCS_HW_RTN_SUCCESS_SYNC;
 3107         uint32_t        index = UINT32_MAX;
 3108 
 3109         if (!hw || !rnode) {
 3110                 ocs_log_err(NULL, "bad parameter(s) hw=%p rnode=%p\n",
 3111                             hw, rnode);
 3112                 return OCS_HW_RTN_ERROR;
 3113         }
 3114 
 3115         /*
 3116          * Check if the chip is in an error state (UE'd) before proceeding.
 3117          */
 3118         if (sli_fw_error_status(&hw->sli) > 0) {
 3119                 ocs_log_crit(hw->os, "Chip is in an error state - reset needed\n");
 3120                 return OCS_HW_RTN_ERROR;
 3121         }
 3122 
 3123         index = rnode->index;
 3124 
 3125         if (rnode->sport) {
 3126                 uint32_t        count = 0;
 3127                 uint32_t        fc_id;
 3128 
 3129                 if (!rnode->attached) {
 3130                         return OCS_HW_RTN_SUCCESS_SYNC;
 3131                 }
 3132 
 3133                 buf = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
 3134                 if (!buf) {
 3135                         ocs_log_err(hw->os, "no buffer for command\n");
 3136                         return OCS_HW_RTN_NO_MEMORY;
 3137                 }
 3138 
 3139                 count = ocs_atomic_sub_return(&hw->rpi_ref[index].rpi_count, 1);
 3140 
 3141                 if (count <= 1) {
 3142                         /* There are no other references to this RPI
 3143                          * so unregister it and free the resource. */
 3144                         fc_id = UINT32_MAX;
 3145                         rnode->node_group = FALSE;
 3146                         rnode->free_group = TRUE;
 3147                 } else {
 3148                         if (sli_get_hlm(&hw->sli) == FALSE) {
 3149                                 ocs_log_test(hw->os, "Invalid count with HLM disabled, count=%d\n",
 3150                                                 count);
 3151                         }
 3152                         fc_id = rnode->fc_id & 0x00ffffff;
 3153                 }
 3154 
 3155                 rc = OCS_HW_RTN_ERROR;
 3156 
 3157                 if (sli_cmd_unreg_rpi(&hw->sli, buf, SLI4_BMBX_SIZE, rnode->indicator,
 3158                                         SLI_RSRC_FCOE_RPI, fc_id)) {
 3159                         rc = ocs_hw_command(hw, buf, OCS_CMD_NOWAIT, ocs_hw_cb_node_free, rnode);
 3160                 }
 3161 
 3162                 if (rc != OCS_HW_RTN_SUCCESS) {
 3163                         ocs_log_err(hw->os, "UNREG_RPI failed\n");
 3164                         ocs_free(hw->os, buf, SLI4_BMBX_SIZE);
 3165                         rc = OCS_HW_RTN_ERROR;
 3166                 }
 3167         }
 3168 
 3169         return rc;
 3170 }
 3171 
 3172 /**
 3173  * @ingroup node
 3174  * @brief Free all remote node objects.
 3175  *
 3176  * @param hw Hardware context.
 3177  *
 3178  * @return Returns 0 on success, or a non-zero value on failure.
 3179  */
 3180 ocs_hw_rtn_e
 3181 ocs_hw_node_free_all(ocs_hw_t *hw)
 3182 {
 3183         uint8_t *buf = NULL;
 3184         ocs_hw_rtn_e    rc = OCS_HW_RTN_ERROR;
 3185 
 3186         if (!hw) {
 3187                 ocs_log_err(NULL, "bad parameter hw=%p\n", hw);
 3188                 return OCS_HW_RTN_ERROR;
 3189         }
 3190 
 3191         /*
 3192          * Check if the chip is in an error state (UE'd) before proceeding.
 3193          */
 3194         if (sli_fw_error_status(&hw->sli) > 0) {
 3195                 ocs_log_crit(hw->os, "Chip is in an error state - reset needed\n");
 3196                 return OCS_HW_RTN_ERROR;
 3197         }
 3198 
 3199         buf = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
 3200         if (!buf) {
 3201                 ocs_log_err(hw->os, "no buffer for command\n");
 3202                 return OCS_HW_RTN_NO_MEMORY;
 3203         }
 3204 
 3205         if (sli_cmd_unreg_rpi(&hw->sli, buf, SLI4_BMBX_SIZE, 0xffff,
 3206                                 SLI_RSRC_FCOE_FCFI, UINT32_MAX)) {
 3207                 rc = ocs_hw_command(hw, buf, OCS_CMD_NOWAIT, ocs_hw_cb_node_free_all,
 3208                                 NULL);
 3209         }
 3210 
 3211         if (rc != OCS_HW_RTN_SUCCESS) {
 3212                 ocs_log_err(hw->os, "UNREG_RPI failed\n");
 3213                 ocs_free(hw->os, buf, SLI4_BMBX_SIZE);
 3214                 rc = OCS_HW_RTN_ERROR;
 3215         }
 3216 
 3217         return rc;
 3218 }
 3219 
 3220 ocs_hw_rtn_e
 3221 ocs_hw_node_group_alloc(ocs_hw_t *hw, ocs_remote_node_group_t *ngroup)
 3222 {
 3223 
 3224         if (!hw || !ngroup) {
 3225                 ocs_log_err(NULL, "bad parameter hw=%p ngroup=%p\n",
 3226                                 hw, ngroup);
 3227                 return OCS_HW_RTN_ERROR;
 3228         }
 3229 
 3230         if (sli_resource_alloc(&hw->sli, SLI_RSRC_FCOE_RPI, &ngroup->indicator,
 3231                                 &ngroup->index)) {
 3232                 ocs_log_err(hw->os, "FCOE_RPI allocation failure addr=%#x\n",
 3233                                 ngroup->indicator);
 3234                 return OCS_HW_RTN_ERROR;
 3235         }
 3236 
 3237         return OCS_HW_RTN_SUCCESS;
 3238 }
 3239 
 3240 ocs_hw_rtn_e
 3241 ocs_hw_node_group_attach(ocs_hw_t *hw, ocs_remote_node_group_t *ngroup, ocs_remote_node_t *rnode)
 3242 {
 3243 
 3244         if (!hw || !ngroup || !rnode) {
 3245                 ocs_log_err(NULL, "bad parameter hw=%p ngroup=%p rnode=%p\n",
 3246                             hw, ngroup, rnode);
 3247                 return OCS_HW_RTN_ERROR;
 3248         }
 3249 
 3250         if (rnode->attached) {
 3251                 ocs_log_err(hw->os, "node already attached RPI=%#x addr=%#x\n",
 3252                             rnode->indicator, rnode->fc_id);
 3253                 return OCS_HW_RTN_ERROR;
 3254         }
 3255 
 3256         if (sli_resource_free(&hw->sli, SLI_RSRC_FCOE_RPI, rnode->indicator)) {
 3257                 ocs_log_err(hw->os, "FCOE_RPI free failure RPI=%#x\n",
 3258                                 rnode->indicator);
 3259                 return OCS_HW_RTN_ERROR;
 3260         }
 3261 
 3262         rnode->indicator = ngroup->indicator;
 3263         rnode->index = ngroup->index;
 3264 
 3265         return OCS_HW_RTN_SUCCESS;
 3266 }
 3267 
 3268 ocs_hw_rtn_e
 3269 ocs_hw_node_group_free(ocs_hw_t *hw, ocs_remote_node_group_t *ngroup)
 3270 {
 3271         int     ref;
 3272 
 3273         if (!hw || !ngroup) {
 3274                 ocs_log_err(NULL, "bad parameter hw=%p ngroup=%p\n",
 3275                                 hw, ngroup);
 3276                 return OCS_HW_RTN_ERROR;
 3277         }
 3278 
 3279         ref = ocs_atomic_read(&hw->rpi_ref[ngroup->index].rpi_count);
 3280         if (ref) {
 3281                 /* Hmmm, the reference count is non-zero */
 3282                 ocs_log_debug(hw->os, "node group reference=%d (RPI=%#x)\n",
 3283                                 ref, ngroup->indicator);
 3284 
 3285                 if (sli_resource_free(&hw->sli, SLI_RSRC_FCOE_RPI, ngroup->indicator)) {
 3286                         ocs_log_err(hw->os, "FCOE_RPI free failure RPI=%#x\n",
 3287                                     ngroup->indicator);
 3288                         return OCS_HW_RTN_ERROR;
 3289                 }
 3290 
 3291                 ocs_atomic_set(&hw->rpi_ref[ngroup->index].rpi_count, 0);
 3292         }
 3293 
 3294         ngroup->indicator = UINT32_MAX;
 3295         ngroup->index = UINT32_MAX;
 3296 
 3297         return OCS_HW_RTN_SUCCESS;
 3298 }
 3299 
 3300 /**
 3301  * @brief Initialize IO fields on each free call.
 3302  *
 3303  * @n @b Note: This is done on each free call (as opposed to each
 3304  * alloc call) because port-owned XRIs are not
 3305  * allocated with ocs_hw_io_alloc() but are freed with this
 3306  * function.
 3307  *
 3308  * @param io Pointer to HW IO.
 3309  */
 3310 static inline void
 3311 ocs_hw_init_free_io(ocs_hw_io_t *io)
 3312 {
 3313         /*
 3314          * Set io->done to NULL, to avoid any callbacks, should
 3315          * a completion be received for one of these IOs
 3316          */
 3317         io->done = NULL;
 3318         io->abort_done = NULL;
 3319         io->status_saved = 0;
 3320         io->abort_in_progress = FALSE;
 3321         io->port_owned_abort_count = 0;
 3322         io->rnode = NULL;
 3323         io->type = 0xFFFF;
 3324         io->wq = NULL;
 3325         io->ul_io = NULL;
 3326         io->tgt_wqe_timeout = 0;
 3327 }
 3328 
 3329 /**
 3330  * @ingroup io
 3331  * @brief Lockless allocate a HW IO object.
 3332  *
 3333  * @par Description
 3334  * Assume that hw->ocs_lock is held. This function is only used if
 3335  * use_dif_sec_xri workaround is being used.
 3336  *
 3337  * @param hw Hardware context.
 3338  *
 3339  * @return Returns a pointer to an object on success, or NULL on failure.
 3340  */
 3341 static inline ocs_hw_io_t *
 3342 _ocs_hw_io_alloc(ocs_hw_t *hw)
 3343 {
 3344         ocs_hw_io_t     *io = NULL;
 3345 
 3346         if (NULL != (io = ocs_list_remove_head(&hw->io_free))) {
 3347                 ocs_list_add_tail(&hw->io_inuse, io);
 3348                 io->state = OCS_HW_IO_STATE_INUSE;
 3349                 io->quarantine = FALSE;
 3350                 io->quarantine_first_phase = TRUE;
 3351                 io->abort_reqtag = UINT32_MAX;
 3352                 ocs_ref_init(&io->ref, ocs_hw_io_free_internal, io);
 3353         } else {
 3354                 ocs_atomic_add_return(&hw->io_alloc_failed_count, 1);
 3355         }
 3356 
 3357         return io;
 3358 }
 3359 /**
 3360  * @ingroup io
 3361  * @brief Allocate a HW IO object.
 3362  *
 3363  * @par Description
 3364  * @n @b Note: This function applies to non-port owned XRIs
 3365  * only.
 3366  *
 3367  * @param hw Hardware context.
 3368  *
 3369  * @return Returns a pointer to an object on success, or NULL on failure.
 3370  */
 3371 ocs_hw_io_t *
 3372 ocs_hw_io_alloc(ocs_hw_t *hw)
 3373 {
 3374         ocs_hw_io_t     *io = NULL;
 3375 
 3376         ocs_lock(&hw->io_lock);
 3377                 io = _ocs_hw_io_alloc(hw);
 3378         ocs_unlock(&hw->io_lock);
 3379 
 3380         return io;
 3381 }
 3382 
 3383 /**
 3384  * @ingroup io
 3385  * @brief Allocate/Activate a port owned HW IO object.
 3386  *
 3387  * @par Description
 3388  * This function is called by the transport layer when an XRI is
 3389  * allocated by the SLI-Port. This will "activate" the HW IO
 3390  * associated with the XRI received from the SLI-Port to mirror
 3391  * the state of the XRI.
 3392  * @n @n @b Note: This function applies to port owned XRIs only.
 3393  *
 3394  * @param hw Hardware context.
 3395  * @param io Pointer HW IO to activate/allocate.
 3396  *
 3397  * @return Returns a pointer to an object on success, or NULL on failure.
 3398  */
 3399 ocs_hw_io_t *
 3400 ocs_hw_io_activate_port_owned(ocs_hw_t *hw, ocs_hw_io_t *io)
 3401 {
 3402         if (ocs_ref_read_count(&io->ref) > 0) {
 3403                 ocs_log_err(hw->os, "Bad parameter: refcount > 0\n");
 3404                 return NULL;
 3405         }
 3406 
 3407         if (io->wq != NULL) {
 3408                 ocs_log_err(hw->os, "XRI %x already in use\n", io->indicator);
 3409                 return NULL;
 3410         }
 3411 
 3412         ocs_ref_init(&io->ref, ocs_hw_io_free_port_owned, io);
 3413         io->xbusy = TRUE;
 3414 
 3415         return io;
 3416 }
 3417 
 3418 /**
 3419  * @ingroup io
 3420  * @brief When an IO is freed, depending on the exchange busy flag, and other
 3421  * workarounds, move it to the correct list.
 3422  *
 3423  * @par Description
 3424  * @n @b Note: Assumes that the hw->io_lock is held and the item has been removed
 3425  * from the busy or wait_free list.
 3426  *
 3427  * @param hw Hardware context.
 3428  * @param io Pointer to the IO object to move.
 3429  */
 3430 static void
 3431 ocs_hw_io_free_move_correct_list(ocs_hw_t *hw, ocs_hw_io_t *io)
 3432 {
 3433         if (io->xbusy) {
 3434                 /* add to wait_free list and wait for XRI_ABORTED CQEs to clean up */
 3435                 ocs_list_add_tail(&hw->io_wait_free, io);
 3436                 io->state = OCS_HW_IO_STATE_WAIT_FREE;
 3437         } else {
 3438                 /* IO not busy, add to free list */
 3439                 ocs_list_add_tail(&hw->io_free, io);
 3440                 io->state = OCS_HW_IO_STATE_FREE;
 3441         }
 3442 
 3443         /* BZ 161832 workaround */
 3444         if (hw->workaround.use_dif_sec_xri) {
 3445                 ocs_hw_check_sec_hio_list(hw);
 3446         }
 3447 }
 3448 
 3449 /**
 3450  * @ingroup io
 3451  * @brief Free a HW IO object. Perform cleanup common to
 3452  * port and host-owned IOs.
 3453  *
 3454  * @param hw Hardware context.
 3455  * @param io Pointer to the HW IO object.
 3456  */
 3457 static inline void
 3458 ocs_hw_io_free_common(ocs_hw_t *hw, ocs_hw_io_t *io)
 3459 {
 3460         /* initialize IO fields */
 3461         ocs_hw_init_free_io(io);
 3462 
 3463         /* Restore default SGL */
 3464         ocs_hw_io_restore_sgl(hw, io);
 3465 }
 3466 
 3467 /**
 3468  * @ingroup io
 3469  * @brief Free a HW IO object associated with a port-owned XRI.
 3470  *
 3471  * @param arg Pointer to the HW IO object.
 3472  */
 3473 static void
 3474 ocs_hw_io_free_port_owned(void *arg)
 3475 {
 3476         ocs_hw_io_t *io = (ocs_hw_io_t *)arg;
 3477         ocs_hw_t *hw = io->hw;
 3478 
 3479         /*
 3480          * For auto xfer rdy, if the dnrx bit is set, then add it to the list of XRIs
 3481          * waiting for buffers.
 3482          */
 3483         if (io->auto_xfer_rdy_dnrx) {
 3484                 ocs_lock(&hw->io_lock);
 3485                         /* take a reference count because we still own the IO until the buffer is posted */
 3486                         ocs_ref_init(&io->ref, ocs_hw_io_free_port_owned, io);
 3487                         ocs_list_add_tail(&hw->io_port_dnrx, io);
 3488                 ocs_unlock(&hw->io_lock);
 3489         }
 3490 
 3491         /* perform common cleanup */
 3492         ocs_hw_io_free_common(hw, io);
 3493 }
 3494 
 3495 /**
 3496  * @ingroup io
 3497  * @brief Free a previously-allocated HW IO object. Called when
 3498  * IO refcount goes to zero (host-owned IOs only).
 3499  *
 3500  * @param arg Pointer to the HW IO object.
 3501  */
 3502 static void
 3503 ocs_hw_io_free_internal(void *arg)
 3504 {
 3505         ocs_hw_io_t *io = (ocs_hw_io_t *)arg;
 3506         ocs_hw_t *hw = io->hw;
 3507 
 3508         /* perform common cleanup */
 3509         ocs_hw_io_free_common(hw, io);
 3510 
 3511         ocs_lock(&hw->io_lock);
 3512                 /* remove from in-use list */
 3513                 ocs_list_remove(&hw->io_inuse, io);
 3514                 ocs_hw_io_free_move_correct_list(hw, io);
 3515         ocs_unlock(&hw->io_lock);
 3516 }
 3517 
 3518 /**
 3519  * @ingroup io
 3520  * @brief Free a previously-allocated HW IO object.
 3521  *
 3522  * @par Description
 3523  * @n @b Note: This function applies to port and host owned XRIs.
 3524  *
 3525  * @param hw Hardware context.
 3526  * @param io Pointer to the HW IO object.
 3527  *
 3528  * @return Returns a non-zero value if HW IO was freed, 0 if references
 3529  * on the IO still exist, or a negative value if an error occurred.
 3530  */
 3531 int32_t
 3532 ocs_hw_io_free(ocs_hw_t *hw, ocs_hw_io_t *io)
 3533 {
 3534         /* just put refcount */
 3535         if (ocs_ref_read_count(&io->ref) <= 0) {
 3536                 ocs_log_err(hw->os, "Bad parameter: refcount <= 0 xri=%x tag=%x\n",
 3537                             io->indicator, io->reqtag);
 3538                 return -1;
 3539         }
 3540 
 3541         return ocs_ref_put(&io->ref); /* ocs_ref_get(): ocs_hw_io_alloc() */
 3542 }
 3543 
 3544 /**
 3545  * @ingroup io
 3546  * @brief Check if given HW IO is in-use
 3547  *
 3548  * @par Description
 3549  * This function returns TRUE if the given HW IO has been
 3550  * allocated and is in-use, and FALSE otherwise. It applies to
 3551  * port and host owned XRIs.
 3552  *
 3553  * @param hw Hardware context.
 3554  * @param io Pointer to the HW IO object.
 3555  *
 3556  * @return TRUE if an IO is in use, or FALSE otherwise.
 3557  */
 3558 uint8_t
 3559 ocs_hw_io_inuse(ocs_hw_t *hw, ocs_hw_io_t *io)
 3560 {
 3561         return (ocs_ref_read_count(&io->ref) > 0);
 3562 }
 3563 
 3564 /**
 3565  * @brief Write a HW IO to a work queue.
 3566  *
 3567  * @par Description
 3568  * A HW IO is written to a work queue.
 3569  *
 3570  * @param wq Pointer to work queue.
 3571  * @param wqe Pointer to WQ entry.
 3572  *
 3573  * @n @b Note: Assumes the SLI-4 queue lock is held.
 3574  *
 3575  * @return Returns 0 on success, or a negative error code value on failure.
 3576  */
 3577 static int32_t
 3578 _hw_wq_write(hw_wq_t *wq, ocs_hw_wqe_t *wqe)
 3579 {
 3580         int32_t rc;
 3581         int32_t queue_rc;
 3582 
 3583         /* Every so often, set the wqec bit to generate comsummed completions */
 3584         if (wq->wqec_count) {
 3585                 wq->wqec_count--;
 3586         }
 3587         if (wq->wqec_count == 0) {
 3588                 sli4_generic_wqe_t *genwqe = (void*)wqe->wqebuf;
 3589                 genwqe->wqec = 1;
 3590                 wq->wqec_count = wq->wqec_set_count;
 3591         }
 3592 
 3593         /* Decrement WQ free count */
 3594         wq->free_count--;
 3595 
 3596         queue_rc = _sli_queue_write(&wq->hw->sli, wq->queue, wqe->wqebuf);
 3597 
 3598         if (queue_rc < 0) {
 3599                 rc = -1;
 3600         } else {
 3601                 rc = 0;
 3602                 ocs_queue_history_wq(&wq->hw->q_hist, (void *) wqe->wqebuf, wq->queue->id, queue_rc);
 3603         }
 3604 
 3605         return rc;
 3606 }
 3607 
 3608 /**
 3609  * @brief Write a HW IO to a work queue.
 3610  *
 3611  * @par Description
 3612  * A HW IO is written to a work queue.
 3613  *
 3614  * @param wq Pointer to work queue.
 3615  * @param wqe Pointer to WQE entry.
 3616  *
 3617  * @n @b Note: Takes the SLI-4 queue lock.
 3618  *
 3619  * @return Returns 0 on success, or a negative error code value on failure.
 3620  */
 3621 int32_t
 3622 hw_wq_write(hw_wq_t *wq, ocs_hw_wqe_t *wqe)
 3623 {
 3624         int32_t rc = 0;
 3625 
 3626         sli_queue_lock(wq->queue);
 3627                 if ( ! ocs_list_empty(&wq->pending_list)) {
 3628                         ocs_list_add_tail(&wq->pending_list, wqe);
 3629                         OCS_STAT(wq->wq_pending_count++;)
 3630                         while ((wq->free_count > 0) && ((wqe = ocs_list_remove_head(&wq->pending_list)) != NULL)) {
 3631                                 rc = _hw_wq_write(wq, wqe);
 3632                                 if (rc < 0) {
 3633                                         break;
 3634                                 }
 3635                                 if (wqe->abort_wqe_submit_needed) {
 3636                                         wqe->abort_wqe_submit_needed = 0;
 3637                                         sli_abort_wqe(&wq->hw->sli, wqe->wqebuf, wq->hw->sli.config.wqe_size, SLI_ABORT_XRI, 
 3638                                                         wqe->send_abts, wqe->id, 0, wqe->abort_reqtag, SLI4_CQ_DEFAULT );
 3639                                         ocs_list_add_tail(&wq->pending_list, wqe);
 3640                                         OCS_STAT(wq->wq_pending_count++;)
 3641                                 }
 3642                         }
 3643                 } else {
 3644                         if (wq->free_count > 0) {
 3645                                 rc = _hw_wq_write(wq, wqe);
 3646                         } else {
 3647                                 ocs_list_add_tail(&wq->pending_list, wqe);
 3648                                 OCS_STAT(wq->wq_pending_count++;)
 3649                         }
 3650                 }
 3651 
 3652         sli_queue_unlock(wq->queue);
 3653 
 3654         return rc;
 3655 
 3656 }
 3657 
 3658 /**
 3659  * @brief Update free count and submit any pending HW IOs
 3660  *
 3661  * @par Description
 3662  * The WQ free count is updated, and any pending HW IOs are submitted that
 3663  * will fit in the queue.
 3664  *
 3665  * @param wq Pointer to work queue.
 3666  * @param update_free_count Value added to WQs free count.
 3667  *
 3668  * @return None.
 3669  */
 3670 static void
 3671 hw_wq_submit_pending(hw_wq_t *wq, uint32_t update_free_count)
 3672 {
 3673         ocs_hw_wqe_t *wqe;
 3674 
 3675         sli_queue_lock(wq->queue);
 3676 
 3677                 /* Update free count with value passed in */
 3678                 wq->free_count += update_free_count;
 3679 
 3680                 while ((wq->free_count > 0) && ((wqe = ocs_list_remove_head(&wq->pending_list)) != NULL)) {
 3681                         _hw_wq_write(wq, wqe);
 3682 
 3683                         if (wqe->abort_wqe_submit_needed) {
 3684                                 wqe->abort_wqe_submit_needed = 0;
 3685                                 sli_abort_wqe(&wq->hw->sli, wqe->wqebuf, wq->hw->sli.config.wqe_size, SLI_ABORT_XRI, 
 3686                                                 wqe->send_abts, wqe->id, 0, wqe->abort_reqtag, SLI4_CQ_DEFAULT);
 3687                                 ocs_list_add_tail(&wq->pending_list, wqe);
 3688                                 OCS_STAT(wq->wq_pending_count++;)
 3689                         }
 3690                 }
 3691 
 3692         sli_queue_unlock(wq->queue);
 3693 }
 3694 
 3695 /**
 3696  * @brief Check to see if there are any BZ 161832 workaround waiting IOs
 3697  *
 3698  * @par Description
 3699  * Checks hw->sec_hio_wait_list, if an IO is waiting for a HW IO, then try
 3700  * to allocate a secondary HW io, and dispatch it.
 3701  *
 3702  * @n @b Note: hw->io_lock MUST be taken when called.
 3703  *
 3704  * @param hw pointer to HW object
 3705  *
 3706  * @return none
 3707  */
 3708 static void
 3709 ocs_hw_check_sec_hio_list(ocs_hw_t *hw)
 3710 {
 3711         ocs_hw_io_t *io;
 3712         ocs_hw_io_t *sec_io;
 3713         int rc = 0;
 3714 
 3715         while (!ocs_list_empty(&hw->sec_hio_wait_list)) {
 3716                 uint16_t flags;
 3717 
 3718                 sec_io = _ocs_hw_io_alloc(hw);
 3719                 if (sec_io == NULL) {
 3720                         break;
 3721                 }
 3722 
 3723                 io = ocs_list_remove_head(&hw->sec_hio_wait_list);
 3724                 ocs_list_add_tail(&hw->io_inuse, io);
 3725                 io->state = OCS_HW_IO_STATE_INUSE;
 3726                 io->sec_hio = sec_io;
 3727 
 3728                 /* mark secondary XRI for second and subsequent data phase as quarantine */
 3729                 if (io->xbusy) {
 3730                         sec_io->quarantine = TRUE;
 3731                 }
 3732 
 3733                 flags = io->sec_iparam.fcp_tgt.flags;
 3734                 if (io->xbusy) {
 3735                         flags |= SLI4_IO_CONTINUATION;
 3736                 } else {
 3737                         flags &= ~SLI4_IO_CONTINUATION;
 3738                 }
 3739 
 3740                 io->tgt_wqe_timeout = io->sec_iparam.fcp_tgt.timeout;
 3741 
 3742                 /* Complete (continue) TRECV IO */
 3743                 if (io->xbusy) {
 3744                         if (sli_fcp_cont_treceive64_wqe(&hw->sli, io->wqe.wqebuf, hw->sli.config.wqe_size, &io->def_sgl,
 3745                                 io->first_data_sge,
 3746                                 io->sec_iparam.fcp_tgt.offset, io->sec_len, io->indicator, io->sec_hio->indicator,
 3747                                 io->reqtag, SLI4_CQ_DEFAULT,
 3748                                 io->sec_iparam.fcp_tgt.ox_id, io->rnode->indicator, io->rnode,
 3749                                 flags,
 3750                                 io->sec_iparam.fcp_tgt.dif_oper, io->sec_iparam.fcp_tgt.blk_size, io->sec_iparam.fcp_tgt.cs_ctl, io->sec_iparam.fcp_tgt.app_id)) {
 3751                                         ocs_log_test(hw->os, "TRECEIVE WQE error\n");
 3752                                         break;
 3753                         }
 3754                 } else {
 3755                         if (sli_fcp_treceive64_wqe(&hw->sli, io->wqe.wqebuf, hw->sli.config.wqe_size, &io->def_sgl,
 3756                                 io->first_data_sge,
 3757                                 io->sec_iparam.fcp_tgt.offset, io->sec_len, io->indicator,
 3758                                 io->reqtag, SLI4_CQ_DEFAULT,
 3759                                 io->sec_iparam.fcp_tgt.ox_id, io->rnode->indicator, io->rnode,
 3760                                 flags,
 3761                                 io->sec_iparam.fcp_tgt.dif_oper, io->sec_iparam.fcp_tgt.blk_size,
 3762                                 io->sec_iparam.fcp_tgt.cs_ctl, io->sec_iparam.fcp_tgt.app_id)) {
 3763                                         ocs_log_test(hw->os, "TRECEIVE WQE error\n");
 3764                                         break;
 3765                         }
 3766                 }
 3767 
 3768                 if (io->wq == NULL) {
 3769                         io->wq = ocs_hw_queue_next_wq(hw, io);
 3770                         ocs_hw_assert(io->wq != NULL);
 3771                 }
 3772                 io->xbusy = TRUE;
 3773 
 3774                 /*
 3775                  * Add IO to active io wqe list before submitting, in case the
 3776                  * wcqe processing preempts this thread.
 3777                  */
 3778                 ocs_hw_add_io_timed_wqe(hw, io);
 3779                 rc = hw_wq_write(io->wq, &io->wqe);
 3780                 if (rc >= 0) {
 3781                         /* non-negative return is success */
 3782                         rc = 0;
 3783                 } else {
 3784                         /* failed to write wqe, remove from active wqe list */
 3785                         ocs_log_err(hw->os, "sli_queue_write failed: %d\n", rc);
 3786                         io->xbusy = FALSE;
 3787                         ocs_hw_remove_io_timed_wqe(hw, io);
 3788                 }
 3789         }
 3790 }
 3791 
 3792 /**
 3793  * @ingroup io
 3794  * @brief Send a Single Request/Response Sequence (SRRS).
 3795  *
 3796  * @par Description
 3797  * This routine supports communication sequences consisting of a single
 3798  * request and single response between two endpoints. Examples include:
 3799  *  - Sending an ELS request.
 3800  *  - Sending an ELS response - To send an ELS reponse, the caller must provide
 3801  * the OX_ID from the received request.
 3802  *  - Sending a FC Common Transport (FC-CT) request - To send a FC-CT request,
 3803  * the caller must provide the R_CTL, TYPE, and DF_CTL
 3804  * values to place in the FC frame header.
 3805  *  .
 3806  * @n @b Note: The caller is expected to provide both send and receive
 3807  * buffers for requests. In the case of sending a response, no receive buffer
 3808  * is necessary and the caller may pass in a NULL pointer.
 3809  *
 3810  * @param hw Hardware context.
 3811  * @param type Type of sequence (ELS request/response, FC-CT).
 3812  * @param io Previously-allocated HW IO object.
 3813  * @param send DMA memory holding data to send (for example, ELS request, BLS response).
 3814  * @param len Length, in bytes, of data to send.
 3815  * @param receive Optional DMA memory to hold a response.
 3816  * @param rnode Destination of data (that is, a remote node).
 3817  * @param iparam IO parameters (ELS response and FC-CT).
 3818  * @param cb Function call upon completion of sending the data (may be NULL).
 3819  * @param arg Argument to pass to IO completion function.
 3820  *
 3821  * @return Returns 0 on success, or a non-zero on failure.
 3822  */
 3823 ocs_hw_rtn_e
 3824 ocs_hw_srrs_send(ocs_hw_t *hw, ocs_hw_io_type_e type, ocs_hw_io_t *io,
 3825                   ocs_dma_t *send, uint32_t len, ocs_dma_t *receive,
 3826                   ocs_remote_node_t *rnode, ocs_hw_io_param_t *iparam,
 3827                   ocs_hw_srrs_cb_t cb, void *arg)
 3828 {
 3829         sli4_sge_t      *sge = NULL;
 3830         ocs_hw_rtn_e    rc = OCS_HW_RTN_SUCCESS;
 3831         uint16_t        local_flags = 0;
 3832 
 3833         if (!hw || !io || !rnode || !iparam) {
 3834                 ocs_log_err(NULL, "bad parm hw=%p io=%p send=%p receive=%p rnode=%p iparam=%p\n",
 3835                             hw, io, send, receive, rnode, iparam);
 3836                 return OCS_HW_RTN_ERROR;
 3837         }
 3838 
 3839         if (hw->state != OCS_HW_STATE_ACTIVE) {
 3840                 ocs_log_test(hw->os, "cannot send SRRS, HW state=%d\n", hw->state);
 3841                 return OCS_HW_RTN_ERROR;
 3842         }
 3843 
 3844         if (ocs_hw_is_xri_port_owned(hw, io->indicator)) {
 3845                 /* We must set the XC bit for port owned XRIs */
 3846                 local_flags |= SLI4_IO_CONTINUATION;
 3847         }
 3848         io->rnode = rnode;
 3849         io->type  = type;
 3850         io->done = cb;
 3851         io->arg  = arg;
 3852 
 3853         sge = io->sgl->virt;
 3854 
 3855         /* clear both SGE */
 3856         ocs_memset(io->sgl->virt, 0, 2 * sizeof(sli4_sge_t));
 3857 
 3858         if (send) {
 3859                 sge[0].buffer_address_high = ocs_addr32_hi(send->phys);
 3860                 sge[0].buffer_address_low  = ocs_addr32_lo(send->phys);
 3861                 sge[0].sge_type = SLI4_SGE_TYPE_DATA;
 3862                 sge[0].buffer_length = len;
 3863         }
 3864 
 3865         if ((OCS_HW_ELS_REQ == type) || (OCS_HW_FC_CT == type)) {
 3866                 sge[1].buffer_address_high = ocs_addr32_hi(receive->phys);
 3867                 sge[1].buffer_address_low  = ocs_addr32_lo(receive->phys);
 3868                 sge[1].sge_type = SLI4_SGE_TYPE_DATA;
 3869                 sge[1].buffer_length = receive->size;
 3870                 sge[1].last = TRUE;
 3871         } else {
 3872                 sge[0].last = TRUE;
 3873         }
 3874 
 3875         switch (type) {
 3876         case OCS_HW_ELS_REQ:
 3877                 if ( (!send) || sli_els_request64_wqe(&hw->sli, io->wqe.wqebuf, hw->sli.config.wqe_size, io->sgl,
 3878                                                         *((uint8_t *)(send->virt)), /* req_type */
 3879                                                         len, receive->size,
 3880                                                         iparam->els.timeout, io->indicator, io->reqtag, SLI4_CQ_DEFAULT, rnode)) {
 3881                         ocs_log_err(hw->os, "REQ WQE error\n");
 3882                         rc = OCS_HW_RTN_ERROR;
 3883                 }
 3884                 break;
 3885         case OCS_HW_ELS_RSP:
 3886                 if ( (!send) || sli_xmit_els_rsp64_wqe(&hw->sli, io->wqe.wqebuf, hw->sli.config.wqe_size, send, len,
 3887                                            io->indicator, io->reqtag, SLI4_CQ_DEFAULT,
 3888                                            iparam->els.ox_id,
 3889                                                         rnode, local_flags, UINT32_MAX)) {
 3890                         ocs_log_err(hw->os, "RSP WQE error\n");
 3891                         rc = OCS_HW_RTN_ERROR;
 3892                 }
 3893                 break;
 3894         case OCS_HW_ELS_RSP_SID:
 3895                 if ( (!send) || sli_xmit_els_rsp64_wqe(&hw->sli, io->wqe.wqebuf, hw->sli.config.wqe_size, send, len,
 3896                                            io->indicator, io->reqtag, SLI4_CQ_DEFAULT,
 3897                                            iparam->els_sid.ox_id,
 3898                                                         rnode, local_flags, iparam->els_sid.s_id)) {
 3899                         ocs_log_err(hw->os, "RSP (SID) WQE error\n");
 3900                         rc = OCS_HW_RTN_ERROR;
 3901                 }
 3902                 break;
 3903         case OCS_HW_FC_CT:
 3904                 if ( (!send) || sli_gen_request64_wqe(&hw->sli, io->wqe.wqebuf, hw->sli.config.wqe_size, io->sgl, len,
 3905                                           receive->size, iparam->fc_ct.timeout, io->indicator,
 3906                                           io->reqtag, SLI4_CQ_DEFAULT, rnode, iparam->fc_ct.r_ctl,
 3907                                           iparam->fc_ct.type, iparam->fc_ct.df_ctl)) {
 3908                         ocs_log_err(hw->os, "GEN WQE error\n");
 3909                         rc = OCS_HW_RTN_ERROR;
 3910                 }
 3911                 break;
 3912         case OCS_HW_FC_CT_RSP:
 3913                 if ( (!send) || sli_xmit_sequence64_wqe(&hw->sli, io->wqe.wqebuf, hw->sli.config.wqe_size, io->sgl, len,
 3914                                           iparam->fc_ct_rsp.timeout, iparam->fc_ct_rsp.ox_id, io->indicator,
 3915                                           io->reqtag, rnode, iparam->fc_ct_rsp.r_ctl,
 3916                                           iparam->fc_ct_rsp.type, iparam->fc_ct_rsp.df_ctl)) {
 3917                         ocs_log_err(hw->os, "XMIT SEQ WQE error\n");
 3918                         rc = OCS_HW_RTN_ERROR;
 3919                 }
 3920                 break;
 3921         case OCS_HW_BLS_ACC:
 3922         case OCS_HW_BLS_RJT:
 3923         {
 3924                 sli_bls_payload_t       bls;
 3925 
 3926                 if (OCS_HW_BLS_ACC == type) {
 3927                         bls.type = SLI_BLS_ACC;
 3928                         ocs_memcpy(&bls.u.acc, iparam->bls.payload, sizeof(bls.u.acc));
 3929                 } else {
 3930                         bls.type = SLI_BLS_RJT;
 3931                         ocs_memcpy(&bls.u.rjt, iparam->bls.payload, sizeof(bls.u.rjt));
 3932                 }
 3933 
 3934                 bls.ox_id = iparam->bls.ox_id;
 3935                 bls.rx_id = iparam->bls.rx_id;
 3936 
 3937                 if (sli_xmit_bls_rsp64_wqe(&hw->sli, io->wqe.wqebuf, hw->sli.config.wqe_size, &bls,
 3938                                            io->indicator, io->reqtag,
 3939                                            SLI4_CQ_DEFAULT,
 3940                                            rnode, UINT32_MAX)) {
 3941                         ocs_log_err(hw->os, "XMIT_BLS_RSP64 WQE error\n");
 3942                         rc = OCS_HW_RTN_ERROR;
 3943                 }
 3944                 break;
 3945         }
 3946         case OCS_HW_BLS_ACC_SID:
 3947         {
 3948                 sli_bls_payload_t       bls;
 3949 
 3950                 bls.type = SLI_BLS_ACC;
 3951                 ocs_memcpy(&bls.u.acc, iparam->bls_sid.payload, sizeof(bls.u.acc));
 3952 
 3953                 bls.ox_id = iparam->bls_sid.ox_id;
 3954                 bls.rx_id = iparam->bls_sid.rx_id;
 3955 
 3956                 if (sli_xmit_bls_rsp64_wqe(&hw->sli, io->wqe.wqebuf, hw->sli.config.wqe_size, &bls,
 3957                                            io->indicator, io->reqtag,
 3958                                            SLI4_CQ_DEFAULT,
 3959                                            rnode, iparam->bls_sid.s_id)) {
 3960                         ocs_log_err(hw->os, "XMIT_BLS_RSP64 WQE SID error\n");
 3961                         rc = OCS_HW_RTN_ERROR;
 3962                 }
 3963                 break;
 3964         }
 3965         case OCS_HW_BCAST:
 3966                 if ( (!send) || sli_xmit_bcast64_wqe(&hw->sli, io->wqe.wqebuf, hw->sli.config.wqe_size, send, len,
 3967                                         iparam->bcast.timeout, io->indicator, io->reqtag,
 3968                                         SLI4_CQ_DEFAULT, rnode,
 3969                                         iparam->bcast.r_ctl, iparam->bcast.type, iparam->bcast.df_ctl)) {
 3970                         ocs_log_err(hw->os, "XMIT_BCAST64 WQE error\n");
 3971                         rc = OCS_HW_RTN_ERROR;
 3972                 }
 3973                 break;
 3974         default:
 3975                 ocs_log_err(hw->os, "bad SRRS type %#x\n", type);
 3976                 rc = OCS_HW_RTN_ERROR;
 3977         }
 3978 
 3979         if (OCS_HW_RTN_SUCCESS == rc) {
 3980                 if (io->wq == NULL) {
 3981                         io->wq = ocs_hw_queue_next_wq(hw, io);
 3982                         ocs_hw_assert(io->wq != NULL);
 3983                 }
 3984                 io->xbusy = TRUE;
 3985 
 3986                 /*
 3987                  * Add IO to active io wqe list before submitting, in case the
 3988                  * wcqe processing preempts this thread.
 3989                  */
 3990                 OCS_STAT(io->wq->use_count++);
 3991                 ocs_hw_add_io_timed_wqe(hw, io);
 3992                 rc = hw_wq_write(io->wq, &io->wqe);
 3993                 if (rc >= 0) {
 3994                         /* non-negative return is success */
 3995                         rc = 0;
 3996                 } else {
 3997                         /* failed to write wqe, remove from active wqe list */
 3998                         ocs_log_err(hw->os, "sli_queue_write failed: %d\n", rc);
 3999                         io->xbusy = FALSE;
 4000                         ocs_hw_remove_io_timed_wqe(hw, io);
 4001                 }
 4002         }
 4003 
 4004         return rc;
 4005 }
 4006 
 4007 /**
 4008  * @ingroup io
 4009  * @brief Send a read, write, or response IO.
 4010  *
 4011  * @par Description
 4012  * This routine supports sending a higher-level IO (for example, FCP) between two endpoints
 4013  * as a target or initiator. Examples include:
 4014  *  - Sending read data and good response (target).
 4015  *  - Sending a response (target with no data or after receiving write data).
 4016  *  .
 4017  * This routine assumes all IOs use the SGL associated with the HW IO. Prior to
 4018  * calling this routine, the data should be loaded using ocs_hw_io_add_sge().
 4019  *
 4020  * @param hw Hardware context.
 4021  * @param type Type of IO (target read, target response, and so on).
 4022  * @param io Previously-allocated HW IO object.
 4023  * @param len Length, in bytes, of data to send.
 4024  * @param iparam IO parameters.
 4025  * @param rnode Destination of data (that is, a remote node).
 4026  * @param cb Function call upon completion of sending data (may be NULL).
 4027  * @param arg Argument to pass to IO completion function.
 4028  *
 4029  * @return Returns 0 on success, or a non-zero value on failure.
 4030  *
 4031  * @todo
 4032  *  - Support specifiying relative offset.
 4033  *  - Use a WQ other than 0.
 4034  */
 4035 ocs_hw_rtn_e
 4036 ocs_hw_io_send(ocs_hw_t *hw, ocs_hw_io_type_e type, ocs_hw_io_t *io,
 4037                 uint32_t len, ocs_hw_io_param_t *iparam, ocs_remote_node_t *rnode,
 4038                 void *cb, void *arg)
 4039 {
 4040         ocs_hw_rtn_e    rc = OCS_HW_RTN_SUCCESS;
 4041         uint32_t        rpi;
 4042         uint8_t         send_wqe = TRUE;
 4043 
 4044         CPUTRACE("");
 4045 
 4046         if (!hw || !io || !rnode || !iparam) {
 4047                 ocs_log_err(NULL, "bad parm hw=%p io=%p iparam=%p rnode=%p\n",
 4048                             hw, io, iparam, rnode);
 4049                 return OCS_HW_RTN_ERROR;
 4050         }
 4051 
 4052         if (hw->state != OCS_HW_STATE_ACTIVE) {
 4053                 ocs_log_err(hw->os, "cannot send IO, HW state=%d\n", hw->state);
 4054                 return OCS_HW_RTN_ERROR;
 4055         }
 4056 
 4057         rpi = rnode->indicator;
 4058 
 4059         if (hw->workaround.use_unregistered_rpi && (rpi == UINT32_MAX)) {
 4060                 rpi = hw->workaround.unregistered_rid;
 4061                 ocs_log_test(hw->os, "using unregistered RPI: %d\n", rpi);
 4062         }
 4063 
 4064         /*
 4065          * Save state needed during later stages
 4066          */
 4067         io->rnode = rnode;
 4068         io->type  = type;
 4069         io->done  = cb;
 4070         io->arg   = arg;
 4071 
 4072         /*
 4073          * Format the work queue entry used to send the IO
 4074          */
 4075         switch (type) {
 4076         case OCS_HW_IO_INITIATOR_READ:
 4077                 /*
 4078                  * If use_dif_quarantine workaround is in effect, and dif_separates then mark the
 4079                  * initiator read IO for quarantine
 4080                  */
 4081                 if (hw->workaround.use_dif_quarantine && (hw->config.dif_mode == OCS_HW_DIF_MODE_SEPARATE) &&
 4082                     (iparam->fcp_tgt.dif_oper != OCS_HW_DIF_OPER_DISABLED)) {
 4083                         io->quarantine = TRUE;
 4084                 }
 4085 
 4086                 ocs_hw_io_ini_sge(hw, io, iparam->fcp_ini.cmnd, iparam->fcp_ini.cmnd_size,
 4087                                 iparam->fcp_ini.rsp);
 4088 
 4089                 if (sli_fcp_iread64_wqe(&hw->sli, io->wqe.wqebuf, hw->sli.config.wqe_size, &io->def_sgl, io->first_data_sge, len,
 4090                                         io->indicator, io->reqtag, SLI4_CQ_DEFAULT, rpi, rnode,
 4091                                         iparam->fcp_ini.dif_oper, iparam->fcp_ini.blk_size,
 4092                                         iparam->fcp_ini.timeout)) {
 4093                         ocs_log_err(hw->os, "IREAD WQE error\n");
 4094                         rc = OCS_HW_RTN_ERROR;
 4095                 }
 4096                 break;
 4097         case OCS_HW_IO_INITIATOR_WRITE:
 4098                 ocs_hw_io_ini_sge(hw, io, iparam->fcp_ini.cmnd, iparam->fcp_ini.cmnd_size,
 4099                                 iparam->fcp_ini.rsp);
 4100 
 4101                 if (sli_fcp_iwrite64_wqe(&hw->sli, io->wqe.wqebuf, hw->sli.config.wqe_size, &io->def_sgl, io->first_data_sge,
 4102                                          len, iparam->fcp_ini.first_burst,
 4103                                          io->indicator, io->reqtag,
 4104                                         SLI4_CQ_DEFAULT, rpi, rnode,
 4105                                         iparam->fcp_ini.dif_oper, iparam->fcp_ini.blk_size,
 4106                                         iparam->fcp_ini.timeout)) {
 4107                         ocs_log_err(hw->os, "IWRITE WQE error\n");
 4108                         rc = OCS_HW_RTN_ERROR;
 4109                 }
 4110                 break;
 4111         case OCS_HW_IO_INITIATOR_NODATA:
 4112                 ocs_hw_io_ini_sge(hw, io, iparam->fcp_ini.cmnd, iparam->fcp_ini.cmnd_size,
 4113                                 iparam->fcp_ini.rsp);
 4114 
 4115                 if (sli_fcp_icmnd64_wqe(&hw->sli, io->wqe.wqebuf, hw->sli.config.wqe_size, &io->def_sgl,
 4116                                         io->indicator, io->reqtag, SLI4_CQ_DEFAULT,
 4117                                         rpi, rnode, iparam->fcp_ini.timeout)) {
 4118                         ocs_log_err(hw->os, "ICMND WQE error\n");
 4119                         rc = OCS_HW_RTN_ERROR;
 4120                 }
 4121                 break;
 4122         case OCS_HW_IO_TARGET_WRITE: {
 4123                 uint16_t flags = iparam->fcp_tgt.flags;
 4124                 fcp_xfer_rdy_iu_t *xfer = io->xfer_rdy.virt;
 4125 
 4126                 /*
 4127                  * Fill in the XFER_RDY for IF_TYPE 0 devices
 4128                  */
 4129                 *((uint32_t *)xfer->fcp_data_ro) = ocs_htobe32(iparam->fcp_tgt.offset);
 4130                 *((uint32_t *)xfer->fcp_burst_len) = ocs_htobe32(len);
 4131                 *((uint32_t *)xfer->rsvd) = 0;
 4132 
 4133                 if (io->xbusy) {
 4134                         flags |= SLI4_IO_CONTINUATION;
 4135                 } else {
 4136                         flags &= ~SLI4_IO_CONTINUATION;
 4137                 }
 4138 
 4139                 io->tgt_wqe_timeout = iparam->fcp_tgt.timeout;
 4140 
 4141                 /*
 4142                  * If use_dif_quarantine workaround is in effect, and this is a DIF enabled IO
 4143                  * then mark the target write IO for quarantine
 4144                  */
 4145                 if (hw->workaround.use_dif_quarantine && (hw->config.dif_mode == OCS_HW_DIF_MODE_SEPARATE) &&
 4146                     (iparam->fcp_tgt.dif_oper != OCS_HW_DIF_OPER_DISABLED)) {
 4147                         io->quarantine = TRUE;
 4148                 }
 4149 
 4150                 /*
 4151                  * BZ 161832 Workaround:
 4152                  * Check for use_dif_sec_xri workaround.  Note, even though the first dataphase
 4153                  * doesn't really need a secondary XRI, we allocate one anyway, as this avoids the
 4154                  * potential for deadlock where all XRI's are allocated as primaries to IOs that
 4155                  * are on hw->sec_hio_wait_list.   If this secondary XRI is not for the first
 4156                  * data phase, it is marked for quarantine.
 4157                  */
 4158                 if (hw->workaround.use_dif_sec_xri && (iparam->fcp_tgt.dif_oper != OCS_HW_DIF_OPER_DISABLED)) {
 4159                         /*
 4160                          * If we have allocated a chained SGL for skyhawk, then
 4161                          * we can re-use this for the sec_hio.
 4162                          */
 4163                         if (io->ovfl_io != NULL) {
 4164                                 io->sec_hio = io->ovfl_io;
 4165                                 io->sec_hio->quarantine = TRUE;
 4166                         } else {
 4167                                 io->sec_hio = ocs_hw_io_alloc(hw);
 4168                         }
 4169                         if (io->sec_hio == NULL) {
 4170                                 /* Failed to allocate, so save full request context and put
 4171                                  * this IO on the wait list
 4172                                  */
 4173                                 io->sec_iparam = *iparam;
 4174                                 io->sec_len = len;
 4175                                 ocs_lock(&hw->io_lock);
 4176                                         ocs_list_remove(&hw->io_inuse,  io);
 4177                                         ocs_list_add_tail(&hw->sec_hio_wait_list, io);
 4178                                         io->state = OCS_HW_IO_STATE_WAIT_SEC_HIO;
 4179                                         hw->sec_hio_wait_count++;
 4180                                 ocs_unlock(&hw->io_lock);
 4181                                 send_wqe = FALSE;
 4182                                 /* Done */
 4183                                 break;
 4184                         }
 4185                         /* We quarantine the secondary IO if this is the second or subsequent data phase */
 4186                         if (io->xbusy) {
 4187                                 io->sec_hio->quarantine = TRUE;
 4188                         }
 4189                 }
 4190 
 4191                 /*
 4192                  * If not the first data phase, and io->sec_hio has been allocated, then issue
 4193                  * FCP_CONT_TRECEIVE64 WQE, otherwise use the usual FCP_TRECEIVE64 WQE
 4194                  */
 4195                 if (io->xbusy && (io->sec_hio != NULL)) {
 4196                         if (sli_fcp_cont_treceive64_wqe(&hw->sli, io->wqe.wqebuf, hw->sli.config.wqe_size, &io->def_sgl, io->first_data_sge,
 4197                                                    iparam->fcp_tgt.offset, len, io->indicator, io->sec_hio->indicator,
 4198                                                    io->reqtag, SLI4_CQ_DEFAULT,
 4199                                                    iparam->fcp_tgt.ox_id, rpi, rnode,
 4200                                                    flags,
 4201                                                    iparam->fcp_tgt.dif_oper, iparam->fcp_tgt.blk_size,
 4202                                                    iparam->fcp_tgt.cs_ctl, iparam->fcp_tgt.app_id)) {
 4203                                 ocs_log_err(hw->os, "TRECEIVE WQE error\n");
 4204                                 rc = OCS_HW_RTN_ERROR;
 4205                         }
 4206                 } else {
 4207                         if (sli_fcp_treceive64_wqe(&hw->sli, io->wqe.wqebuf, hw->sli.config.wqe_size, &io->def_sgl, io->first_data_sge,
 4208                                                    iparam->fcp_tgt.offset, len, io->indicator, io->reqtag,
 4209                                                    SLI4_CQ_DEFAULT,
 4210                                                    iparam->fcp_tgt.ox_id, rpi, rnode,
 4211                                                    flags,
 4212                                                    iparam->fcp_tgt.dif_oper, iparam->fcp_tgt.blk_size,
 4213                                                    iparam->fcp_tgt.cs_ctl, iparam->fcp_tgt.app_id)) {
 4214                                 ocs_log_err(hw->os, "TRECEIVE WQE error\n");
 4215                                 rc = OCS_HW_RTN_ERROR;
 4216                         }
 4217                 }
 4218                 break;
 4219         }
 4220         case OCS_HW_IO_TARGET_READ: {
 4221                 uint16_t flags = iparam->fcp_tgt.flags;
 4222 
 4223                 if (io->xbusy) {
 4224                         flags |= SLI4_IO_CONTINUATION;
 4225                 } else {
 4226                         flags &= ~SLI4_IO_CONTINUATION;
 4227                 }
 4228 
 4229                 io->tgt_wqe_timeout = iparam->fcp_tgt.timeout;
 4230                 if (sli_fcp_tsend64_wqe(&hw->sli, io->wqe.wqebuf, hw->sli.config.wqe_size, &io->def_sgl, io->first_data_sge,
 4231                                         iparam->fcp_tgt.offset, len, io->indicator, io->reqtag,
 4232                                         SLI4_CQ_DEFAULT,
 4233                                         iparam->fcp_tgt.ox_id, rpi, rnode,
 4234                                         flags,
 4235                                         iparam->fcp_tgt.dif_oper,
 4236                                         iparam->fcp_tgt.blk_size,
 4237                                         iparam->fcp_tgt.cs_ctl,
 4238                                         iparam->fcp_tgt.app_id)) {
 4239                         ocs_log_err(hw->os, "TSEND WQE error\n");
 4240                         rc = OCS_HW_RTN_ERROR;
 4241                 } else if (hw->workaround.retain_tsend_io_length) {
 4242                         io->length = len;
 4243                 }
 4244                 break;
 4245         }
 4246         case OCS_HW_IO_TARGET_RSP: {
 4247                 uint16_t flags = iparam->fcp_tgt.flags;
 4248 
 4249                 if (io->xbusy) {
 4250                         flags |= SLI4_IO_CONTINUATION;
 4251                 } else {
 4252                         flags &= ~SLI4_IO_CONTINUATION;
 4253                 }
 4254 
 4255                 /* post a new auto xfer ready buffer */
 4256                 if (hw->auto_xfer_rdy_enabled && io->is_port_owned) {
 4257                         if ((io->auto_xfer_rdy_dnrx = ocs_hw_rqpair_auto_xfer_rdy_buffer_post(hw, io, 1))) {
 4258                                 flags |= SLI4_IO_DNRX;
 4259                         }
 4260                 }
 4261 
 4262                 io->tgt_wqe_timeout = iparam->fcp_tgt.timeout;
 4263                 if (sli_fcp_trsp64_wqe(&hw->sli, io->wqe.wqebuf, hw->sli.config.wqe_size,
 4264                                         &io->def_sgl,
 4265                                         len,
 4266                                         io->indicator, io->reqtag,
 4267                                         SLI4_CQ_DEFAULT,
 4268                                         iparam->fcp_tgt.ox_id,
 4269                                         rpi, rnode,
 4270                                         flags, iparam->fcp_tgt.cs_ctl,
 4271                                         io->is_port_owned,
 4272                                         iparam->fcp_tgt.app_id)) {
 4273                         ocs_log_err(hw->os, "TRSP WQE error\n");
 4274                         rc = OCS_HW_RTN_ERROR;
 4275                 }
 4276 
 4277                 break;
 4278         }
 4279         default:
 4280                 ocs_log_err(hw->os, "unsupported IO type %#x\n", type);
 4281                 rc = OCS_HW_RTN_ERROR;
 4282         }
 4283 
 4284         if (send_wqe && (OCS_HW_RTN_SUCCESS == rc)) {
 4285                 if (io->wq == NULL) {
 4286                         io->wq = ocs_hw_queue_next_wq(hw, io);
 4287                         ocs_hw_assert(io->wq != NULL);
 4288                 }
 4289 
 4290                 io->xbusy = TRUE;
 4291 
 4292                 /*
 4293                  * Add IO to active io wqe list before submitting, in case the
 4294                  * wcqe processing preempts this thread.
 4295                  */
 4296                 OCS_STAT(hw->tcmd_wq_submit[io->wq->instance]++);
 4297                 OCS_STAT(io->wq->use_count++);
 4298                 ocs_hw_add_io_timed_wqe(hw, io);
 4299                 rc = hw_wq_write(io->wq, &io->wqe);
 4300                 if (rc >= 0) {
 4301                         /* non-negative return is success */
 4302                         rc = 0;
 4303                 } else {
 4304                         /* failed to write wqe, remove from active wqe list */
 4305                         ocs_log_err(hw->os, "sli_queue_write failed: %d\n", rc);
 4306                         io->xbusy = FALSE;
 4307                         ocs_hw_remove_io_timed_wqe(hw, io);
 4308                 }
 4309         }
 4310 
 4311         return rc;
 4312 }
 4313 
 4314 /**
 4315  * @brief Send a raw frame
 4316  *
 4317  * @par Description
 4318  * Using the SEND_FRAME_WQE, a frame consisting of header and payload is sent.
 4319  *
 4320  * @param hw Pointer to HW object.
 4321  * @param hdr Pointer to a little endian formatted FC header.
 4322  * @param sof Value to use as the frame SOF.
 4323  * @param eof Value to use as the frame EOF.
 4324  * @param payload Pointer to payload DMA buffer.
 4325  * @param ctx Pointer to caller provided send frame context.
 4326  * @param callback Callback function.
 4327  * @param arg Callback function argument.
 4328  *
 4329  * @return Returns 0 on success, or a negative error code value on failure.
 4330  */
 4331 ocs_hw_rtn_e
 4332 ocs_hw_send_frame(ocs_hw_t *hw, fc_header_le_t *hdr, uint8_t sof, uint8_t eof, ocs_dma_t *payload,
 4333                    ocs_hw_send_frame_context_t *ctx, void (*callback)(void *arg, uint8_t *cqe, int32_t status), void *arg)
 4334 {
 4335         int32_t rc;
 4336         ocs_hw_wqe_t *wqe;
 4337         uint32_t xri;
 4338         hw_wq_t *wq;
 4339 
 4340         wqe = &ctx->wqe;
 4341 
 4342         /* populate the callback object */
 4343         ctx->hw = hw;
 4344 
 4345         /* Fetch and populate request tag */
 4346         ctx->wqcb = ocs_hw_reqtag_alloc(hw, callback, arg);
 4347         if (ctx->wqcb == NULL) {
 4348                 ocs_log_err(hw->os, "can't allocate request tag\n");
 4349                 return OCS_HW_RTN_NO_RESOURCES;
 4350         }
 4351 
 4352         /* Choose a work queue, first look for a class[1] wq, otherwise just use wq[0] */
 4353         wq = ocs_varray_iter_next(hw->wq_class_array[1]);
 4354         if (wq == NULL) {
 4355                 wq = hw->hw_wq[0];
 4356         }
 4357 
 4358         /* Set XRI and RX_ID in the header based on which WQ, and which send_frame_io we are using */
 4359         xri = wq->send_frame_io->indicator;
 4360 
 4361         /* Build the send frame WQE */
 4362         rc = sli_send_frame_wqe(&hw->sli, wqe->wqebuf, hw->sli.config.wqe_size, sof, eof, (uint32_t*) hdr, payload,
 4363                                 payload->len, OCS_HW_SEND_FRAME_TIMEOUT, xri, ctx->wqcb->instance_index);
 4364         if (rc) {
 4365                 ocs_log_err(hw->os, "sli_send_frame_wqe failed: %d\n", rc);
 4366                 return OCS_HW_RTN_ERROR;
 4367         }
 4368 
 4369         /* Write to WQ */
 4370         rc = hw_wq_write(wq, wqe);
 4371         if (rc) {
 4372                 ocs_log_err(hw->os, "hw_wq_write failed: %d\n", rc);
 4373                 return OCS_HW_RTN_ERROR;
 4374         }
 4375 
 4376         OCS_STAT(wq->use_count++);
 4377 
 4378         return OCS_HW_RTN_SUCCESS;
 4379 }
 4380 
 4381 ocs_hw_rtn_e
 4382 ocs_hw_io_register_sgl(ocs_hw_t *hw, ocs_hw_io_t *io, ocs_dma_t *sgl, uint32_t sgl_count)
 4383 {
 4384         if (sli_get_sgl_preregister(&hw->sli)) {
 4385                 ocs_log_err(hw->os, "can't use temporary SGL with pre-registered SGLs\n");
 4386                 return OCS_HW_RTN_ERROR;
 4387         }
 4388         io->ovfl_sgl = sgl;
 4389         io->ovfl_sgl_count = sgl_count;
 4390         io->ovfl_io = NULL;
 4391 
 4392         return OCS_HW_RTN_SUCCESS;
 4393 }
 4394 
 4395 static void
 4396 ocs_hw_io_restore_sgl(ocs_hw_t *hw, ocs_hw_io_t *io)
 4397 {
 4398         /* Restore the default */
 4399         io->sgl = &io->def_sgl;
 4400         io->sgl_count = io->def_sgl_count;
 4401 
 4402         /*
 4403          * For skyhawk, we need to free the IO allocated for the chained
 4404          * SGL. For all devices, clear the overflow fields on the IO.
 4405          *
 4406          * Note: For DIF IOs, we may be using the same XRI for the sec_hio and
 4407          *       the chained SGLs. If so, then we clear the ovfl_io field
 4408          *       when the sec_hio is freed.
 4409          */
 4410         if (io->ovfl_io != NULL) {
 4411                 ocs_hw_io_free(hw, io->ovfl_io);
 4412                 io->ovfl_io = NULL;
 4413         }
 4414 
 4415         /* Clear the overflow SGL */
 4416         io->ovfl_sgl = NULL;
 4417         io->ovfl_sgl_count = 0;
 4418         io->ovfl_lsp = NULL;
 4419 }
 4420 
 4421 /**
 4422  * @ingroup io
 4423  * @brief Initialize the scatter gather list entries of an IO.
 4424  *
 4425  * @param hw Hardware context.
 4426  * @param io Previously-allocated HW IO object.
 4427  * @param type Type of IO (target read, target response, and so on).
 4428  *
 4429  * @return Returns 0 on success, or a non-zero value on failure.
 4430  */
 4431 ocs_hw_rtn_e
 4432 ocs_hw_io_init_sges(ocs_hw_t *hw, ocs_hw_io_t *io, ocs_hw_io_type_e type)
 4433 {
 4434         sli4_sge_t      *data = NULL;
 4435         uint32_t        i = 0;
 4436         uint32_t        skips = 0;
 4437 
 4438         if (!hw || !io) {
 4439                 ocs_log_err(hw ? hw->os : NULL, "bad parameter hw=%p io=%p\n",
 4440                             hw, io);
 4441                 return OCS_HW_RTN_ERROR;
 4442         }
 4443 
 4444         /* Clear / reset the scatter-gather list */
 4445         io->sgl = &io->def_sgl;
 4446         io->sgl_count = io->def_sgl_count;
 4447         io->first_data_sge = 0;
 4448 
 4449         ocs_memset(io->sgl->virt, 0, 2 * sizeof(sli4_sge_t));
 4450         io->n_sge = 0;
 4451         io->sge_offset = 0;
 4452 
 4453         io->type = type;
 4454 
 4455         data = io->sgl->virt;
 4456 
 4457         /*
 4458          * Some IO types have underlying hardware requirements on the order
 4459          * of SGEs. Process all special entries here.
 4460          */
 4461         switch (type) {
 4462         case OCS_HW_IO_INITIATOR_READ:
 4463         case OCS_HW_IO_INITIATOR_WRITE:
 4464         case OCS_HW_IO_INITIATOR_NODATA:
 4465                 /*
 4466                  * No skips, 2 special for initiator I/Os
 4467                  * The addresses and length are written later
 4468                  */
 4469                 /* setup command pointer */
 4470                 data->sge_type = SLI4_SGE_TYPE_DATA;
 4471                 data++;
 4472 
 4473                 /* setup response pointer */
 4474                 data->sge_type = SLI4_SGE_TYPE_DATA;
 4475 
 4476                 if (OCS_HW_IO_INITIATOR_NODATA == type) {
 4477                         data->last = TRUE;
 4478                 }
 4479                 data++;
 4480 
 4481                 io->n_sge = 2;
 4482                 break;
 4483         case OCS_HW_IO_TARGET_WRITE:
 4484 #define OCS_TARGET_WRITE_SKIPS  2
 4485                 skips = OCS_TARGET_WRITE_SKIPS;
 4486 
 4487                 /* populate host resident XFER_RDY buffer */
 4488                 data->sge_type = SLI4_SGE_TYPE_DATA;
 4489                 data->buffer_address_high = ocs_addr32_hi(io->xfer_rdy.phys);
 4490                 data->buffer_address_low  = ocs_addr32_lo(io->xfer_rdy.phys);
 4491                 data->buffer_length = io->xfer_rdy.size;
 4492                 data++;
 4493 
 4494                 skips--;
 4495 
 4496                 io->n_sge = 1;
 4497                 break;
 4498         case OCS_HW_IO_TARGET_READ:
 4499                 /*
 4500                  * For FCP_TSEND64, the first 2 entries are SKIP SGE's
 4501                  */
 4502 #define OCS_TARGET_READ_SKIPS   2
 4503                 skips = OCS_TARGET_READ_SKIPS;
 4504                 break;
 4505         case OCS_HW_IO_TARGET_RSP:
 4506                 /*
 4507                  * No skips, etc. for FCP_TRSP64
 4508                  */
 4509                 break;
 4510         default:
 4511                 ocs_log_err(hw->os, "unsupported IO type %#x\n", type);
 4512                 return OCS_HW_RTN_ERROR;
 4513         }
 4514 
 4515         /*
 4516          * Write skip entries
 4517          */
 4518         for (i = 0; i < skips; i++) {
 4519                 data->sge_type = SLI4_SGE_TYPE_SKIP;
 4520                 data++;
 4521         }
 4522 
 4523         io->n_sge += skips;
 4524 
 4525         /*
 4526          * Set last
 4527          */
 4528         data->last = TRUE;
 4529 
 4530         return OCS_HW_RTN_SUCCESS;
 4531 }
 4532 
 4533 /**
 4534  * @ingroup io
 4535  * @brief Add a T10 PI seed scatter gather list entry.
 4536  *
 4537  * @param hw Hardware context.
 4538  * @param io Previously-allocated HW IO object.
 4539  * @param dif_info Pointer to T10 DIF fields, or NULL if no DIF.
 4540  *
 4541  * @return Returns 0 on success, or a non-zero value on failure.
 4542  */
 4543 ocs_hw_rtn_e
 4544 ocs_hw_io_add_seed_sge(ocs_hw_t *hw, ocs_hw_io_t *io, ocs_hw_dif_info_t *dif_info)
 4545 {
 4546         sli4_sge_t      *data = NULL;
 4547         sli4_diseed_sge_t *dif_seed;
 4548 
 4549         /* If no dif_info, or dif_oper is disabled, then just return success */
 4550         if ((dif_info == NULL) || (dif_info->dif_oper == OCS_HW_DIF_OPER_DISABLED)) {
 4551                 return OCS_HW_RTN_SUCCESS;
 4552         }
 4553 
 4554         if (!hw || !io) {
 4555                 ocs_log_err(hw ? hw->os : NULL, "bad parameter hw=%p io=%p dif_info=%p\n",
 4556                             hw, io, dif_info);
 4557                 return OCS_HW_RTN_ERROR;
 4558         }
 4559 
 4560         data = io->sgl->virt;
 4561         data += io->n_sge;
 4562 
 4563         /* If we are doing T10 DIF add the DIF Seed SGE */
 4564         ocs_memset(data, 0, sizeof(sli4_diseed_sge_t));
 4565         dif_seed = (sli4_diseed_sge_t *)data;
 4566         dif_seed->ref_tag_cmp = dif_info->ref_tag_cmp;
 4567         dif_seed->ref_tag_repl = dif_info->ref_tag_repl;
 4568         dif_seed->app_tag_repl = dif_info->app_tag_repl;
 4569         dif_seed->repl_app_tag = dif_info->repl_app_tag;
 4570         if (SLI4_IF_TYPE_LANCER_FC_ETH != hw->sli.if_type) {
 4571                 dif_seed->atrt = dif_info->disable_app_ref_ffff;
 4572                 dif_seed->at = dif_info->disable_app_ffff;
 4573         }
 4574         dif_seed->sge_type = SLI4_SGE_TYPE_DISEED;
 4575         /* Workaround for SKH (BZ157233) */
 4576         if (((io->type == OCS_HW_IO_TARGET_WRITE) || (io->type == OCS_HW_IO_INITIATOR_READ)) &&
 4577                 (SLI4_IF_TYPE_LANCER_FC_ETH != hw->sli.if_type) && dif_info->dif_separate) {
 4578                 dif_seed->sge_type = SLI4_SGE_TYPE_SKIP;
 4579         }
 4580 
 4581         dif_seed->app_tag_cmp = dif_info->app_tag_cmp;
 4582         dif_seed->dif_blk_size = dif_info->blk_size;
 4583         dif_seed->auto_incr_ref_tag = dif_info->auto_incr_ref_tag;
 4584         dif_seed->check_app_tag = dif_info->check_app_tag;
 4585         dif_seed->check_ref_tag = dif_info->check_ref_tag;
 4586         dif_seed->check_crc = dif_info->check_guard;
 4587         dif_seed->new_ref_tag = dif_info->repl_ref_tag;
 4588 
 4589         switch(dif_info->dif_oper) {
 4590         case OCS_HW_SGE_DIF_OP_IN_NODIF_OUT_CRC:
 4591                 dif_seed->dif_op_rx = SLI4_SGE_DIF_OP_IN_NODIF_OUT_CRC;
 4592                 dif_seed->dif_op_tx = SLI4_SGE_DIF_OP_IN_NODIF_OUT_CRC;
 4593                 break;
 4594         case OCS_HW_SGE_DIF_OP_IN_CRC_OUT_NODIF:
 4595                 dif_seed->dif_op_rx = SLI4_SGE_DIF_OP_IN_CRC_OUT_NODIF;
 4596                 dif_seed->dif_op_tx = SLI4_SGE_DIF_OP_IN_CRC_OUT_NODIF;
 4597                 break;
 4598         case OCS_HW_SGE_DIF_OP_IN_NODIF_OUT_CHKSUM:
 4599                 dif_seed->dif_op_rx = SLI4_SGE_DIF_OP_IN_NODIF_OUT_CHKSUM;
 4600                 dif_seed->dif_op_tx = SLI4_SGE_DIF_OP_IN_NODIF_OUT_CHKSUM;
 4601                 break;
 4602         case OCS_HW_SGE_DIF_OP_IN_CHKSUM_OUT_NODIF:
 4603                 dif_seed->dif_op_rx = SLI4_SGE_DIF_OP_IN_CHKSUM_OUT_NODIF;
 4604                 dif_seed->dif_op_tx = SLI4_SGE_DIF_OP_IN_CHKSUM_OUT_NODIF;
 4605                 break;
 4606         case OCS_HW_SGE_DIF_OP_IN_CRC_OUT_CRC:
 4607                 dif_seed->dif_op_rx = SLI4_SGE_DIF_OP_IN_CRC_OUT_CRC;
 4608                 dif_seed->dif_op_tx = SLI4_SGE_DIF_OP_IN_CRC_OUT_CRC;
 4609                 break;
 4610         case OCS_HW_SGE_DIF_OP_IN_CHKSUM_OUT_CHKSUM:
 4611                 dif_seed->dif_op_rx = SLI4_SGE_DIF_OP_IN_CHKSUM_OUT_CHKSUM;
 4612                 dif_seed->dif_op_tx = SLI4_SGE_DIF_OP_IN_CHKSUM_OUT_CHKSUM;
 4613                 break;
 4614         case OCS_HW_SGE_DIF_OP_IN_CRC_OUT_CHKSUM:
 4615                 dif_seed->dif_op_rx = SLI4_SGE_DIF_OP_IN_CRC_OUT_CHKSUM;
 4616                 dif_seed->dif_op_tx = SLI4_SGE_DIF_OP_IN_CRC_OUT_CHKSUM;
 4617                 break;
 4618         case OCS_HW_SGE_DIF_OP_IN_CHKSUM_OUT_CRC:
 4619                 dif_seed->dif_op_rx = SLI4_SGE_DIF_OP_IN_CHKSUM_OUT_CRC;
 4620                 dif_seed->dif_op_tx = SLI4_SGE_DIF_OP_IN_CHKSUM_OUT_CRC;
 4621                 break;
 4622         case OCS_HW_SGE_DIF_OP_IN_RAW_OUT_RAW:
 4623                 dif_seed->dif_op_rx = SLI4_SGE_DIF_OP_IN_RAW_OUT_RAW;
 4624                 dif_seed->dif_op_tx = SLI4_SGE_DIF_OP_IN_RAW_OUT_RAW;
 4625                 break;
 4626         default:
 4627                 ocs_log_err(hw->os, "unsupported DIF operation %#x\n",
 4628                             dif_info->dif_oper);
 4629                 return OCS_HW_RTN_ERROR;
 4630         }
 4631 
 4632         /*
 4633          * Set last, clear previous last
 4634          */
 4635         data->last = TRUE;
 4636         if (io->n_sge) {
 4637                 data[-1].last = FALSE;
 4638         }
 4639 
 4640         io->n_sge++;
 4641 
 4642         return OCS_HW_RTN_SUCCESS;
 4643 }
 4644 
 4645 static ocs_hw_rtn_e
 4646 ocs_hw_io_overflow_sgl(ocs_hw_t *hw, ocs_hw_io_t *io)
 4647 {
 4648         sli4_lsp_sge_t *lsp;
 4649 
 4650         /* fail if we're already pointing to the overflow SGL */
 4651         if (io->sgl == io->ovfl_sgl) {
 4652                 return OCS_HW_RTN_ERROR;
 4653         }
 4654 
 4655         /*
 4656          * For skyhawk, we can use another SGL to extend the SGL list. The
 4657          * Chained entry must not be in the first 4 entries.
 4658          *
 4659          * Note: For DIF enabled IOs, we will use the ovfl_io for the sec_hio.
 4660          */
 4661         if (sli_get_sgl_preregister(&hw->sli) &&
 4662             io->def_sgl_count > 4 &&
 4663             io->ovfl_io == NULL &&
 4664             ((SLI4_IF_TYPE_BE3_SKH_PF == sli_get_if_type(&hw->sli)) ||
 4665                 (SLI4_IF_TYPE_BE3_SKH_VF == sli_get_if_type(&hw->sli)))) {
 4666                 io->ovfl_io = ocs_hw_io_alloc(hw);
 4667                 if (io->ovfl_io != NULL) {
 4668                         /*
 4669                          * Note: We can't call ocs_hw_io_register_sgl() here
 4670                          * because it checks that SGLs are not pre-registered
 4671                          * and for shyhawk, preregistered SGLs are required.
 4672                          */
 4673                         io->ovfl_sgl = &io->ovfl_io->def_sgl;
 4674                         io->ovfl_sgl_count = io->ovfl_io->def_sgl_count;
 4675                 }
 4676         }
 4677 
 4678         /* fail if we don't have an overflow SGL registered */
 4679         if (io->ovfl_io == NULL || io->ovfl_sgl == NULL) {
 4680                 return OCS_HW_RTN_ERROR;
 4681         }
 4682 
 4683         /*
 4684          * Overflow, we need to put a link SGE in the last location of the current SGL, after
 4685          * copying the the last SGE to the overflow SGL
 4686          */
 4687 
 4688         ((sli4_sge_t*)io->ovfl_sgl->virt)[0] = ((sli4_sge_t*)io->sgl->virt)[io->n_sge - 1];
 4689 
 4690         lsp = &((sli4_lsp_sge_t*)io->sgl->virt)[io->n_sge - 1];
 4691         ocs_memset(lsp, 0, sizeof(*lsp));
 4692 
 4693         if ((SLI4_IF_TYPE_BE3_SKH_PF == sli_get_if_type(&hw->sli)) ||
 4694             (SLI4_IF_TYPE_BE3_SKH_VF == sli_get_if_type(&hw->sli))) {
 4695                 sli_skh_chain_sge_build(&hw->sli,
 4696                                         (sli4_sge_t*)lsp,
 4697                                         io->ovfl_io->indicator,
 4698                                         0, /* frag_num */
 4699                                         0); /* offset */
 4700         } else {
 4701                 lsp->buffer_address_high = ocs_addr32_hi(io->ovfl_sgl->phys);
 4702                 lsp->buffer_address_low  = ocs_addr32_lo(io->ovfl_sgl->phys);
 4703                 lsp->sge_type = SLI4_SGE_TYPE_LSP;
 4704                 lsp->last = 0;
 4705                 io->ovfl_lsp = lsp;
 4706                 io->ovfl_lsp->segment_length = sizeof(sli4_sge_t);
 4707         }
 4708 
 4709         /* Update the current SGL pointer, and n_sgl */
 4710         io->sgl = io->ovfl_sgl;
 4711         io->sgl_count = io->ovfl_sgl_count;
 4712         io->n_sge = 1;
 4713 
 4714         return OCS_HW_RTN_SUCCESS;
 4715 }
 4716 
 4717 /**
 4718  * @ingroup io
 4719  * @brief Add a scatter gather list entry to an IO.
 4720  *
 4721  * @param hw Hardware context.
 4722  * @param io Previously-allocated HW IO object.
 4723  * @param addr Physical address.
 4724  * @param length Length of memory pointed to by @c addr.
 4725  *
 4726  * @return Returns 0 on success, or a non-zero value on failure.
 4727  */
 4728 ocs_hw_rtn_e
 4729 ocs_hw_io_add_sge(ocs_hw_t *hw, ocs_hw_io_t *io, uintptr_t addr, uint32_t length)
 4730 {
 4731         sli4_sge_t      *data = NULL;
 4732 
 4733         if (!hw || !io || !addr || !length) {
 4734                 ocs_log_err(hw ? hw->os : NULL,
 4735                             "bad parameter hw=%p io=%p addr=%lx length=%u\n",
 4736                             hw, io, addr, length);
 4737                 return OCS_HW_RTN_ERROR;
 4738         }
 4739 
 4740         if ((length != 0) && (io->n_sge + 1) > io->sgl_count) {
 4741                 if (ocs_hw_io_overflow_sgl(hw, io) != OCS_HW_RTN_SUCCESS) {
 4742                         ocs_log_err(hw->os, "SGL full (%d)\n", io->n_sge);
 4743                         return OCS_HW_RTN_ERROR;
 4744                 }
 4745         }
 4746 
 4747         if (length > sli_get_max_sge(&hw->sli)) {
 4748                 ocs_log_err(hw->os, "length of SGE %d bigger than allowed %d\n",
 4749                             length, sli_get_max_sge(&hw->sli));
 4750                 return OCS_HW_RTN_ERROR;
 4751         }
 4752 
 4753         data = io->sgl->virt;
 4754         data += io->n_sge;
 4755 
 4756         data->sge_type = SLI4_SGE_TYPE_DATA;
 4757         data->buffer_address_high = ocs_addr32_hi(addr);
 4758         data->buffer_address_low  = ocs_addr32_lo(addr);
 4759         data->buffer_length = length;
 4760         data->data_offset = io->sge_offset;
 4761         /*
 4762          * Always assume this is the last entry and mark as such.
 4763          * If this is not the first entry unset the "last SGE"
 4764          * indication for the previous entry
 4765          */
 4766         data->last = TRUE;
 4767         if (io->n_sge) {
 4768                 data[-1].last = FALSE;
 4769         }
 4770 
 4771         /* Set first_data_bde if not previously set */
 4772         if (io->first_data_sge == 0) {
 4773                 io->first_data_sge = io->n_sge;
 4774         }
 4775 
 4776         io->sge_offset += length;
 4777         io->n_sge++;
 4778 
 4779         /* Update the linked segment length (only executed after overflow has begun) */
 4780         if (io->ovfl_lsp != NULL) {
 4781                 io->ovfl_lsp->segment_length = io->n_sge * sizeof(sli4_sge_t);
 4782         }
 4783 
 4784         return OCS_HW_RTN_SUCCESS;
 4785 }
 4786 
 4787 /**
 4788  * @ingroup io
 4789  * @brief Add a T10 DIF scatter gather list entry to an IO.
 4790  *
 4791  * @param hw Hardware context.
 4792  * @param io Previously-allocated HW IO object.
 4793  * @param addr DIF physical address.
 4794  *
 4795  * @return Returns 0 on success, or a non-zero value on failure.
 4796  */
 4797 ocs_hw_rtn_e
 4798 ocs_hw_io_add_dif_sge(ocs_hw_t *hw, ocs_hw_io_t *io, uintptr_t addr)
 4799 {
 4800         sli4_dif_sge_t  *data = NULL;
 4801 
 4802         if (!hw || !io || !addr) {
 4803                 ocs_log_err(hw ? hw->os : NULL,
 4804                             "bad parameter hw=%p io=%p addr=%lx\n",
 4805                             hw, io, addr);
 4806                 return OCS_HW_RTN_ERROR;
 4807         }
 4808 
 4809         if ((io->n_sge + 1) > hw->config.n_sgl) {
 4810                 if (ocs_hw_io_overflow_sgl(hw, io) != OCS_HW_RTN_ERROR) {
 4811                         ocs_log_err(hw->os, "SGL full (%d)\n", io->n_sge);
 4812                         return OCS_HW_RTN_ERROR;
 4813                 }
 4814         }
 4815 
 4816         data = io->sgl->virt;
 4817         data += io->n_sge;
 4818 
 4819         data->sge_type = SLI4_SGE_TYPE_DIF;
 4820         /* Workaround for SKH (BZ157233) */
 4821         if (((io->type == OCS_HW_IO_TARGET_WRITE) || (io->type == OCS_HW_IO_INITIATOR_READ)) &&
 4822                 (SLI4_IF_TYPE_LANCER_FC_ETH != hw->sli.if_type)) {
 4823                 data->sge_type = SLI4_SGE_TYPE_SKIP;
 4824         }
 4825 
 4826         data->buffer_address_high = ocs_addr32_hi(addr);
 4827         data->buffer_address_low  = ocs_addr32_lo(addr);
 4828 
 4829         /*
 4830          * Always assume this is the last entry and mark as such.
 4831          * If this is not the first entry unset the "last SGE"
 4832          * indication for the previous entry
 4833          */
 4834         data->last = TRUE;
 4835         if (io->n_sge) {
 4836                 data[-1].last = FALSE;
 4837         }
 4838 
 4839         io->n_sge++;
 4840 
 4841         return OCS_HW_RTN_SUCCESS;
 4842 }
 4843 
 4844 /**
 4845  * @ingroup io
 4846  * @brief Abort a previously-started IO.
 4847  *
 4848  * @param hw Hardware context.
 4849  * @param io_to_abort The IO to abort.
 4850  * @param send_abts Boolean to have the hardware automatically
 4851  * generate an ABTS.
 4852  * @param cb Function call upon completion of the abort (may be NULL).
 4853  * @param arg Argument to pass to abort completion function.
 4854  *
 4855  * @return Returns 0 on success, or a non-zero value on failure.
 4856  */
 4857 ocs_hw_rtn_e
 4858 ocs_hw_io_abort(ocs_hw_t *hw, ocs_hw_io_t *io_to_abort, uint32_t send_abts, void *cb, void *arg)
 4859 {
 4860         sli4_abort_type_e atype = SLI_ABORT_MAX;
 4861         uint32_t        id = 0, mask = 0;
 4862         ocs_hw_rtn_e    rc = OCS_HW_RTN_SUCCESS;
 4863         hw_wq_callback_t *wqcb;
 4864 
 4865         if (!hw || !io_to_abort) {
 4866                 ocs_log_err(hw ? hw->os : NULL,
 4867                             "bad parameter hw=%p io=%p\n",
 4868                             hw, io_to_abort);
 4869                 return OCS_HW_RTN_ERROR;
 4870         }
 4871 
 4872         if (hw->state != OCS_HW_STATE_ACTIVE) {
 4873                 ocs_log_err(hw->os, "cannot send IO abort, HW state=%d\n",
 4874                             hw->state);
 4875                 return OCS_HW_RTN_ERROR;
 4876         }
 4877 
 4878         /* take a reference on IO being aborted */
 4879         if (ocs_ref_get_unless_zero(&io_to_abort->ref) == 0) {
 4880                 /* command no longer active */
 4881                 ocs_log_test(hw ? hw->os : NULL,
 4882                                 "io not active xri=0x%x tag=0x%x\n",
 4883                                 io_to_abort->indicator, io_to_abort->reqtag);
 4884                 return OCS_HW_RTN_IO_NOT_ACTIVE;
 4885         }
 4886 
 4887         /* non-port owned XRI checks */
 4888         /* Must have a valid WQ reference */
 4889         if (io_to_abort->wq == NULL) {
 4890                 ocs_log_test(hw->os, "io_to_abort xri=0x%x not active on WQ\n",
 4891                                 io_to_abort->indicator);
 4892                 ocs_ref_put(&io_to_abort->ref); /* ocs_ref_get(): same function */
 4893                 return OCS_HW_RTN_IO_NOT_ACTIVE;
 4894         }
 4895 
 4896         /* Validation checks complete; now check to see if already being aborted */
 4897         ocs_lock(&hw->io_abort_lock);
 4898                 if (io_to_abort->abort_in_progress) {
 4899                         ocs_unlock(&hw->io_abort_lock);
 4900                         ocs_ref_put(&io_to_abort->ref); /* ocs_ref_get(): same function */
 4901                         ocs_log_debug(hw ? hw->os : NULL,
 4902                                 "io already being aborted xri=0x%x tag=0x%x\n",
 4903                                 io_to_abort->indicator, io_to_abort->reqtag);
 4904                         return OCS_HW_RTN_IO_ABORT_IN_PROGRESS;
 4905                 }
 4906 
 4907                 /*
 4908                  * This IO is not already being aborted. Set flag so we won't try to
 4909                  * abort it again. After all, we only have one abort_done callback.
 4910                  */
 4911                 io_to_abort->abort_in_progress = 1;
 4912         ocs_unlock(&hw->io_abort_lock);
 4913 
 4914         /*
 4915          * If we got here, the possibilities are:
 4916          * - host owned xri
 4917          *      - io_to_abort->wq_index != UINT32_MAX
 4918          *              - submit ABORT_WQE to same WQ
 4919          * - port owned xri:
 4920          *      - rxri: io_to_abort->wq_index == UINT32_MAX
 4921          *              - submit ABORT_WQE to any WQ
 4922          *      - non-rxri
 4923          *              - io_to_abort->index != UINT32_MAX
 4924          *                      - submit ABORT_WQE to same WQ
 4925          *              - io_to_abort->index == UINT32_MAX
 4926          *                      - submit ABORT_WQE to any WQ
 4927          */
 4928         io_to_abort->abort_done = cb;
 4929         io_to_abort->abort_arg  = arg;
 4930 
 4931         atype = SLI_ABORT_XRI;
 4932         id = io_to_abort->indicator;
 4933 
 4934         /* Allocate a request tag for the abort portion of this IO */
 4935         wqcb = ocs_hw_reqtag_alloc(hw, ocs_hw_wq_process_abort, io_to_abort);
 4936         if (wqcb == NULL) {
 4937                 ocs_log_err(hw->os, "can't allocate request tag\n");
 4938                 return OCS_HW_RTN_NO_RESOURCES;
 4939         }
 4940         io_to_abort->abort_reqtag = wqcb->instance_index;
 4941 
 4942         /*
 4943          * If the wqe is on the pending list, then set this wqe to be
 4944          * aborted when the IO's wqe is removed from the list.
 4945          */
 4946         if (io_to_abort->wq != NULL) {
 4947                 sli_queue_lock(io_to_abort->wq->queue);
 4948                         if (ocs_list_on_list(&io_to_abort->wqe.link)) {
 4949                                 io_to_abort->wqe.abort_wqe_submit_needed = 1;
 4950                                 io_to_abort->wqe.send_abts = send_abts;
 4951                                 io_to_abort->wqe.id = id;
 4952                                 io_to_abort->wqe.abort_reqtag = io_to_abort->abort_reqtag;
 4953                                 sli_queue_unlock(io_to_abort->wq->queue);
 4954                                 return 0;
 4955                 }
 4956                 sli_queue_unlock(io_to_abort->wq->queue);
 4957         }
 4958 
 4959         if (sli_abort_wqe(&hw->sli, io_to_abort->wqe.wqebuf, hw->sli.config.wqe_size, atype, send_abts, id, mask,
 4960                           io_to_abort->abort_reqtag, SLI4_CQ_DEFAULT)) {
 4961                 ocs_log_err(hw->os, "ABORT WQE error\n");
 4962                 io_to_abort->abort_reqtag = UINT32_MAX;
 4963                 ocs_hw_reqtag_free(hw, wqcb);
 4964                 rc = OCS_HW_RTN_ERROR;
 4965         }
 4966 
 4967         if (OCS_HW_RTN_SUCCESS == rc) {
 4968                 if (io_to_abort->wq == NULL) {
 4969                         io_to_abort->wq = ocs_hw_queue_next_wq(hw, io_to_abort);
 4970                         ocs_hw_assert(io_to_abort->wq != NULL);
 4971                 }
 4972                 /* ABORT_WQE does not actually utilize an XRI on the Port,
 4973                  * therefore, keep xbusy as-is to track the exchange's state,
 4974                  * not the ABORT_WQE's state
 4975                  */
 4976                 rc = hw_wq_write(io_to_abort->wq, &io_to_abort->wqe);
 4977                 if (rc > 0) {
 4978                         /* non-negative return is success */
 4979                         rc = 0;
 4980                         /* can't abort an abort so skip adding to timed wqe list */
 4981                 }
 4982         }
 4983 
 4984         if (OCS_HW_RTN_SUCCESS != rc) {
 4985                 ocs_lock(&hw->io_abort_lock);
 4986                         io_to_abort->abort_in_progress = 0;
 4987                 ocs_unlock(&hw->io_abort_lock);
 4988                 ocs_ref_put(&io_to_abort->ref); /* ocs_ref_get(): same function */
 4989         }
 4990         return rc;
 4991 }
 4992 
 4993 /**
 4994  * @ingroup io
 4995  * @brief Return the OX_ID/RX_ID of the IO.
 4996  *
 4997  * @param hw Hardware context.
 4998  * @param io HW IO object.
 4999  *
 5000  * @return Returns X_ID on success, or -1 on failure.
 5001  */
 5002 int32_t
 5003 ocs_hw_io_get_xid(ocs_hw_t *hw, ocs_hw_io_t *io)
 5004 {
 5005         if (!hw || !io) {
 5006                 ocs_log_err(hw ? hw->os : NULL,
 5007                             "bad parameter hw=%p io=%p\n", hw, io);
 5008                 return -1;
 5009         }
 5010 
 5011         return io->indicator;
 5012 }
 5013 
 5014 typedef struct ocs_hw_fw_write_cb_arg {
 5015         ocs_hw_fw_cb_t cb;
 5016         void *arg;
 5017 } ocs_hw_fw_write_cb_arg_t;
 5018 
 5019 typedef struct ocs_hw_sfp_cb_arg {
 5020         ocs_hw_sfp_cb_t cb;
 5021         void *arg;
 5022         ocs_dma_t payload;
 5023 } ocs_hw_sfp_cb_arg_t;
 5024 
 5025 typedef struct ocs_hw_temp_cb_arg {
 5026         ocs_hw_temp_cb_t cb;
 5027         void *arg;
 5028 } ocs_hw_temp_cb_arg_t;
 5029 
 5030 typedef struct ocs_hw_link_stat_cb_arg {
 5031         ocs_hw_link_stat_cb_t cb;
 5032         void *arg;
 5033 } ocs_hw_link_stat_cb_arg_t;
 5034 
 5035 typedef struct ocs_hw_host_stat_cb_arg {
 5036         ocs_hw_host_stat_cb_t cb;
 5037         void *arg;
 5038 } ocs_hw_host_stat_cb_arg_t;
 5039 
 5040 typedef struct ocs_hw_dump_get_cb_arg {
 5041         ocs_hw_dump_get_cb_t cb;
 5042         void *arg;
 5043         void *mbox_cmd;
 5044 } ocs_hw_dump_get_cb_arg_t;
 5045 
 5046 typedef struct ocs_hw_dump_clear_cb_arg {
 5047         ocs_hw_dump_clear_cb_t cb;
 5048         void *arg;
 5049         void *mbox_cmd;
 5050 } ocs_hw_dump_clear_cb_arg_t;
 5051 
 5052 /**
 5053  * @brief Write a portion of a firmware image to the device.
 5054  *
 5055  * @par Description
 5056  * Calls the correct firmware write function based on the device type.
 5057  *
 5058  * @param hw Hardware context.
 5059  * @param dma DMA structure containing the firmware image chunk.
 5060  * @param size Size of the firmware image chunk.
 5061  * @param offset Offset, in bytes, from the beginning of the firmware image.
 5062  * @param last True if this is the last chunk of the image.
 5063  * Causes the image to be committed to flash.
 5064  * @param cb Pointer to a callback function that is called when the command completes.
 5065  * The callback function prototype is
 5066  * <tt>void cb(int32_t status, uint32_t bytes_written, void *arg)</tt>.
 5067  * @param arg Pointer to be passed to the callback function.
 5068  *
 5069  * @return Returns 0 on success, or a non-zero value on failure.
 5070  */
 5071 ocs_hw_rtn_e
 5072 ocs_hw_firmware_write(ocs_hw_t *hw, ocs_dma_t *dma, uint32_t size, uint32_t offset, int last, ocs_hw_fw_cb_t cb, void *arg)
 5073 {
 5074         if (hw->sli.if_type == SLI4_IF_TYPE_LANCER_FC_ETH) {
 5075                 return ocs_hw_firmware_write_lancer(hw, dma, size, offset, last, cb, arg);
 5076         } else {
 5077                 /* Write firmware_write for BE3/Skyhawk not supported */
 5078                 return -1;
 5079         }
 5080 }
 5081 
 5082 /**
 5083  * @brief Write a portion of a firmware image to the Emulex XE201 ASIC (Lancer).
 5084  *
 5085  * @par Description
 5086  * Creates a SLI_CONFIG mailbox command, fills it with the correct values to write a
 5087  * firmware image chunk, and then sends the command with ocs_hw_command(). On completion,
 5088  * the callback function ocs_hw_fw_write_cb() gets called to free the mailbox
 5089  * and to signal the caller that the write has completed.
 5090  *
 5091  * @param hw Hardware context.
 5092  * @param dma DMA structure containing the firmware image chunk.
 5093  * @param size Size of the firmware image chunk.
 5094  * @param offset Offset, in bytes, from the beginning of the firmware image.
 5095  * @param last True if this is the last chunk of the image. Causes the image to be committed to flash.
 5096  * @param cb Pointer to a callback function that is called when the command completes.
 5097  * The callback function prototype is
 5098  * <tt>void cb(int32_t status, uint32_t bytes_written, void *arg)</tt>.
 5099  * @param arg Pointer to be passed to the callback function.
 5100  *
 5101  * @return Returns 0 on success, or a non-zero value on failure.
 5102  */
 5103 ocs_hw_rtn_e
 5104 ocs_hw_firmware_write_lancer(ocs_hw_t *hw, ocs_dma_t *dma, uint32_t size, uint32_t offset, int last, ocs_hw_fw_cb_t cb, void *arg)
 5105 {
 5106         ocs_hw_rtn_e rc = OCS_HW_RTN_ERROR;
 5107         uint8_t *mbxdata;
 5108         ocs_hw_fw_write_cb_arg_t *cb_arg;
 5109         int noc=0;      /* No Commit bit - set to 1 for testing */
 5110 
 5111         if (SLI4_IF_TYPE_LANCER_FC_ETH != sli_get_if_type(&hw->sli)) {
 5112                 ocs_log_test(hw->os, "Function only supported for I/F type 2\n");
 5113                 return OCS_HW_RTN_ERROR;
 5114         }
 5115 
 5116         mbxdata = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
 5117         if (mbxdata == NULL) {
 5118                 ocs_log_err(hw->os, "failed to malloc mbox\n");
 5119                 return OCS_HW_RTN_NO_MEMORY;
 5120         }
 5121 
 5122         cb_arg = ocs_malloc(hw->os, sizeof(ocs_hw_fw_write_cb_arg_t), OCS_M_NOWAIT);
 5123         if (cb_arg == NULL) {
 5124                 ocs_log_err(hw->os, "failed to malloc cb_arg\n");
 5125                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 5126                 return OCS_HW_RTN_NO_MEMORY;
 5127         }
 5128 
 5129         cb_arg->cb = cb;
 5130         cb_arg->arg = arg;
 5131 
 5132         if (sli_cmd_common_write_object(&hw->sli, mbxdata, SLI4_BMBX_SIZE, noc, last,
 5133                         size, offset, "/prg/", dma)) {
 5134                 rc = ocs_hw_command(hw, mbxdata, OCS_CMD_NOWAIT, ocs_hw_cb_fw_write, cb_arg);
 5135         }
 5136 
 5137         if (rc != OCS_HW_RTN_SUCCESS) {
 5138                 ocs_log_test(hw->os, "COMMON_WRITE_OBJECT failed\n");
 5139                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 5140                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_fw_write_cb_arg_t));
 5141         }
 5142 
 5143         return rc;
 5144 
 5145 }
 5146 
 5147 /**
 5148  * @brief Called when the WRITE OBJECT command completes.
 5149  *
 5150  * @par Description
 5151  * Get the number of bytes actually written out of the response, free the mailbox
 5152  * that was malloc'd by ocs_hw_firmware_write(),
 5153  * then call the callback and pass the status and bytes written.
 5154  *
 5155  * @param hw Hardware context.
 5156  * @param status Status field from the mbox completion.
 5157  * @param mqe Mailbox response structure.
 5158  * @param arg Pointer to a callback function that signals the caller that the command is done.
 5159  * The callback function prototype is <tt>void cb(int32_t status, uint32_t bytes_written)</tt>.
 5160  *
 5161  * @return Returns 0.
 5162  */
 5163 static int32_t
 5164 ocs_hw_cb_fw_write(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void  *arg)
 5165 {
 5166 
 5167         sli4_cmd_sli_config_t* mbox_rsp = (sli4_cmd_sli_config_t*) mqe;
 5168         sli4_res_common_write_object_t* wr_obj_rsp = (sli4_res_common_write_object_t*) &(mbox_rsp->payload.embed);
 5169         ocs_hw_fw_write_cb_arg_t *cb_arg = arg;
 5170         uint32_t bytes_written;
 5171         uint16_t mbox_status;
 5172         uint32_t change_status;
 5173 
 5174         bytes_written = wr_obj_rsp->actual_write_length;
 5175         mbox_status = mbox_rsp->hdr.status;
 5176         change_status = wr_obj_rsp->change_status;
 5177 
 5178         ocs_free(hw->os, mqe, SLI4_BMBX_SIZE);
 5179 
 5180         if (cb_arg) {
 5181                 if (cb_arg->cb) {
 5182                         if ((status == 0) && mbox_status) {
 5183                                 status = mbox_status;
 5184                         }
 5185                         cb_arg->cb(status, bytes_written, change_status, cb_arg->arg);
 5186                 }
 5187 
 5188                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_fw_write_cb_arg_t));
 5189         }
 5190 
 5191         return 0;
 5192 
 5193 }
 5194 
 5195 /**
 5196  * @brief Called when the READ_TRANSCEIVER_DATA command completes.
 5197  *
 5198  * @par Description
 5199  * Get the number of bytes read out of the response, free the mailbox that was malloc'd
 5200  * by ocs_hw_get_sfp(), then call the callback and pass the status and bytes written.
 5201  *
 5202  * @param hw Hardware context.
 5203  * @param status Status field from the mbox completion.
 5204  * @param mqe Mailbox response structure.
 5205  * @param arg Pointer to a callback function that signals the caller that the command is done.
 5206  * The callback function prototype is
 5207  * <tt>void cb(int32_t status, uint32_t bytes_written, uint32_t *data, void *arg)</tt>.
 5208  *
 5209  * @return Returns 0.
 5210  */
 5211 static int32_t
 5212 ocs_hw_cb_sfp(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void  *arg)
 5213 {
 5214 
 5215         ocs_hw_sfp_cb_arg_t *cb_arg = arg;
 5216         ocs_dma_t *payload = NULL;
 5217         sli4_res_common_read_transceiver_data_t* mbox_rsp = NULL;
 5218         uint32_t bytes_written;
 5219 
 5220         if (cb_arg) {
 5221                 payload = &(cb_arg->payload);
 5222                 if (cb_arg->cb) {
 5223                         mbox_rsp = (sli4_res_common_read_transceiver_data_t*) payload->virt;
 5224                         bytes_written = mbox_rsp->hdr.response_length;
 5225                         if ((status == 0) && mbox_rsp->hdr.status) {
 5226                                 status = mbox_rsp->hdr.status;
 5227                         }
 5228                         cb_arg->cb(hw->os, status, bytes_written, mbox_rsp->page_data, cb_arg->arg);
 5229                 }
 5230 
 5231                 ocs_dma_free(hw->os, &cb_arg->payload);
 5232                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_sfp_cb_arg_t));
 5233         }
 5234 
 5235         ocs_free(hw->os, mqe, SLI4_BMBX_SIZE);
 5236         return 0;
 5237 }
 5238 
 5239 /**
 5240  * @ingroup io
 5241  * @brief Function to retrieve the SFP information.
 5242  *
 5243  * @param hw Hardware context.
 5244  * @param page The page of SFP data to retrieve (0xa0 or 0xa2).
 5245  * @param cb Function call upon completion of sending the data (may be NULL).
 5246  * @param arg Argument to pass to IO completion function.
 5247  *
 5248  * @return Returns OCS_HW_RTN_SUCCESS, OCS_HW_RTN_ERROR, or OCS_HW_RTN_NO_MEMORY.
 5249  */
 5250 ocs_hw_rtn_e
 5251 ocs_hw_get_sfp(ocs_hw_t *hw, uint16_t page, ocs_hw_sfp_cb_t cb, void *arg)
 5252 {
 5253         ocs_hw_rtn_e rc = OCS_HW_RTN_ERROR;
 5254         ocs_hw_sfp_cb_arg_t *cb_arg;
 5255         uint8_t *mbxdata;
 5256 
 5257         /* mbxdata holds the header of the command */
 5258         mbxdata = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
 5259         if (mbxdata == NULL) {
 5260                 ocs_log_err(hw->os, "failed to malloc mbox\n");
 5261                 return OCS_HW_RTN_NO_MEMORY;
 5262         }
 5263 
 5264         /* cb_arg holds the data that will be passed to the callback on completion */
 5265         cb_arg = ocs_malloc(hw->os, sizeof(ocs_hw_sfp_cb_arg_t), OCS_M_NOWAIT);
 5266         if (cb_arg == NULL) {
 5267                 ocs_log_err(hw->os, "failed to malloc cb_arg\n");
 5268                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 5269                 return OCS_HW_RTN_NO_MEMORY;
 5270         }
 5271 
 5272         cb_arg->cb = cb;
 5273         cb_arg->arg = arg;
 5274 
 5275         /* payload holds the non-embedded portion */
 5276         if (ocs_dma_alloc(hw->os, &cb_arg->payload, sizeof(sli4_res_common_read_transceiver_data_t),
 5277                           OCS_MIN_DMA_ALIGNMENT)) {
 5278                 ocs_log_err(hw->os, "Failed to allocate DMA buffer\n");
 5279                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_sfp_cb_arg_t));
 5280                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 5281                 return OCS_HW_RTN_NO_MEMORY;
 5282         }
 5283 
 5284         /* Send the HW command */
 5285         if (sli_cmd_common_read_transceiver_data(&hw->sli, mbxdata, SLI4_BMBX_SIZE, page,
 5286             &cb_arg->payload)) {
 5287                 rc = ocs_hw_command(hw, mbxdata, OCS_CMD_NOWAIT, ocs_hw_cb_sfp, cb_arg);
 5288         }
 5289 
 5290         if (rc != OCS_HW_RTN_SUCCESS) {
 5291                 ocs_log_test(hw->os, "READ_TRANSCEIVER_DATA failed with status %d\n",
 5292                                 rc);
 5293                 ocs_dma_free(hw->os, &cb_arg->payload);
 5294                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_sfp_cb_arg_t));
 5295                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 5296         }
 5297 
 5298         return rc;
 5299 }
 5300 
 5301 /**
 5302  * @brief Function to retrieve the temperature information.
 5303  *
 5304  * @param hw Hardware context.
 5305  * @param cb Function call upon completion of sending the data (may be NULL).
 5306  * @param arg Argument to pass to IO completion function.
 5307  *
 5308  * @return Returns OCS_HW_RTN_SUCCESS, OCS_HW_RTN_ERROR, or OCS_HW_RTN_NO_MEMORY.
 5309  */
 5310 ocs_hw_rtn_e
 5311 ocs_hw_get_temperature(ocs_hw_t *hw, ocs_hw_temp_cb_t cb, void *arg)
 5312 {
 5313         ocs_hw_rtn_e rc = OCS_HW_RTN_ERROR;
 5314         ocs_hw_temp_cb_arg_t *cb_arg;
 5315         uint8_t *mbxdata;
 5316 
 5317         mbxdata = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
 5318         if (mbxdata == NULL) {
 5319                 ocs_log_err(hw->os, "failed to malloc mbox");
 5320                 return OCS_HW_RTN_NO_MEMORY;
 5321         }
 5322 
 5323         cb_arg = ocs_malloc(hw->os, sizeof(ocs_hw_temp_cb_arg_t), OCS_M_NOWAIT);
 5324         if (cb_arg == NULL) {
 5325                 ocs_log_err(hw->os, "failed to malloc cb_arg");
 5326                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 5327                 return OCS_HW_RTN_NO_MEMORY;
 5328         }
 5329 
 5330         cb_arg->cb = cb;
 5331         cb_arg->arg = arg;
 5332 
 5333         if (sli_cmd_dump_type4(&hw->sli, mbxdata, SLI4_BMBX_SIZE,
 5334                                 SLI4_WKI_TAG_SAT_TEM)) {
 5335                 rc = ocs_hw_command(hw, mbxdata, OCS_CMD_NOWAIT, ocs_hw_cb_temp, cb_arg);
 5336         }
 5337 
 5338         if (rc != OCS_HW_RTN_SUCCESS) {
 5339                 ocs_log_test(hw->os, "DUMP_TYPE4 failed\n");
 5340                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 5341                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_temp_cb_arg_t));
 5342         }
 5343 
 5344         return rc;
 5345 }
 5346 
 5347 /**
 5348  * @brief Called when the DUMP command completes.
 5349  *
 5350  * @par Description
 5351  * Get the temperature data out of the response, free the mailbox that was malloc'd
 5352  * by ocs_hw_get_temperature(), then call the callback and pass the status and data.
 5353  *
 5354  * @param hw Hardware context.
 5355  * @param status Status field from the mbox completion.
 5356  * @param mqe Mailbox response structure.
 5357  * @param arg Pointer to a callback function that signals the caller that the command is done.
 5358  * The callback function prototype is defined by ocs_hw_temp_cb_t.
 5359  *
 5360  * @return Returns 0.
 5361  */
 5362 static int32_t
 5363 ocs_hw_cb_temp(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void  *arg)
 5364 {
 5365 
 5366         sli4_cmd_dump4_t* mbox_rsp = (sli4_cmd_dump4_t*) mqe;
 5367         ocs_hw_temp_cb_arg_t *cb_arg = arg;
 5368         uint32_t curr_temp = mbox_rsp->resp_data[0]; /* word 5 */
 5369         uint32_t crit_temp_thrshld = mbox_rsp->resp_data[1]; /* word 6*/
 5370         uint32_t warn_temp_thrshld = mbox_rsp->resp_data[2]; /* word 7 */
 5371         uint32_t norm_temp_thrshld = mbox_rsp->resp_data[3]; /* word 8 */
 5372         uint32_t fan_off_thrshld = mbox_rsp->resp_data[4];   /* word 9 */
 5373         uint32_t fan_on_thrshld = mbox_rsp->resp_data[5];    /* word 10 */
 5374 
 5375         if (cb_arg) {
 5376                 if (cb_arg->cb) {
 5377                         if ((status == 0) && mbox_rsp->hdr.status) {
 5378                                 status = mbox_rsp->hdr.status;
 5379                         }
 5380                         cb_arg->cb(status,
 5381                                    curr_temp,
 5382                                    crit_temp_thrshld,
 5383                                    warn_temp_thrshld,
 5384                                    norm_temp_thrshld,
 5385                                    fan_off_thrshld,
 5386                                    fan_on_thrshld,
 5387                                    cb_arg->arg);
 5388                 }
 5389 
 5390                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_temp_cb_arg_t));
 5391         }
 5392         ocs_free(hw->os, mqe, SLI4_BMBX_SIZE);
 5393 
 5394         return 0;
 5395 }
 5396 
 5397 /**
 5398  * @brief Function to retrieve the link statistics.
 5399  *
 5400  * @param hw Hardware context.
 5401  * @param req_ext_counters If TRUE, then the extended counters will be requested.
 5402  * @param clear_overflow_flags If TRUE, then overflow flags will be cleared.
 5403  * @param clear_all_counters If TRUE, the counters will be cleared.
 5404  * @param cb Function call upon completion of sending the data (may be NULL).
 5405  * @param arg Argument to pass to IO completion function.
 5406  *
 5407  * @return Returns OCS_HW_RTN_SUCCESS, OCS_HW_RTN_ERROR, or OCS_HW_RTN_NO_MEMORY.
 5408  */
 5409 ocs_hw_rtn_e
 5410 ocs_hw_get_link_stats(ocs_hw_t *hw,
 5411                         uint8_t req_ext_counters,
 5412                         uint8_t clear_overflow_flags,
 5413                         uint8_t clear_all_counters,
 5414                         ocs_hw_link_stat_cb_t cb,
 5415                         void *arg)
 5416 {
 5417         ocs_hw_rtn_e rc = OCS_HW_RTN_ERROR;
 5418         ocs_hw_link_stat_cb_arg_t *cb_arg;
 5419         uint8_t *mbxdata;
 5420 
 5421         mbxdata = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
 5422         if (mbxdata == NULL) {
 5423                 ocs_log_err(hw->os, "failed to malloc mbox");
 5424                 return OCS_HW_RTN_NO_MEMORY;
 5425         }
 5426 
 5427         cb_arg = ocs_malloc(hw->os, sizeof(ocs_hw_link_stat_cb_arg_t), OCS_M_NOWAIT);
 5428         if (cb_arg == NULL) {
 5429                 ocs_log_err(hw->os, "failed to malloc cb_arg");
 5430                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 5431                 return OCS_HW_RTN_NO_MEMORY;
 5432         }
 5433 
 5434         cb_arg->cb = cb;
 5435         cb_arg->arg = arg;
 5436 
 5437         if (sli_cmd_read_link_stats(&hw->sli, mbxdata, SLI4_BMBX_SIZE,
 5438                                     req_ext_counters,
 5439                                     clear_overflow_flags,
 5440                                     clear_all_counters)) {
 5441                 rc = ocs_hw_command(hw, mbxdata, OCS_CMD_NOWAIT, ocs_hw_cb_link_stat, cb_arg);
 5442         }
 5443 
 5444         if (rc != OCS_HW_RTN_SUCCESS) {
 5445                 ocs_log_test(hw->os, "READ_LINK_STATS failed\n");
 5446                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 5447                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_link_stat_cb_arg_t));
 5448         }
 5449 
 5450         return rc;
 5451 }
 5452 
 5453 /**
 5454  * @brief Called when the READ_LINK_STAT command completes.
 5455  *
 5456  * @par Description
 5457  * Get the counters out of the response, free the mailbox that was malloc'd
 5458  * by ocs_hw_get_link_stats(), then call the callback and pass the status and data.
 5459  *
 5460  * @param hw Hardware context.
 5461  * @param status Status field from the mbox completion.
 5462  * @param mqe Mailbox response structure.
 5463  * @param arg Pointer to a callback function that signals the caller that the command is done.
 5464  * The callback function prototype is defined by ocs_hw_link_stat_cb_t.
 5465  *
 5466  * @return Returns 0.
 5467  */
 5468 static int32_t
 5469 ocs_hw_cb_link_stat(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void  *arg)
 5470 {
 5471 
 5472         sli4_cmd_read_link_stats_t* mbox_rsp = (sli4_cmd_read_link_stats_t*) mqe;
 5473         ocs_hw_link_stat_cb_arg_t *cb_arg = arg;
 5474         ocs_hw_link_stat_counts_t counts[OCS_HW_LINK_STAT_MAX];
 5475         uint32_t num_counters = (mbox_rsp->gec ? 20 : 13);
 5476 
 5477         ocs_memset(counts, 0, sizeof(ocs_hw_link_stat_counts_t) *
 5478                    OCS_HW_LINK_STAT_MAX);
 5479 
 5480         counts[OCS_HW_LINK_STAT_LINK_FAILURE_COUNT].overflow = mbox_rsp->w02of;
 5481         counts[OCS_HW_LINK_STAT_LOSS_OF_SYNC_COUNT].overflow = mbox_rsp->w03of;
 5482         counts[OCS_HW_LINK_STAT_LOSS_OF_SIGNAL_COUNT].overflow = mbox_rsp->w04of;
 5483         counts[OCS_HW_LINK_STAT_PRIMITIVE_SEQ_COUNT].overflow = mbox_rsp->w05of;
 5484         counts[OCS_HW_LINK_STAT_INVALID_XMIT_WORD_COUNT].overflow = mbox_rsp->w06of;
 5485         counts[OCS_HW_LINK_STAT_CRC_COUNT].overflow = mbox_rsp->w07of;
 5486         counts[OCS_HW_LINK_STAT_PRIMITIVE_SEQ_TIMEOUT_COUNT].overflow = mbox_rsp->w08of;
 5487         counts[OCS_HW_LINK_STAT_ELASTIC_BUFFER_OVERRUN_COUNT].overflow = mbox_rsp->w09of;
 5488         counts[OCS_HW_LINK_STAT_ARB_TIMEOUT_COUNT].overflow = mbox_rsp->w10of;
 5489         counts[OCS_HW_LINK_STAT_ADVERTISED_RCV_B2B_CREDIT].overflow = mbox_rsp->w11of;
 5490         counts[OCS_HW_LINK_STAT_CURR_RCV_B2B_CREDIT].overflow = mbox_rsp->w12of;
 5491         counts[OCS_HW_LINK_STAT_ADVERTISED_XMIT_B2B_CREDIT].overflow = mbox_rsp->w13of;
 5492         counts[OCS_HW_LINK_STAT_CURR_XMIT_B2B_CREDIT].overflow = mbox_rsp->w14of;
 5493         counts[OCS_HW_LINK_STAT_RCV_EOFA_COUNT].overflow = mbox_rsp->w15of;
 5494         counts[OCS_HW_LINK_STAT_RCV_EOFDTI_COUNT].overflow = mbox_rsp->w16of;
 5495         counts[OCS_HW_LINK_STAT_RCV_EOFNI_COUNT].overflow = mbox_rsp->w17of;
 5496         counts[OCS_HW_LINK_STAT_RCV_SOFF_COUNT].overflow = mbox_rsp->w18of;
 5497         counts[OCS_HW_LINK_STAT_RCV_DROPPED_NO_AER_COUNT].overflow = mbox_rsp->w19of;
 5498         counts[OCS_HW_LINK_STAT_RCV_DROPPED_NO_RPI_COUNT].overflow = mbox_rsp->w20of;
 5499         counts[OCS_HW_LINK_STAT_RCV_DROPPED_NO_XRI_COUNT].overflow = mbox_rsp->w21of;
 5500 
 5501         counts[OCS_HW_LINK_STAT_LINK_FAILURE_COUNT].counter = mbox_rsp->link_failure_error_count;
 5502         counts[OCS_HW_LINK_STAT_LOSS_OF_SYNC_COUNT].counter = mbox_rsp->loss_of_sync_error_count;
 5503         counts[OCS_HW_LINK_STAT_LOSS_OF_SIGNAL_COUNT].counter = mbox_rsp->loss_of_signal_error_count;
 5504         counts[OCS_HW_LINK_STAT_PRIMITIVE_SEQ_COUNT].counter = mbox_rsp->primitive_sequence_error_count;
 5505         counts[OCS_HW_LINK_STAT_INVALID_XMIT_WORD_COUNT].counter = mbox_rsp->invalid_transmission_word_error_count;
 5506         counts[OCS_HW_LINK_STAT_CRC_COUNT].counter = mbox_rsp->crc_error_count;
 5507         counts[OCS_HW_LINK_STAT_PRIMITIVE_SEQ_TIMEOUT_COUNT].counter = mbox_rsp->primitive_sequence_event_timeout_count;
 5508         counts[OCS_HW_LINK_STAT_ELASTIC_BUFFER_OVERRUN_COUNT].counter = mbox_rsp->elastic_buffer_overrun_error_count;
 5509         counts[OCS_HW_LINK_STAT_ARB_TIMEOUT_COUNT].counter = mbox_rsp->arbitration_fc_al_timout_count;
 5510         counts[OCS_HW_LINK_STAT_ADVERTISED_RCV_B2B_CREDIT].counter = mbox_rsp->advertised_receive_bufftor_to_buffer_credit;
 5511         counts[OCS_HW_LINK_STAT_CURR_RCV_B2B_CREDIT].counter = mbox_rsp->current_receive_buffer_to_buffer_credit;
 5512         counts[OCS_HW_LINK_STAT_ADVERTISED_XMIT_B2B_CREDIT].counter = mbox_rsp->advertised_transmit_buffer_to_buffer_credit;
 5513         counts[OCS_HW_LINK_STAT_CURR_XMIT_B2B_CREDIT].counter = mbox_rsp->current_transmit_buffer_to_buffer_credit;
 5514         counts[OCS_HW_LINK_STAT_RCV_EOFA_COUNT].counter = mbox_rsp->received_eofa_count;
 5515         counts[OCS_HW_LINK_STAT_RCV_EOFDTI_COUNT].counter = mbox_rsp->received_eofdti_count;
 5516         counts[OCS_HW_LINK_STAT_RCV_EOFNI_COUNT].counter = mbox_rsp->received_eofni_count;
 5517         counts[OCS_HW_LINK_STAT_RCV_SOFF_COUNT].counter = mbox_rsp->received_soff_count;
 5518         counts[OCS_HW_LINK_STAT_RCV_DROPPED_NO_AER_COUNT].counter = mbox_rsp->received_dropped_no_aer_count;
 5519         counts[OCS_HW_LINK_STAT_RCV_DROPPED_NO_RPI_COUNT].counter = mbox_rsp->received_dropped_no_available_rpi_resources_count;
 5520         counts[OCS_HW_LINK_STAT_RCV_DROPPED_NO_XRI_COUNT].counter = mbox_rsp->received_dropped_no_available_xri_resources_count;
 5521 
 5522         if (cb_arg) {
 5523                 if (cb_arg->cb) {
 5524                         if ((status == 0) && mbox_rsp->hdr.status) {
 5525                                 status = mbox_rsp->hdr.status;
 5526                         }
 5527                         cb_arg->cb(status,
 5528                                    num_counters,
 5529                                    counts,
 5530                                    cb_arg->arg);
 5531                 }
 5532 
 5533                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_link_stat_cb_arg_t));
 5534         }
 5535         ocs_free(hw->os, mqe, SLI4_BMBX_SIZE);
 5536 
 5537         return 0;
 5538 }
 5539 
 5540 /**
 5541  * @brief Function to retrieve the link and host statistics.
 5542  *
 5543  * @param hw Hardware context.
 5544  * @param cc clear counters, if TRUE all counters will be cleared.
 5545  * @param cb Function call upon completion of receiving the data.
 5546  * @param arg Argument to pass to pointer fc hosts statistics structure.
 5547  *
 5548  * @return Returns OCS_HW_RTN_SUCCESS, OCS_HW_RTN_ERROR, or OCS_HW_RTN_NO_MEMORY.
 5549  */
 5550 ocs_hw_rtn_e
 5551 ocs_hw_get_host_stats(ocs_hw_t *hw, uint8_t cc, ocs_hw_host_stat_cb_t cb, void *arg)
 5552 {
 5553         ocs_hw_rtn_e rc = OCS_HW_RTN_ERROR;
 5554         ocs_hw_host_stat_cb_arg_t *cb_arg;
 5555         uint8_t *mbxdata;
 5556 
 5557         mbxdata = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_ZERO);
 5558         if (mbxdata == NULL) {
 5559                 ocs_log_err(hw->os, "failed to malloc mbox");
 5560                 return OCS_HW_RTN_NO_MEMORY;
 5561         }
 5562 
 5563         cb_arg = ocs_malloc(hw->os, sizeof(ocs_hw_host_stat_cb_arg_t), 0);
 5564         if (cb_arg == NULL) {
 5565                 ocs_log_err(hw->os, "failed to malloc cb_arg");
 5566                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 5567                 return OCS_HW_RTN_NO_MEMORY;
 5568          }
 5569 
 5570          cb_arg->cb = cb;
 5571          cb_arg->arg = arg;
 5572 
 5573          /* Send the HW command to get the host stats */
 5574         if (sli_cmd_read_status(&hw->sli, mbxdata, SLI4_BMBX_SIZE, cc)) {
 5575                  rc = ocs_hw_command(hw, mbxdata, OCS_CMD_NOWAIT, ocs_hw_cb_host_stat, cb_arg);
 5576         }
 5577 
 5578         if (rc != OCS_HW_RTN_SUCCESS) {
 5579                 ocs_log_test(hw->os, "READ_HOST_STATS failed\n");
 5580                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 5581                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_host_stat_cb_arg_t));
 5582         }
 5583 
 5584         return rc;
 5585 }
 5586 
 5587 /**
 5588  * @brief Called when the READ_STATUS command completes.
 5589  *
 5590  * @par Description
 5591  * Get the counters out of the response, free the mailbox that was malloc'd
 5592  * by ocs_hw_get_host_stats(), then call the callback and pass
 5593  * the status and data.
 5594  *
 5595  * @param hw Hardware context.
 5596  * @param status Status field from the mbox completion.
 5597  * @param mqe Mailbox response structure.
 5598  * @param arg Pointer to a callback function that signals the caller that the command is done.
 5599  * The callback function prototype is defined by
 5600  * ocs_hw_host_stat_cb_t.
 5601  *
 5602  * @return Returns 0.
 5603  */
 5604 static int32_t
 5605 ocs_hw_cb_host_stat(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void  *arg)
 5606 {
 5607 
 5608         sli4_cmd_read_status_t* mbox_rsp = (sli4_cmd_read_status_t*) mqe;
 5609         ocs_hw_host_stat_cb_arg_t *cb_arg = arg;
 5610         ocs_hw_host_stat_counts_t counts[OCS_HW_HOST_STAT_MAX];
 5611         uint32_t num_counters = OCS_HW_HOST_STAT_MAX;
 5612 
 5613         ocs_memset(counts, 0, sizeof(ocs_hw_host_stat_counts_t) *
 5614                    OCS_HW_HOST_STAT_MAX);
 5615 
 5616         counts[OCS_HW_HOST_STAT_TX_KBYTE_COUNT].counter = mbox_rsp->transmit_kbyte_count;
 5617         counts[OCS_HW_HOST_STAT_RX_KBYTE_COUNT].counter = mbox_rsp->receive_kbyte_count;
 5618         counts[OCS_HW_HOST_STAT_TX_FRAME_COUNT].counter = mbox_rsp->transmit_frame_count;
 5619         counts[OCS_HW_HOST_STAT_RX_FRAME_COUNT].counter = mbox_rsp->receive_frame_count;
 5620         counts[OCS_HW_HOST_STAT_TX_SEQ_COUNT].counter = mbox_rsp->transmit_sequence_count;
 5621         counts[OCS_HW_HOST_STAT_RX_SEQ_COUNT].counter = mbox_rsp->receive_sequence_count;
 5622         counts[OCS_HW_HOST_STAT_TOTAL_EXCH_ORIG].counter = mbox_rsp->total_exchanges_originator;
 5623         counts[OCS_HW_HOST_STAT_TOTAL_EXCH_RESP].counter = mbox_rsp->total_exchanges_responder;
 5624         counts[OCS_HW_HOSY_STAT_RX_P_BSY_COUNT].counter = mbox_rsp->receive_p_bsy_count;
 5625         counts[OCS_HW_HOST_STAT_RX_F_BSY_COUNT].counter = mbox_rsp->receive_f_bsy_count;
 5626         counts[OCS_HW_HOST_STAT_DROP_FRM_DUE_TO_NO_RQ_BUF_COUNT].counter = mbox_rsp->dropped_frames_due_to_no_rq_buffer_count;
 5627         counts[OCS_HW_HOST_STAT_EMPTY_RQ_TIMEOUT_COUNT].counter = mbox_rsp->empty_rq_timeout_count;
 5628         counts[OCS_HW_HOST_STAT_DROP_FRM_DUE_TO_NO_XRI_COUNT].counter = mbox_rsp->dropped_frames_due_to_no_xri_count;
 5629         counts[OCS_HW_HOST_STAT_EMPTY_XRI_POOL_COUNT].counter = mbox_rsp->empty_xri_pool_count;
 5630 
 5631         if (cb_arg) {
 5632                 if (cb_arg->cb) {
 5633                         if ((status == 0) && mbox_rsp->hdr.status) {
 5634                                 status = mbox_rsp->hdr.status;
 5635                         }
 5636                         cb_arg->cb(status,
 5637                                    num_counters,
 5638                                    counts,
 5639                                    cb_arg->arg);
 5640                 }
 5641 
 5642                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_host_stat_cb_arg_t));
 5643         }
 5644         ocs_free(hw->os, mqe, SLI4_BMBX_SIZE);
 5645 
 5646         return 0;
 5647 }
 5648 
 5649 /**
 5650  * @brief HW link configuration enum to the CLP string value mapping.
 5651  *
 5652  * This structure provides a mapping from the ocs_hw_linkcfg_e
 5653  * enum (enum exposed for the OCS_HW_PORT_SET_LINK_CONFIG port
 5654  * control) to the CLP string that is used
 5655  * in the DMTF_CLP_CMD mailbox command.
 5656  */
 5657 typedef struct ocs_hw_linkcfg_map_s {
 5658         ocs_hw_linkcfg_e linkcfg;
 5659         const char *clp_str;
 5660 } ocs_hw_linkcfg_map_t;
 5661 
 5662 /**
 5663  * @brief Mapping from the HW linkcfg enum to the CLP command value
 5664  * string.
 5665  */
 5666 static ocs_hw_linkcfg_map_t linkcfg_map[] = {
 5667         {OCS_HW_LINKCFG_4X10G, "ELX_4x10G"},
 5668         {OCS_HW_LINKCFG_1X40G, "ELX_1x40G"},
 5669         {OCS_HW_LINKCFG_2X16G, "ELX_2x16G"},
 5670         {OCS_HW_LINKCFG_4X8G, "ELX_4x8G"},
 5671         {OCS_HW_LINKCFG_4X1G, "ELX_4x1G"},
 5672         {OCS_HW_LINKCFG_2X10G, "ELX_2x10G"},
 5673         {OCS_HW_LINKCFG_2X10G_2X8G, "ELX_2x10G_2x8G"}};
 5674 
 5675 /**
 5676  * @brief HW link configuration enum to Skyhawk link config ID mapping.
 5677  *
 5678  * This structure provides a mapping from the ocs_hw_linkcfg_e
 5679  * enum (enum exposed for the OCS_HW_PORT_SET_LINK_CONFIG port
 5680  * control) to the link config ID numbers used by Skyhawk
 5681  */
 5682 typedef struct ocs_hw_skyhawk_linkcfg_map_s {
 5683         ocs_hw_linkcfg_e linkcfg;
 5684         uint32_t        config_id;
 5685 } ocs_hw_skyhawk_linkcfg_map_t;
 5686 
 5687 /**
 5688  * @brief Mapping from the HW linkcfg enum to the Skyhawk link config IDs
 5689  */
 5690 static ocs_hw_skyhawk_linkcfg_map_t skyhawk_linkcfg_map[] = {
 5691         {OCS_HW_LINKCFG_4X10G, 0x0a},
 5692         {OCS_HW_LINKCFG_1X40G, 0x09},
 5693 };
 5694 
 5695 /**
 5696  * @brief Helper function for getting the HW linkcfg enum from the CLP
 5697  * string value
 5698  *
 5699  * @param clp_str CLP string value from OEMELX_LinkConfig.
 5700  *
 5701  * @return Returns the HW linkcfg enum corresponding to clp_str.
 5702  */
 5703 static ocs_hw_linkcfg_e
 5704 ocs_hw_linkcfg_from_clp(const char *clp_str)
 5705 {
 5706         uint32_t i;
 5707         for (i = 0; i < ARRAY_SIZE(linkcfg_map); i++) {
 5708                 if (ocs_strncmp(linkcfg_map[i].clp_str, clp_str, ocs_strlen(clp_str)) == 0) {
 5709                         return linkcfg_map[i].linkcfg;
 5710                 }
 5711         }
 5712         return OCS_HW_LINKCFG_NA;
 5713 }
 5714 
 5715 /**
 5716  * @brief Helper function for getting the CLP string value from the HW
 5717  * linkcfg enum.
 5718  *
 5719  * @param linkcfg HW linkcfg enum.
 5720  *
 5721  * @return Returns the OEMELX_LinkConfig CLP string value corresponding to
 5722  * given linkcfg.
 5723  */
 5724 static const char *
 5725 ocs_hw_clp_from_linkcfg(ocs_hw_linkcfg_e linkcfg)
 5726 {
 5727         uint32_t i;
 5728         for (i = 0; i < ARRAY_SIZE(linkcfg_map); i++) {
 5729                 if (linkcfg_map[i].linkcfg == linkcfg) {
 5730                         return linkcfg_map[i].clp_str;
 5731                 }
 5732         }
 5733         return NULL;
 5734 }
 5735 
 5736 /**
 5737  * @brief Helper function for getting a Skyhawk link config ID from the HW
 5738  * linkcfg enum.
 5739  *
 5740  * @param linkcfg HW linkcfg enum.
 5741  *
 5742  * @return Returns the Skyhawk link config ID corresponding to
 5743  * given linkcfg.
 5744  */
 5745 static uint32_t
 5746 ocs_hw_config_id_from_linkcfg(ocs_hw_linkcfg_e linkcfg)
 5747 {
 5748         uint32_t i;
 5749         for (i = 0; i < ARRAY_SIZE(skyhawk_linkcfg_map); i++) {
 5750                 if (skyhawk_linkcfg_map[i].linkcfg == linkcfg) {
 5751                         return skyhawk_linkcfg_map[i].config_id;
 5752                 }
 5753         }
 5754         return 0;
 5755 }
 5756 
 5757 /**
 5758  * @brief Helper function for getting the HW linkcfg enum from a
 5759  * Skyhawk config ID.
 5760  *
 5761  * @param config_id Skyhawk link config ID.
 5762  *
 5763  * @return Returns the HW linkcfg enum corresponding to config_id.
 5764  */
 5765 static ocs_hw_linkcfg_e
 5766 ocs_hw_linkcfg_from_config_id(const uint32_t config_id)
 5767 {
 5768         uint32_t i;
 5769         for (i = 0; i < ARRAY_SIZE(skyhawk_linkcfg_map); i++) {
 5770                 if (skyhawk_linkcfg_map[i].config_id == config_id) {
 5771                         return skyhawk_linkcfg_map[i].linkcfg;
 5772                 }
 5773         }
 5774         return OCS_HW_LINKCFG_NA;
 5775 }
 5776 
 5777 /**
 5778  * @brief Link configuration callback argument.
 5779  */
 5780 typedef struct ocs_hw_linkcfg_cb_arg_s {
 5781         ocs_hw_port_control_cb_t cb;
 5782         void *arg;
 5783         uint32_t opts;
 5784         int32_t status;
 5785         ocs_dma_t dma_cmd;
 5786         ocs_dma_t dma_resp;
 5787         uint32_t result_len;
 5788 } ocs_hw_linkcfg_cb_arg_t;
 5789 
 5790 /**
 5791  * @brief Set link configuration.
 5792  *
 5793  * @param hw Hardware context.
 5794  * @param value Link configuration enum to which the link configuration is
 5795  * set.
 5796  * @param opts Mailbox command options (OCS_CMD_NOWAIT/POLL).
 5797  * @param cb Callback function to invoke following mbx command.
 5798  * @param arg Callback argument.
 5799  *
 5800  * @return Returns OCS_HW_RTN_SUCCESS on success.
 5801  */
 5802 static ocs_hw_rtn_e
 5803 ocs_hw_set_linkcfg(ocs_hw_t *hw, ocs_hw_linkcfg_e value, uint32_t opts, ocs_hw_port_control_cb_t cb, void *arg)
 5804 {
 5805         if (!sli_link_is_configurable(&hw->sli)) {
 5806                 ocs_log_debug(hw->os, "Function not supported\n");
 5807                 return OCS_HW_RTN_ERROR;
 5808         }
 5809 
 5810         if (SLI4_IF_TYPE_LANCER_FC_ETH == sli_get_if_type(&hw->sli)) {
 5811                 return ocs_hw_set_linkcfg_lancer(hw, value, opts, cb, arg);
 5812         } else if ((SLI4_IF_TYPE_BE3_SKH_PF == sli_get_if_type(&hw->sli)) ||
 5813                    (SLI4_IF_TYPE_BE3_SKH_VF == sli_get_if_type(&hw->sli))) {
 5814                 return ocs_hw_set_linkcfg_skyhawk(hw, value, opts, cb, arg);
 5815         } else {
 5816                 ocs_log_test(hw->os, "Function not supported for this IF_TYPE\n");
 5817                 return OCS_HW_RTN_ERROR;
 5818         }
 5819 }
 5820 
 5821 /**
 5822  * @brief Set link configuration for Lancer
 5823  *
 5824  * @param hw Hardware context.
 5825  * @param value Link configuration enum to which the link configuration is
 5826  * set.
 5827  * @param opts Mailbox command options (OCS_CMD_NOWAIT/POLL).
 5828  * @param cb Callback function to invoke following mbx command.
 5829  * @param arg Callback argument.
 5830  *
 5831  * @return Returns OCS_HW_RTN_SUCCESS on success.
 5832  */
 5833 static ocs_hw_rtn_e
 5834 ocs_hw_set_linkcfg_lancer(ocs_hw_t *hw, ocs_hw_linkcfg_e value, uint32_t opts, ocs_hw_port_control_cb_t cb, void *arg)
 5835 {
 5836         char cmd[OCS_HW_DMTF_CLP_CMD_MAX];
 5837         ocs_hw_linkcfg_cb_arg_t *cb_arg;
 5838         const char *value_str = NULL;
 5839         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 5840 
 5841         /* translate ocs_hw_linkcfg_e to CLP string */
 5842         value_str = ocs_hw_clp_from_linkcfg(value);
 5843 
 5844         /* allocate memory for callback argument */
 5845         cb_arg = ocs_malloc(hw->os, sizeof(*cb_arg), OCS_M_NOWAIT);
 5846         if (cb_arg == NULL) {
 5847                 ocs_log_err(hw->os, "failed to malloc cb_arg");
 5848                 return OCS_HW_RTN_NO_MEMORY;
 5849         }
 5850 
 5851         ocs_snprintf(cmd, OCS_HW_DMTF_CLP_CMD_MAX, "set / OEMELX_LinkConfig=%s", value_str);
 5852         /* allocate DMA for command  */
 5853         if (ocs_dma_alloc(hw->os, &cb_arg->dma_cmd, ocs_strlen(cmd)+1, 4096)) {
 5854                 ocs_log_err(hw->os, "malloc failed\n");
 5855                 ocs_free(hw->os, cb_arg, sizeof(*cb_arg));
 5856                 return OCS_HW_RTN_NO_MEMORY;
 5857         }
 5858         ocs_memset(cb_arg->dma_cmd.virt, 0, ocs_strlen(cmd)+1);
 5859         ocs_memcpy(cb_arg->dma_cmd.virt, cmd, ocs_strlen(cmd));
 5860 
 5861         /* allocate DMA for response */
 5862         if (ocs_dma_alloc(hw->os, &cb_arg->dma_resp, OCS_HW_DMTF_CLP_RSP_MAX, 4096)) {
 5863                 ocs_log_err(hw->os, "malloc failed\n");
 5864                 ocs_dma_free(hw->os, &cb_arg->dma_cmd);
 5865                 ocs_free(hw->os, cb_arg, sizeof(*cb_arg));
 5866                 return OCS_HW_RTN_NO_MEMORY;
 5867         }
 5868         cb_arg->cb = cb;
 5869         cb_arg->arg = arg;
 5870         cb_arg->opts = opts;
 5871 
 5872         rc = ocs_hw_exec_dmtf_clp_cmd(hw, &cb_arg->dma_cmd, &cb_arg->dma_resp,
 5873                                         opts, ocs_hw_linkcfg_dmtf_clp_cb, cb_arg);
 5874 
 5875         if (opts == OCS_CMD_POLL || rc != OCS_HW_RTN_SUCCESS) {
 5876                 /* if failed, or polling, free memory here; if success and not
 5877                  * polling, will free in callback function
 5878                  */
 5879                 if (rc) {
 5880                         ocs_log_test(hw->os, "CLP cmd=\"%s\" failed\n",
 5881                                         (char *)cb_arg->dma_cmd.virt);
 5882                 }
 5883                 ocs_dma_free(hw->os, &cb_arg->dma_cmd);
 5884                 ocs_dma_free(hw->os, &cb_arg->dma_resp);
 5885                 ocs_free(hw->os, cb_arg, sizeof(*cb_arg));
 5886         }
 5887         return rc;
 5888 }
 5889 
 5890 /**
 5891  * @brief Callback for ocs_hw_set_linkcfg_skyhawk
 5892  *
 5893  * @param hw Hardware context.
 5894  * @param status Status from the RECONFIG_GET_LINK_INFO command.
 5895  * @param mqe Mailbox response structure.
 5896  * @param arg Pointer to a callback argument.
 5897  *
 5898  * @return none
 5899  */
 5900 static void
 5901 ocs_hw_set_active_link_config_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void  *arg)
 5902 {
 5903         ocs_hw_linkcfg_cb_arg_t *cb_arg = (ocs_hw_linkcfg_cb_arg_t *)arg;
 5904 
 5905         if (status) {
 5906                 ocs_log_test(hw->os, "SET_RECONFIG_LINK_ID failed, status=%d\n", status);
 5907         }
 5908 
 5909         /* invoke callback */
 5910         if (cb_arg->cb) {
 5911                 cb_arg->cb(status, 0, cb_arg->arg);
 5912         }
 5913 
 5914         /* if polling, will free memory in calling function */
 5915         if (cb_arg->opts != OCS_CMD_POLL) {
 5916                 ocs_free(hw->os, cb_arg, sizeof(*cb_arg));
 5917         }
 5918 }
 5919 
 5920 /**
 5921  * @brief Set link configuration for a Skyhawk
 5922  *
 5923  * @param hw Hardware context.
 5924  * @param value Link configuration enum to which the link configuration is
 5925  * set.
 5926  * @param opts Mailbox command options (OCS_CMD_NOWAIT/POLL).
 5927  * @param cb Callback function to invoke following mbx command.
 5928  * @param arg Callback argument.
 5929  *
 5930  * @return Returns OCS_HW_RTN_SUCCESS on success.
 5931  */
 5932 static ocs_hw_rtn_e
 5933 ocs_hw_set_linkcfg_skyhawk(ocs_hw_t *hw, ocs_hw_linkcfg_e value, uint32_t opts, ocs_hw_port_control_cb_t cb, void *arg)
 5934 {
 5935         uint8_t *mbxdata;
 5936         ocs_hw_linkcfg_cb_arg_t *cb_arg;
 5937         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 5938         uint32_t config_id;
 5939 
 5940         config_id = ocs_hw_config_id_from_linkcfg(value);
 5941 
 5942         if (config_id == 0) {
 5943                 ocs_log_test(hw->os, "Link config %d not supported by Skyhawk\n", value);
 5944                 return OCS_HW_RTN_ERROR;
 5945         }
 5946 
 5947         /* mbxdata holds the header of the command */
 5948         mbxdata = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
 5949         if (mbxdata == NULL) {
 5950                 ocs_log_err(hw->os, "failed to malloc mbox\n");
 5951                 return OCS_HW_RTN_NO_MEMORY;
 5952         }
 5953 
 5954         /* cb_arg holds the data that will be passed to the callback on completion */
 5955         cb_arg = ocs_malloc(hw->os, sizeof(ocs_hw_linkcfg_cb_arg_t), OCS_M_NOWAIT);
 5956         if (cb_arg == NULL) {
 5957                 ocs_log_err(hw->os, "failed to malloc cb_arg\n");
 5958                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 5959                 return OCS_HW_RTN_NO_MEMORY;
 5960         }
 5961 
 5962         cb_arg->cb = cb;
 5963         cb_arg->arg = arg;
 5964 
 5965         if (sli_cmd_common_set_reconfig_link_id(&hw->sli, mbxdata, SLI4_BMBX_SIZE, NULL, 0, config_id)) {
 5966                 rc = ocs_hw_command(hw, mbxdata, opts, ocs_hw_set_active_link_config_cb, cb_arg);
 5967         }
 5968 
 5969         if (rc != OCS_HW_RTN_SUCCESS) {
 5970                 ocs_log_err(hw->os, "SET_RECONFIG_LINK_ID failed\n");
 5971                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 5972                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_linkcfg_cb_arg_t));
 5973         } else if (opts == OCS_CMD_POLL) {
 5974                 /* if we're polling we have to call the callback here. */
 5975                 ocs_hw_set_active_link_config_cb(hw, 0, mbxdata, cb_arg);
 5976                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 5977                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_linkcfg_cb_arg_t));
 5978         } else {
 5979                 /* We weren't poling, so the callback got called */
 5980                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 5981         }
 5982 
 5983         return rc;
 5984 }
 5985 
 5986 /**
 5987  * @brief Get link configuration.
 5988  *
 5989  * @param hw Hardware context.
 5990  * @param opts Mailbox command options (OCS_CMD_NOWAIT/POLL).
 5991  * @param cb Callback function to invoke following mbx command.
 5992  * @param arg Callback argument.
 5993  *
 5994  * @return Returns OCS_HW_RTN_SUCCESS on success.
 5995  */
 5996 static ocs_hw_rtn_e
 5997 ocs_hw_get_linkcfg(ocs_hw_t *hw, uint32_t opts, ocs_hw_port_control_cb_t cb, void *arg)
 5998 {
 5999         if (!sli_link_is_configurable(&hw->sli)) {
 6000                 ocs_log_debug(hw->os, "Function not supported\n");
 6001                 return OCS_HW_RTN_ERROR;
 6002         }
 6003 
 6004         if (SLI4_IF_TYPE_LANCER_FC_ETH == sli_get_if_type(&hw->sli)) {
 6005                 return ocs_hw_get_linkcfg_lancer(hw, opts, cb, arg);
 6006         } else if ((SLI4_IF_TYPE_BE3_SKH_PF == sli_get_if_type(&hw->sli)) ||
 6007                    (SLI4_IF_TYPE_BE3_SKH_VF == sli_get_if_type(&hw->sli))) {
 6008                 return ocs_hw_get_linkcfg_skyhawk(hw, opts, cb, arg);
 6009         } else {
 6010                 ocs_log_test(hw->os, "Function not supported for this IF_TYPE\n");
 6011                 return OCS_HW_RTN_ERROR;
 6012         }
 6013 }
 6014 
 6015 /**
 6016  * @brief Get link configuration for a Lancer
 6017  *
 6018  * @param hw Hardware context.
 6019  * @param opts Mailbox command options (OCS_CMD_NOWAIT/POLL).
 6020  * @param cb Callback function to invoke following mbx command.
 6021  * @param arg Callback argument.
 6022  *
 6023  * @return Returns OCS_HW_RTN_SUCCESS on success.
 6024  */
 6025 static ocs_hw_rtn_e
 6026 ocs_hw_get_linkcfg_lancer(ocs_hw_t *hw, uint32_t opts, ocs_hw_port_control_cb_t cb, void *arg)
 6027 {
 6028         char cmd[OCS_HW_DMTF_CLP_CMD_MAX];
 6029         ocs_hw_linkcfg_cb_arg_t *cb_arg;
 6030         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 6031 
 6032         /* allocate memory for callback argument */
 6033         cb_arg = ocs_malloc(hw->os, sizeof(*cb_arg), OCS_M_NOWAIT);
 6034         if (cb_arg == NULL) {
 6035                 ocs_log_err(hw->os, "failed to malloc cb_arg");
 6036                 return OCS_HW_RTN_NO_MEMORY;
 6037         }
 6038 
 6039         ocs_snprintf(cmd, OCS_HW_DMTF_CLP_CMD_MAX, "show / OEMELX_LinkConfig");
 6040 
 6041         /* allocate DMA for command  */
 6042         if (ocs_dma_alloc(hw->os, &cb_arg->dma_cmd, ocs_strlen(cmd)+1, 4096)) {
 6043                 ocs_log_err(hw->os, "malloc failed\n");
 6044                 ocs_free(hw->os, cb_arg, sizeof(*cb_arg));
 6045                 return OCS_HW_RTN_NO_MEMORY;
 6046         }
 6047 
 6048         /* copy CLP command to DMA command */
 6049         ocs_memset(cb_arg->dma_cmd.virt, 0, ocs_strlen(cmd)+1);
 6050         ocs_memcpy(cb_arg->dma_cmd.virt, cmd, ocs_strlen(cmd));
 6051 
 6052         /* allocate DMA for response */
 6053         if (ocs_dma_alloc(hw->os, &cb_arg->dma_resp, OCS_HW_DMTF_CLP_RSP_MAX, 4096)) {
 6054                 ocs_log_err(hw->os, "malloc failed\n");
 6055                 ocs_dma_free(hw->os, &cb_arg->dma_cmd);
 6056                 ocs_free(hw->os, cb_arg, sizeof(*cb_arg));
 6057                 return OCS_HW_RTN_NO_MEMORY;
 6058         }
 6059         cb_arg->cb = cb;
 6060         cb_arg->arg = arg;
 6061         cb_arg->opts = opts;
 6062 
 6063         rc = ocs_hw_exec_dmtf_clp_cmd(hw, &cb_arg->dma_cmd, &cb_arg->dma_resp,
 6064                                         opts, ocs_hw_linkcfg_dmtf_clp_cb, cb_arg);
 6065 
 6066         if (opts == OCS_CMD_POLL || rc != OCS_HW_RTN_SUCCESS) {
 6067                 /* if failed or polling, free memory here; if not polling and success,
 6068                  * will free in callback function
 6069                  */
 6070                 if (rc) {
 6071                         ocs_log_test(hw->os, "CLP cmd=\"%s\" failed\n",
 6072                                         (char *)cb_arg->dma_cmd.virt);
 6073                 }
 6074                 ocs_dma_free(hw->os, &cb_arg->dma_cmd);
 6075                 ocs_dma_free(hw->os, &cb_arg->dma_resp);
 6076                 ocs_free(hw->os, cb_arg, sizeof(*cb_arg));
 6077         }
 6078         return rc;
 6079 }
 6080 
 6081 /**
 6082  * @brief Get the link configuration callback.
 6083  *
 6084  * @param hw Hardware context.
 6085  * @param status Status from the RECONFIG_GET_LINK_INFO command.
 6086  * @param mqe Mailbox response structure.
 6087  * @param arg Pointer to a callback argument.
 6088  *
 6089  * @return none
 6090  */
 6091 static void
 6092 ocs_hw_get_active_link_config_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void  *arg)
 6093 {
 6094         ocs_hw_linkcfg_cb_arg_t *cb_arg = (ocs_hw_linkcfg_cb_arg_t *)arg;
 6095         sli4_res_common_get_reconfig_link_info_t *rsp = cb_arg->dma_cmd.virt;
 6096         ocs_hw_linkcfg_e value = OCS_HW_LINKCFG_NA;
 6097 
 6098         if (status) {
 6099                 ocs_log_test(hw->os, "GET_RECONFIG_LINK_INFO failed, status=%d\n", status);
 6100         } else {
 6101                 /* Call was successful */
 6102                 value = ocs_hw_linkcfg_from_config_id(rsp->active_link_config_id);
 6103         }
 6104 
 6105         /* invoke callback */
 6106         if (cb_arg->cb) {
 6107                 cb_arg->cb(status, value, cb_arg->arg);
 6108         }
 6109 
 6110         /* if polling, will free memory in calling function */
 6111         if (cb_arg->opts != OCS_CMD_POLL) {
 6112                 ocs_dma_free(hw->os, &cb_arg->dma_cmd);
 6113                 ocs_free(hw->os, cb_arg, sizeof(*cb_arg));
 6114         }
 6115 }
 6116 
 6117 /**
 6118  * @brief Get link configuration for a Skyhawk.
 6119  *
 6120  * @param hw Hardware context.
 6121  * @param opts Mailbox command options (OCS_CMD_NOWAIT/POLL).
 6122  * @param cb Callback function to invoke following mbx command.
 6123  * @param arg Callback argument.
 6124  *
 6125  * @return Returns OCS_HW_RTN_SUCCESS on success.
 6126  */
 6127 static ocs_hw_rtn_e
 6128 ocs_hw_get_linkcfg_skyhawk(ocs_hw_t *hw, uint32_t opts, ocs_hw_port_control_cb_t cb, void *arg)
 6129 {
 6130         uint8_t *mbxdata;
 6131         ocs_hw_linkcfg_cb_arg_t *cb_arg;
 6132         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 6133 
 6134         /* mbxdata holds the header of the command */
 6135         mbxdata = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
 6136         if (mbxdata == NULL) {
 6137                 ocs_log_err(hw->os, "failed to malloc mbox\n");
 6138                 return OCS_HW_RTN_NO_MEMORY;
 6139         }
 6140 
 6141         /* cb_arg holds the data that will be passed to the callback on completion */
 6142         cb_arg = ocs_malloc(hw->os, sizeof(ocs_hw_linkcfg_cb_arg_t), OCS_M_NOWAIT);
 6143         if (cb_arg == NULL) {
 6144                 ocs_log_err(hw->os, "failed to malloc cb_arg\n");
 6145                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 6146                 return OCS_HW_RTN_NO_MEMORY;
 6147         }
 6148 
 6149         cb_arg->cb = cb;
 6150         cb_arg->arg = arg;
 6151         cb_arg->opts = opts;
 6152 
 6153         /* dma_mem holds the non-embedded portion */
 6154         if (ocs_dma_alloc(hw->os, &cb_arg->dma_cmd, sizeof(sli4_res_common_get_reconfig_link_info_t), 4)) {
 6155                 ocs_log_err(hw->os, "Failed to allocate DMA buffer\n");
 6156                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 6157                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_linkcfg_cb_arg_t));
 6158                 return OCS_HW_RTN_NO_MEMORY;
 6159         }
 6160 
 6161         if (sli_cmd_common_get_reconfig_link_info(&hw->sli, mbxdata, SLI4_BMBX_SIZE, &cb_arg->dma_cmd)) {
 6162                 rc = ocs_hw_command(hw, mbxdata, opts, ocs_hw_get_active_link_config_cb, cb_arg);
 6163         }
 6164 
 6165         if (rc != OCS_HW_RTN_SUCCESS) {
 6166                 ocs_log_err(hw->os, "GET_RECONFIG_LINK_INFO failed\n");
 6167                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 6168                 ocs_dma_free(hw->os, &cb_arg->dma_cmd);
 6169                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_linkcfg_cb_arg_t));
 6170         } else if (opts == OCS_CMD_POLL) {
 6171                 /* if we're polling we have to call the callback here. */
 6172                 ocs_hw_get_active_link_config_cb(hw, 0, mbxdata, cb_arg);
 6173                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 6174                 ocs_dma_free(hw->os, &cb_arg->dma_cmd);
 6175                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_linkcfg_cb_arg_t));
 6176         } else {
 6177                 /* We weren't poling, so the callback got called */
 6178                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 6179         }
 6180 
 6181         return rc;
 6182 }
 6183 
 6184 /**
 6185  * @brief Sets the DIF seed value.
 6186  *
 6187  * @param hw Hardware context.
 6188  *
 6189  * @return Returns OCS_HW_RTN_SUCCESS on success.
 6190  */
 6191 static ocs_hw_rtn_e
 6192 ocs_hw_set_dif_seed(ocs_hw_t *hw)
 6193 {
 6194         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 6195         uint8_t buf[SLI4_BMBX_SIZE];
 6196         sli4_req_common_set_features_dif_seed_t seed_param;
 6197 
 6198         ocs_memset(&seed_param, 0, sizeof(seed_param));
 6199         seed_param.seed = hw->config.dif_seed;
 6200 
 6201         /* send set_features command */
 6202         if (sli_cmd_common_set_features(&hw->sli, buf, SLI4_BMBX_SIZE,
 6203                                         SLI4_SET_FEATURES_DIF_SEED,
 6204                                         4,
 6205                                         (uint32_t*)&seed_param)) {
 6206                 rc = ocs_hw_command(hw, buf, OCS_CMD_POLL, NULL, NULL);
 6207                 if (rc) {
 6208                         ocs_log_err(hw->os, "ocs_hw_command returns %d\n", rc);
 6209                 } else {
 6210                         ocs_log_debug(hw->os, "DIF seed set to 0x%x\n",
 6211                                         hw->config.dif_seed);
 6212                 }
 6213         } else {
 6214                 ocs_log_err(hw->os, "sli_cmd_common_set_features failed\n");
 6215                 rc = OCS_HW_RTN_ERROR;
 6216         }
 6217         return rc;
 6218 }
 6219 
 6220 /**
 6221  * @brief Sets the DIF mode value.
 6222  *
 6223  * @param hw Hardware context.
 6224  *
 6225  * @return Returns OCS_HW_RTN_SUCCESS on success.
 6226  */
 6227 static ocs_hw_rtn_e
 6228 ocs_hw_set_dif_mode(ocs_hw_t *hw)
 6229 {
 6230         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 6231         uint8_t buf[SLI4_BMBX_SIZE];
 6232         sli4_req_common_set_features_t10_pi_mem_model_t mode_param;
 6233 
 6234         ocs_memset(&mode_param, 0, sizeof(mode_param));
 6235         mode_param.tmm = (hw->config.dif_mode == OCS_HW_DIF_MODE_INLINE ? 0 : 1);
 6236 
 6237         /* send set_features command */
 6238         if (sli_cmd_common_set_features(&hw->sli, buf, SLI4_BMBX_SIZE,
 6239                                         SLI4_SET_FEATURES_DIF_MEMORY_MODE,
 6240                                         sizeof(mode_param),
 6241                                         (uint32_t*)&mode_param)) {
 6242                 rc = ocs_hw_command(hw, buf, OCS_CMD_POLL, NULL, NULL);
 6243                 if (rc) {
 6244                         ocs_log_err(hw->os, "ocs_hw_command returns %d\n", rc);
 6245                 } else {
 6246                         ocs_log_test(hw->os, "DIF mode set to %s\n",
 6247                                 (hw->config.dif_mode == OCS_HW_DIF_MODE_INLINE ? "inline" : "separate"));
 6248                 }
 6249         } else {
 6250                 ocs_log_err(hw->os, "sli_cmd_common_set_features failed\n");
 6251                 rc = OCS_HW_RTN_ERROR;
 6252         }
 6253         return rc;
 6254 }
 6255 
 6256 static void 
 6257 ocs_hw_watchdog_timer_cb(void *arg)
 6258 {
 6259         ocs_hw_t *hw = (ocs_hw_t *)arg;
 6260 
 6261         ocs_hw_config_watchdog_timer(hw);
 6262         return;
 6263 }
 6264 
 6265 static void
 6266 ocs_hw_cb_cfg_watchdog(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void  *arg)
 6267 {
 6268         uint16_t timeout = hw->watchdog_timeout;
 6269 
 6270         if (status != 0) {
 6271                 ocs_log_err(hw->os, "config watchdog timer failed, rc = %d\n", status);
 6272         } else {
 6273                 if(timeout != 0) {
 6274                         /* keeping callback 500ms before timeout to keep heartbeat alive */
 6275                         ocs_setup_timer(hw->os, &hw->watchdog_timer, ocs_hw_watchdog_timer_cb, hw, (timeout*1000 - 500) );
 6276                 }else {
 6277                         ocs_del_timer(&hw->watchdog_timer);
 6278                 }
 6279         }
 6280 
 6281         ocs_free(hw->os, mqe, SLI4_BMBX_SIZE);
 6282         return;
 6283 }
 6284 
 6285 /**
 6286  * @brief Set configuration parameters for watchdog timer feature.
 6287  *
 6288  * @param hw Hardware context.
 6289  * @param timeout Timeout for watchdog timer in seconds
 6290  *
 6291  * @return Returns OCS_HW_RTN_SUCCESS on success.
 6292  */
 6293 static ocs_hw_rtn_e
 6294 ocs_hw_config_watchdog_timer(ocs_hw_t *hw)
 6295 {
 6296         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 6297         uint8_t *buf = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
 6298 
 6299         if (!buf) {
 6300                 ocs_log_err(hw->os, "no buffer for command\n");
 6301                 return OCS_HW_RTN_NO_MEMORY;
 6302         }
 6303 
 6304         sli4_cmd_lowlevel_set_watchdog(&hw->sli, buf, SLI4_BMBX_SIZE, hw->watchdog_timeout);
 6305         rc = ocs_hw_command(hw, buf, OCS_CMD_NOWAIT, ocs_hw_cb_cfg_watchdog, NULL);
 6306         if (rc) {
 6307                 ocs_free(hw->os, buf, SLI4_BMBX_SIZE);
 6308                 ocs_log_err(hw->os, "config watchdog timer failed, rc = %d\n", rc);
 6309         }
 6310         return rc;
 6311 }
 6312 
 6313 /**
 6314  * @brief Set configuration parameters for auto-generate xfer_rdy T10 PI feature.
 6315  *
 6316  * @param hw Hardware context.
 6317  * @param buf Pointer to a mailbox buffer area.
 6318  *
 6319  * @return Returns OCS_HW_RTN_SUCCESS on success.
 6320  */
 6321 static ocs_hw_rtn_e
 6322 ocs_hw_config_auto_xfer_rdy_t10pi(ocs_hw_t *hw, uint8_t *buf)
 6323 {
 6324         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 6325         sli4_req_common_set_features_xfer_rdy_t10pi_t param;
 6326 
 6327         ocs_memset(&param, 0, sizeof(param));
 6328         param.rtc = (hw->config.auto_xfer_rdy_ref_tag_is_lba ? 0 : 1);
 6329         param.atv = (hw->config.auto_xfer_rdy_app_tag_valid ? 1 : 0);
 6330         param.tmm = ((hw->config.dif_mode == OCS_HW_DIF_MODE_INLINE) ? 0 : 1);
 6331         param.app_tag = hw->config.auto_xfer_rdy_app_tag_value;
 6332         param.blk_size = hw->config.auto_xfer_rdy_blk_size_chip;
 6333 
 6334         switch (hw->config.auto_xfer_rdy_p_type) {
 6335         case 1:
 6336                 param.p_type = 0;
 6337                 break;
 6338         case 3:
 6339                 param.p_type = 2;
 6340                 break;
 6341         default:
 6342                 ocs_log_err(hw->os, "unsupported p_type %d\n",
 6343                         hw->config.auto_xfer_rdy_p_type);
 6344                 return OCS_HW_RTN_ERROR;
 6345         }
 6346 
 6347         /* build the set_features command */
 6348         sli_cmd_common_set_features(&hw->sli, buf, SLI4_BMBX_SIZE,
 6349                                     SLI4_SET_FEATURES_SET_CONFIG_AUTO_XFER_RDY_T10PI,
 6350                                     sizeof(param),
 6351                                     &param);
 6352 
 6353         rc = ocs_hw_command(hw, buf, OCS_CMD_POLL, NULL, NULL);
 6354         if (rc) {
 6355                 ocs_log_err(hw->os, "ocs_hw_command returns %d\n", rc);
 6356         } else {
 6357                 ocs_log_test(hw->os, "Auto XFER RDY T10 PI configured rtc:%d atv:%d p_type:%d app_tag:%x blk_size:%d\n",
 6358                                 param.rtc, param.atv, param.p_type,
 6359                                 param.app_tag, param.blk_size);
 6360         }
 6361 
 6362         return rc;
 6363 }
 6364 
 6365 /**
 6366  * @brief enable sli port health check
 6367  *
 6368  * @param hw Hardware context.
 6369  * @param buf Pointer to a mailbox buffer area.
 6370  * @param query current status of the health check feature enabled/disabled
 6371  * @param enable if 1: enable 0: disable
 6372  * @param buf Pointer to a mailbox buffer area.
 6373  *
 6374  * @return Returns OCS_HW_RTN_SUCCESS on success.
 6375  */
 6376 static ocs_hw_rtn_e
 6377 ocs_hw_config_sli_port_health_check(ocs_hw_t *hw, uint8_t query, uint8_t enable)
 6378 {
 6379         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 6380         uint8_t buf[SLI4_BMBX_SIZE];
 6381         sli4_req_common_set_features_health_check_t param;
 6382 
 6383         ocs_memset(&param, 0, sizeof(param));
 6384         param.hck = enable;
 6385         param.qry = query;
 6386 
 6387         /* build the set_features command */
 6388         sli_cmd_common_set_features(&hw->sli, buf, SLI4_BMBX_SIZE,
 6389                                     SLI4_SET_FEATURES_SLI_PORT_HEALTH_CHECK,
 6390                                     sizeof(param),
 6391                                     &param);
 6392 
 6393         rc = ocs_hw_command(hw, buf, OCS_CMD_POLL, NULL, NULL);
 6394         if (rc) {
 6395                 ocs_log_err(hw->os, "ocs_hw_command returns %d\n", rc);
 6396         } else {
 6397                 ocs_log_test(hw->os, "SLI Port Health Check is enabled \n");
 6398         }
 6399 
 6400         return rc;
 6401 }
 6402 
 6403 /**
 6404  * @brief Set FTD transfer hint feature
 6405  *
 6406  * @param hw Hardware context.
 6407  * @param fdt_xfer_hint size in bytes where read requests are segmented.
 6408  *
 6409  * @return Returns OCS_HW_RTN_SUCCESS on success.
 6410  */
 6411 static ocs_hw_rtn_e
 6412 ocs_hw_config_set_fdt_xfer_hint(ocs_hw_t *hw, uint32_t fdt_xfer_hint)
 6413 {
 6414         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 6415         uint8_t buf[SLI4_BMBX_SIZE];
 6416         sli4_req_common_set_features_set_fdt_xfer_hint_t param;
 6417 
 6418         ocs_memset(&param, 0, sizeof(param));
 6419         param.fdt_xfer_hint = fdt_xfer_hint;
 6420         /* build the set_features command */
 6421         sli_cmd_common_set_features(&hw->sli, buf, SLI4_BMBX_SIZE,
 6422                                     SLI4_SET_FEATURES_SET_FTD_XFER_HINT,
 6423                                     sizeof(param),
 6424                                     &param);
 6425 
 6426         rc = ocs_hw_command(hw, buf, OCS_CMD_POLL, NULL, NULL);
 6427         if (rc) {
 6428                 ocs_log_warn(hw->os, "set FDT hint %d failed: %d\n", fdt_xfer_hint, rc);
 6429         } else {
 6430                 ocs_log_debug(hw->os, "Set FTD transfer hint to %d\n", param.fdt_xfer_hint);
 6431         }
 6432 
 6433         return rc;
 6434 }
 6435 
 6436 /**
 6437  * @brief Get the link configuration callback.
 6438  *
 6439  * @param hw Hardware context.
 6440  * @param status Status from the DMTF CLP command.
 6441  * @param result_len Length, in bytes, of the DMTF CLP result.
 6442  * @param arg Pointer to a callback argument.
 6443  *
 6444  * @return Returns OCS_HW_RTN_SUCCESS on success.
 6445  */
 6446 static void
 6447 ocs_hw_linkcfg_dmtf_clp_cb(ocs_hw_t *hw, int32_t status, uint32_t result_len, void *arg)
 6448 {
 6449         int32_t rval;
 6450         char retdata_str[64];
 6451         ocs_hw_linkcfg_cb_arg_t *cb_arg = (ocs_hw_linkcfg_cb_arg_t *)arg;
 6452         ocs_hw_linkcfg_e linkcfg = OCS_HW_LINKCFG_NA;
 6453 
 6454         if (status) {
 6455                 ocs_log_test(hw->os, "CLP cmd failed, status=%d\n", status);
 6456         } else {
 6457                 /* parse CLP response to get return data */
 6458                 rval = ocs_hw_clp_resp_get_value(hw, "retdata", retdata_str,
 6459                                                   sizeof(retdata_str),
 6460                                                   cb_arg->dma_resp.virt,
 6461                                                   result_len);
 6462 
 6463                 if (rval <= 0) {
 6464                         ocs_log_err(hw->os, "failed to get retdata %d\n", result_len);
 6465                 } else {
 6466                         /* translate string into hw enum */
 6467                         linkcfg = ocs_hw_linkcfg_from_clp(retdata_str);
 6468                 }
 6469         }
 6470 
 6471         /* invoke callback */
 6472         if (cb_arg->cb) {
 6473                 cb_arg->cb(status, linkcfg, cb_arg->arg);
 6474         }
 6475 
 6476         /* if polling, will free memory in calling function */
 6477         if (cb_arg->opts != OCS_CMD_POLL) {
 6478                 ocs_dma_free(hw->os, &cb_arg->dma_cmd);
 6479                 ocs_dma_free(hw->os, &cb_arg->dma_resp);
 6480                 ocs_free(hw->os, cb_arg, sizeof(*cb_arg));
 6481         }
 6482 }
 6483 
 6484 /**
 6485  * @brief Set the Lancer dump location
 6486  * @par Description
 6487  * This function tells a Lancer chip to use a specific DMA
 6488  * buffer as a dump location rather than the internal flash.
 6489  *
 6490  * @param hw Hardware context.
 6491  * @param num_buffers The number of DMA buffers to hold the dump (1..n).
 6492  * @param dump_buffers DMA buffers to hold the dump.
 6493  *
 6494  * @return Returns OCS_HW_RTN_SUCCESS on success.
 6495  */
 6496 ocs_hw_rtn_e
 6497 ocs_hw_set_dump_location(ocs_hw_t *hw, uint32_t num_buffers, ocs_dma_t *dump_buffers, uint8_t fdb)
 6498 {
 6499         uint8_t bus, dev, func;
 6500         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 6501         uint8_t buf[SLI4_BMBX_SIZE];
 6502 
 6503         /*
 6504          * Make sure the FW is new enough to support this command. If the FW
 6505          * is too old, the FW will UE.
 6506          */
 6507         if (hw->workaround.disable_dump_loc) {
 6508                 ocs_log_test(hw->os, "FW version is too old for this feature\n");
 6509                 return OCS_HW_RTN_ERROR;
 6510         }
 6511 
 6512         /* This command is only valid for physical port 0 */
 6513         ocs_get_bus_dev_func(hw->os, &bus, &dev, &func);
 6514         if (fdb == 0 && func != 0) {
 6515                 ocs_log_test(hw->os, "function only valid for pci function 0, %d passed\n",
 6516                              func);
 6517                 return OCS_HW_RTN_ERROR;
 6518         }
 6519 
 6520         /*
 6521          * If a single buffer is used, then it may be passed as is to the chip. For multiple buffers,
 6522          * We must allocate a SGL list and then pass the address of the list to the chip.
 6523          */
 6524         if (num_buffers > 1) {
 6525                 uint32_t sge_size = num_buffers * sizeof(sli4_sge_t);
 6526                 sli4_sge_t *sge;
 6527                 uint32_t i;
 6528 
 6529                 if (hw->dump_sges.size < sge_size) {
 6530                         ocs_dma_free(hw->os, &hw->dump_sges);
 6531                         if (ocs_dma_alloc(hw->os, &hw->dump_sges, sge_size, OCS_MIN_DMA_ALIGNMENT)) {
 6532                                 ocs_log_err(hw->os, "SGE DMA allocation failed\n");
 6533                                 return OCS_HW_RTN_NO_MEMORY;
 6534                         }
 6535                 }
 6536                 /* build the SGE list */
 6537                 ocs_memset(hw->dump_sges.virt, 0, hw->dump_sges.size);
 6538                 hw->dump_sges.len = sge_size;
 6539                 sge = hw->dump_sges.virt;
 6540                 for (i = 0; i < num_buffers; i++) {
 6541                         sge[i].buffer_address_high = ocs_addr32_hi(dump_buffers[i].phys);
 6542                         sge[i].buffer_address_low = ocs_addr32_lo(dump_buffers[i].phys);
 6543                         sge[i].last = (i == num_buffers - 1 ? 1 : 0);
 6544                         sge[i].buffer_length = dump_buffers[i].size;
 6545                 }
 6546                 rc = sli_cmd_common_set_dump_location(&hw->sli, (void *)buf,
 6547                                                       SLI4_BMBX_SIZE, FALSE, TRUE,
 6548                                                       &hw->dump_sges, fdb);
 6549         } else {
 6550                 dump_buffers->len = dump_buffers->size;
 6551                 rc = sli_cmd_common_set_dump_location(&hw->sli, (void *)buf,
 6552                                                       SLI4_BMBX_SIZE, FALSE, FALSE,
 6553                                                       dump_buffers, fdb);
 6554         }
 6555 
 6556         if (rc) {
 6557                 rc = ocs_hw_command(hw, buf, OCS_CMD_POLL,
 6558                                      NULL, NULL);
 6559                 if (rc) {
 6560                         ocs_log_err(hw->os, "ocs_hw_command returns %d\n",
 6561                                 rc);
 6562                 }
 6563         } else {
 6564                 ocs_log_err(hw->os,
 6565                         "sli_cmd_common_set_dump_location failed\n");
 6566                 rc = OCS_HW_RTN_ERROR;
 6567         }
 6568 
 6569         return rc;
 6570 }
 6571 
 6572 /**
 6573  * @brief Set the Ethernet license.
 6574  *
 6575  * @par Description
 6576  * This function sends the appropriate mailbox command (DMTF
 6577  * CLP) to set the Ethernet license to the given license value.
 6578  * Since it is used during the time of ocs_hw_init(), the mailbox
 6579  * command is sent via polling (the BMBX route).
 6580  *
 6581  * @param hw Hardware context.
 6582  * @param license 32-bit license value.
 6583  *
 6584  * @return Returns OCS_HW_RTN_SUCCESS on success.
 6585  */
 6586 static ocs_hw_rtn_e
 6587 ocs_hw_set_eth_license(ocs_hw_t *hw, uint32_t license)
 6588 {
 6589         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 6590         char cmd[OCS_HW_DMTF_CLP_CMD_MAX];
 6591         ocs_dma_t dma_cmd;
 6592         ocs_dma_t dma_resp;
 6593 
 6594         /* only for lancer right now */
 6595         if (SLI4_IF_TYPE_LANCER_FC_ETH != sli_get_if_type(&hw->sli)) {
 6596                 ocs_log_test(hw->os, "Function only supported for I/F type 2\n");
 6597                 return OCS_HW_RTN_ERROR;
 6598         }
 6599 
 6600         ocs_snprintf(cmd, OCS_HW_DMTF_CLP_CMD_MAX, "set / OEMELX_Ethernet_License=%X", license);
 6601         /* allocate DMA for command  */
 6602         if (ocs_dma_alloc(hw->os, &dma_cmd, ocs_strlen(cmd)+1, 4096)) {
 6603                 ocs_log_err(hw->os, "malloc failed\n");
 6604                 return OCS_HW_RTN_NO_MEMORY;
 6605         }
 6606         ocs_memset(dma_cmd.virt, 0, ocs_strlen(cmd)+1);
 6607         ocs_memcpy(dma_cmd.virt, cmd, ocs_strlen(cmd));
 6608 
 6609         /* allocate DMA for response */
 6610         if (ocs_dma_alloc(hw->os, &dma_resp, OCS_HW_DMTF_CLP_RSP_MAX, 4096)) {
 6611                 ocs_log_err(hw->os, "malloc failed\n");
 6612                 ocs_dma_free(hw->os, &dma_cmd);
 6613                 return OCS_HW_RTN_NO_MEMORY;
 6614         }
 6615 
 6616         /* send DMTF CLP command mbx and poll */
 6617         if (ocs_hw_exec_dmtf_clp_cmd(hw, &dma_cmd, &dma_resp, OCS_CMD_POLL, NULL, NULL)) {
 6618                 ocs_log_err(hw->os, "CLP cmd=\"%s\" failed\n", (char *)dma_cmd.virt);
 6619                 rc = OCS_HW_RTN_ERROR;
 6620         }
 6621 
 6622         ocs_dma_free(hw->os, &dma_cmd);
 6623         ocs_dma_free(hw->os, &dma_resp);
 6624         return rc;
 6625 }
 6626 
 6627 /**
 6628  * @brief Callback argument structure for the DMTF CLP commands.
 6629  */
 6630 typedef struct ocs_hw_clp_cb_arg_s {
 6631         ocs_hw_dmtf_clp_cb_t cb;
 6632         ocs_dma_t *dma_resp;
 6633         int32_t status;
 6634         uint32_t opts;
 6635         void *arg;
 6636 } ocs_hw_clp_cb_arg_t;
 6637 
 6638 /**
 6639  * @brief Execute the DMTF CLP command.
 6640  *
 6641  * @param hw Hardware context.
 6642  * @param dma_cmd DMA buffer containing the CLP command.
 6643  * @param dma_resp DMA buffer that will contain the response (if successful).
 6644  * @param opts Mailbox command options (such as OCS_CMD_NOWAIT and POLL).
 6645  * @param cb Callback function.
 6646  * @param arg Callback argument.
 6647  *
 6648  * @return Returns the number of bytes written to the response
 6649  * buffer on success, or a negative value if failed.
 6650  */
 6651 static ocs_hw_rtn_e
 6652 ocs_hw_exec_dmtf_clp_cmd(ocs_hw_t *hw, ocs_dma_t *dma_cmd, ocs_dma_t *dma_resp, uint32_t opts, ocs_hw_dmtf_clp_cb_t cb, void *arg)
 6653 {
 6654         ocs_hw_rtn_e rc = OCS_HW_RTN_ERROR;
 6655         ocs_hw_clp_cb_arg_t *cb_arg;
 6656         uint8_t *mbxdata;
 6657 
 6658         /* allocate DMA for mailbox */
 6659         mbxdata = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
 6660         if (mbxdata == NULL) {
 6661                 ocs_log_err(hw->os, "failed to malloc mbox\n");
 6662                 return OCS_HW_RTN_NO_MEMORY;
 6663         }
 6664 
 6665         /* allocate memory for callback argument */
 6666         cb_arg = ocs_malloc(hw->os, sizeof(*cb_arg), OCS_M_NOWAIT);
 6667         if (cb_arg == NULL) {
 6668                 ocs_log_err(hw->os, "failed to malloc cb_arg");
 6669                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 6670                 return OCS_HW_RTN_NO_MEMORY;
 6671         }
 6672 
 6673         cb_arg->cb = cb;
 6674         cb_arg->arg = arg;
 6675         cb_arg->dma_resp = dma_resp;
 6676         cb_arg->opts = opts;
 6677 
 6678         /* Send the HW command */
 6679         if (sli_cmd_dmtf_exec_clp_cmd(&hw->sli, mbxdata, SLI4_BMBX_SIZE,
 6680                                       dma_cmd, dma_resp)) {
 6681                 rc = ocs_hw_command(hw, mbxdata, opts, ocs_hw_dmtf_clp_cb, cb_arg);
 6682 
 6683                 if (opts == OCS_CMD_POLL && rc == OCS_HW_RTN_SUCCESS) {
 6684                         /* if we're polling, copy response and invoke callback to
 6685                          * parse result */
 6686                         ocs_memcpy(mbxdata, hw->sli.bmbx.virt, SLI4_BMBX_SIZE);
 6687                         ocs_hw_dmtf_clp_cb(hw, 0, mbxdata, cb_arg);
 6688 
 6689                         /* set rc to resulting or "parsed" status */
 6690                         rc = cb_arg->status;
 6691                 }
 6692 
 6693                 /* if failed, or polling, free memory here */
 6694                 if (opts == OCS_CMD_POLL || rc != OCS_HW_RTN_SUCCESS) {
 6695                         if (rc != OCS_HW_RTN_SUCCESS) {
 6696                                 ocs_log_test(hw->os, "ocs_hw_command failed\n");
 6697                         }
 6698                         ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 6699                         ocs_free(hw->os, cb_arg, sizeof(*cb_arg));
 6700                 }
 6701         } else {
 6702                 ocs_log_test(hw->os, "sli_cmd_dmtf_exec_clp_cmd failed\n");
 6703                 rc = OCS_HW_RTN_ERROR;
 6704                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 6705                 ocs_free(hw->os, cb_arg, sizeof(*cb_arg));
 6706         }
 6707 
 6708         return rc;
 6709 }
 6710 
 6711 /**
 6712  * @brief Called when the DMTF CLP command completes.
 6713  *
 6714  * @param hw Hardware context.
 6715  * @param status Status field from the mbox completion.
 6716  * @param mqe Mailbox response structure.
 6717  * @param arg Pointer to a callback argument.
 6718  *
 6719  * @return None.
 6720  *
 6721  */
 6722 static void
 6723 ocs_hw_dmtf_clp_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void  *arg)
 6724 {
 6725         int32_t cb_status = 0;
 6726         sli4_cmd_sli_config_t* mbox_rsp = (sli4_cmd_sli_config_t*) mqe;
 6727         sli4_res_dmtf_exec_clp_cmd_t *clp_rsp = (sli4_res_dmtf_exec_clp_cmd_t *) mbox_rsp->payload.embed;
 6728         ocs_hw_clp_cb_arg_t *cb_arg = arg;
 6729         uint32_t result_len = 0;
 6730         int32_t stat_len;
 6731         char stat_str[8];
 6732 
 6733         /* there are several status codes here, check them all and condense
 6734          * into a single callback status
 6735          */
 6736         if (status || mbox_rsp->hdr.status || clp_rsp->clp_status) {
 6737                 ocs_log_debug(hw->os, "status=x%x/x%x/x%x  addl=x%x clp=x%x detail=x%x\n",
 6738                         status,
 6739                         mbox_rsp->hdr.status,
 6740                         clp_rsp->hdr.status,
 6741                         clp_rsp->hdr.additional_status,
 6742                         clp_rsp->clp_status,
 6743                         clp_rsp->clp_detailed_status);
 6744                 if (status) {
 6745                         cb_status = status;
 6746                 } else if (mbox_rsp->hdr.status) {
 6747                         cb_status = mbox_rsp->hdr.status;
 6748                 } else {
 6749                         cb_status = clp_rsp->clp_status;
 6750                 }
 6751         } else {
 6752                 result_len = clp_rsp->resp_length;
 6753         }
 6754 
 6755         if (cb_status) {
 6756                 goto ocs_hw_cb_dmtf_clp_done;
 6757         }
 6758 
 6759         if ((result_len == 0) || (cb_arg->dma_resp->size < result_len)) {
 6760                 ocs_log_test(hw->os, "Invalid response length: resp_len=%zu result len=%d\n",
 6761                              cb_arg->dma_resp->size, result_len);
 6762                 cb_status = -1;
 6763                 goto ocs_hw_cb_dmtf_clp_done;
 6764         }
 6765 
 6766         /* parse CLP response to get status */
 6767         stat_len = ocs_hw_clp_resp_get_value(hw, "status", stat_str,
 6768                                               sizeof(stat_str),
 6769                                               cb_arg->dma_resp->virt,
 6770                                               result_len);
 6771 
 6772         if (stat_len <= 0) {
 6773                 ocs_log_test(hw->os, "failed to get status %d\n", stat_len);
 6774                 cb_status = -1;
 6775                 goto ocs_hw_cb_dmtf_clp_done;
 6776         }
 6777 
 6778         if (ocs_strcmp(stat_str, "") != 0) {
 6779                 ocs_log_test(hw->os, "CLP status indicates failure=%s\n", stat_str);
 6780                 cb_status = -1;
 6781                 goto ocs_hw_cb_dmtf_clp_done;
 6782         }
 6783 
 6784 ocs_hw_cb_dmtf_clp_done:
 6785 
 6786         /* save status in cb_arg for callers with NULL cb's + polling */
 6787         cb_arg->status = cb_status;
 6788         if (cb_arg->cb) {
 6789                 cb_arg->cb(hw, cb_status, result_len, cb_arg->arg);
 6790         }
 6791         /* if polling, caller will free memory */
 6792         if (cb_arg->opts != OCS_CMD_POLL) {
 6793                 ocs_free(hw->os, cb_arg, sizeof(*cb_arg));
 6794                 ocs_free(hw->os, mqe, SLI4_BMBX_SIZE);
 6795         }
 6796 }
 6797 
 6798 /**
 6799  * @brief Parse the CLP result and get the value corresponding to the given
 6800  * keyword.
 6801  *
 6802  * @param hw Hardware context.
 6803  * @param keyword CLP keyword for which the value is returned.
 6804  * @param value Location to which the resulting value is copied.
 6805  * @param value_len Length of the value parameter.
 6806  * @param resp Pointer to the response buffer that is searched
 6807  * for the keyword and value.
 6808  * @param resp_len Length of response buffer passed in.
 6809  *
 6810  * @return Returns the number of bytes written to the value
 6811  * buffer on success, or a negative vaue on failure.
 6812  */
 6813 static int32_t
 6814 ocs_hw_clp_resp_get_value(ocs_hw_t *hw, const char *keyword, char *value, uint32_t value_len, const char *resp, uint32_t resp_len)
 6815 {
 6816         char *start = NULL;
 6817         char *end = NULL;
 6818 
 6819         /* look for specified keyword in string */
 6820         start = ocs_strstr(resp, keyword);
 6821         if (start == NULL) {
 6822                 ocs_log_test(hw->os, "could not find keyword=%s in CLP response\n",
 6823                              keyword);
 6824                 return -1;
 6825         }
 6826 
 6827         /* now look for '=' and go one past */
 6828         start = ocs_strchr(start, '=');
 6829         if (start == NULL) {
 6830                 ocs_log_test(hw->os, "could not find \'=\' in CLP response for keyword=%s\n",
 6831                              keyword);
 6832                 return -1;
 6833         }
 6834         start++;
 6835 
 6836         /* \r\n terminates value */
 6837         end = ocs_strstr(start, "\r\n");
 6838         if (end == NULL) {
 6839                 ocs_log_test(hw->os, "could not find \\r\\n for keyword=%s in CLP response\n",
 6840                              keyword);
 6841                 return -1;
 6842         }
 6843 
 6844         /* make sure given result array is big enough */
 6845         if ((end - start + 1) > value_len) {
 6846                 ocs_log_test(hw->os, "value len=%d not large enough for actual=%ld\n",
 6847                              value_len, (end-start));
 6848                 return -1;
 6849         }
 6850 
 6851         ocs_strncpy(value, start, (end - start));
 6852         value[end-start] = '\0';
 6853         return (end-start+1);
 6854 }
 6855 
 6856 /**
 6857  * @brief Cause chip to enter an unrecoverable error state.
 6858  *
 6859  * @par Description
 6860  * Cause chip to enter an unrecoverable error state. This is
 6861  * used when detecting unexpected FW behavior so that the FW can be
 6862  * hwted from the driver as soon as the error is detected.
 6863  *
 6864  * @param hw Hardware context.
 6865  * @param dump Generate dump as part of reset.
 6866  *
 6867  * @return Returns 0 on success, or a non-zero value on failure.
 6868  *
 6869  */
 6870 ocs_hw_rtn_e
 6871 ocs_hw_raise_ue(ocs_hw_t *hw, uint8_t dump)
 6872 {
 6873         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 6874 
 6875         if (sli_raise_ue(&hw->sli, dump) != 0) {
 6876                 rc = OCS_HW_RTN_ERROR;
 6877         } else {
 6878                 if (hw->state != OCS_HW_STATE_UNINITIALIZED) {
 6879                         hw->state = OCS_HW_STATE_QUEUES_ALLOCATED;
 6880                 }
 6881         }
 6882 
 6883         return rc;
 6884 }
 6885 
 6886 /**
 6887  * @brief Called when the OBJECT_GET command completes.
 6888  *
 6889  * @par Description
 6890  * Get the number of bytes actually written out of the response, free the mailbox
 6891  * that was malloc'd by ocs_hw_dump_get(), then call the callback
 6892  * and pass the status and bytes read.
 6893  *
 6894  * @param hw Hardware context.
 6895  * @param status Status field from the mbox completion.
 6896  * @param mqe Mailbox response structure.
 6897  * @param arg Pointer to a callback function that signals the caller that the command is done.
 6898  * The callback function prototype is <tt>void cb(int32_t status, uint32_t bytes_read)</tt>.
 6899  *
 6900  * @return Returns 0.
 6901  */
 6902 static int32_t
 6903 ocs_hw_cb_dump_get(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void  *arg)
 6904 {
 6905         sli4_cmd_sli_config_t* mbox_rsp = (sli4_cmd_sli_config_t*) mqe;
 6906         sli4_res_common_read_object_t* rd_obj_rsp = (sli4_res_common_read_object_t*) mbox_rsp->payload.embed;
 6907         ocs_hw_dump_get_cb_arg_t *cb_arg = arg;
 6908         uint32_t bytes_read;
 6909         uint8_t eof;
 6910 
 6911         bytes_read = rd_obj_rsp->actual_read_length;
 6912         eof = rd_obj_rsp->eof;
 6913 
 6914         if (cb_arg) {
 6915                 if (cb_arg->cb) {
 6916                         if ((status == 0) && mbox_rsp->hdr.status) {
 6917                                 status = mbox_rsp->hdr.status;
 6918                         }
 6919                         cb_arg->cb(status, bytes_read, eof, cb_arg->arg);
 6920                 }
 6921 
 6922                 ocs_free(hw->os, cb_arg->mbox_cmd, SLI4_BMBX_SIZE);
 6923                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_dump_get_cb_arg_t));
 6924         }
 6925 
 6926         return 0;
 6927 }
 6928 
 6929 /**
 6930  * @brief Read a dump image to the host.
 6931  *
 6932  * @par Description
 6933  * Creates a SLI_CONFIG mailbox command, fills in the correct values to read a
 6934  * dump image chunk, then sends the command with the ocs_hw_command(). On completion,
 6935  * the callback function ocs_hw_cb_dump_get() gets called to free the mailbox
 6936  * and signal the caller that the read has completed.
 6937  *
 6938  * @param hw Hardware context.
 6939  * @param dma DMA structure to transfer the dump chunk into.
 6940  * @param size Size of the dump chunk.
 6941  * @param offset Offset, in bytes, from the beginning of the dump.
 6942  * @param cb Pointer to a callback function that is called when the command completes.
 6943  * The callback function prototype is
 6944  * <tt>void cb(int32_t status, uint32_t bytes_read, uint8_t eof, void *arg)</tt>.
 6945  * @param arg Pointer to be passed to the callback function.
 6946  *
 6947  * @return Returns 0 on success, or a non-zero value on failure.
 6948  */
 6949 ocs_hw_rtn_e
 6950 ocs_hw_dump_get(ocs_hw_t *hw, ocs_dma_t *dma, uint32_t size, uint32_t offset, ocs_hw_dump_get_cb_t cb, void *arg)
 6951 {
 6952         ocs_hw_rtn_e rc = OCS_HW_RTN_ERROR;
 6953         uint8_t *mbxdata;
 6954         ocs_hw_dump_get_cb_arg_t *cb_arg;
 6955         uint32_t opts = (hw->state == OCS_HW_STATE_ACTIVE ? OCS_CMD_NOWAIT : OCS_CMD_POLL);
 6956 
 6957         if (SLI4_IF_TYPE_LANCER_FC_ETH != sli_get_if_type(&hw->sli)) {
 6958                 ocs_log_test(hw->os, "Function only supported for I/F type 2\n");
 6959                 return OCS_HW_RTN_ERROR;
 6960         }
 6961 
 6962         if (1 != sli_dump_is_present(&hw->sli)) {
 6963                 ocs_log_test(hw->os, "No dump is present\n");
 6964                 return OCS_HW_RTN_ERROR;
 6965         }
 6966 
 6967         if (1 == sli_reset_required(&hw->sli)) {
 6968                 ocs_log_test(hw->os, "device reset required\n");
 6969                 return OCS_HW_RTN_ERROR;
 6970         }
 6971 
 6972         mbxdata = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
 6973         if (mbxdata == NULL) {
 6974                 ocs_log_err(hw->os, "failed to malloc mbox\n");
 6975                 return OCS_HW_RTN_NO_MEMORY;
 6976         }
 6977 
 6978         cb_arg = ocs_malloc(hw->os, sizeof(ocs_hw_dump_get_cb_arg_t), OCS_M_NOWAIT);
 6979         if (cb_arg == NULL) {
 6980                 ocs_log_err(hw->os, "failed to malloc cb_arg\n");
 6981                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 6982                 return OCS_HW_RTN_NO_MEMORY;
 6983         }
 6984 
 6985         cb_arg->cb = cb;
 6986         cb_arg->arg = arg;
 6987         cb_arg->mbox_cmd = mbxdata;
 6988 
 6989         if (sli_cmd_common_read_object(&hw->sli, mbxdata, SLI4_BMBX_SIZE,
 6990                         size, offset, "/dbg/dump.bin", dma)) {
 6991                 rc = ocs_hw_command(hw, mbxdata, opts, ocs_hw_cb_dump_get, cb_arg);
 6992                 if (rc == 0 && opts == OCS_CMD_POLL) {
 6993                         ocs_memcpy(mbxdata, hw->sli.bmbx.virt, SLI4_BMBX_SIZE);
 6994                         rc = ocs_hw_cb_dump_get(hw, 0, mbxdata, cb_arg);
 6995                 }
 6996         }
 6997 
 6998         if (rc != OCS_HW_RTN_SUCCESS) {
 6999                 ocs_log_test(hw->os, "COMMON_READ_OBJECT failed\n");
 7000                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 7001                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_dump_get_cb_arg_t));
 7002         }
 7003 
 7004         return rc;
 7005 }
 7006 
 7007 /**
 7008  * @brief Called when the OBJECT_DELETE command completes.
 7009  *
 7010  * @par Description
 7011  * Free the mailbox that was malloc'd
 7012  * by ocs_hw_dump_clear(), then call the callback and pass the status.
 7013  *
 7014  * @param hw Hardware context.
 7015  * @param status Status field from the mbox completion.
 7016  * @param mqe Mailbox response structure.
 7017  * @param arg Pointer to a callback function that signals the caller that the command is done.
 7018  * The callback function prototype is <tt>void cb(int32_t status, void *arg)</tt>.
 7019  *
 7020  * @return Returns 0.
 7021  */
 7022 static int32_t
 7023 ocs_hw_cb_dump_clear(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void  *arg)
 7024 {
 7025         ocs_hw_dump_clear_cb_arg_t *cb_arg = arg;
 7026         sli4_cmd_sli_config_t* mbox_rsp = (sli4_cmd_sli_config_t*) mqe;
 7027 
 7028         if (cb_arg) {
 7029                 if (cb_arg->cb) {
 7030                         if ((status == 0) && mbox_rsp->hdr.status) {
 7031                                 status = mbox_rsp->hdr.status;
 7032                         }
 7033                         cb_arg->cb(status, cb_arg->arg);
 7034                 }
 7035 
 7036                 ocs_free(hw->os, cb_arg->mbox_cmd, SLI4_BMBX_SIZE);
 7037                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_dump_clear_cb_arg_t));
 7038         }
 7039 
 7040         return 0;
 7041 }
 7042 
 7043 /**
 7044  * @brief Clear a dump image from the device.
 7045  *
 7046  * @par Description
 7047  * Creates a SLI_CONFIG mailbox command, fills it with the correct values to clear
 7048  * the dump, then sends the command with ocs_hw_command(). On completion,
 7049  * the callback function ocs_hw_cb_dump_clear() gets called to free the mailbox
 7050  * and to signal the caller that the write has completed.
 7051  *
 7052  * @param hw Hardware context.
 7053  * @param cb Pointer to a callback function that is called when the command completes.
 7054  * The callback function prototype is
 7055  * <tt>void cb(int32_t status, uint32_t bytes_written, void *arg)</tt>.
 7056  * @param arg Pointer to be passed to the callback function.
 7057  *
 7058  * @return Returns 0 on success, or a non-zero value on failure.
 7059  */
 7060 ocs_hw_rtn_e
 7061 ocs_hw_dump_clear(ocs_hw_t *hw, ocs_hw_dump_clear_cb_t cb, void *arg)
 7062 {
 7063         ocs_hw_rtn_e rc = OCS_HW_RTN_ERROR;
 7064         uint8_t *mbxdata;
 7065         ocs_hw_dump_clear_cb_arg_t *cb_arg;
 7066         uint32_t opts = (hw->state == OCS_HW_STATE_ACTIVE ? OCS_CMD_NOWAIT : OCS_CMD_POLL);
 7067 
 7068         if (SLI4_IF_TYPE_LANCER_FC_ETH != sli_get_if_type(&hw->sli)) {
 7069                 ocs_log_test(hw->os, "Function only supported for I/F type 2\n");
 7070                 return OCS_HW_RTN_ERROR;
 7071         }
 7072 
 7073         mbxdata = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
 7074         if (mbxdata == NULL) {
 7075                 ocs_log_err(hw->os, "failed to malloc mbox\n");
 7076                 return OCS_HW_RTN_NO_MEMORY;
 7077         }
 7078 
 7079         cb_arg = ocs_malloc(hw->os, sizeof(ocs_hw_dump_clear_cb_arg_t), OCS_M_NOWAIT);
 7080         if (cb_arg == NULL) {
 7081                 ocs_log_err(hw->os, "failed to malloc cb_arg\n");
 7082                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 7083                 return OCS_HW_RTN_NO_MEMORY;
 7084         }
 7085 
 7086         cb_arg->cb = cb;
 7087         cb_arg->arg = arg;
 7088         cb_arg->mbox_cmd = mbxdata;
 7089 
 7090         if (sli_cmd_common_delete_object(&hw->sli, mbxdata, SLI4_BMBX_SIZE,
 7091                         "/dbg/dump.bin")) {
 7092                 rc = ocs_hw_command(hw, mbxdata, opts, ocs_hw_cb_dump_clear, cb_arg);
 7093                 if (rc == 0 && opts == OCS_CMD_POLL) {
 7094                         ocs_memcpy(mbxdata, hw->sli.bmbx.virt, SLI4_BMBX_SIZE);
 7095                         rc = ocs_hw_cb_dump_clear(hw, 0, mbxdata, cb_arg);
 7096                 }
 7097         }
 7098 
 7099         if (rc != OCS_HW_RTN_SUCCESS) {
 7100                 ocs_log_test(hw->os, "COMMON_DELETE_OBJECT failed\n");
 7101                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 7102                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_dump_clear_cb_arg_t));
 7103         }
 7104 
 7105         return rc;
 7106 }
 7107 
 7108 typedef struct ocs_hw_get_port_protocol_cb_arg_s {
 7109         ocs_get_port_protocol_cb_t cb;
 7110         void *arg;
 7111         uint32_t pci_func;
 7112         ocs_dma_t payload;
 7113 } ocs_hw_get_port_protocol_cb_arg_t;
 7114 
 7115 /**
 7116  * @brief Called for the completion of get_port_profile for a
 7117  *        user request.
 7118  *
 7119  * @param hw Hardware context.
 7120  * @param status The status from the MQE.
 7121  * @param mqe Pointer to mailbox command buffer.
 7122  * @param arg Pointer to a callback argument.
 7123  *
 7124  * @return Returns 0 on success, or a non-zero value on failure.
 7125  */
 7126 static int32_t
 7127 ocs_hw_get_port_protocol_cb(ocs_hw_t *hw, int32_t status,
 7128                             uint8_t *mqe, void *arg)
 7129 {
 7130         ocs_hw_get_port_protocol_cb_arg_t *cb_arg = arg;
 7131         ocs_dma_t *payload = &(cb_arg->payload);
 7132         sli4_res_common_get_profile_config_t* response = (sli4_res_common_get_profile_config_t*) payload->virt;
 7133         ocs_hw_port_protocol_e port_protocol;
 7134         int num_descriptors;
 7135         sli4_resource_descriptor_v1_t *desc_p;
 7136         sli4_pcie_resource_descriptor_v1_t *pcie_desc_p;
 7137         int i;
 7138 
 7139         port_protocol = OCS_HW_PORT_PROTOCOL_OTHER;
 7140 
 7141         num_descriptors = response->desc_count;
 7142         desc_p = (sli4_resource_descriptor_v1_t *)response->desc;
 7143         for (i=0; i<num_descriptors; i++) {
 7144                 if (desc_p->descriptor_type == SLI4_RESOURCE_DESCRIPTOR_TYPE_PCIE) {
 7145                         pcie_desc_p = (sli4_pcie_resource_descriptor_v1_t*) desc_p;
 7146                         if (pcie_desc_p->pf_number == cb_arg->pci_func) {
 7147                                 switch(pcie_desc_p->pf_type) {
 7148                                 case 0x02:
 7149                                         port_protocol = OCS_HW_PORT_PROTOCOL_ISCSI;
 7150                                         break;
 7151                                 case 0x04:
 7152                                         port_protocol = OCS_HW_PORT_PROTOCOL_FCOE;
 7153                                         break;
 7154                                 case 0x10:
 7155                                         port_protocol = OCS_HW_PORT_PROTOCOL_FC;
 7156                                         break;
 7157                                 default:
 7158                                         port_protocol = OCS_HW_PORT_PROTOCOL_OTHER;
 7159                                         break;
 7160                                 }
 7161                         }
 7162                 }
 7163 
 7164                 desc_p = (sli4_resource_descriptor_v1_t *) ((uint8_t *)desc_p + desc_p->descriptor_length);
 7165         }
 7166 
 7167         if (cb_arg->cb) {
 7168                 cb_arg->cb(status, port_protocol, cb_arg->arg);
 7169         }
 7170 
 7171         ocs_dma_free(hw->os, &cb_arg->payload);
 7172         ocs_free(hw->os, cb_arg, sizeof(ocs_hw_get_port_protocol_cb_arg_t));
 7173         ocs_free(hw->os, mqe, SLI4_BMBX_SIZE);
 7174 
 7175         return 0;
 7176 }
 7177 
 7178 /**
 7179  * @ingroup io
 7180  * @brief  Get the current port protocol.
 7181  * @par Description
 7182  * Issues a SLI4 COMMON_GET_PROFILE_CONFIG mailbox.  When the
 7183  * command completes the provided mgmt callback function is
 7184  * called.
 7185  *
 7186  * @param hw Hardware context.
 7187  * @param pci_func PCI function to query for current protocol.
 7188  * @param cb Callback function to be called when the command completes.
 7189  * @param ul_arg An argument that is passed to the callback function.
 7190  *
 7191  * @return
 7192  * - OCS_HW_RTN_SUCCESS on success.
 7193  * - OCS_HW_RTN_NO_MEMORY if a malloc fails.
 7194  * - OCS_HW_RTN_NO_RESOURCES if unable to get a command
 7195  *   context.
 7196  * - OCS_HW_RTN_ERROR on any other error.
 7197  */
 7198 ocs_hw_rtn_e
 7199 ocs_hw_get_port_protocol(ocs_hw_t *hw, uint32_t pci_func,
 7200         ocs_get_port_protocol_cb_t cb, void* ul_arg)
 7201 {
 7202         uint8_t *mbxdata;
 7203         ocs_hw_get_port_protocol_cb_arg_t *cb_arg;
 7204         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 7205 
 7206         /* Only supported on Skyhawk */
 7207         if (sli_get_if_type(&hw->sli) != SLI4_IF_TYPE_BE3_SKH_PF) {
 7208                 return OCS_HW_RTN_ERROR;
 7209         }
 7210 
 7211         /* mbxdata holds the header of the command */
 7212         mbxdata = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
 7213         if (mbxdata == NULL) {
 7214                 ocs_log_err(hw->os, "failed to malloc mbox\n");
 7215                 return OCS_HW_RTN_NO_MEMORY;
 7216         }
 7217 
 7218         /* cb_arg holds the data that will be passed to the callback on completion */
 7219         cb_arg = ocs_malloc(hw->os, sizeof(ocs_hw_get_port_protocol_cb_arg_t), OCS_M_NOWAIT);
 7220         if (cb_arg == NULL) {
 7221                 ocs_log_err(hw->os, "failed to malloc cb_arg\n");
 7222                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 7223                 return OCS_HW_RTN_NO_MEMORY;
 7224         }
 7225 
 7226         cb_arg->cb = cb;
 7227         cb_arg->arg = ul_arg;
 7228         cb_arg->pci_func = pci_func;
 7229 
 7230         /* dma_mem holds the non-embedded portion */
 7231         if (ocs_dma_alloc(hw->os, &cb_arg->payload, 4096, 4)) {
 7232                 ocs_log_err(hw->os, "Failed to allocate DMA buffer\n");
 7233                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 7234                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_get_port_protocol_cb_arg_t));
 7235                 return OCS_HW_RTN_NO_MEMORY;
 7236         }
 7237 
 7238         if (sli_cmd_common_get_profile_config(&hw->sli, mbxdata, SLI4_BMBX_SIZE, &cb_arg->payload)) {
 7239                 rc = ocs_hw_command(hw, mbxdata, OCS_CMD_NOWAIT, ocs_hw_get_port_protocol_cb, cb_arg);
 7240         }
 7241 
 7242         if (rc != OCS_HW_RTN_SUCCESS) {
 7243                 ocs_log_test(hw->os, "GET_PROFILE_CONFIG failed\n");
 7244                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 7245                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_fw_write_cb_arg_t));
 7246                 ocs_dma_free(hw->os, &cb_arg->payload);
 7247         }
 7248 
 7249         return rc;
 7250 
 7251 }
 7252 
 7253 typedef struct ocs_hw_set_port_protocol_cb_arg_s {
 7254         ocs_set_port_protocol_cb_t cb;
 7255         void *arg;
 7256         ocs_dma_t payload;
 7257         uint32_t new_protocol;
 7258         uint32_t pci_func;
 7259 } ocs_hw_set_port_protocol_cb_arg_t;
 7260 
 7261 /**
 7262  * @brief Called for the completion of set_port_profile for a
 7263  *        user request.
 7264  *
 7265  * @par Description
 7266  * This is the second of two callbacks for the set_port_protocol
 7267  * function. The set operation is a read-modify-write. This
 7268  * callback is called when the write (SET_PROFILE_CONFIG)
 7269  * completes.
 7270  *
 7271  * @param hw Hardware context.
 7272  * @param status The status from the MQE.
 7273  * @param mqe Pointer to mailbox command buffer.
 7274  * @param arg Pointer to a callback argument.
 7275  *
 7276  * @return 0 on success, non-zero otherwise
 7277  */
 7278 static int32_t
 7279 ocs_hw_set_port_protocol_cb2(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
 7280 {
 7281         ocs_hw_set_port_protocol_cb_arg_t *cb_arg = arg;
 7282 
 7283         if (cb_arg->cb) {
 7284                 cb_arg->cb( status, cb_arg->arg);
 7285         }
 7286 
 7287         ocs_dma_free(hw->os, &(cb_arg->payload));
 7288         ocs_free(hw->os, mqe, SLI4_BMBX_SIZE);
 7289         ocs_free(hw->os, arg, sizeof(ocs_hw_set_port_protocol_cb_arg_t));
 7290 
 7291         return 0;
 7292 }
 7293 
 7294 /**
 7295  * @brief Called for the completion of set_port_profile for a
 7296  *        user request.
 7297  *
 7298  * @par Description
 7299  * This is the first of two callbacks for the set_port_protocol
 7300  * function.  The set operation is a read-modify-write.  This
 7301  * callback is called when the read completes
 7302  * (GET_PROFILE_CONFG).  It will updated the resource
 7303  * descriptors, then queue the write (SET_PROFILE_CONFIG).
 7304  *
 7305  * On entry there are three memory areas that were allocated by
 7306  * ocs_hw_set_port_protocol.  If a failure is detected in this
 7307  * function those need to be freed.  If this function succeeds
 7308  * it allocates three more areas.
 7309  *
 7310  * @param hw Hardware context.
 7311  * @param status The status from the MQE
 7312  * @param mqe Pointer to mailbox command buffer.
 7313  * @param arg Pointer to a callback argument.
 7314  *
 7315  * @return Returns 0 on success, or a non-zero value otherwise.
 7316  */
 7317 static int32_t
 7318 ocs_hw_set_port_protocol_cb1(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
 7319 {
 7320         ocs_hw_set_port_protocol_cb_arg_t *cb_arg = arg;
 7321         ocs_dma_t *payload = &(cb_arg->payload);
 7322         sli4_res_common_get_profile_config_t* response = (sli4_res_common_get_profile_config_t*) payload->virt;
 7323         int num_descriptors;
 7324         sli4_resource_descriptor_v1_t *desc_p;
 7325         sli4_pcie_resource_descriptor_v1_t *pcie_desc_p;
 7326         int i;
 7327         ocs_hw_set_port_protocol_cb_arg_t *new_cb_arg;
 7328         ocs_hw_port_protocol_e new_protocol;
 7329         uint8_t *dst;
 7330         sli4_isap_resouce_descriptor_v1_t *isap_desc_p;
 7331         uint8_t *mbxdata;
 7332         int pci_descriptor_count;
 7333         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 7334         int num_fcoe_ports = 0;
 7335         int num_iscsi_ports = 0;
 7336 
 7337         new_protocol = (ocs_hw_port_protocol_e)cb_arg->new_protocol;
 7338 
 7339         num_descriptors = response->desc_count;
 7340 
 7341         /* Count PCI descriptors */
 7342         pci_descriptor_count = 0;
 7343         desc_p = (sli4_resource_descriptor_v1_t *)response->desc;
 7344         for (i=0; i<num_descriptors; i++) {
 7345                 if (desc_p->descriptor_type == SLI4_RESOURCE_DESCRIPTOR_TYPE_PCIE) {
 7346                         ++pci_descriptor_count;
 7347                 }
 7348                 desc_p = (sli4_resource_descriptor_v1_t *) ((uint8_t *)desc_p + desc_p->descriptor_length);
 7349         }
 7350 
 7351         /* mbxdata holds the header of the command */
 7352         mbxdata = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
 7353         if (mbxdata == NULL) {
 7354                 ocs_log_err(hw->os, "failed to malloc mbox\n");
 7355                 return OCS_HW_RTN_NO_MEMORY;
 7356         }
 7357 
 7358         /* cb_arg holds the data that will be passed to the callback on completion */
 7359         new_cb_arg = ocs_malloc(hw->os, sizeof(ocs_hw_set_port_protocol_cb_arg_t), OCS_M_NOWAIT);
 7360         if (new_cb_arg == NULL) {
 7361                 ocs_log_err(hw->os, "failed to malloc cb_arg\n");
 7362                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 7363                 return OCS_HW_RTN_NO_MEMORY;
 7364         }
 7365 
 7366         new_cb_arg->cb = cb_arg->cb;
 7367         new_cb_arg->arg = cb_arg->arg;
 7368 
 7369         /* Allocate memory for the descriptors we're going to send.  This is
 7370          * one for each PCI descriptor plus one ISAP descriptor. */
 7371         if (ocs_dma_alloc(hw->os, &new_cb_arg->payload, sizeof(sli4_req_common_set_profile_config_t) +
 7372                           (pci_descriptor_count * sizeof(sli4_pcie_resource_descriptor_v1_t)) +
 7373                           sizeof(sli4_isap_resouce_descriptor_v1_t), 4)) {
 7374                 ocs_log_err(hw->os, "Failed to allocate DMA buffer\n");
 7375                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 7376                 ocs_free(hw->os, new_cb_arg, sizeof(ocs_hw_set_port_protocol_cb_arg_t));
 7377                 return OCS_HW_RTN_NO_MEMORY;
 7378         }
 7379 
 7380         sli_cmd_common_set_profile_config(&hw->sli, mbxdata, SLI4_BMBX_SIZE,
 7381                                                    &new_cb_arg->payload,
 7382                                                    0, pci_descriptor_count+1, 1);
 7383 
 7384         /* Point dst to the first descriptor entry in the SET_PROFILE_CONFIG command */
 7385         dst = (uint8_t *)&(((sli4_req_common_set_profile_config_t *) new_cb_arg->payload.virt)->desc);
 7386 
 7387         /* Loop over all descriptors.  If the descriptor is a PCIe descriptor, copy it
 7388          * to the SET_PROFILE_CONFIG command to be written back.  If it's the descriptor
 7389          * that we're trying to change also set its pf_type.
 7390          */
 7391         desc_p = (sli4_resource_descriptor_v1_t *)response->desc;
 7392         for (i=0; i<num_descriptors; i++) {
 7393                 if (desc_p->descriptor_type == SLI4_RESOURCE_DESCRIPTOR_TYPE_PCIE) {
 7394                         pcie_desc_p = (sli4_pcie_resource_descriptor_v1_t*) desc_p;
 7395                         if (pcie_desc_p->pf_number == cb_arg->pci_func) {
 7396                                 /* This is the PCIe descriptor for this OCS instance.
 7397                                  * Update it with the new pf_type */
 7398                                 switch(new_protocol) {
 7399                                 case OCS_HW_PORT_PROTOCOL_FC:
 7400                                         pcie_desc_p->pf_type = SLI4_PROTOCOL_FC;
 7401                                         break;
 7402                                 case OCS_HW_PORT_PROTOCOL_FCOE:
 7403                                         pcie_desc_p->pf_type = SLI4_PROTOCOL_FCOE;
 7404                                         break;
 7405                                 case OCS_HW_PORT_PROTOCOL_ISCSI:
 7406                                         pcie_desc_p->pf_type = SLI4_PROTOCOL_ISCSI;
 7407                                         break;
 7408                                 default:
 7409                                         pcie_desc_p->pf_type = SLI4_PROTOCOL_DEFAULT;
 7410                                         break;
 7411                                 }
 7412                         }
 7413 
 7414                         if (pcie_desc_p->pf_type == SLI4_PROTOCOL_FCOE) {
 7415                                 ++num_fcoe_ports;
 7416                         }
 7417                         if (pcie_desc_p->pf_type == SLI4_PROTOCOL_ISCSI) {
 7418                                 ++num_iscsi_ports;
 7419                         }
 7420                         ocs_memcpy(dst, pcie_desc_p, sizeof(sli4_pcie_resource_descriptor_v1_t));
 7421                         dst += sizeof(sli4_pcie_resource_descriptor_v1_t);
 7422                 }
 7423 
 7424                 desc_p = (sli4_resource_descriptor_v1_t *) ((uint8_t *)desc_p + desc_p->descriptor_length);
 7425         }
 7426 
 7427         /* Create an ISAP resource descriptor */
 7428         isap_desc_p = (sli4_isap_resouce_descriptor_v1_t*)dst;
 7429         isap_desc_p->descriptor_type = SLI4_RESOURCE_DESCRIPTOR_TYPE_ISAP;
 7430         isap_desc_p->descriptor_length = sizeof(sli4_isap_resouce_descriptor_v1_t);
 7431         if (num_iscsi_ports > 0) {
 7432                 isap_desc_p->iscsi_tgt = 1;
 7433                 isap_desc_p->iscsi_ini = 1;
 7434                 isap_desc_p->iscsi_dif = 1;
 7435         }
 7436         if (num_fcoe_ports > 0) {
 7437                 isap_desc_p->fcoe_tgt = 1;
 7438                 isap_desc_p->fcoe_ini = 1;
 7439                 isap_desc_p->fcoe_dif = 1;
 7440         }
 7441 
 7442         /* At this point we're done with the memory allocated by ocs_port_set_protocol */
 7443         ocs_dma_free(hw->os, &cb_arg->payload);
 7444         ocs_free(hw->os, mqe, SLI4_BMBX_SIZE);
 7445         ocs_free(hw->os, cb_arg, sizeof(ocs_hw_set_port_protocol_cb_arg_t));
 7446 
 7447         /* Send a SET_PROFILE_CONFIG mailbox command with the new descriptors */
 7448         rc = ocs_hw_command(hw, mbxdata, OCS_CMD_NOWAIT, ocs_hw_set_port_protocol_cb2, new_cb_arg);
 7449         if (rc) {
 7450                 ocs_log_err(hw->os, "Error posting COMMON_SET_PROFILE_CONFIG\n");
 7451                 /* Call the upper level callback to report a failure */
 7452                 if (new_cb_arg->cb) {
 7453                         new_cb_arg->cb( rc, new_cb_arg->arg);
 7454                 }
 7455 
 7456                 /* Free the memory allocated by this function */
 7457                 ocs_dma_free(hw->os, &new_cb_arg->payload);
 7458                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 7459                 ocs_free(hw->os, new_cb_arg, sizeof(ocs_hw_set_port_protocol_cb_arg_t));
 7460         }
 7461 
 7462         return rc;
 7463 }
 7464 
 7465 /**
 7466  * @ingroup io
 7467  * @brief  Set the port protocol.
 7468  * @par Description
 7469  * Setting the port protocol is a read-modify-write operation.
 7470  * This function submits a GET_PROFILE_CONFIG command to read
 7471  * the current settings.  The callback function will modify the
 7472  * settings and issue the write.
 7473  *
 7474  * On successful completion this function will have allocated
 7475  * two regular memory areas and one dma area which will need to
 7476  * get freed later in the callbacks.
 7477  *
 7478  * @param hw Hardware context.
 7479  * @param new_protocol New protocol to use.
 7480  * @param pci_func PCI function to configure.
 7481  * @param cb Callback function to be called when the command completes.
 7482  * @param ul_arg An argument that is passed to the callback function.
 7483  *
 7484  * @return
 7485  * - OCS_HW_RTN_SUCCESS on success.
 7486  * - OCS_HW_RTN_NO_MEMORY if a malloc fails.
 7487  * - OCS_HW_RTN_NO_RESOURCES if unable to get a command
 7488  *   context.
 7489  * - OCS_HW_RTN_ERROR on any other error.
 7490  */
 7491 ocs_hw_rtn_e
 7492 ocs_hw_set_port_protocol(ocs_hw_t *hw, ocs_hw_port_protocol_e new_protocol,
 7493                 uint32_t pci_func, ocs_set_port_protocol_cb_t cb, void *ul_arg)
 7494 {
 7495         uint8_t *mbxdata;
 7496         ocs_hw_set_port_protocol_cb_arg_t *cb_arg;
 7497         ocs_hw_rtn_e rc = OCS_HW_RTN_ERROR;
 7498 
 7499         /* Only supported on Skyhawk */
 7500         if (sli_get_if_type(&hw->sli) != SLI4_IF_TYPE_BE3_SKH_PF) {
 7501                 return OCS_HW_RTN_ERROR;
 7502         }
 7503 
 7504         /* mbxdata holds the header of the command */
 7505         mbxdata = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
 7506         if (mbxdata == NULL) {
 7507                 ocs_log_err(hw->os, "failed to malloc mbox\n");
 7508                 return OCS_HW_RTN_NO_MEMORY;
 7509         }
 7510 
 7511         /* cb_arg holds the data that will be passed to the callback on completion */
 7512         cb_arg = ocs_malloc(hw->os, sizeof(ocs_hw_set_port_protocol_cb_arg_t), OCS_M_NOWAIT);
 7513         if (cb_arg == NULL) {
 7514                 ocs_log_err(hw->os, "failed to malloc cb_arg\n");
 7515                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 7516                 return OCS_HW_RTN_NO_MEMORY;
 7517         }
 7518 
 7519         cb_arg->cb = cb;
 7520         cb_arg->arg = ul_arg;
 7521         cb_arg->new_protocol = new_protocol;
 7522         cb_arg->pci_func = pci_func;
 7523 
 7524         /* dma_mem holds the non-embedded portion */
 7525         if (ocs_dma_alloc(hw->os, &cb_arg->payload, 4096, 4)) {
 7526                 ocs_log_err(hw->os, "Failed to allocate DMA buffer\n");
 7527                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 7528                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_get_port_protocol_cb_arg_t));
 7529                 return OCS_HW_RTN_NO_MEMORY;
 7530         }
 7531 
 7532         if (sli_cmd_common_get_profile_config(&hw->sli, mbxdata, SLI4_BMBX_SIZE, &cb_arg->payload)) {
 7533                 rc = ocs_hw_command(hw, mbxdata, OCS_CMD_NOWAIT, ocs_hw_set_port_protocol_cb1, cb_arg);
 7534         }
 7535 
 7536         if (rc != OCS_HW_RTN_SUCCESS) {
 7537                 ocs_log_test(hw->os, "GET_PROFILE_CONFIG failed\n");
 7538                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 7539                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_fw_write_cb_arg_t));
 7540                 ocs_dma_free(hw->os, &cb_arg->payload);
 7541         }
 7542 
 7543         return rc;
 7544 }
 7545 
 7546 typedef struct ocs_hw_get_profile_list_cb_arg_s {
 7547         ocs_get_profile_list_cb_t cb;
 7548         void *arg;
 7549         ocs_dma_t payload;
 7550 } ocs_hw_get_profile_list_cb_arg_t;
 7551 
 7552 /**
 7553  * @brief Called for the completion of get_profile_list for a
 7554  *        user request.
 7555  * @par Description
 7556  * This function is called when the COMMMON_GET_PROFILE_LIST
 7557  * mailbox completes.  The response will be in
 7558  * ctx->non_embedded_mem.virt.  This function parses the
 7559  * response and creates a ocs_hw_profile_list, then calls the
 7560  * mgmt_cb callback function and passes that list to it.
 7561  *
 7562  * @param hw Hardware context.
 7563  * @param status The status from the MQE
 7564  * @param mqe Pointer to mailbox command buffer.
 7565  * @param arg Pointer to a callback argument.
 7566  *
 7567  * @return Returns 0 on success, or a non-zero value on failure.
 7568  */
 7569 static int32_t
 7570 ocs_hw_get_profile_list_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
 7571 {
 7572         ocs_hw_profile_list_t *list;
 7573         ocs_hw_get_profile_list_cb_arg_t *cb_arg = arg;
 7574         ocs_dma_t *payload = &(cb_arg->payload);
 7575         sli4_res_common_get_profile_list_t *response = (sli4_res_common_get_profile_list_t *)payload->virt;
 7576         int i;
 7577         int num_descriptors;
 7578 
 7579         list = ocs_malloc(hw->os, sizeof(ocs_hw_profile_list_t), OCS_M_ZERO);
 7580         list->num_descriptors = response->profile_descriptor_count;
 7581 
 7582         num_descriptors = list->num_descriptors;
 7583         if (num_descriptors > OCS_HW_MAX_PROFILES) {
 7584                 num_descriptors = OCS_HW_MAX_PROFILES;
 7585         }
 7586 
 7587         for (i=0; i<num_descriptors; i++) {
 7588                 list->descriptors[i].profile_id = response->profile_descriptor[i].profile_id;
 7589                 list->descriptors[i].profile_index = response->profile_descriptor[i].profile_index;
 7590                 ocs_strcpy(list->descriptors[i].profile_description, (char *)response->profile_descriptor[i].profile_description);
 7591         }
 7592 
 7593         if (cb_arg->cb) {
 7594                 cb_arg->cb(status, list, cb_arg->arg);
 7595         } else {
 7596                 ocs_free(hw->os, list, sizeof(*list));
 7597         }
 7598 
 7599         ocs_free(hw->os, mqe, SLI4_BMBX_SIZE);
 7600         ocs_dma_free(hw->os, &cb_arg->payload);
 7601         ocs_free(hw->os, cb_arg, sizeof(ocs_hw_get_profile_list_cb_arg_t));
 7602 
 7603         return 0;
 7604 }
 7605 
 7606 /**
 7607  * @ingroup io
 7608  * @brief  Get a list of available profiles.
 7609  * @par Description
 7610  * Issues a SLI-4 COMMON_GET_PROFILE_LIST mailbox.  When the
 7611  * command completes the provided mgmt callback function is
 7612  * called.
 7613  *
 7614  * @param hw Hardware context.
 7615  * @param cb Callback function to be called when the
 7616  *                command completes.
 7617  * @param ul_arg An argument that is passed to the callback
 7618  *               function.
 7619  *
 7620  * @return
 7621  * - OCS_HW_RTN_SUCCESS on success.
 7622  * - OCS_HW_RTN_NO_MEMORY if a malloc fails.
 7623  * - OCS_HW_RTN_NO_RESOURCES if unable to get a command
 7624  *   context.
 7625  * - OCS_HW_RTN_ERROR on any other error.
 7626  */
 7627 ocs_hw_rtn_e
 7628 ocs_hw_get_profile_list(ocs_hw_t *hw, ocs_get_profile_list_cb_t cb, void* ul_arg)
 7629 {
 7630         uint8_t *mbxdata;
 7631         ocs_hw_get_profile_list_cb_arg_t *cb_arg;
 7632         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 7633 
 7634         /* Only supported on Skyhawk */
 7635         if (sli_get_if_type(&hw->sli) != SLI4_IF_TYPE_BE3_SKH_PF) {
 7636                 return OCS_HW_RTN_ERROR;
 7637         }
 7638 
 7639         /* mbxdata holds the header of the command */
 7640         mbxdata = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
 7641         if (mbxdata == NULL) {
 7642                 ocs_log_err(hw->os, "failed to malloc mbox\n");
 7643                 return OCS_HW_RTN_NO_MEMORY;
 7644         }
 7645 
 7646         /* cb_arg holds the data that will be passed to the callback on completion */
 7647         cb_arg = ocs_malloc(hw->os, sizeof(ocs_hw_get_profile_list_cb_arg_t), OCS_M_NOWAIT);
 7648         if (cb_arg == NULL) {
 7649                 ocs_log_err(hw->os, "failed to malloc cb_arg\n");
 7650                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 7651                 return OCS_HW_RTN_NO_MEMORY;
 7652         }
 7653 
 7654         cb_arg->cb = cb;
 7655         cb_arg->arg = ul_arg;
 7656 
 7657         /* dma_mem holds the non-embedded portion */
 7658         if (ocs_dma_alloc(hw->os, &cb_arg->payload, sizeof(sli4_res_common_get_profile_list_t), 4)) {
 7659                 ocs_log_err(hw->os, "Failed to allocate DMA buffer\n");
 7660                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 7661                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_get_profile_list_cb_arg_t));
 7662                 return OCS_HW_RTN_NO_MEMORY;
 7663         }
 7664 
 7665         if (sli_cmd_common_get_profile_list(&hw->sli, mbxdata, SLI4_BMBX_SIZE, 0, &cb_arg->payload)) {
 7666                 rc = ocs_hw_command(hw, mbxdata, OCS_CMD_NOWAIT, ocs_hw_get_profile_list_cb, cb_arg);
 7667         }
 7668 
 7669         if (rc != OCS_HW_RTN_SUCCESS) {
 7670                 ocs_log_test(hw->os, "GET_PROFILE_LIST failed\n");
 7671                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 7672                 ocs_dma_free(hw->os, &cb_arg->payload);
 7673                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_get_profile_list_cb_arg_t));
 7674         }
 7675 
 7676         return rc;
 7677 }
 7678 
 7679 typedef struct ocs_hw_get_active_profile_cb_arg_s {
 7680         ocs_get_active_profile_cb_t cb;
 7681         void *arg;
 7682 } ocs_hw_get_active_profile_cb_arg_t;
 7683 
 7684 /**
 7685  * @brief Called for the completion of get_active_profile for a
 7686  *        user request.
 7687  *
 7688  * @param hw Hardware context.
 7689  * @param status The status from the MQE
 7690  * @param mqe Pointer to mailbox command buffer.
 7691  * @param arg Pointer to a callback argument.
 7692  *
 7693  * @return Returns 0 on success, or a non-zero value on failure.
 7694  */
 7695 static int32_t
 7696 ocs_hw_get_active_profile_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
 7697 {
 7698         ocs_hw_get_active_profile_cb_arg_t *cb_arg = arg;
 7699         sli4_cmd_sli_config_t* mbox_rsp = (sli4_cmd_sli_config_t*) mqe;
 7700         sli4_res_common_get_active_profile_t* response = (sli4_res_common_get_active_profile_t*) mbox_rsp->payload.embed;
 7701         uint32_t active_profile;
 7702 
 7703         active_profile = response->active_profile_id;
 7704 
 7705         if (cb_arg->cb) {
 7706                 cb_arg->cb(status, active_profile, cb_arg->arg);
 7707         }
 7708 
 7709         ocs_free(hw->os, mqe, SLI4_BMBX_SIZE);
 7710         ocs_free(hw->os, cb_arg, sizeof(ocs_hw_get_active_profile_cb_arg_t));
 7711 
 7712         return 0;
 7713 }
 7714 
 7715 /**
 7716  * @ingroup io
 7717  * @brief  Get the currently active profile.
 7718  * @par Description
 7719  * Issues a SLI-4 COMMON_GET_ACTIVE_PROFILE mailbox. When the
 7720  * command completes the provided mgmt callback function is
 7721  * called.
 7722  *
 7723  * @param hw Hardware context.
 7724  * @param cb Callback function to be called when the
 7725  *           command completes.
 7726  * @param ul_arg An argument that is passed to the callback
 7727  *               function.
 7728  *
 7729  * @return
 7730  * - OCS_HW_RTN_SUCCESS on success.
 7731  * - OCS_HW_RTN_NO_MEMORY if a malloc fails.
 7732  * - OCS_HW_RTN_NO_RESOURCES if unable to get a command
 7733  *   context.
 7734  * - OCS_HW_RTN_ERROR on any other error.
 7735  */
 7736 int32_t
 7737 ocs_hw_get_active_profile(ocs_hw_t *hw, ocs_get_active_profile_cb_t cb, void* ul_arg)
 7738 {
 7739         uint8_t *mbxdata;
 7740         ocs_hw_get_active_profile_cb_arg_t *cb_arg;
 7741         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 7742 
 7743         /* Only supported on Skyhawk */
 7744         if (sli_get_if_type(&hw->sli) != SLI4_IF_TYPE_BE3_SKH_PF) {
 7745                 return OCS_HW_RTN_ERROR;
 7746         }
 7747 
 7748         /* mbxdata holds the header of the command */
 7749         mbxdata = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
 7750         if (mbxdata == NULL) {
 7751                 ocs_log_err(hw->os, "failed to malloc mbox\n");
 7752                 return OCS_HW_RTN_NO_MEMORY;
 7753         }
 7754 
 7755         /* cb_arg holds the data that will be passed to the callback on completion */
 7756         cb_arg = ocs_malloc(hw->os, sizeof(ocs_hw_get_active_profile_cb_arg_t), OCS_M_NOWAIT);
 7757         if (cb_arg == NULL) {
 7758                 ocs_log_err(hw->os, "failed to malloc cb_arg\n");
 7759                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 7760                 return OCS_HW_RTN_NO_MEMORY;
 7761         }
 7762 
 7763         cb_arg->cb = cb;
 7764         cb_arg->arg = ul_arg;
 7765 
 7766         if (sli_cmd_common_get_active_profile(&hw->sli, mbxdata, SLI4_BMBX_SIZE)) {
 7767                 rc = ocs_hw_command(hw, mbxdata, OCS_CMD_NOWAIT, ocs_hw_get_active_profile_cb, cb_arg);
 7768         }
 7769 
 7770         if (rc != OCS_HW_RTN_SUCCESS) {
 7771                 ocs_log_test(hw->os, "GET_ACTIVE_PROFILE failed\n");
 7772                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 7773                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_get_active_profile_cb_arg_t));
 7774         }
 7775 
 7776         return rc;
 7777 }
 7778 
 7779 typedef struct ocs_hw_get_nvparms_cb_arg_s {
 7780         ocs_get_nvparms_cb_t cb;
 7781         void *arg;
 7782 } ocs_hw_get_nvparms_cb_arg_t;
 7783 
 7784 /**
 7785  * @brief Called for the completion of get_nvparms for a
 7786  *        user request.
 7787  *
 7788  * @param hw Hardware context.
 7789  * @param status The status from the MQE.
 7790  * @param mqe Pointer to mailbox command buffer.
 7791  * @param arg Pointer to a callback argument.
 7792  *
 7793  * @return 0 on success, non-zero otherwise
 7794  */
 7795 static int32_t
 7796 ocs_hw_get_nvparms_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
 7797 {
 7798         ocs_hw_get_nvparms_cb_arg_t *cb_arg = arg;
 7799         sli4_cmd_read_nvparms_t* mbox_rsp = (sli4_cmd_read_nvparms_t*) mqe;
 7800 
 7801         if (cb_arg->cb) {
 7802                 cb_arg->cb(status, mbox_rsp->wwpn, mbox_rsp->wwnn, mbox_rsp->hard_alpa,
 7803                                 mbox_rsp->preferred_d_id, cb_arg->arg);
 7804         }
 7805 
 7806         ocs_free(hw->os, mqe, SLI4_BMBX_SIZE);
 7807         ocs_free(hw->os, cb_arg, sizeof(ocs_hw_get_nvparms_cb_arg_t));
 7808 
 7809         return 0;
 7810 }
 7811 
 7812 /**
 7813  * @ingroup io
 7814  * @brief  Read non-volatile parms.
 7815  * @par Description
 7816  * Issues a SLI-4 READ_NVPARMS mailbox. When the
 7817  * command completes the provided mgmt callback function is
 7818  * called.
 7819  *
 7820  * @param hw Hardware context.
 7821  * @param cb Callback function to be called when the
 7822  *        command completes.
 7823  * @param ul_arg An argument that is passed to the callback
 7824  *        function.
 7825  *
 7826  * @return
 7827  * - OCS_HW_RTN_SUCCESS on success.
 7828  * - OCS_HW_RTN_NO_MEMORY if a malloc fails.
 7829  * - OCS_HW_RTN_NO_RESOURCES if unable to get a command
 7830  *   context.
 7831  * - OCS_HW_RTN_ERROR on any other error.
 7832  */
 7833 int32_t
 7834 ocs_hw_get_nvparms(ocs_hw_t *hw, ocs_get_nvparms_cb_t cb, void* ul_arg)
 7835 {
 7836         uint8_t *mbxdata;
 7837         ocs_hw_get_nvparms_cb_arg_t *cb_arg;
 7838         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 7839 
 7840         /* mbxdata holds the header of the command */
 7841         mbxdata = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
 7842         if (mbxdata == NULL) {
 7843                 ocs_log_err(hw->os, "failed to malloc mbox\n");
 7844                 return OCS_HW_RTN_NO_MEMORY;
 7845         }
 7846 
 7847         /* cb_arg holds the data that will be passed to the callback on completion */
 7848         cb_arg = ocs_malloc(hw->os, sizeof(ocs_hw_get_nvparms_cb_arg_t), OCS_M_NOWAIT);
 7849         if (cb_arg == NULL) {
 7850                 ocs_log_err(hw->os, "failed to malloc cb_arg\n");
 7851                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 7852                 return OCS_HW_RTN_NO_MEMORY;
 7853         }
 7854 
 7855         cb_arg->cb = cb;
 7856         cb_arg->arg = ul_arg;
 7857 
 7858         if (sli_cmd_read_nvparms(&hw->sli, mbxdata, SLI4_BMBX_SIZE)) {
 7859                 rc = ocs_hw_command(hw, mbxdata, OCS_CMD_NOWAIT, ocs_hw_get_nvparms_cb, cb_arg);
 7860         }
 7861 
 7862         if (rc != OCS_HW_RTN_SUCCESS) {
 7863                 ocs_log_test(hw->os, "READ_NVPARMS failed\n");
 7864                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 7865                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_get_nvparms_cb_arg_t));
 7866         }
 7867 
 7868         return rc;
 7869 }
 7870 
 7871 typedef struct ocs_hw_set_nvparms_cb_arg_s {
 7872         ocs_set_nvparms_cb_t cb;
 7873         void *arg;
 7874 } ocs_hw_set_nvparms_cb_arg_t;
 7875 
 7876 /**
 7877  * @brief Called for the completion of set_nvparms for a
 7878  *        user request.
 7879  *
 7880  * @param hw Hardware context.
 7881  * @param status The status from the MQE.
 7882  * @param mqe Pointer to mailbox command buffer.
 7883  * @param arg Pointer to a callback argument.
 7884  *
 7885  * @return Returns 0 on success, or a non-zero value on failure.
 7886  */
 7887 static int32_t
 7888 ocs_hw_set_nvparms_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
 7889 {
 7890         ocs_hw_set_nvparms_cb_arg_t *cb_arg = arg;
 7891 
 7892         if (cb_arg->cb) {
 7893                 cb_arg->cb(status, cb_arg->arg);
 7894         }
 7895 
 7896         ocs_free(hw->os, mqe, SLI4_BMBX_SIZE);
 7897         ocs_free(hw->os, cb_arg, sizeof(ocs_hw_set_nvparms_cb_arg_t));
 7898 
 7899         return 0;
 7900 }
 7901 
 7902 /**
 7903  * @ingroup io
 7904  * @brief  Write non-volatile parms.
 7905  * @par Description
 7906  * Issues a SLI-4 WRITE_NVPARMS mailbox. When the
 7907  * command completes the provided mgmt callback function is
 7908  * called.
 7909  *
 7910  * @param hw Hardware context.
 7911  * @param cb Callback function to be called when the
 7912  *        command completes.
 7913  * @param wwpn Port's WWPN in big-endian order, or NULL to use default.
 7914  * @param wwnn Port's WWNN in big-endian order, or NULL to use default.
 7915  * @param hard_alpa A hard AL_PA address setting used during loop
 7916  * initialization. If no hard AL_PA is required, set to 0.
 7917  * @param preferred_d_id A preferred D_ID address setting
 7918  * that may be overridden with the CONFIG_LINK mailbox command.
 7919  * If there is no preference, set to 0.
 7920  * @param ul_arg An argument that is passed to the callback
 7921  *        function.
 7922  *
 7923  * @return
 7924  * - OCS_HW_RTN_SUCCESS on success.
 7925  * - OCS_HW_RTN_NO_MEMORY if a malloc fails.
 7926  * - OCS_HW_RTN_NO_RESOURCES if unable to get a command
 7927  *   context.
 7928  * - OCS_HW_RTN_ERROR on any other error.
 7929  */
 7930 int32_t
 7931 ocs_hw_set_nvparms(ocs_hw_t *hw, ocs_set_nvparms_cb_t cb, uint8_t *wwpn,
 7932                 uint8_t *wwnn, uint8_t hard_alpa, uint32_t preferred_d_id, void* ul_arg)
 7933 {
 7934         uint8_t *mbxdata;
 7935         ocs_hw_set_nvparms_cb_arg_t *cb_arg;
 7936         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 7937 
 7938         /* mbxdata holds the header of the command */
 7939         mbxdata = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
 7940         if (mbxdata == NULL) {
 7941                 ocs_log_err(hw->os, "failed to malloc mbox\n");
 7942                 return OCS_HW_RTN_NO_MEMORY;
 7943         }
 7944 
 7945         /* cb_arg holds the data that will be passed to the callback on completion */
 7946         cb_arg = ocs_malloc(hw->os, sizeof(ocs_hw_set_nvparms_cb_arg_t), OCS_M_NOWAIT);
 7947         if (cb_arg == NULL) {
 7948                 ocs_log_err(hw->os, "failed to malloc cb_arg\n");
 7949                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 7950                 return OCS_HW_RTN_NO_MEMORY;
 7951         }
 7952 
 7953         cb_arg->cb = cb;
 7954         cb_arg->arg = ul_arg;
 7955 
 7956         if (sli_cmd_write_nvparms(&hw->sli, mbxdata, SLI4_BMBX_SIZE, wwpn, wwnn, hard_alpa, preferred_d_id)) {
 7957                 rc = ocs_hw_command(hw, mbxdata, OCS_CMD_NOWAIT, ocs_hw_set_nvparms_cb, cb_arg);
 7958         }
 7959 
 7960         if (rc != OCS_HW_RTN_SUCCESS) {
 7961                 ocs_log_test(hw->os, "SET_NVPARMS failed\n");
 7962                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 7963                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_set_nvparms_cb_arg_t));
 7964         }
 7965 
 7966         return rc;
 7967 }
 7968 
 7969 /**
 7970  * @brief Called to obtain the count for the specified type.
 7971  *
 7972  * @param hw Hardware context.
 7973  * @param io_count_type IO count type (inuse, free, wait_free).
 7974  *
 7975  * @return Returns the number of IOs on the specified list type.
 7976  */
 7977 uint32_t
 7978 ocs_hw_io_get_count(ocs_hw_t *hw, ocs_hw_io_count_type_e io_count_type)
 7979 {
 7980         ocs_hw_io_t *io = NULL;
 7981         uint32_t count = 0;
 7982 
 7983         ocs_lock(&hw->io_lock);
 7984 
 7985         switch (io_count_type) {
 7986         case OCS_HW_IO_INUSE_COUNT :
 7987                 ocs_list_foreach(&hw->io_inuse, io) {
 7988                         count++;
 7989                 }
 7990                 break;
 7991         case OCS_HW_IO_FREE_COUNT :
 7992                  ocs_list_foreach(&hw->io_free, io) {
 7993                          count++;
 7994                  }
 7995                  break;
 7996         case OCS_HW_IO_WAIT_FREE_COUNT :
 7997                  ocs_list_foreach(&hw->io_wait_free, io) {
 7998                          count++;
 7999                  }
 8000                  break;
 8001         case OCS_HW_IO_PORT_OWNED_COUNT:
 8002                  ocs_list_foreach(&hw->io_port_owned, io) {
 8003                          count++;
 8004                  }
 8005                  break;
 8006         case OCS_HW_IO_N_TOTAL_IO_COUNT :
 8007                 count = hw->config.n_io;
 8008                 break;
 8009         }
 8010 
 8011         ocs_unlock(&hw->io_lock);
 8012 
 8013         return count;
 8014 }
 8015 
 8016 /**
 8017  * @brief Called to obtain the count of produced RQs.
 8018  *
 8019  * @param hw Hardware context.
 8020  *
 8021  * @return Returns the number of RQs produced.
 8022  */
 8023 uint32_t
 8024 ocs_hw_get_rqes_produced_count(ocs_hw_t *hw)
 8025 {
 8026         uint32_t count = 0;
 8027         uint32_t i;
 8028         uint32_t j;
 8029 
 8030         for (i = 0; i < hw->hw_rq_count; i++) {
 8031                 hw_rq_t *rq = hw->hw_rq[i];
 8032                 if (rq->rq_tracker != NULL) {
 8033                         for (j = 0; j < rq->entry_count; j++) {
 8034                                 if (rq->rq_tracker[j] != NULL) {
 8035                                         count++;
 8036                                 }
 8037                         }
 8038                 }
 8039         }
 8040 
 8041         return count;
 8042 }
 8043 
 8044 typedef struct ocs_hw_set_active_profile_cb_arg_s {
 8045         ocs_set_active_profile_cb_t cb;
 8046         void *arg;
 8047 } ocs_hw_set_active_profile_cb_arg_t;
 8048 
 8049 /**
 8050  * @brief Called for the completion of set_active_profile for a
 8051  *        user request.
 8052  *
 8053  * @param hw Hardware context.
 8054  * @param status The status from the MQE
 8055  * @param mqe Pointer to mailbox command buffer.
 8056  * @param arg Pointer to a callback argument.
 8057  *
 8058  * @return Returns 0 on success, or a non-zero value on failure.
 8059  */
 8060 static int32_t
 8061 ocs_hw_set_active_profile_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
 8062 {
 8063         ocs_hw_set_active_profile_cb_arg_t *cb_arg = arg;
 8064 
 8065         if (cb_arg->cb) {
 8066                 cb_arg->cb(status, cb_arg->arg);
 8067         }
 8068 
 8069         ocs_free(hw->os, mqe, SLI4_BMBX_SIZE);
 8070         ocs_free(hw->os, cb_arg, sizeof(ocs_hw_get_active_profile_cb_arg_t));
 8071 
 8072         return 0;
 8073 }
 8074 
 8075 /**
 8076  * @ingroup io
 8077  * @brief  Set the currently active profile.
 8078  * @par Description
 8079  * Issues a SLI4 COMMON_GET_ACTIVE_PROFILE mailbox. When the
 8080  * command completes the provided mgmt callback function is
 8081  * called.
 8082  *
 8083  * @param hw Hardware context.
 8084  * @param profile_id Profile ID to activate.
 8085  * @param cb Callback function to be called when the command completes.
 8086  * @param ul_arg An argument that is passed to the callback function.
 8087  *
 8088  * @return
 8089  * - OCS_HW_RTN_SUCCESS on success.
 8090  * - OCS_HW_RTN_NO_MEMORY if a malloc fails.
 8091  * - OCS_HW_RTN_NO_RESOURCES if unable to get a command
 8092  *   context.
 8093  * - OCS_HW_RTN_ERROR on any other error.
 8094  */
 8095 int32_t
 8096 ocs_hw_set_active_profile(ocs_hw_t *hw, ocs_set_active_profile_cb_t cb, uint32_t profile_id, void* ul_arg)
 8097 {
 8098         uint8_t *mbxdata;
 8099         ocs_hw_set_active_profile_cb_arg_t *cb_arg;
 8100         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 8101 
 8102         /* Only supported on Skyhawk */
 8103         if (sli_get_if_type(&hw->sli) != SLI4_IF_TYPE_BE3_SKH_PF) {
 8104                 return OCS_HW_RTN_ERROR;
 8105         }
 8106 
 8107         /* mbxdata holds the header of the command */
 8108         mbxdata = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
 8109         if (mbxdata == NULL) {
 8110                 ocs_log_err(hw->os, "failed to malloc mbox\n");
 8111                 return OCS_HW_RTN_NO_MEMORY;
 8112         }
 8113 
 8114         /* cb_arg holds the data that will be passed to the callback on completion */
 8115         cb_arg = ocs_malloc(hw->os, sizeof(ocs_hw_set_active_profile_cb_arg_t), OCS_M_NOWAIT);
 8116         if (cb_arg == NULL) {
 8117                 ocs_log_err(hw->os, "failed to malloc cb_arg\n");
 8118                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 8119                 return OCS_HW_RTN_NO_MEMORY;
 8120         }
 8121 
 8122         cb_arg->cb = cb;
 8123         cb_arg->arg = ul_arg;
 8124 
 8125         if (sli_cmd_common_set_active_profile(&hw->sli, mbxdata, SLI4_BMBX_SIZE, 0, profile_id)) {
 8126                 rc = ocs_hw_command(hw, mbxdata, OCS_CMD_NOWAIT, ocs_hw_set_active_profile_cb, cb_arg);
 8127         }
 8128 
 8129         if (rc != OCS_HW_RTN_SUCCESS) {
 8130                 ocs_log_test(hw->os, "SET_ACTIVE_PROFILE failed\n");
 8131                 ocs_free(hw->os, mbxdata, SLI4_BMBX_SIZE);
 8132                 ocs_free(hw->os, cb_arg, sizeof(ocs_hw_set_active_profile_cb_arg_t));
 8133         }
 8134 
 8135         return rc;
 8136 }
 8137 
 8138 /*
 8139  * Private functions
 8140  */
 8141 
 8142 /**
 8143  * @brief Update the queue hash with the ID and index.
 8144  *
 8145  * @param hash Pointer to hash table.
 8146  * @param id ID that was created.
 8147  * @param index The index into the hash object.
 8148  */
 8149 static void
 8150 ocs_hw_queue_hash_add(ocs_queue_hash_t *hash, uint16_t id, uint16_t index)
 8151 {
 8152         uint32_t        hash_index = id & (OCS_HW_Q_HASH_SIZE - 1);
 8153 
 8154         /*
 8155          * Since the hash is always bigger than the number of queues, then we
 8156          * never have to worry about an infinite loop.
 8157          */
 8158         while(hash[hash_index].in_use) {
 8159                 hash_index = (hash_index + 1) & (OCS_HW_Q_HASH_SIZE - 1);
 8160         }
 8161 
 8162         /* not used, claim the entry */
 8163         hash[hash_index].id = id;
 8164         hash[hash_index].in_use = 1;
 8165         hash[hash_index].index = index;
 8166 }
 8167 
 8168 /**
 8169  * @brief Find index given queue ID.
 8170  *
 8171  * @param hash Pointer to hash table.
 8172  * @param id ID to find.
 8173  *
 8174  * @return Returns the index into the HW cq array or -1 if not found.
 8175  */
 8176 int32_t
 8177 ocs_hw_queue_hash_find(ocs_queue_hash_t *hash, uint16_t id)
 8178 {
 8179         int32_t rc = -1;
 8180         int32_t index = id & (OCS_HW_Q_HASH_SIZE - 1);
 8181 
 8182         /*
 8183          * Since the hash is always bigger than the maximum number of Qs, then we
 8184          * never have to worry about an infinite loop. We will always find an
 8185          * unused entry.
 8186          */
 8187         do {
 8188                 if (hash[index].in_use &&
 8189                     hash[index].id == id) {
 8190                         rc = hash[index].index;
 8191                 } else {
 8192                         index = (index + 1) & (OCS_HW_Q_HASH_SIZE - 1);
 8193                 }
 8194         } while(rc == -1 && hash[index].in_use);
 8195 
 8196         return rc;
 8197 }
 8198 
 8199 static int32_t
 8200 ocs_hw_domain_add(ocs_hw_t *hw, ocs_domain_t *domain)
 8201 {
 8202         int32_t         rc = OCS_HW_RTN_ERROR;
 8203         uint16_t        fcfi = UINT16_MAX;
 8204 
 8205         if ((hw == NULL) || (domain == NULL)) {
 8206                 ocs_log_err(NULL, "bad parameter hw=%p domain=%p\n",
 8207                                 hw, domain);
 8208                 return OCS_HW_RTN_ERROR;
 8209         }
 8210 
 8211         fcfi = domain->fcf_indicator;
 8212 
 8213         if (fcfi < SLI4_MAX_FCFI) {
 8214                 uint16_t        fcf_index = UINT16_MAX;
 8215 
 8216                 ocs_log_debug(hw->os, "adding domain %p @ %#x\n",
 8217                                 domain, fcfi);
 8218                 hw->domains[fcfi] = domain;
 8219 
 8220                 /* HW_WORKAROUND_OVERRIDE_FCFI_IN_SRB */
 8221                 if (hw->workaround.override_fcfi) {
 8222                         if (hw->first_domain_idx < 0) {
 8223                                 hw->first_domain_idx = fcfi;
 8224                         }
 8225                 }
 8226 
 8227                 fcf_index = domain->fcf;
 8228 
 8229                 if (fcf_index < SLI4_MAX_FCF_INDEX) {
 8230                         ocs_log_debug(hw->os, "adding map of FCF index %d to FCFI %d\n",
 8231                                       fcf_index, fcfi);
 8232                         hw->fcf_index_fcfi[fcf_index] = fcfi;
 8233                         rc = OCS_HW_RTN_SUCCESS;
 8234                 } else {
 8235                         ocs_log_test(hw->os, "FCF index %d out of range (max %d)\n",
 8236                                      fcf_index, SLI4_MAX_FCF_INDEX);
 8237                         hw->domains[fcfi] = NULL;
 8238                 }
 8239         } else {
 8240                 ocs_log_test(hw->os, "FCFI %#x out of range (max %#x)\n",
 8241                                 fcfi, SLI4_MAX_FCFI);
 8242         }
 8243 
 8244         return rc;
 8245 }
 8246 
 8247 static int32_t
 8248 ocs_hw_domain_del(ocs_hw_t *hw, ocs_domain_t *domain)
 8249 {
 8250         int32_t         rc = OCS_HW_RTN_ERROR;
 8251         uint16_t        fcfi = UINT16_MAX;
 8252 
 8253         if ((hw == NULL) || (domain == NULL)) {
 8254                 ocs_log_err(NULL, "bad parameter hw=%p domain=%p\n",
 8255                                 hw, domain);
 8256                 return OCS_HW_RTN_ERROR;
 8257         }
 8258 
 8259         fcfi = domain->fcf_indicator;
 8260 
 8261         if (fcfi < SLI4_MAX_FCFI) {
 8262                 uint16_t        fcf_index = UINT16_MAX;
 8263 
 8264                 ocs_log_debug(hw->os, "deleting domain %p @ %#x\n",
 8265                                 domain, fcfi);
 8266 
 8267                 if (domain != hw->domains[fcfi]) {
 8268                         ocs_log_test(hw->os, "provided domain %p does not match stored domain %p\n",
 8269                                      domain, hw->domains[fcfi]);
 8270                         return OCS_HW_RTN_ERROR;
 8271                 }
 8272 
 8273                 hw->domains[fcfi] = NULL;
 8274 
 8275                 /* HW_WORKAROUND_OVERRIDE_FCFI_IN_SRB */
 8276                 if (hw->workaround.override_fcfi) {
 8277                         if (hw->first_domain_idx == fcfi) {
 8278                                 hw->first_domain_idx = -1;
 8279                         }
 8280                 }
 8281 
 8282                 fcf_index = domain->fcf;
 8283 
 8284                 if (fcf_index < SLI4_MAX_FCF_INDEX) {
 8285                         if (hw->fcf_index_fcfi[fcf_index] == fcfi) {
 8286                                 hw->fcf_index_fcfi[fcf_index] = 0;
 8287                                 rc = OCS_HW_RTN_SUCCESS;
 8288                         } else {
 8289                                 ocs_log_test(hw->os, "indexed FCFI %#x doesn't match provided %#x @ %d\n",
 8290                                              hw->fcf_index_fcfi[fcf_index], fcfi, fcf_index);
 8291                         }
 8292                 } else {
 8293                         ocs_log_test(hw->os, "FCF index %d out of range (max %d)\n",
 8294                                      fcf_index, SLI4_MAX_FCF_INDEX);
 8295                 }
 8296         } else {
 8297                 ocs_log_test(hw->os, "FCFI %#x out of range (max %#x)\n",
 8298                                 fcfi, SLI4_MAX_FCFI);
 8299         }
 8300 
 8301         return rc;
 8302 }
 8303 
 8304 ocs_domain_t *
 8305 ocs_hw_domain_get(ocs_hw_t *hw, uint16_t fcfi)
 8306 {
 8307 
 8308         if (hw == NULL) {
 8309                 ocs_log_err(NULL, "bad parameter hw=%p\n", hw);
 8310                 return NULL;
 8311         }
 8312 
 8313         if (fcfi < SLI4_MAX_FCFI) {
 8314                 return hw->domains[fcfi];
 8315         } else {
 8316                 ocs_log_test(hw->os, "FCFI %#x out of range (max %#x)\n",
 8317                                 fcfi, SLI4_MAX_FCFI);
 8318                 return NULL;
 8319         }
 8320 }
 8321 
 8322 static ocs_domain_t *
 8323 ocs_hw_domain_get_indexed(ocs_hw_t *hw, uint16_t fcf_index)
 8324 {
 8325 
 8326         if (hw == NULL) {
 8327                 ocs_log_err(NULL, "bad parameter hw=%p\n", hw);
 8328                 return NULL;
 8329         }
 8330 
 8331         if (fcf_index < SLI4_MAX_FCF_INDEX) {
 8332                 return ocs_hw_domain_get(hw, hw->fcf_index_fcfi[fcf_index]);
 8333         } else {
 8334                 ocs_log_test(hw->os, "FCF index %d out of range (max %d)\n",
 8335                              fcf_index, SLI4_MAX_FCF_INDEX);
 8336                 return NULL;
 8337         }
 8338 }
 8339 
 8340 /**
 8341  * @brief Quaratine an IO by taking a reference count and adding it to the
 8342  *        quarantine list. When the IO is popped from the list then the
 8343  *        count is released and the IO MAY be freed depending on whether
 8344  *        it is still referenced by the IO.
 8345  *
 8346  *        @n @b Note: BZ 160124 - If this is a target write or an initiator read using
 8347  *        DIF, then we must add the XRI to a quarantine list until we receive
 8348  *        4 more completions of this same type.
 8349  *
 8350  * @param hw Hardware context.
 8351  * @param wq Pointer to the WQ associated with the IO object to quarantine.
 8352  * @param io Pointer to the io object to quarantine.
 8353  */
 8354 static void
 8355 ocs_hw_io_quarantine(ocs_hw_t *hw, hw_wq_t *wq, ocs_hw_io_t *io)
 8356 {
 8357         ocs_quarantine_info_t *q_info = &wq->quarantine_info;
 8358         uint32_t        index;
 8359         ocs_hw_io_t     *free_io = NULL;
 8360 
 8361         /* return if the QX bit was clear */
 8362         if (!io->quarantine) {
 8363                 return;
 8364         }
 8365 
 8366         /* increment the IO refcount to prevent it from being freed before the quarantine is over */
 8367         if (ocs_ref_get_unless_zero(&io->ref) == 0) {
 8368                 /* command no longer active */
 8369                 ocs_log_debug(hw ? hw->os : NULL,
 8370                               "io not active xri=0x%x tag=0x%x\n",
 8371                               io->indicator, io->reqtag);
 8372                 return;
 8373         }
 8374 
 8375         sli_queue_lock(wq->queue);
 8376                 index = q_info->quarantine_index;
 8377                 free_io = q_info->quarantine_ios[index];
 8378                 q_info->quarantine_ios[index] = io;
 8379                 q_info->quarantine_index = (index + 1) % OCS_HW_QUARANTINE_QUEUE_DEPTH;
 8380         sli_queue_unlock(wq->queue);
 8381 
 8382         if (free_io != NULL) {
 8383                 ocs_ref_put(&free_io->ref); /* ocs_ref_get(): same function */
 8384         }
 8385 }
 8386 
 8387 /**
 8388  * @brief Process entries on the given completion queue.
 8389  *
 8390  * @param hw Hardware context.
 8391  * @param cq Pointer to the HW completion queue object.
 8392  *
 8393  * @return None.
 8394  */
 8395 void
 8396 ocs_hw_cq_process(ocs_hw_t *hw, hw_cq_t *cq)
 8397 {
 8398         uint8_t         cqe[sizeof(sli4_mcqe_t)];
 8399         uint16_t        rid = UINT16_MAX;
 8400         sli4_qentry_e   ctype;          /* completion type */
 8401         int32_t         status;
 8402         uint32_t        n_processed = 0;
 8403         time_t          tstart;
 8404         time_t          telapsed;
 8405 
 8406         tstart = ocs_msectime();
 8407 
 8408         while (!sli_queue_read(&hw->sli, cq->queue, cqe)) {
 8409                 status = sli_cq_parse(&hw->sli, cq->queue, cqe, &ctype, &rid);
 8410                 /*
 8411                  * The sign of status is significant. If status is:
 8412                  * == 0 : call completed correctly and the CQE indicated success
 8413                  *  > 0 : call completed correctly and the CQE indicated an error
 8414                  *  < 0 : call failed and no information is available about the CQE
 8415                  */
 8416                 if (status < 0) {
 8417                         if (status == -2) {
 8418                                 /* Notification that an entry was consumed, but not completed */
 8419                                 continue;
 8420                         }
 8421 
 8422                         break;
 8423                 }
 8424 
 8425                 switch (ctype) {
 8426                 case SLI_QENTRY_ASYNC:
 8427                         CPUTRACE("async");
 8428                         sli_cqe_async(&hw->sli, cqe);
 8429                         break;
 8430                 case SLI_QENTRY_MQ:
 8431                         /*
 8432                          * Process MQ entry. Note there is no way to determine
 8433                          * the MQ_ID from the completion entry.
 8434                          */
 8435                         CPUTRACE("mq");
 8436                         ocs_hw_mq_process(hw, status, hw->mq);
 8437                         break;
 8438                 case SLI_QENTRY_OPT_WRITE_CMD:
 8439                         ocs_hw_rqpair_process_auto_xfr_rdy_cmd(hw, cq, cqe);
 8440                         break;
 8441                 case SLI_QENTRY_OPT_WRITE_DATA:
 8442                         ocs_hw_rqpair_process_auto_xfr_rdy_data(hw, cq, cqe);
 8443                         break;
 8444                 case SLI_QENTRY_WQ:
 8445                         CPUTRACE("wq");
 8446                         ocs_hw_wq_process(hw, cq, cqe, status, rid);
 8447                         break;
 8448                 case SLI_QENTRY_WQ_RELEASE: {
 8449                         uint32_t wq_id = rid;
 8450                         int32_t index = ocs_hw_queue_hash_find(hw->wq_hash, wq_id);
 8451 
 8452                         if (unlikely(index < 0)) {
 8453                                 ocs_log_err(hw->os, "unknown idx=%#x rid=%#x\n",
 8454                                             index, rid);
 8455                                 break;
 8456                         }
 8457 
 8458                         hw_wq_t *wq = hw->hw_wq[index];
 8459 
 8460                         /* Submit any HW IOs that are on the WQ pending list */
 8461                         hw_wq_submit_pending(wq, wq->wqec_set_count);
 8462 
 8463                         break;
 8464                 }
 8465 
 8466                 case SLI_QENTRY_RQ:
 8467                         CPUTRACE("rq");
 8468                         ocs_hw_rqpair_process_rq(hw, cq, cqe);
 8469                         break;
 8470                 case SLI_QENTRY_XABT: {
 8471                         CPUTRACE("xabt");
 8472                         ocs_hw_xabt_process(hw, cq, cqe, rid);
 8473                         break;
 8474                 }
 8475                 default:
 8476                         ocs_log_test(hw->os, "unhandled ctype=%#x rid=%#x\n", ctype, rid);
 8477                         break;
 8478                 }
 8479 
 8480                 n_processed++;
 8481                 if (n_processed == cq->queue->proc_limit) {
 8482                         break;
 8483                 }
 8484 
 8485                 if (cq->queue->n_posted >= (cq->queue->posted_limit)) {
 8486                         sli_queue_arm(&hw->sli, cq->queue, FALSE);
 8487                 }
 8488         }
 8489 
 8490         sli_queue_arm(&hw->sli, cq->queue, TRUE);
 8491 
 8492         if (n_processed > cq->queue->max_num_processed) {
 8493                 cq->queue->max_num_processed = n_processed;
 8494         }
 8495         telapsed = ocs_msectime() - tstart;
 8496         if (telapsed > cq->queue->max_process_time) {
 8497                 cq->queue->max_process_time = telapsed;
 8498         }
 8499 }
 8500 
 8501 /**
 8502  * @brief Process WQ completion queue entries.
 8503  *
 8504  * @param hw Hardware context.
 8505  * @param cq Pointer to the HW completion queue object.
 8506  * @param cqe Pointer to WQ completion queue.
 8507  * @param status Completion status.
 8508  * @param rid Resource ID (IO tag).
 8509  *
 8510  * @return none
 8511  */
 8512 void
 8513 ocs_hw_wq_process(ocs_hw_t *hw, hw_cq_t *cq, uint8_t *cqe, int32_t status, uint16_t rid)
 8514 {
 8515         hw_wq_callback_t *wqcb;
 8516 
 8517         ocs_queue_history_cqe(&hw->q_hist, SLI_QENTRY_WQ, (void *)cqe, ((sli4_fc_wcqe_t *)cqe)->status, cq->queue->id,
 8518                               ((cq->queue->index - 1) & (cq->queue->length - 1)));
 8519 
 8520         if(rid == OCS_HW_REQUE_XRI_REGTAG) {
 8521                 if(status) {
 8522                         ocs_log_err(hw->os, "reque xri failed, status = %d \n", status);
 8523                 }
 8524                 return;
 8525         }
 8526 
 8527         wqcb = ocs_hw_reqtag_get_instance(hw, rid);
 8528         if (wqcb == NULL) {
 8529                 ocs_log_err(hw->os, "invalid request tag: x%x\n", rid);
 8530                 return;
 8531         }
 8532 
 8533         if (wqcb->callback == NULL) {
 8534                 ocs_log_err(hw->os, "wqcb callback is NULL\n");
 8535                 return;
 8536         }
 8537 
 8538         (*wqcb->callback)(wqcb->arg, cqe, status);
 8539 }
 8540 
 8541 /**
 8542  * @brief Process WQ completions for IO requests
 8543  *
 8544  * @param arg Generic callback argument
 8545  * @param cqe Pointer to completion queue entry
 8546  * @param status Completion status
 8547  *
 8548  * @par Description
 8549  * @n @b Note:  Regarding io->reqtag, the reqtag is assigned once when HW IOs are initialized
 8550  * in ocs_hw_setup_io(), and don't need to be returned to the hw->wq_reqtag_pool.
 8551  *
 8552  * @return None.
 8553  */
 8554 static void
 8555 ocs_hw_wq_process_io(void *arg, uint8_t *cqe, int32_t status)
 8556 {
 8557         ocs_hw_io_t *io = arg;
 8558         ocs_hw_t *hw = io->hw;
 8559         sli4_fc_wcqe_t *wcqe = (void *)cqe;
 8560         uint32_t        len = 0;
 8561         uint32_t ext = 0;
 8562         uint8_t out_of_order_axr_cmd = 0;
 8563         uint8_t out_of_order_axr_data = 0;
 8564         uint8_t lock_taken = 0;
 8565 #if defined(OCS_DISC_SPIN_DELAY)
 8566         uint32_t delay = 0;
 8567         char prop_buf[32];
 8568 #endif
 8569 
 8570         /*
 8571          * For the primary IO, this will also be used for the
 8572          * response. So it is important to only set/clear this
 8573          * flag on the first data phase of the IO because
 8574          * subsequent phases will be done on the secondary XRI.
 8575          */
 8576         if (io->quarantine && io->quarantine_first_phase) {
 8577                 io->quarantine = (wcqe->qx == 1);
 8578                 ocs_hw_io_quarantine(hw, io->wq, io);
 8579         }
 8580         io->quarantine_first_phase = FALSE;
 8581 
 8582         /* BZ 161832 - free secondary HW IO */
 8583         if (io->sec_hio != NULL &&
 8584             io->sec_hio->quarantine) {
 8585                 /*
 8586                  * If the quarantine flag is set on the
 8587                  * IO, then set it on the secondary IO
 8588                  * based on the quarantine XRI (QX) bit
 8589                  * sent by the FW.
 8590                  */
 8591                 io->sec_hio->quarantine = (wcqe->qx == 1);
 8592                 /* use the primary io->wq because it is not set on the secondary IO. */
 8593                 ocs_hw_io_quarantine(hw, io->wq, io->sec_hio);
 8594         }
 8595 
 8596         ocs_hw_remove_io_timed_wqe(hw, io);
 8597 
 8598         /* clear xbusy flag if WCQE[XB] is clear */
 8599         if (io->xbusy && wcqe->xb == 0) {
 8600                 io->xbusy = FALSE;
 8601         }
 8602 
 8603         /* get extended CQE status */
 8604         switch (io->type) {
 8605         case OCS_HW_BLS_ACC:
 8606         case OCS_HW_BLS_ACC_SID:
 8607                 break;
 8608         case OCS_HW_ELS_REQ:
 8609                 sli_fc_els_did(&hw->sli, cqe, &ext);
 8610                 len = sli_fc_response_length(&hw->sli, cqe);
 8611                 break;
 8612         case OCS_HW_ELS_RSP:
 8613         case OCS_HW_ELS_RSP_SID:
 8614         case OCS_HW_FC_CT_RSP:
 8615                 break;
 8616         case OCS_HW_FC_CT:
 8617                 len = sli_fc_response_length(&hw->sli, cqe);
 8618                 break;
 8619         case OCS_HW_IO_TARGET_WRITE:
 8620                 len = sli_fc_io_length(&hw->sli, cqe);
 8621 #if defined(OCS_DISC_SPIN_DELAY)
 8622                 if (ocs_get_property("disk_spin_delay", prop_buf, sizeof(prop_buf)) == 0) {
 8623                         delay = ocs_strtoul(prop_buf, 0, 0);
 8624                         ocs_udelay(delay);
 8625                 }
 8626 #endif
 8627                 break;
 8628         case OCS_HW_IO_TARGET_READ:
 8629                 len = sli_fc_io_length(&hw->sli, cqe);
 8630                 /*
 8631                  * if_type == 2 seems to return 0 "total length placed" on
 8632                  * FCP_TSEND64_WQE completions. If this appears to happen,
 8633                  * use the CTIO data transfer length instead.
 8634                  */
 8635                 if (hw->workaround.retain_tsend_io_length && !len && !status) {
 8636                         len = io->length;
 8637                 }
 8638 
 8639                 break;
 8640         case OCS_HW_IO_TARGET_RSP:
 8641                 if(io->is_port_owned) {
 8642                         ocs_lock(&io->axr_lock);
 8643                         lock_taken = 1;
 8644                         if(io->axr_buf->call_axr_cmd) {
 8645                                 out_of_order_axr_cmd = 1;
 8646                         }
 8647                         if(io->axr_buf->call_axr_data) {
 8648                                 out_of_order_axr_data = 1;
 8649                         }
 8650                 }
 8651                 break;
 8652         case OCS_HW_IO_INITIATOR_READ:
 8653                 len = sli_fc_io_length(&hw->sli, cqe);
 8654                 break;
 8655         case OCS_HW_IO_INITIATOR_WRITE:
 8656                 len = sli_fc_io_length(&hw->sli, cqe);
 8657                 break;
 8658         case OCS_HW_IO_INITIATOR_NODATA:
 8659                 break;
 8660         case OCS_HW_IO_DNRX_REQUEUE:
 8661                 /* release the count for re-posting the buffer */
 8662                 //ocs_hw_io_free(hw, io);
 8663                 break;
 8664         default:
 8665                 ocs_log_test(hw->os, "XXX unhandled io type %#x for XRI 0x%x\n",
 8666                              io->type, io->indicator);
 8667                 break;
 8668         }
 8669         if (status) {
 8670                 ext = sli_fc_ext_status(&hw->sli, cqe);
 8671                 /* Emulate IAAB=0 for initiator WQEs only; i.e. automatically
 8672                  * abort exchange if an error occurred and exchange is still busy.
 8673                  */
 8674                 if (hw->config.i_only_aab &&
 8675                     (ocs_hw_iotype_is_originator(io->type)) &&
 8676                     (ocs_hw_wcqe_abort_needed(status, ext, wcqe->xb))) {
 8677                         ocs_hw_rtn_e rc;
 8678 
 8679                         ocs_log_debug(hw->os, "aborting xri=%#x tag=%#x\n",
 8680                                       io->indicator, io->reqtag);
 8681                         /*
 8682                          * Because the initiator will not issue another IO phase, then it is OK to to issue the
 8683                          * callback on the abort completion, but for consistency with the target, wait for the
 8684                          * XRI_ABORTED CQE to issue the IO callback.
 8685                          */
 8686                         rc = ocs_hw_io_abort(hw, io, TRUE, NULL, NULL);
 8687 
 8688                         if (rc == OCS_HW_RTN_SUCCESS) {
 8689                                 /* latch status to return after abort is complete */
 8690                                 io->status_saved = 1;
 8691                                 io->saved_status = status;
 8692                                 io->saved_ext = ext;
 8693                                 io->saved_len = len;
 8694                                 goto exit_ocs_hw_wq_process_io;
 8695                         } else if (rc == OCS_HW_RTN_IO_ABORT_IN_PROGRESS) {
 8696                                 /*
 8697                                  * Already being aborted by someone else (ABTS
 8698                                  * perhaps). Just fall through and return original
 8699                                  * error.
 8700                                  */
 8701                                 ocs_log_debug(hw->os, "abort in progress xri=%#x tag=%#x\n",
 8702                                               io->indicator, io->reqtag);
 8703 
 8704                         } else {
 8705                                 /* Failed to abort for some other reason, log error */
 8706                                 ocs_log_test(hw->os, "Failed to abort xri=%#x tag=%#x rc=%d\n",
 8707                                              io->indicator, io->reqtag, rc);
 8708                         }
 8709                 }
 8710 
 8711                 /*
 8712                  * If we're not an originator IO, and XB is set, then issue abort for the IO from within the HW
 8713                  */
 8714                 if ( (! ocs_hw_iotype_is_originator(io->type)) && wcqe->xb) {
 8715                         ocs_hw_rtn_e rc;
 8716 
 8717                         ocs_log_debug(hw->os, "aborting xri=%#x tag=%#x\n", io->indicator, io->reqtag);
 8718 
 8719                         /*
 8720                          * Because targets may send a response when the IO completes using the same XRI, we must
 8721                          * wait for the XRI_ABORTED CQE to issue the IO callback
 8722                          */
 8723                         rc = ocs_hw_io_abort(hw, io, FALSE, NULL, NULL);
 8724                         if (rc == OCS_HW_RTN_SUCCESS) {
 8725                                 /* latch status to return after abort is complete */
 8726                                 io->status_saved = 1;
 8727                                 io->saved_status = status;
 8728                                 io->saved_ext = ext;
 8729                                 io->saved_len = len;
 8730                                 goto exit_ocs_hw_wq_process_io;
 8731                         } else if (rc == OCS_HW_RTN_IO_ABORT_IN_PROGRESS) {
 8732                                 /*
 8733                                  * Already being aborted by someone else (ABTS
 8734                                  * perhaps). Just fall through and return original
 8735                                  * error.
 8736                                  */
 8737                                 ocs_log_debug(hw->os, "abort in progress xri=%#x tag=%#x\n",
 8738                                               io->indicator, io->reqtag);
 8739 
 8740                         } else {
 8741                                 /* Failed to abort for some other reason, log error */
 8742                                 ocs_log_test(hw->os, "Failed to abort xri=%#x tag=%#x rc=%d\n",
 8743                                              io->indicator, io->reqtag, rc);
 8744                         }
 8745                 }
 8746         }
 8747         /* BZ 161832 - free secondary HW IO */
 8748         if (io->sec_hio != NULL) {
 8749                 ocs_hw_io_free(hw, io->sec_hio);
 8750                 io->sec_hio = NULL;
 8751         }
 8752 
 8753         if (io->done != NULL) {
 8754                 ocs_hw_done_t  done = io->done;
 8755                 void            *arg = io->arg;
 8756 
 8757                 io->done = NULL;
 8758 
 8759                 if (io->status_saved) {
 8760                         /* use latched status if exists */
 8761                         status = io->saved_status;
 8762                         len = io->saved_len;
 8763                         ext = io->saved_ext;
 8764                         io->status_saved = 0;
 8765                 }
 8766 
 8767                 /* Restore default SGL */
 8768                 ocs_hw_io_restore_sgl(hw, io);
 8769                 done(io, io->rnode, len, status, ext, arg);
 8770         }
 8771 
 8772         if(out_of_order_axr_cmd) {
 8773                 /* bounce enabled, single RQ, we snoop the ox_id to choose the cpuidx */
 8774                 if (hw->config.bounce) {
 8775                         fc_header_t *hdr = io->axr_buf->cmd_seq->header->dma.virt;
 8776                         uint32_t s_id = fc_be24toh(hdr->s_id);
 8777                         uint32_t d_id = fc_be24toh(hdr->d_id);
 8778                         uint32_t ox_id =  ocs_be16toh(hdr->ox_id);
 8779                         if (hw->callback.bounce != NULL) {
 8780                                 (*hw->callback.bounce)(ocs_hw_unsol_process_bounce, io->axr_buf->cmd_seq, s_id, d_id, ox_id);
 8781                         }
 8782                 }else {
 8783                         hw->callback.unsolicited(hw->args.unsolicited, io->axr_buf->cmd_seq);
 8784                 }
 8785 
 8786                 if(out_of_order_axr_data) {
 8787                         /* bounce enabled, single RQ, we snoop the ox_id to choose the cpuidx */
 8788                         if (hw->config.bounce) {
 8789                                 fc_header_t *hdr = io->axr_buf->seq.header->dma.virt;
 8790                                 uint32_t s_id = fc_be24toh(hdr->s_id);
 8791                                 uint32_t d_id = fc_be24toh(hdr->d_id);
 8792                                 uint32_t ox_id =  ocs_be16toh(hdr->ox_id);
 8793                                 if (hw->callback.bounce != NULL) {
 8794                                         (*hw->callback.bounce)(ocs_hw_unsol_process_bounce, &io->axr_buf->seq, s_id, d_id, ox_id);
 8795                                 }
 8796                         }else {
 8797                                 hw->callback.unsolicited(hw->args.unsolicited, &io->axr_buf->seq);
 8798                         }
 8799                 }
 8800         }
 8801 
 8802 exit_ocs_hw_wq_process_io:
 8803         if(lock_taken) {
 8804                 ocs_unlock(&io->axr_lock);
 8805         }       
 8806 }
 8807 
 8808 /**
 8809  * @brief Process WQ completions for abort requests.
 8810  *
 8811  * @param arg Generic callback argument.
 8812  * @param cqe Pointer to completion queue entry.
 8813  * @param status Completion status.
 8814  *
 8815  * @return None.
 8816  */
 8817 static void
 8818 ocs_hw_wq_process_abort(void *arg, uint8_t *cqe, int32_t status)
 8819 {
 8820         ocs_hw_io_t *io = arg;
 8821         ocs_hw_t *hw = io->hw;
 8822         uint32_t ext = 0;
 8823         uint32_t len = 0;
 8824         hw_wq_callback_t *wqcb;
 8825 
 8826         /*
 8827          * For IOs that were aborted internally, we may need to issue the callback here depending
 8828          * on whether a XRI_ABORTED CQE is expected ot not. If the status is Local Reject/No XRI, then
 8829          * issue the callback now.
 8830         */
 8831         ext = sli_fc_ext_status(&hw->sli, cqe);
 8832         if (status == SLI4_FC_WCQE_STATUS_LOCAL_REJECT &&
 8833             ext == SLI4_FC_LOCAL_REJECT_NO_XRI &&
 8834                 io->done != NULL) {
 8835                 ocs_hw_done_t  done = io->done;
 8836                 void            *arg = io->arg;
 8837 
 8838                 io->done = NULL;
 8839 
 8840                 /*
 8841                  * Use latched status as this is always saved for an internal abort
 8842                  *
 8843                  * Note: We wont have both a done and abort_done function, so don't worry about
 8844                  *       clobbering the len, status and ext fields.
 8845                  */
 8846                 status = io->saved_status;
 8847                 len = io->saved_len;
 8848                 ext = io->saved_ext;
 8849                 io->status_saved = 0;
 8850                 done(io, io->rnode, len, status, ext, arg);
 8851         }
 8852 
 8853         if (io->abort_done != NULL) {
 8854                 ocs_hw_done_t  done = io->abort_done;
 8855                 void            *arg = io->abort_arg;
 8856 
 8857                 io->abort_done = NULL;
 8858 
 8859                 done(io, io->rnode, len, status, ext, arg);
 8860         }
 8861         ocs_lock(&hw->io_abort_lock);
 8862                 /* clear abort bit to indicate abort is complete */
 8863                 io->abort_in_progress = 0;
 8864         ocs_unlock(&hw->io_abort_lock);
 8865 
 8866         /* Free the WQ callback */
 8867         ocs_hw_assert(io->abort_reqtag != UINT32_MAX);
 8868         wqcb = ocs_hw_reqtag_get_instance(hw, io->abort_reqtag);
 8869         ocs_hw_reqtag_free(hw, wqcb);
 8870 
 8871         /*
 8872          * Call ocs_hw_io_free() because this releases the WQ reservation as
 8873          * well as doing the refcount put. Don't duplicate the code here.
 8874          */
 8875         (void)ocs_hw_io_free(hw, io);
 8876 }
 8877 
 8878 /**
 8879  * @brief Process XABT completions
 8880  *
 8881  * @param hw Hardware context.
 8882  * @param cq Pointer to the HW completion queue object.
 8883  * @param cqe Pointer to WQ completion queue.
 8884  * @param rid Resource ID (IO tag).
 8885  *
 8886  *
 8887  * @return None.
 8888  */
 8889 void
 8890 ocs_hw_xabt_process(ocs_hw_t *hw, hw_cq_t *cq, uint8_t *cqe, uint16_t rid)
 8891 {
 8892         /* search IOs wait free list */
 8893         ocs_hw_io_t *io = NULL;
 8894 
 8895         io = ocs_hw_io_lookup(hw, rid);
 8896 
 8897         ocs_queue_history_cqe(&hw->q_hist, SLI_QENTRY_XABT, (void *)cqe, 0, cq->queue->id,
 8898                               ((cq->queue->index - 1) & (cq->queue->length - 1)));
 8899         if (io == NULL) {
 8900                 /* IO lookup failure should never happen */
 8901                 ocs_log_err(hw->os, "Error: xabt io lookup failed rid=%#x\n", rid);
 8902                 return;
 8903         }
 8904 
 8905         if (!io->xbusy) {
 8906                 ocs_log_debug(hw->os, "xabt io not busy rid=%#x\n", rid);
 8907         } else {
 8908                 /* mark IO as no longer busy */
 8909                 io->xbusy = FALSE;
 8910         }
 8911 
 8912        if (io->is_port_owned) {
 8913                ocs_lock(&hw->io_lock);
 8914                /* Take reference so that below callback will not free io before reque */
 8915                ocs_ref_get(&io->ref);
 8916                ocs_unlock(&hw->io_lock);
 8917        }
 8918 
 8919         /* For IOs that were aborted internally, we need to issue any pending callback here. */
 8920         if (io->done != NULL) {
 8921                 ocs_hw_done_t  done = io->done;
 8922                 void            *arg = io->arg;
 8923 
 8924                 /* Use latched status as this is always saved for an internal abort */
 8925                 int32_t status = io->saved_status;
 8926                 uint32_t len = io->saved_len;
 8927                 uint32_t ext = io->saved_ext;
 8928 
 8929                 io->done = NULL;
 8930                 io->status_saved = 0;
 8931 
 8932                 done(io, io->rnode, len, status, ext, arg);
 8933         }
 8934 
 8935         /* Check to see if this is a port owned XRI */
 8936         if (io->is_port_owned) {
 8937                 ocs_lock(&hw->io_lock);
 8938                 ocs_hw_reque_xri(hw, io);
 8939                 ocs_unlock(&hw->io_lock);
 8940                 /* Not hanlding reque xri completion, free io */
 8941                 ocs_hw_io_free(hw, io);
 8942                 return;
 8943         }
 8944 
 8945         ocs_lock(&hw->io_lock);
 8946                 if ((io->state == OCS_HW_IO_STATE_INUSE) || (io->state == OCS_HW_IO_STATE_WAIT_FREE)) {
 8947                         /* if on wait_free list, caller has already freed IO;
 8948                          * remove from wait_free list and add to free list.
 8949                          * if on in-use list, already marked as no longer busy;
 8950                          * just leave there and wait for caller to free.
 8951                          */
 8952                         if (io->state == OCS_HW_IO_STATE_WAIT_FREE) {
 8953                                 io->state = OCS_HW_IO_STATE_FREE;
 8954                                 ocs_list_remove(&hw->io_wait_free, io);
 8955                                 ocs_hw_io_free_move_correct_list(hw, io);
 8956                         }
 8957                 }
 8958         ocs_unlock(&hw->io_lock);
 8959 }
 8960 
 8961 /**
 8962  * @brief Adjust the number of WQs and CQs within the HW.
 8963  *
 8964  * @par Description
 8965  * Calculates the number of WQs and associated CQs needed in the HW based on
 8966  * the number of IOs. Calculates the starting CQ index for each WQ, RQ and
 8967  * MQ.
 8968  *
 8969  * @param hw Hardware context allocated by the caller.
 8970  */
 8971 static void
 8972 ocs_hw_adjust_wqs(ocs_hw_t *hw)
 8973 {
 8974         uint32_t max_wq_num = sli_get_max_queue(&hw->sli, SLI_QTYPE_WQ);
 8975         uint32_t max_wq_entries = hw->num_qentries[SLI_QTYPE_WQ];
 8976         uint32_t max_cq_entries = hw->num_qentries[SLI_QTYPE_CQ];
 8977 
 8978         /*
 8979          * possibly adjust the the size of the WQs so that the CQ is twice as
 8980          * big as the WQ to allow for 2 completions per IO. This allows us to
 8981          * handle multi-phase as well as aborts.
 8982          */
 8983         if (max_cq_entries < max_wq_entries * 2) {
 8984                 max_wq_entries = hw->num_qentries[SLI_QTYPE_WQ] = max_cq_entries / 2;
 8985         }
 8986 
 8987         /*
 8988          * Calculate the number of WQs to use base on the number of IOs.
 8989          *
 8990          * Note: We need to reserve room for aborts which must be sent down
 8991          *       the same WQ as the IO. So we allocate enough WQ space to
 8992          *       handle 2 times the number of IOs. Half of the space will be
 8993          *       used for normal IOs and the other hwf is reserved for aborts.
 8994          */
 8995         hw->config.n_wq = ((hw->config.n_io * 2) + (max_wq_entries - 1)) / max_wq_entries;
 8996 
 8997         /*
 8998          * For performance reasons, it is best to use use a minimum of 4 WQs
 8999          * for BE3 and Skyhawk.
 9000          */
 9001         if (hw->config.n_wq < 4 &&
 9002             SLI4_IF_TYPE_BE3_SKH_PF == sli_get_if_type(&hw->sli)) {
 9003                 hw->config.n_wq = 4;
 9004         }
 9005 
 9006         /*
 9007          * For dual-chute support, we need to have at least one WQ per chute.
 9008          */
 9009         if (hw->config.n_wq < 2 &&
 9010             ocs_hw_get_num_chutes(hw) > 1) {
 9011                 hw->config.n_wq = 2;
 9012         }
 9013 
 9014         /* make sure we haven't exceeded the max supported in the HW */
 9015         if (hw->config.n_wq > OCS_HW_MAX_NUM_WQ) {
 9016                 hw->config.n_wq = OCS_HW_MAX_NUM_WQ;
 9017         }
 9018 
 9019         /* make sure we haven't exceeded the chip maximum */
 9020         if (hw->config.n_wq > max_wq_num) {
 9021                 hw->config.n_wq = max_wq_num;
 9022         }
 9023 
 9024         /*
 9025          * Using Queue Topology string, we divide by number of chutes
 9026          */
 9027         hw->config.n_wq /= ocs_hw_get_num_chutes(hw);
 9028 }
 9029 
 9030 static int32_t
 9031 ocs_hw_command_process(ocs_hw_t *hw, int32_t status, uint8_t *mqe, size_t size)
 9032 {
 9033         ocs_command_ctx_t *ctx = NULL;
 9034 
 9035         ocs_lock(&hw->cmd_lock);
 9036                 if (NULL == (ctx = ocs_list_remove_head(&hw->cmd_head))) {
 9037                         ocs_log_err(hw->os, "XXX no command context?!?\n");
 9038                         ocs_unlock(&hw->cmd_lock);
 9039                         return -1;
 9040                 }
 9041 
 9042                 hw->cmd_head_count--;
 9043 
 9044                 /* Post any pending requests */
 9045                 ocs_hw_cmd_submit_pending(hw);
 9046 
 9047         ocs_unlock(&hw->cmd_lock);
 9048 
 9049         if (ctx->cb) {
 9050                 if (ctx->buf) {
 9051                         ocs_memcpy(ctx->buf, mqe, size);
 9052                 }
 9053                 ctx->cb(hw, status, ctx->buf, ctx->arg);
 9054         }
 9055 
 9056         ocs_memset(ctx, 0, sizeof(ocs_command_ctx_t));
 9057         ocs_free(hw->os, ctx, sizeof(ocs_command_ctx_t));
 9058 
 9059         return 0;
 9060 }
 9061 
 9062 /**
 9063  * @brief Process entries on the given mailbox queue.
 9064  *
 9065  * @param hw Hardware context.
 9066  * @param status CQE status.
 9067  * @param mq Pointer to the mailbox queue object.
 9068  *
 9069  * @return Returns 0 on success, or a non-zero value on failure.
 9070  */
 9071 static int32_t
 9072 ocs_hw_mq_process(ocs_hw_t *hw, int32_t status, sli4_queue_t *mq)
 9073 {
 9074         uint8_t         mqe[SLI4_BMBX_SIZE];
 9075 
 9076         if (!sli_queue_read(&hw->sli, mq, mqe)) {
 9077                 ocs_hw_command_process(hw, status, mqe, mq->size);
 9078         }
 9079 
 9080         return 0;
 9081 }
 9082 
 9083 /**
 9084  * @brief Read a FCF table entry.
 9085  *
 9086  * @param hw Hardware context.
 9087  * @param index Table index to read. Use SLI4_FCOE_FCF_TABLE_FIRST for the first
 9088  * read and the next_index field from the FCOE_READ_FCF_TABLE command
 9089  * for subsequent reads.
 9090  *
 9091  * @return Returns 0 on success, or a non-zero value on failure.
 9092  */
 9093 static ocs_hw_rtn_e
 9094 ocs_hw_read_fcf(ocs_hw_t *hw, uint32_t index)
 9095 {
 9096         uint8_t         *buf = NULL;
 9097         int32_t         rc = OCS_HW_RTN_ERROR;
 9098 
 9099         buf = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
 9100         if (!buf) {
 9101                 ocs_log_err(hw->os, "no buffer for command\n");
 9102                 return OCS_HW_RTN_NO_MEMORY;
 9103         }
 9104 
 9105         if (sli_cmd_fcoe_read_fcf_table(&hw->sli, buf, SLI4_BMBX_SIZE, &hw->fcf_dmem,
 9106                         index)) {
 9107                 rc = ocs_hw_command(hw, buf, OCS_CMD_NOWAIT, ocs_hw_cb_read_fcf, &hw->fcf_dmem);
 9108         }
 9109 
 9110         if (rc != OCS_HW_RTN_SUCCESS) {
 9111                 ocs_log_test(hw->os, "FCOE_READ_FCF_TABLE failed\n");
 9112                 ocs_free(hw->os, buf, SLI4_BMBX_SIZE);
 9113         }
 9114 
 9115         return rc;
 9116 }
 9117 
 9118 /**
 9119  * @brief Callback function for the FCOE_READ_FCF_TABLE command.
 9120  *
 9121  * @par Description
 9122  * Note that the caller has allocated:
 9123  *  - DMA memory to hold the table contents
 9124  *  - DMA memory structure
 9125  *  - Command/results buffer
 9126  *  .
 9127  * Each of these must be freed here.
 9128  *
 9129  * @param hw Hardware context.
 9130  * @param status Hardware status.
 9131  * @param mqe Pointer to the mailbox command/results buffer.
 9132  * @param arg Pointer to the DMA memory structure.
 9133  *
 9134  * @return Returns 0 on success, or a non-zero value on failure.
 9135  */
 9136 static int32_t
 9137 ocs_hw_cb_read_fcf(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
 9138 {
 9139         ocs_dma_t       *dma = arg;
 9140         sli4_mbox_command_header_t      *hdr = (sli4_mbox_command_header_t *)mqe;
 9141 
 9142         if (status || hdr->status) {
 9143                 ocs_log_test(hw->os, "bad status cqe=%#x mqe=%#x\n",
 9144                                 status, hdr->status);
 9145         } else if (dma->virt) {
 9146                 sli4_res_fcoe_read_fcf_table_t *read_fcf = dma->virt;
 9147 
 9148                 /* if FC or FCOE and FCF entry valid, process it */
 9149                 if (read_fcf->fcf_entry.fc ||
 9150                                 (read_fcf->fcf_entry.val && !read_fcf->fcf_entry.sol)) {
 9151                         if (hw->callback.domain != NULL) {
 9152                                 ocs_domain_record_t drec = {0};
 9153 
 9154                                 if (read_fcf->fcf_entry.fc) {
 9155                                         /*
 9156                                          * This is a pseudo FCF entry. Create a domain
 9157                                          * record based on the read topology information
 9158                                          */
 9159                                         drec.speed = hw->link.speed;
 9160                                         drec.fc_id = hw->link.fc_id;
 9161                                         drec.is_fc = TRUE;
 9162                                         if (SLI_LINK_TOPO_LOOP == hw->link.topology) {
 9163                                                 drec.is_loop = TRUE;
 9164                                                 ocs_memcpy(drec.map.loop, hw->link.loop_map,
 9165                                                            sizeof(drec.map.loop));
 9166                                         } else if (SLI_LINK_TOPO_NPORT == hw->link.topology) {
 9167                                                 drec.is_nport = TRUE;
 9168                                         }
 9169                                 } else {
 9170                                         drec.index = read_fcf->fcf_entry.fcf_index;
 9171                                         drec.priority = read_fcf->fcf_entry.fip_priority;
 9172 
 9173                                         /* copy address, wwn and vlan_bitmap */
 9174                                         ocs_memcpy(drec.address, read_fcf->fcf_entry.fcf_mac_address,
 9175                                                    sizeof(drec.address));
 9176                                         ocs_memcpy(drec.wwn, read_fcf->fcf_entry.fabric_name_id,
 9177                                                    sizeof(drec.wwn));
 9178                                         ocs_memcpy(drec.map.vlan, read_fcf->fcf_entry.vlan_bitmap,
 9179                                                    sizeof(drec.map.vlan));
 9180 
 9181                                         drec.is_ethernet = TRUE;
 9182                                         drec.is_nport = TRUE;
 9183                                 }
 9184 
 9185                                 hw->callback.domain(hw->args.domain,
 9186                                                 OCS_HW_DOMAIN_FOUND,
 9187                                                 &drec);
 9188                         }
 9189                 } else {
 9190                         /* if FCOE and FCF is not valid, ignore it */
 9191                         ocs_log_test(hw->os, "ignore invalid FCF entry\n");
 9192                 }
 9193 
 9194                 if (SLI4_FCOE_FCF_TABLE_LAST != read_fcf->next_index) {
 9195                         ocs_hw_read_fcf(hw, read_fcf->next_index);
 9196                 }
 9197         }
 9198 
 9199         ocs_free(hw->os, mqe, SLI4_BMBX_SIZE);
 9200         //ocs_dma_free(hw->os, dma);
 9201         //ocs_free(hw->os, dma, sizeof(ocs_dma_t));
 9202 
 9203         return 0;
 9204 }
 9205 
 9206 /**
 9207  * @brief Callback function for the SLI link events.
 9208  *
 9209  * @par Description
 9210  * This function allocates memory which must be freed in its callback.
 9211  *
 9212  * @param ctx Hardware context pointer (that is, ocs_hw_t *).
 9213  * @param e Event structure pointer (that is, sli4_link_event_t *).
 9214  *
 9215  * @return Returns 0 on success, or a non-zero value on failure.
 9216  */
 9217 static int32_t
 9218 ocs_hw_cb_link(void *ctx, void *e)
 9219 {
 9220         ocs_hw_t        *hw = ctx;
 9221         sli4_link_event_t *event = e;
 9222         ocs_domain_t    *d = NULL;
 9223         uint32_t        i = 0;
 9224         int32_t         rc = OCS_HW_RTN_ERROR;
 9225         ocs_t           *ocs = hw->os;
 9226 
 9227         ocs_hw_link_event_init(hw);
 9228 
 9229         switch (event->status) {
 9230         case SLI_LINK_STATUS_UP:
 9231 
 9232                 hw->link = *event;
 9233 
 9234                 if (SLI_LINK_TOPO_NPORT == event->topology) {
 9235                         device_printf(ocs->dev, "Link Up, NPORT, speed is %d\n", event->speed);
 9236                         ocs_hw_read_fcf(hw, SLI4_FCOE_FCF_TABLE_FIRST);
 9237                 } else if (SLI_LINK_TOPO_LOOP == event->topology) {
 9238                         uint8_t *buf = NULL;
 9239                         device_printf(ocs->dev, "Link Up, LOOP, speed is %d\n", event->speed);
 9240 
 9241                         buf = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
 9242                         if (!buf) {
 9243                                 ocs_log_err(hw->os, "no buffer for command\n");
 9244                                 break;
 9245                         }
 9246 
 9247                         if (sli_cmd_read_topology(&hw->sli, buf, SLI4_BMBX_SIZE, &hw->loop_map)) {
 9248                                 rc = ocs_hw_command(hw, buf, OCS_CMD_NOWAIT, __ocs_read_topology_cb, NULL);
 9249                         }
 9250 
 9251                         if (rc != OCS_HW_RTN_SUCCESS) {
 9252                                 ocs_log_test(hw->os, "READ_TOPOLOGY failed\n");
 9253                                 ocs_free(hw->os, buf, SLI4_BMBX_SIZE);
 9254                         }
 9255                 } else {
 9256                         device_printf(ocs->dev, "Link Up, unsupported topology (%#x), speed is %d\n",
 9257                                         event->topology, event->speed);
 9258                 }
 9259                 break;
 9260         case SLI_LINK_STATUS_DOWN:
 9261                 device_printf(ocs->dev, "Link Down\n");
 9262 
 9263                 hw->link.status = event->status;
 9264 
 9265                 for (i = 0; i < SLI4_MAX_FCFI; i++) {
 9266                         d = hw->domains[i];
 9267                         if (d != NULL &&
 9268                             hw->callback.domain != NULL) {
 9269                                 hw->callback.domain(hw->args.domain, OCS_HW_DOMAIN_LOST, d);
 9270                         }
 9271                 }
 9272                 break;
 9273         default:
 9274                 ocs_log_test(hw->os, "unhandled link status %#x\n", event->status);
 9275                 break;
 9276         }
 9277 
 9278         return 0;
 9279 }
 9280 
 9281 static int32_t
 9282 ocs_hw_cb_fip(void *ctx, void *e)
 9283 {
 9284         ocs_hw_t        *hw = ctx;
 9285         ocs_domain_t    *domain = NULL;
 9286         sli4_fip_event_t *event = e;
 9287 
 9288         ocs_hw_assert(event);
 9289         ocs_hw_assert(hw);
 9290 
 9291         /* Find the associated domain object */
 9292         if (event->type == SLI4_FCOE_FIP_FCF_CLEAR_VLINK) {
 9293                 ocs_domain_t *d = NULL;
 9294                 uint32_t        i = 0;
 9295 
 9296                 /* Clear VLINK is different from the other FIP events as it passes back
 9297                  * a VPI instead of a FCF index. Check all attached SLI ports for a
 9298                  * matching VPI */
 9299                 for (i = 0; i < SLI4_MAX_FCFI; i++) {
 9300                         d = hw->domains[i];
 9301                         if (d != NULL) {
 9302                                 ocs_sport_t     *sport = NULL;
 9303 
 9304                                 ocs_list_foreach(&d->sport_list, sport) {
 9305                                         if (sport->indicator == event->index) {
 9306                                                 domain = d;
 9307                                                 break;
 9308                                         }
 9309                                 }
 9310 
 9311                                 if (domain != NULL) {
 9312                                         break;
 9313                                 }
 9314                         }
 9315                 }
 9316         } else {
 9317                 domain = ocs_hw_domain_get_indexed(hw, event->index);
 9318         }
 9319 
 9320         switch (event->type) {
 9321         case SLI4_FCOE_FIP_FCF_DISCOVERED:
 9322                 ocs_hw_read_fcf(hw, event->index);
 9323                 break;
 9324         case SLI4_FCOE_FIP_FCF_DEAD:
 9325                 if (domain != NULL &&
 9326                     hw->callback.domain != NULL) {
 9327                         hw->callback.domain(hw->args.domain, OCS_HW_DOMAIN_LOST, domain);
 9328                 }
 9329                 break;
 9330         case SLI4_FCOE_FIP_FCF_CLEAR_VLINK:
 9331                 if (domain != NULL &&
 9332                     hw->callback.domain != NULL) {
 9333                         /*
 9334                          * We will want to issue rediscover FCF when this domain is free'd  in order
 9335                          * to invalidate the FCF table
 9336                          */
 9337                         domain->req_rediscover_fcf = TRUE;
 9338                         hw->callback.domain(hw->args.domain, OCS_HW_DOMAIN_LOST, domain);
 9339                 }
 9340                 break;
 9341         case SLI4_FCOE_FIP_FCF_MODIFIED:
 9342                 if (domain != NULL &&
 9343                     hw->callback.domain != NULL) {
 9344                         hw->callback.domain(hw->args.domain, OCS_HW_DOMAIN_LOST, domain);
 9345                 }
 9346 
 9347                 ocs_hw_read_fcf(hw, event->index);
 9348                 break;
 9349         default:
 9350                 ocs_log_test(hw->os, "unsupported event %#x\n", event->type);
 9351         }
 9352 
 9353         return 0;
 9354 }
 9355 
 9356 static int32_t
 9357 ocs_hw_cb_node_attach(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
 9358 {
 9359         ocs_remote_node_t *rnode = arg;
 9360         sli4_mbox_command_header_t      *hdr = (sli4_mbox_command_header_t *)mqe;
 9361         ocs_hw_remote_node_event_e      evt = 0;
 9362 
 9363         if (status || hdr->status) {
 9364                 ocs_log_debug(hw->os, "bad status cqe=%#x mqe=%#x\n", status,
 9365                                 hdr->status);
 9366                 ocs_atomic_sub_return(&hw->rpi_ref[rnode->index].rpi_count, 1);
 9367                 rnode->attached = FALSE;
 9368                 ocs_atomic_set(&hw->rpi_ref[rnode->index].rpi_attached, 0);
 9369                 evt = OCS_HW_NODE_ATTACH_FAIL;
 9370         } else {
 9371                 rnode->attached = TRUE;
 9372                 ocs_atomic_set(&hw->rpi_ref[rnode->index].rpi_attached, 1);
 9373                 evt = OCS_HW_NODE_ATTACH_OK;
 9374         }
 9375 
 9376         if (hw->callback.rnode != NULL) {
 9377                 hw->callback.rnode(hw->args.rnode, evt, rnode);
 9378         }
 9379         ocs_free(hw->os, mqe, SLI4_BMBX_SIZE);
 9380 
 9381         return 0;
 9382 }
 9383 
 9384 static int32_t
 9385 ocs_hw_cb_node_free(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
 9386 {
 9387         ocs_remote_node_t *rnode = arg;
 9388         sli4_mbox_command_header_t      *hdr = (sli4_mbox_command_header_t *)mqe;
 9389         ocs_hw_remote_node_event_e      evt = OCS_HW_NODE_FREE_FAIL;
 9390         int32_t         rc = 0;
 9391 
 9392         if (status || hdr->status) {
 9393                 ocs_log_debug(hw->os, "bad status cqe=%#x mqe=%#x\n", status,
 9394                                 hdr->status);
 9395 
 9396                 /*
 9397                  * In certain cases, a non-zero MQE status is OK (all must be true):
 9398                  *   - node is attached
 9399                  *   - if High Login Mode is enabled, node is part of a node group
 9400                  *   - status is 0x1400
 9401                  */
 9402                 if (!rnode->attached || ((sli_get_hlm(&hw->sli) == TRUE) && !rnode->node_group) ||
 9403                                 (hdr->status != SLI4_MBOX_STATUS_RPI_NOT_REG)) {
 9404                         rc = -1;
 9405                 }
 9406         }
 9407 
 9408         if (rc == 0) {
 9409                 rnode->node_group = FALSE;
 9410                 rnode->attached = FALSE;
 9411 
 9412                 if (ocs_atomic_read(&hw->rpi_ref[rnode->index].rpi_count) == 0) {
 9413                         ocs_atomic_set(&hw->rpi_ref[rnode->index].rpi_attached, 0);
 9414                 }
 9415 
 9416                 evt = OCS_HW_NODE_FREE_OK;
 9417         }
 9418 
 9419         if (hw->callback.rnode != NULL) {
 9420                 hw->callback.rnode(hw->args.rnode, evt, rnode);
 9421         }
 9422 
 9423         ocs_free(hw->os, mqe, SLI4_BMBX_SIZE);
 9424 
 9425         return rc;
 9426 }
 9427 
 9428 static int32_t
 9429 ocs_hw_cb_node_free_all(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
 9430 {
 9431         sli4_mbox_command_header_t      *hdr = (sli4_mbox_command_header_t *)mqe;
 9432         ocs_hw_remote_node_event_e      evt = OCS_HW_NODE_FREE_FAIL;
 9433         int32_t         rc = 0;
 9434         uint32_t        i;
 9435 
 9436         if (status || hdr->status) {
 9437                 ocs_log_debug(hw->os, "bad status cqe=%#x mqe=%#x\n", status,
 9438                                 hdr->status);
 9439         } else {
 9440                 evt = OCS_HW_NODE_FREE_ALL_OK;
 9441         }
 9442 
 9443         if (evt == OCS_HW_NODE_FREE_ALL_OK) {
 9444                 for (i = 0; i < sli_get_max_rsrc(&hw->sli, SLI_RSRC_FCOE_RPI); i++) {
 9445                         ocs_atomic_set(&hw->rpi_ref[i].rpi_count, 0);
 9446                 }
 9447 
 9448                 if (sli_resource_reset(&hw->sli, SLI_RSRC_FCOE_RPI)) {
 9449                         ocs_log_test(hw->os, "FCOE_RPI free all failure\n");
 9450                         rc = -1;
 9451                 }
 9452         }
 9453 
 9454         if (hw->callback.rnode != NULL) {
 9455                 hw->callback.rnode(hw->args.rnode, evt, NULL);
 9456         }
 9457 
 9458         ocs_free(hw->os, mqe, SLI4_BMBX_SIZE);
 9459 
 9460         return rc;
 9461 }
 9462 
 9463 /**
 9464  * @brief Initialize the pool of HW IO objects.
 9465  *
 9466  * @param hw Hardware context.
 9467  *
 9468  * @return Returns 0 on success, or a non-zero value on failure.
 9469  */
 9470 static ocs_hw_rtn_e
 9471 ocs_hw_setup_io(ocs_hw_t *hw)
 9472 {
 9473         uint32_t        i = 0;
 9474         ocs_hw_io_t     *io = NULL;
 9475         uintptr_t       xfer_virt = 0;
 9476         uintptr_t       xfer_phys = 0;
 9477         uint32_t        index;
 9478         uint8_t         new_alloc = TRUE;
 9479 
 9480         if (NULL == hw->io) {
 9481                 hw->io = ocs_malloc(hw->os, hw->config.n_io * sizeof(ocs_hw_io_t *), OCS_M_ZERO | OCS_M_NOWAIT);
 9482 
 9483                 if (NULL == hw->io) {
 9484                         ocs_log_err(hw->os, "IO pointer memory allocation failed, %d Ios at size %zu\n",
 9485                                     hw->config.n_io,
 9486                                     sizeof(ocs_hw_io_t *));
 9487                         return OCS_HW_RTN_NO_MEMORY;
 9488                 }
 9489                 for (i = 0; i < hw->config.n_io; i++) {
 9490                         hw->io[i] = ocs_malloc(hw->os, sizeof(ocs_hw_io_t),
 9491                                                 OCS_M_ZERO | OCS_M_NOWAIT);
 9492                         if (hw->io[i] == NULL) {
 9493                                 ocs_log_err(hw->os, "IO(%d) memory allocation failed\n", i);
 9494                                 goto error;
 9495                         }
 9496                 }
 9497 
 9498                 /* Create WQE buffs for IO */
 9499                 hw->wqe_buffs = ocs_malloc(hw->os, hw->config.n_io * hw->sli.config.wqe_size,
 9500                                 OCS_M_ZERO | OCS_M_NOWAIT);
 9501                 if (NULL == hw->wqe_buffs) {
 9502                         ocs_free(hw->os, hw->io, hw->config.n_io * sizeof(ocs_hw_io_t));
 9503                         ocs_log_err(hw->os, "%s: IO WQE buff allocation failed, %d Ios at size %zu\n",
 9504                                         __func__, hw->config.n_io, hw->sli.config.wqe_size);
 9505                         return OCS_HW_RTN_NO_MEMORY;
 9506                 }
 9507 
 9508         } else {
 9509                 /* re-use existing IOs, including SGLs */
 9510                 new_alloc = FALSE;
 9511         }
 9512 
 9513         if (new_alloc) {
 9514                 if (ocs_dma_alloc(hw->os, &hw->xfer_rdy,
 9515                                         sizeof(fcp_xfer_rdy_iu_t) * hw->config.n_io,
 9516                                         4/*XXX what does this need to be? */)) {
 9517                         ocs_log_err(hw->os, "XFER_RDY buffer allocation failed\n");
 9518                         return OCS_HW_RTN_NO_MEMORY;
 9519                 }
 9520         }
 9521         xfer_virt = (uintptr_t)hw->xfer_rdy.virt;
 9522         xfer_phys = hw->xfer_rdy.phys;
 9523 
 9524         for (i = 0; i < hw->config.n_io; i++) {
 9525                 hw_wq_callback_t *wqcb;
 9526 
 9527                 io = hw->io[i];
 9528 
 9529                 /* initialize IO fields */
 9530                 io->hw = hw;
 9531 
 9532                 /* Assign a WQE buff */ 
 9533                 io->wqe.wqebuf = &hw->wqe_buffs[i * hw->sli.config.wqe_size]; 
 9534 
 9535                 /* Allocate the request tag for this IO */
 9536                 wqcb = ocs_hw_reqtag_alloc(hw, ocs_hw_wq_process_io, io);
 9537                 if (wqcb == NULL) {
 9538                         ocs_log_err(hw->os, "can't allocate request tag\n");
 9539                         return OCS_HW_RTN_NO_RESOURCES;
 9540                 }
 9541                 io->reqtag = wqcb->instance_index;
 9542 
 9543                 /* Now for the fields that are initialized on each free */
 9544                 ocs_hw_init_free_io(io);
 9545 
 9546                 /* The XB flag isn't cleared on IO free, so initialize it to zero here */
 9547                 io->xbusy = 0;
 9548 
 9549                 if (sli_resource_alloc(&hw->sli, SLI_RSRC_FCOE_XRI, &io->indicator, &index)) {
 9550                         ocs_log_err(hw->os, "sli_resource_alloc failed @ %d\n", i);
 9551                         return OCS_HW_RTN_NO_MEMORY;
 9552                 }
 9553 
 9554                 if (new_alloc && ocs_dma_alloc(hw->os, &io->def_sgl, hw->config.n_sgl * sizeof(sli4_sge_t), 64)) {
 9555                         ocs_log_err(hw->os, "ocs_dma_alloc failed @ %d\n", i);
 9556                         ocs_memset(&io->def_sgl, 0, sizeof(ocs_dma_t));
 9557                         return OCS_HW_RTN_NO_MEMORY;
 9558                 }
 9559                 io->def_sgl_count = hw->config.n_sgl;
 9560                 io->sgl = &io->def_sgl;
 9561                 io->sgl_count = io->def_sgl_count;
 9562 
 9563                 if (hw->xfer_rdy.size) {
 9564                         io->xfer_rdy.virt = (void *)xfer_virt;
 9565                         io->xfer_rdy.phys = xfer_phys;
 9566                         io->xfer_rdy.size = sizeof(fcp_xfer_rdy_iu_t);
 9567 
 9568                         xfer_virt += sizeof(fcp_xfer_rdy_iu_t);
 9569                         xfer_phys += sizeof(fcp_xfer_rdy_iu_t);
 9570                 }
 9571         }
 9572 
 9573         return OCS_HW_RTN_SUCCESS;
 9574 error:
 9575         for (i = 0; i < hw->config.n_io && hw->io[i]; i++) {
 9576                 ocs_free(hw->os, hw->io[i], sizeof(ocs_hw_io_t));
 9577                 hw->io[i] = NULL;
 9578         }
 9579 
 9580         return OCS_HW_RTN_NO_MEMORY;
 9581 }
 9582 
 9583 static ocs_hw_rtn_e
 9584 ocs_hw_init_io(ocs_hw_t *hw)
 9585 {
 9586         uint32_t        i = 0, io_index = 0;
 9587         uint32_t        prereg = 0;
 9588         ocs_hw_io_t     *io = NULL;
 9589         uint8_t         cmd[SLI4_BMBX_SIZE];
 9590         ocs_hw_rtn_e rc = OCS_HW_RTN_SUCCESS;
 9591         uint32_t        nremaining;
 9592         uint32_t        n = 0;
 9593         uint32_t        sgls_per_request = 256;
 9594         ocs_dma_t       **sgls = NULL;
 9595         ocs_dma_t       reqbuf = { 0 };
 9596 
 9597         prereg = sli_get_sgl_preregister(&hw->sli);
 9598 
 9599         if (prereg) {
 9600                 sgls = ocs_malloc(hw->os, sizeof(*sgls) * sgls_per_request, OCS_M_NOWAIT);
 9601                 if (sgls == NULL) {
 9602                         ocs_log_err(hw->os, "ocs_malloc sgls failed\n");
 9603                         return OCS_HW_RTN_NO_MEMORY;
 9604                 }
 9605 
 9606                 rc = ocs_dma_alloc(hw->os, &reqbuf, 32 + sgls_per_request*16, OCS_MIN_DMA_ALIGNMENT);
 9607                 if (rc) {
 9608                         ocs_log_err(hw->os, "ocs_dma_alloc reqbuf failed\n");
 9609                         ocs_free(hw->os, sgls, sizeof(*sgls) * sgls_per_request);
 9610                         return OCS_HW_RTN_NO_MEMORY;
 9611                 }
 9612         }
 9613 
 9614         io = hw->io[io_index];
 9615         for (nremaining = hw->config.n_io; nremaining; nremaining -= n) {
 9616                 if (prereg) {
 9617                         /* Copy address of SGL's into local sgls[] array, break out if the xri
 9618                          * is not contiguous.
 9619                          */
 9620                         for (n = 0; n < MIN(sgls_per_request, nremaining); n++) {
 9621                                 /* Check that we have contiguous xri values */
 9622                                 if (n > 0) {
 9623                                         if (hw->io[io_index + n]->indicator != (hw->io[io_index + n-1]->indicator+1)) {
 9624                                                 break;
 9625                                         }
 9626                                 }
 9627                                 sgls[n] = hw->io[io_index + n]->sgl;
 9628                         }
 9629 
 9630                         if (sli_cmd_fcoe_post_sgl_pages(&hw->sli, cmd, sizeof(cmd),
 9631                                                 io->indicator, n, sgls, NULL, &reqbuf)) {
 9632                                 if (ocs_hw_command(hw, cmd, OCS_CMD_POLL, NULL, NULL)) {
 9633                                         rc = OCS_HW_RTN_ERROR;
 9634                                         ocs_log_err(hw->os, "SGL post failed\n");
 9635                                         break;
 9636                                 }
 9637                         }
 9638                 } else {
 9639                         n = nremaining;
 9640                 }
 9641 
 9642                 /* Add to tail if successful */
 9643                 for (i = 0; i < n; i ++) {
 9644                         io->is_port_owned = 0;
 9645                         io->state = OCS_HW_IO_STATE_FREE;
 9646                         ocs_list_add_tail(&hw->io_free, io);
 9647                         io = hw->io[io_index+1];
 9648                         io_index++;
 9649                 }
 9650         }
 9651 
 9652         if (prereg) {
 9653                 ocs_dma_free(hw->os, &reqbuf);
 9654                 ocs_free(hw->os, sgls, sizeof(*sgls) * sgls_per_request);
 9655         }
 9656 
 9657         return rc;
 9658 }
 9659 
 9660 static int32_t
 9661 ocs_hw_flush(ocs_hw_t *hw)
 9662 {
 9663         uint32_t        i = 0;
 9664 
 9665         /* Process any remaining completions */
 9666         for (i = 0; i < hw->eq_count; i++) {
 9667                 ocs_hw_process(hw, i, ~0);
 9668         }
 9669 
 9670         return 0;
 9671 }
 9672 
 9673 static int32_t
 9674 ocs_hw_command_cancel(ocs_hw_t *hw)
 9675 {
 9676 
 9677         ocs_lock(&hw->cmd_lock);
 9678 
 9679         /*
 9680          * Manually clean up remaining commands. Note: since this calls
 9681          * ocs_hw_command_process(), we'll also process the cmd_pending
 9682          * list, so no need to manually clean that out.
 9683          */
 9684         while (!ocs_list_empty(&hw->cmd_head)) {
 9685                 uint8_t         mqe[SLI4_BMBX_SIZE] = { 0 };
 9686                 ocs_command_ctx_t *ctx = ocs_list_get_head(&hw->cmd_head);
 9687 
 9688                 ocs_log_test(hw->os, "hung command %08x\n",
 9689                                 NULL == ctx ? UINT32_MAX :
 9690                                 (NULL == ctx->buf ? UINT32_MAX : *((uint32_t *)ctx->buf)));
 9691                 ocs_unlock(&hw->cmd_lock);
 9692                 ocs_hw_command_process(hw, -1/*Bad status*/, mqe, SLI4_BMBX_SIZE);
 9693                 ocs_lock(&hw->cmd_lock);
 9694         }
 9695 
 9696         ocs_unlock(&hw->cmd_lock);
 9697 
 9698         return 0;
 9699 }
 9700 
 9701 /**
 9702  * @brief Find IO given indicator (xri).
 9703  *
 9704  * @param hw Hal context.
 9705  * @param indicator Indicator (xri) to look for.
 9706  *
 9707  * @return Returns io if found, NULL otherwise.
 9708  */
 9709 ocs_hw_io_t *
 9710 ocs_hw_io_lookup(ocs_hw_t *hw, uint32_t xri)
 9711 {
 9712         uint32_t ioindex;
 9713         ioindex = xri - hw->sli.config.extent[SLI_RSRC_FCOE_XRI].base[0];
 9714         return hw->io[ioindex];
 9715 }
 9716 
 9717 /**
 9718  * @brief Issue any pending callbacks for an IO and remove off the timer and pending lists.
 9719  *
 9720  * @param hw Hal context.
 9721  * @param io Pointer to the IO to cleanup.
 9722  */
 9723 static void
 9724 ocs_hw_io_cancel_cleanup(ocs_hw_t *hw, ocs_hw_io_t *io)
 9725 {
 9726         ocs_hw_done_t  done = io->done;
 9727         ocs_hw_done_t  abort_done = io->abort_done;
 9728 
 9729         /* first check active_wqe list and remove if there */
 9730         if (ocs_list_on_list(&io->wqe_link)) {
 9731                 ocs_list_remove(&hw->io_timed_wqe, io);
 9732         }
 9733 
 9734         /* Remove from WQ pending list */
 9735         if ((io->wq != NULL) && ocs_list_on_list(&io->wq->pending_list)) {
 9736                 ocs_list_remove(&io->wq->pending_list, io);
 9737         }
 9738 
 9739         if (io->done) {
 9740                 void            *arg = io->arg;
 9741 
 9742                 io->done = NULL;
 9743                 ocs_unlock(&hw->io_lock);
 9744                 done(io, io->rnode, 0, SLI4_FC_WCQE_STATUS_SHUTDOWN, 0, arg);
 9745                 ocs_lock(&hw->io_lock);
 9746         }
 9747 
 9748         if (io->abort_done != NULL) {
 9749                 void            *abort_arg = io->abort_arg;
 9750 
 9751                 io->abort_done = NULL;
 9752                 ocs_unlock(&hw->io_lock);
 9753                 abort_done(io, io->rnode, 0, SLI4_FC_WCQE_STATUS_SHUTDOWN, 0, abort_arg);
 9754                 ocs_lock(&hw->io_lock);
 9755         }
 9756 }
 9757 
 9758 static int32_t
 9759 ocs_hw_io_cancel(ocs_hw_t *hw)
 9760 {
 9761         ocs_hw_io_t     *io = NULL;
 9762         ocs_hw_io_t     *tmp_io = NULL;
 9763         uint32_t        iters = 100; /* One second limit */
 9764 
 9765         /*
 9766          * Manually clean up outstanding IO.
 9767          * Only walk through list once: the backend will cleanup any IOs when done/abort_done is called.
 9768          */
 9769         ocs_lock(&hw->io_lock);
 9770         ocs_list_foreach_safe(&hw->io_inuse, io, tmp_io) {
 9771                 ocs_hw_done_t  done = io->done;
 9772                 ocs_hw_done_t  abort_done = io->abort_done;
 9773 
 9774                 ocs_hw_io_cancel_cleanup(hw, io);
 9775 
 9776                 /*
 9777                  * Since this is called in a reset/shutdown
 9778                  * case, If there is no callback, then just
 9779                  * free the IO.
 9780                  *
 9781                  * Note: A port owned XRI cannot be on
 9782                  *       the in use list. We cannot call
 9783                  *       ocs_hw_io_free() because we already
 9784                  *       hold the io_lock.
 9785                  */
 9786                 if (done == NULL &&
 9787                     abort_done == NULL) {
 9788                         /*
 9789                          * Since this is called in a reset/shutdown
 9790                          * case, If there is no callback, then just
 9791                          * free the IO.
 9792                          */
 9793                         ocs_hw_io_free_common(hw, io);
 9794                         ocs_list_remove(&hw->io_inuse, io);
 9795                         ocs_hw_io_free_move_correct_list(hw, io);
 9796                 }
 9797         }
 9798 
 9799         /*
 9800          * For port owned XRIs, they are not on the in use list, so
 9801          * walk though XRIs and issue any callbacks.
 9802          */
 9803         ocs_list_foreach_safe(&hw->io_port_owned, io, tmp_io) {
 9804                 /* check  list and remove if there */
 9805                 if (ocs_list_on_list(&io->dnrx_link)) {
 9806                         ocs_list_remove(&hw->io_port_dnrx, io);
 9807                         ocs_ref_put(&io->ref); /* ocs_ref_get(): same function */
 9808                 }
 9809                 ocs_hw_io_cancel_cleanup(hw, io);
 9810                 ocs_list_remove(&hw->io_port_owned, io);
 9811                 ocs_hw_io_free_common(hw, io);
 9812         }
 9813         ocs_unlock(&hw->io_lock);
 9814 
 9815         /* Give time for the callbacks to complete */
 9816         do {
 9817                 ocs_udelay(10000);
 9818                 iters--;
 9819         } while (!ocs_list_empty(&hw->io_inuse) && iters);
 9820 
 9821         /* Leave a breadcrumb that cleanup is not yet complete. */
 9822         if (!ocs_list_empty(&hw->io_inuse)) {
 9823                 ocs_log_test(hw->os, "io_inuse list is not empty\n");
 9824         }
 9825 
 9826         return 0;
 9827 }
 9828 
 9829 static int32_t
 9830 ocs_hw_io_ini_sge(ocs_hw_t *hw, ocs_hw_io_t *io, ocs_dma_t *cmnd, uint32_t cmnd_size,
 9831                 ocs_dma_t *rsp)
 9832 {
 9833         sli4_sge_t      *data = NULL;
 9834 
 9835         if (!hw || !io) {
 9836                 ocs_log_err(NULL, "bad parm hw=%p io=%p\n", hw, io);
 9837                 return OCS_HW_RTN_ERROR;
 9838         }
 9839 
 9840         data = io->def_sgl.virt;
 9841 
 9842         /* setup command pointer */
 9843         data->buffer_address_high = ocs_addr32_hi(cmnd->phys);
 9844         data->buffer_address_low  = ocs_addr32_lo(cmnd->phys);
 9845         data->buffer_length = cmnd_size;
 9846         data++;
 9847 
 9848         /* setup response pointer */
 9849         data->buffer_address_high = ocs_addr32_hi(rsp->phys);
 9850         data->buffer_address_low  = ocs_addr32_lo(rsp->phys);
 9851         data->buffer_length = rsp->size;
 9852 
 9853         return 0;
 9854 }
 9855 
 9856 static int32_t
 9857 __ocs_read_topology_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
 9858 {
 9859         sli4_cmd_read_topology_t *read_topo = (sli4_cmd_read_topology_t *)mqe;
 9860 
 9861         if (status || read_topo->hdr.status) {
 9862                 ocs_log_debug(hw->os, "bad status cqe=%#x mqe=%#x\n",
 9863                                 status, read_topo->hdr.status);
 9864                 ocs_free(hw->os, mqe, SLI4_BMBX_SIZE);
 9865                 return -1;
 9866         }
 9867 
 9868         switch (read_topo->attention_type) {
 9869         case SLI4_READ_TOPOLOGY_LINK_UP:
 9870                 hw->link.status = SLI_LINK_STATUS_UP;
 9871                 break;
 9872         case SLI4_READ_TOPOLOGY_LINK_DOWN:
 9873                 hw->link.status = SLI_LINK_STATUS_DOWN;
 9874                 break;
 9875         case SLI4_READ_TOPOLOGY_LINK_NO_ALPA:
 9876                 hw->link.status = SLI_LINK_STATUS_NO_ALPA;
 9877                 break;
 9878         default:
 9879                 hw->link.status = SLI_LINK_STATUS_MAX;
 9880                 break;
 9881         }
 9882 
 9883         switch (read_topo->topology) {
 9884         case SLI4_READ_TOPOLOGY_NPORT:
 9885                 hw->link.topology = SLI_LINK_TOPO_NPORT;
 9886                 break;
 9887         case SLI4_READ_TOPOLOGY_FC_AL:
 9888                 hw->link.topology = SLI_LINK_TOPO_LOOP;
 9889                 if (SLI_LINK_STATUS_UP == hw->link.status) {
 9890                         hw->link.loop_map = hw->loop_map.virt;
 9891                 }
 9892                 hw->link.fc_id = read_topo->acquired_al_pa;
 9893                 break;
 9894         default:
 9895                 hw->link.topology = SLI_LINK_TOPO_MAX;
 9896                 break;
 9897         }
 9898 
 9899         hw->link.medium = SLI_LINK_MEDIUM_FC;
 9900 
 9901         switch (read_topo->link_current.link_speed) {
 9902         case SLI4_READ_TOPOLOGY_SPEED_1G:
 9903                 hw->link.speed =  1 * 1000;
 9904                 break;
 9905         case SLI4_READ_TOPOLOGY_SPEED_2G:
 9906                 hw->link.speed =  2 * 1000;
 9907                 break;
 9908         case SLI4_READ_TOPOLOGY_SPEED_4G:
 9909                 hw->link.speed =  4 * 1000;
 9910                 break;
 9911         case SLI4_READ_TOPOLOGY_SPEED_8G:
 9912                 hw->link.speed =  8 * 1000;
 9913                 break;
 9914         case SLI4_READ_TOPOLOGY_SPEED_16G:
 9915                 hw->link.speed = 16 * 1000;
 9916                 hw->link.loop_map = NULL;
 9917                 break;
 9918         case SLI4_READ_TOPOLOGY_SPEED_32G:
 9919                 hw->link.speed = 32 * 1000;
 9920                 hw->link.loop_map = NULL;
 9921                 break;
 9922         }
 9923 
 9924         ocs_free(hw->os, mqe, SLI4_BMBX_SIZE);
 9925 
 9926         ocs_hw_read_fcf(hw, SLI4_FCOE_FCF_TABLE_FIRST);
 9927 
 9928         return 0;
 9929 }
 9930 
 9931 static int32_t
 9932 __ocs_hw_port_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
 9933 {
 9934         ocs_sli_port_t  *sport = ctx->app;
 9935         ocs_hw_t        *hw = sport->hw;
 9936 
 9937         smtrace("port");
 9938 
 9939         switch (evt) {
 9940         case OCS_EVT_EXIT:
 9941                 /* ignore */
 9942                 break;
 9943 
 9944         case OCS_EVT_HW_PORT_REQ_FREE:
 9945         case OCS_EVT_HW_PORT_REQ_ATTACH:
 9946                 if (data != NULL) {
 9947                         ocs_free(hw->os, data, SLI4_BMBX_SIZE);
 9948                 }
 9949                 /* fall through */
 9950         default:
 9951                 ocs_log_test(hw->os, "%s %-20s not handled\n", funcname, ocs_sm_event_name(evt));
 9952                 break;
 9953         }
 9954 
 9955         return 0;
 9956 }
 9957 
 9958 static void *
 9959 __ocs_hw_port_free_report_fail(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
 9960 {
 9961         ocs_sli_port_t  *sport = ctx->app;
 9962         ocs_hw_t        *hw = sport->hw;
 9963 
 9964         smtrace("port");
 9965 
 9966         switch (evt) {
 9967         case OCS_EVT_ENTER:
 9968                 if (data != NULL) {
 9969                         ocs_free(hw->os, data, SLI4_BMBX_SIZE);
 9970                 }
 9971                 if (hw->callback.port != NULL) {
 9972                         hw->callback.port(hw->args.port,
 9973                                         OCS_HW_PORT_FREE_FAIL, sport);
 9974                 }
 9975                 break;
 9976         default:
 9977                 break;
 9978         }
 9979 
 9980         return NULL;
 9981 }
 9982 
 9983 static void *
 9984 __ocs_hw_port_freed(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
 9985 {
 9986         ocs_sli_port_t  *sport = ctx->app;
 9987         ocs_hw_t        *hw = sport->hw;
 9988 
 9989         smtrace("port");
 9990 
 9991         switch (evt) {
 9992         case OCS_EVT_ENTER:
 9993                 /* free SLI resource */
 9994                 if (sli_resource_free(&hw->sli, SLI_RSRC_FCOE_VPI, sport->indicator)) {
 9995                         ocs_log_err(hw->os, "FCOE_VPI free failure addr=%#x\n", sport->fc_id);
 9996                 }
 9997 
 9998                 /* free mailbox buffer */
 9999                 if (data != NULL) {
10000                         ocs_free(hw->os, data, SLI4_BMBX_SIZE);
10001                 }
10002                 if (hw->callback.port != NULL) {
10003                         hw->callback.port(hw->args.port,
10004                                         OCS_HW_PORT_FREE_OK, sport);
10005                 }
10006                 break;
10007         default:
10008                 break;
10009         }
10010 
10011         return NULL;
10012 }
10013 
10014 static void *
10015 __ocs_hw_port_attach_report_fail(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
10016 {
10017         ocs_sli_port_t  *sport = ctx->app;
10018         ocs_hw_t        *hw = sport->hw;
10019 
10020         smtrace("port");
10021 
10022         switch (evt) {
10023         case OCS_EVT_ENTER:
10024                 /* free SLI resource */
10025                 sli_resource_free(&hw->sli, SLI_RSRC_FCOE_VPI, sport->indicator);
10026 
10027                 /* free mailbox buffer */
10028                 if (data != NULL) {
10029                         ocs_free(hw->os, data, SLI4_BMBX_SIZE);
10030                 }
10031 
10032                 if (hw->callback.port != NULL) {
10033                         hw->callback.port(hw->args.port,
10034                                         OCS_HW_PORT_ATTACH_FAIL, sport);
10035                 }
10036                 if (sport->sm_free_req_pending) {
10037                         ocs_sm_transition(ctx, __ocs_hw_port_free_unreg_vpi, NULL);
10038                 }
10039                 break;
10040         default:
10041                 __ocs_hw_port_common(__func__, ctx, evt, data);
10042                 break;
10043         }
10044 
10045         return NULL;
10046 }
10047 
10048 static void *
10049 __ocs_hw_port_free_unreg_vpi(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
10050 {
10051         ocs_sli_port_t  *sport = ctx->app;
10052         ocs_hw_t        *hw = sport->hw;
10053         uint8_t         *cmd = NULL;
10054 
10055         smtrace("port");
10056 
10057         switch (evt) {
10058         case OCS_EVT_ENTER:
10059                 /* allocate memory and send unreg_vpi */
10060                 cmd = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
10061                 if (!cmd) {
10062                         ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
10063                         break;
10064                 }
10065 
10066                 if (0 == sli_cmd_unreg_vpi(&hw->sli, cmd, SLI4_BMBX_SIZE, sport->indicator,
10067                                            SLI4_UNREG_TYPE_PORT)) {
10068                         ocs_log_err(hw->os, "UNREG_VPI format failure\n");
10069                         ocs_free(hw->os, cmd, SLI4_BMBX_SIZE);
10070                         ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
10071                         break;
10072                 }
10073 
10074                 if (ocs_hw_command(hw, cmd, OCS_CMD_NOWAIT, __ocs_hw_port_cb, sport)) {
10075                         ocs_log_err(hw->os, "UNREG_VPI command failure\n");
10076                         ocs_free(hw->os, cmd, SLI4_BMBX_SIZE);
10077                         ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
10078                         break;
10079                 }
10080                 break;
10081         case OCS_EVT_RESPONSE:
10082                 ocs_sm_transition(ctx, __ocs_hw_port_freed, data);
10083                 break;
10084         case OCS_EVT_ERROR:
10085                 ocs_sm_transition(ctx, __ocs_hw_port_free_report_fail, data);
10086                 break;
10087         default:
10088                 __ocs_hw_port_common(__func__, ctx, evt, data);
10089                 break;
10090         }
10091 
10092         return NULL;
10093 }
10094 
10095 static void *
10096 __ocs_hw_port_free_nop(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
10097 {
10098         ocs_sli_port_t  *sport = ctx->app;
10099         ocs_hw_t        *hw = sport->hw;
10100 
10101         smtrace("port");
10102 
10103         switch (evt) {
10104         case OCS_EVT_ENTER:
10105                 /* Forward to execute in mailbox completion processing context */
10106                 if (ocs_hw_async_call(hw, __ocs_hw_port_realloc_cb, sport)) {
10107                         ocs_log_err(hw->os, "ocs_hw_async_call failed\n");
10108                 }
10109                 break;
10110         case OCS_EVT_RESPONSE:
10111                 ocs_sm_transition(ctx, __ocs_hw_port_freed, data);
10112                 break;
10113         case OCS_EVT_ERROR:
10114                 ocs_sm_transition(ctx, __ocs_hw_port_free_report_fail, data);
10115                 break;
10116         default:
10117                 break;
10118         }
10119 
10120         return NULL;
10121 }
10122 
10123 static void *
10124 __ocs_hw_port_attached(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
10125 {
10126         ocs_sli_port_t  *sport = ctx->app;
10127         ocs_hw_t        *hw = sport->hw;
10128 
10129         smtrace("port");
10130 
10131         switch (evt) {
10132         case OCS_EVT_ENTER:
10133                 if (data != NULL) {
10134                         ocs_free(hw->os, data, SLI4_BMBX_SIZE);
10135                 }
10136                 if (hw->callback.port != NULL) {
10137                         hw->callback.port(hw->args.port,
10138                                         OCS_HW_PORT_ATTACH_OK, sport);
10139                 }
10140                 if (sport->sm_free_req_pending) {
10141                         ocs_sm_transition(ctx, __ocs_hw_port_free_unreg_vpi, NULL);
10142                 }
10143                 break;
10144         case OCS_EVT_HW_PORT_REQ_FREE:
10145                 /* virtual/physical port request free */
10146                 ocs_sm_transition(ctx, __ocs_hw_port_free_unreg_vpi, NULL);
10147                 break;
10148         default:
10149                 __ocs_hw_port_common(__func__, ctx, evt, data);
10150                 break;
10151         }
10152 
10153         return NULL;
10154 }
10155 
10156 static void *
10157 __ocs_hw_port_attach_reg_vpi(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
10158 {
10159         ocs_sli_port_t  *sport = ctx->app;
10160         ocs_hw_t        *hw = sport->hw;
10161 
10162         smtrace("port");
10163 
10164         switch (evt) {
10165         case OCS_EVT_ENTER:
10166                 if (0 == sli_cmd_reg_vpi(&hw->sli, data, SLI4_BMBX_SIZE, sport, FALSE)) {
10167                         ocs_log_err(hw->os, "REG_VPI format failure\n");
10168                         ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
10169                         break;
10170                 }
10171 
10172                 if (ocs_hw_command(hw, data, OCS_CMD_NOWAIT, __ocs_hw_port_cb, sport)) {
10173                         ocs_log_err(hw->os, "REG_VPI command failure\n");
10174                         ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
10175                         break;
10176                 }
10177                 break;
10178         case OCS_EVT_RESPONSE:
10179                 ocs_sm_transition(ctx, __ocs_hw_port_attached, data);
10180                 break;
10181         case OCS_EVT_ERROR:
10182                 ocs_sm_transition(ctx, __ocs_hw_port_attach_report_fail, data);
10183                 break;
10184         case OCS_EVT_HW_PORT_REQ_FREE:
10185                 /* Wait for attach response and then free */
10186                 sport->sm_free_req_pending = 1;
10187                 break;
10188         default:
10189                 __ocs_hw_port_common(__func__, ctx, evt, data);
10190                 break;
10191         }
10192 
10193         return NULL;
10194 }
10195 
10196 static void *
10197 __ocs_hw_port_done(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
10198 {
10199         ocs_sli_port_t  *sport = ctx->app;
10200         ocs_hw_t        *hw = sport->hw;
10201 
10202         smtrace("port");
10203 
10204         switch (evt) {
10205         case OCS_EVT_ENTER:
10206                 /* free SLI resource */
10207                 sli_resource_free(&hw->sli, SLI_RSRC_FCOE_VPI, sport->indicator);
10208 
10209                 /* free mailbox buffer */
10210                 if (data != NULL) {
10211                         ocs_free(hw->os, data, SLI4_BMBX_SIZE);
10212                 }
10213                 break;
10214         default:
10215                 __ocs_hw_port_common(__func__, ctx, evt, data);
10216                 break;
10217         }
10218 
10219         return NULL;
10220 }
10221 
10222 static void *
10223 __ocs_hw_port_allocated(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
10224 {
10225         ocs_sli_port_t  *sport = ctx->app;
10226         ocs_hw_t        *hw = sport->hw;
10227 
10228         smtrace("port");
10229 
10230         switch (evt) {
10231         case OCS_EVT_ENTER:
10232                 if (data != NULL) {
10233                         ocs_free(hw->os, data, SLI4_BMBX_SIZE);
10234                 }
10235                 if (hw->callback.port != NULL) {
10236                         hw->callback.port(hw->args.port,
10237                                         OCS_HW_PORT_ALLOC_OK, sport);
10238                 }
10239                 /* If there is a pending free request, then handle it now */
10240                 if (sport->sm_free_req_pending) {
10241                         ocs_sm_transition(ctx, __ocs_hw_port_free_unreg_vpi, NULL);
10242                 }
10243                 break;
10244         case OCS_EVT_HW_PORT_REQ_ATTACH:
10245                 /* virtual port requests attach */
10246                 ocs_sm_transition(ctx, __ocs_hw_port_attach_reg_vpi, data);
10247                 break;
10248         case OCS_EVT_HW_PORT_ATTACH_OK:
10249                 /* physical port attached (as part of attaching domain) */
10250                 ocs_sm_transition(ctx, __ocs_hw_port_attached, data);
10251                 break;
10252         case OCS_EVT_HW_PORT_REQ_FREE:
10253                 /* virtual port request free */
10254                 if (SLI4_IF_TYPE_LANCER_FC_ETH == sli_get_if_type(&hw->sli)) {
10255                         ocs_sm_transition(ctx, __ocs_hw_port_free_unreg_vpi, NULL);
10256                 } else {
10257                         /*
10258                          * Note: BE3/Skyhawk will respond with a status of 0x20
10259                          *       unless the reg_vpi has been issued, so we can
10260                          *       skip the unreg_vpi for these adapters.
10261                          *
10262                          * Send a nop to make sure that free doesn't occur in
10263                          * same context
10264                          */
10265                         ocs_sm_transition(ctx, __ocs_hw_port_free_nop, NULL);
10266                 }
10267                 break;
10268         default:
10269                 __ocs_hw_port_common(__func__, ctx, evt, data);
10270                 break;
10271         }
10272 
10273         return NULL;
10274 }
10275 
10276 static void *
10277 __ocs_hw_port_alloc_report_fail(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
10278 {
10279         ocs_sli_port_t  *sport = ctx->app;
10280         ocs_hw_t        *hw = sport->hw;
10281 
10282         smtrace("port");
10283 
10284         switch (evt) {
10285         case OCS_EVT_ENTER:
10286                 /* free SLI resource */
10287                 sli_resource_free(&hw->sli, SLI_RSRC_FCOE_VPI, sport->indicator);
10288 
10289                 /* free mailbox buffer */
10290                 if (data != NULL) {
10291                         ocs_free(hw->os, data, SLI4_BMBX_SIZE);
10292                 }
10293 
10294                 if (hw->callback.port != NULL) {
10295                         hw->callback.port(hw->args.port,
10296                                         OCS_HW_PORT_ALLOC_FAIL, sport);
10297                 }
10298 
10299                 /* If there is a pending free request, then handle it now */
10300                 if (sport->sm_free_req_pending) {
10301                         ocs_sm_transition(ctx, __ocs_hw_port_free_unreg_vpi, NULL);
10302                 }
10303                 break;
10304         default:
10305                 __ocs_hw_port_common(__func__, ctx, evt, data);
10306                 break;
10307         }
10308 
10309         return NULL;
10310 }
10311 
10312 static void *
10313 __ocs_hw_port_alloc_read_sparm64(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
10314 {
10315         ocs_sli_port_t  *sport = ctx->app;
10316         ocs_hw_t        *hw = sport->hw;
10317         uint8_t         *payload = NULL;
10318 
10319         smtrace("port");
10320 
10321         switch (evt) {
10322         case OCS_EVT_ENTER:
10323                 /* allocate memory for the service parameters */
10324                 if (ocs_dma_alloc(hw->os, &sport->dma, 112, 4)) {
10325                         ocs_log_err(hw->os, "Failed to allocate DMA memory\n");
10326                         ocs_sm_transition(ctx, __ocs_hw_port_done, data);
10327                         break;
10328                 }
10329 
10330                 if (0 == sli_cmd_read_sparm64(&hw->sli, data, SLI4_BMBX_SIZE,
10331                                         &sport->dma, sport->indicator)) {
10332                         ocs_log_err(hw->os, "READ_SPARM64 allocation failure\n");
10333                         ocs_dma_free(hw->os, &sport->dma);
10334                         ocs_sm_transition(ctx, __ocs_hw_port_done, data);
10335                         break;
10336                 }
10337 
10338                 if (ocs_hw_command(hw, data, OCS_CMD_NOWAIT, __ocs_hw_port_cb, sport)) {
10339                         ocs_log_err(hw->os, "READ_SPARM64 command failure\n");
10340                         ocs_dma_free(hw->os, &sport->dma);
10341                         ocs_sm_transition(ctx, __ocs_hw_port_done, data);
10342                         break;
10343                 }
10344                 break;
10345         case OCS_EVT_RESPONSE:
10346                 payload = sport->dma.virt;
10347 
10348                 ocs_display_sparams(sport->display_name, "sport sparm64", 0, NULL, payload);
10349 
10350                 ocs_memcpy(&sport->sli_wwpn, payload + SLI4_READ_SPARM64_WWPN_OFFSET,
10351                                 sizeof(sport->sli_wwpn));
10352                 ocs_memcpy(&sport->sli_wwnn, payload + SLI4_READ_SPARM64_WWNN_OFFSET,
10353                                 sizeof(sport->sli_wwnn));
10354 
10355                 ocs_dma_free(hw->os, &sport->dma);
10356                 ocs_sm_transition(ctx, __ocs_hw_port_alloc_init_vpi, data);
10357                 break;
10358         case OCS_EVT_ERROR:
10359                 ocs_dma_free(hw->os, &sport->dma);
10360                 ocs_sm_transition(ctx, __ocs_hw_port_alloc_report_fail, data);
10361                 break;
10362         case OCS_EVT_HW_PORT_REQ_FREE:
10363                 /* Wait for attach response and then free */
10364                 sport->sm_free_req_pending = 1;
10365                 break;
10366         case OCS_EVT_EXIT:
10367                 break;
10368         default:
10369                 __ocs_hw_port_common(__func__, ctx, evt, data);
10370                 break;
10371         }
10372 
10373         return NULL;
10374 }
10375 
10376 static void *
10377 __ocs_hw_port_alloc_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
10378 {
10379         ocs_sli_port_t  *sport = ctx->app;
10380 
10381         smtrace("port");
10382 
10383         switch (evt) {
10384         case OCS_EVT_ENTER:
10385                 /* no-op */
10386                 break;
10387         case OCS_EVT_HW_PORT_ALLOC_OK:
10388                 ocs_sm_transition(ctx, __ocs_hw_port_allocated, NULL);
10389                 break;
10390         case OCS_EVT_HW_PORT_ALLOC_FAIL:
10391                 ocs_sm_transition(ctx, __ocs_hw_port_alloc_report_fail, NULL);
10392                 break;
10393         case OCS_EVT_HW_PORT_REQ_FREE:
10394                 /* Wait for attach response and then free */
10395                 sport->sm_free_req_pending = 1;
10396                 break;
10397         default:
10398                 __ocs_hw_port_common(__func__, ctx, evt, data);
10399                 break;
10400         }
10401 
10402         return NULL;
10403 }
10404 
10405 static void *
10406 __ocs_hw_port_alloc_init_vpi(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
10407 {
10408         ocs_sli_port_t  *sport = ctx->app;
10409         ocs_hw_t        *hw = sport->hw;
10410 
10411         smtrace("port");
10412 
10413         switch (evt) {
10414         case OCS_EVT_ENTER:
10415                 /* If there is a pending free request, then handle it now */
10416                 if (sport->sm_free_req_pending) {
10417                         ocs_sm_transition(ctx, __ocs_hw_port_freed, NULL);
10418                         return NULL;
10419                 }
10420 
10421                 /* TODO XXX transitioning to done only works if this is called
10422                  * directly from ocs_hw_port_alloc BUT not if called from
10423                  * read_sparm64. In the later case, we actually want to go
10424                  * through report_ok/fail
10425                  */
10426                 if (0 == sli_cmd_init_vpi(&hw->sli, data, SLI4_BMBX_SIZE,
10427                                         sport->indicator, sport->domain->indicator)) {
10428                         ocs_log_err(hw->os, "INIT_VPI allocation failure\n");
10429                         ocs_sm_transition(ctx, __ocs_hw_port_done, data);
10430                         break;
10431                 }
10432 
10433                 if (ocs_hw_command(hw, data, OCS_CMD_NOWAIT, __ocs_hw_port_cb, sport)) {
10434                         ocs_log_err(hw->os, "INIT_VPI command failure\n");
10435                         ocs_sm_transition(ctx, __ocs_hw_port_done, data);
10436                         break;
10437                 }
10438                 break;
10439         case OCS_EVT_RESPONSE:
10440                 ocs_sm_transition(ctx, __ocs_hw_port_allocated, data);
10441                 break;
10442         case OCS_EVT_ERROR:
10443                 ocs_sm_transition(ctx, __ocs_hw_port_alloc_report_fail, data);
10444                 break;
10445         case OCS_EVT_HW_PORT_REQ_FREE:
10446                 /* Wait for attach response and then free */
10447                 sport->sm_free_req_pending = 1;
10448                 break;
10449         case OCS_EVT_EXIT:
10450                 break;
10451         default:
10452                 __ocs_hw_port_common(__func__, ctx, evt, data);
10453                 break;
10454         }
10455 
10456         return NULL;
10457 }
10458 
10459 static int32_t
10460 __ocs_hw_port_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
10461 {
10462         ocs_sli_port_t *sport = arg;
10463         sli4_mbox_command_header_t      *hdr = (sli4_mbox_command_header_t *)mqe;
10464         ocs_sm_event_t  evt;
10465 
10466         if (status || hdr->status) {
10467                 ocs_log_debug(hw->os, "bad status vpi=%#x st=%x hdr=%x\n",
10468                               sport->indicator, status, hdr->status);
10469                 evt = OCS_EVT_ERROR;
10470         } else {
10471                 evt = OCS_EVT_RESPONSE;
10472         }
10473 
10474         ocs_sm_post_event(&sport->ctx, evt, mqe);
10475 
10476         return 0;
10477 }
10478 
10479 static int32_t
10480 __ocs_hw_port_realloc_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
10481 {
10482         ocs_sli_port_t *sport = arg;
10483         sli4_mbox_command_header_t      *hdr = (sli4_mbox_command_header_t *)mqe;
10484         ocs_sm_event_t  evt;
10485         uint8_t *mqecpy;
10486 
10487         if (status || hdr->status) {
10488                 ocs_log_debug(hw->os, "bad status vpi=%#x st=%x hdr=%x\n",
10489                               sport->indicator, status, hdr->status);
10490                 evt = OCS_EVT_ERROR;
10491         } else {
10492                 evt = OCS_EVT_RESPONSE;
10493         }
10494 
10495         /*
10496          * In this case we have to malloc a mailbox command buffer, as it is reused
10497          * in the state machine post event call, and eventually freed
10498          */
10499         mqecpy = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
10500         if (mqecpy == NULL) {
10501                 ocs_log_err(hw->os, "malloc mqecpy failed\n");
10502                 return -1;
10503         }
10504         ocs_memcpy(mqecpy, mqe, SLI4_BMBX_SIZE);
10505 
10506         ocs_sm_post_event(&sport->ctx, evt, mqecpy);
10507 
10508         return 0;
10509 }
10510 
10511 /***************************************************************************
10512  * Domain state machine
10513  */
10514 
10515 static int32_t
10516 __ocs_hw_domain_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
10517 {
10518         ocs_domain_t    *domain = ctx->app;
10519         ocs_hw_t        *hw = domain->hw;
10520 
10521         smtrace("domain");
10522 
10523         switch (evt) {
10524         case OCS_EVT_EXIT:
10525                 /* ignore */
10526                 break;
10527 
10528         default:
10529                 ocs_log_test(hw->os, "%s %-20s not handled\n", funcname, ocs_sm_event_name(evt));
10530                 break;
10531         }
10532 
10533         return 0;
10534 }
10535 
10536 static void *
10537 __ocs_hw_domain_alloc_report_fail(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
10538 {
10539         ocs_domain_t    *domain = ctx->app;
10540         ocs_hw_t        *hw = domain->hw;
10541 
10542         smtrace("domain");
10543 
10544         switch (evt) {
10545         case OCS_EVT_ENTER:
10546                 /* free command buffer */
10547                 if (data != NULL) {
10548                         ocs_free(hw->os, data, SLI4_BMBX_SIZE);
10549                 }
10550                 /* free SLI resources */
10551                 sli_resource_free(&hw->sli, SLI_RSRC_FCOE_VFI, domain->indicator);
10552                 /* TODO how to free FCFI (or do we at all)? */
10553 
10554                 if (hw->callback.domain != NULL) {
10555                         hw->callback.domain(hw->args.domain,
10556                                         OCS_HW_DOMAIN_ALLOC_FAIL,
10557                                         domain);
10558                 }
10559                 break;
10560         default:
10561                 __ocs_hw_domain_common(__func__, ctx, evt, data);
10562                 break;
10563         }
10564 
10565         return NULL;
10566 }
10567 
10568 static void *
10569 __ocs_hw_domain_attached(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
10570 {
10571         ocs_domain_t    *domain = ctx->app;
10572         ocs_hw_t        *hw = domain->hw;
10573 
10574         smtrace("domain");
10575 
10576         switch (evt) {
10577         case OCS_EVT_ENTER:
10578                 /* free mailbox buffer and send alloc ok to physical sport */
10579                 ocs_free(hw->os, data, SLI4_BMBX_SIZE);
10580                 ocs_sm_post_event(&domain->sport->ctx, OCS_EVT_HW_PORT_ATTACH_OK, NULL);
10581 
10582                 /* now inform registered callbacks */
10583                 if (hw->callback.domain != NULL) {
10584                         hw->callback.domain(hw->args.domain,
10585                                         OCS_HW_DOMAIN_ATTACH_OK,
10586                                         domain);
10587                 }
10588                 break;
10589         case OCS_EVT_HW_DOMAIN_REQ_FREE:
10590                 ocs_sm_transition(ctx, __ocs_hw_domain_free_unreg_vfi, NULL);
10591                 break;
10592         default:
10593                 __ocs_hw_domain_common(__func__, ctx, evt, data);
10594                 break;
10595         }
10596 
10597         return NULL;
10598 }
10599 
10600 static void *
10601 __ocs_hw_domain_attach_report_fail(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
10602 {
10603         ocs_domain_t    *domain = ctx->app;
10604         ocs_hw_t        *hw = domain->hw;
10605 
10606         smtrace("domain");
10607 
10608         switch (evt) {
10609         case OCS_EVT_ENTER:
10610                 if (data != NULL) {
10611                         ocs_free(hw->os, data, SLI4_BMBX_SIZE);
10612                 }
10613                 /* free SLI resources */
10614                 sli_resource_free(&hw->sli, SLI_RSRC_FCOE_VFI, domain->indicator);
10615                 /* TODO how to free FCFI (or do we at all)? */
10616 
10617                 if (hw->callback.domain != NULL) {
10618                         hw->callback.domain(hw->args.domain,
10619                                         OCS_HW_DOMAIN_ATTACH_FAIL,
10620                                         domain);
10621                 }
10622                 break;
10623         case OCS_EVT_EXIT:
10624                 break;
10625         default:
10626                 __ocs_hw_domain_common(__func__, ctx, evt, data);
10627                 break;
10628         }
10629 
10630         return NULL;
10631 }
10632 
10633 static void *
10634 __ocs_hw_domain_attach_reg_vfi(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
10635 {
10636         ocs_domain_t    *domain = ctx->app;
10637         ocs_hw_t        *hw = domain->hw;
10638 
10639         smtrace("domain");
10640 
10641         switch (evt) {
10642         case OCS_EVT_ENTER:
10643 
10644                 ocs_display_sparams("", "reg vpi", 0, NULL, domain->dma.virt);
10645 
10646                 if (0 == sli_cmd_reg_vfi(&hw->sli, data, SLI4_BMBX_SIZE, domain)) {
10647                         ocs_log_err(hw->os, "REG_VFI format failure\n");
10648                         ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
10649                         break;
10650                 }
10651 
10652                 if (ocs_hw_command(hw, data, OCS_CMD_NOWAIT, __ocs_hw_domain_cb, domain)) {
10653                         ocs_log_err(hw->os, "REG_VFI command failure\n");
10654                         ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
10655                         break;
10656                 }
10657                 break;
10658         case OCS_EVT_RESPONSE:
10659                 ocs_sm_transition(ctx, __ocs_hw_domain_attached, data);
10660                 break;
10661         case OCS_EVT_ERROR:
10662                 ocs_sm_transition(ctx, __ocs_hw_domain_attach_report_fail, data);
10663                 break;
10664         default:
10665                 __ocs_hw_domain_common(__func__, ctx, evt, data);
10666                 break;
10667         }
10668 
10669         return NULL;
10670 }
10671 
10672 static void *
10673 __ocs_hw_domain_allocated(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
10674 {
10675         ocs_domain_t    *domain = ctx->app;
10676         ocs_hw_t        *hw = domain->hw;
10677 
10678         smtrace("domain");
10679 
10680         switch (evt) {
10681         case OCS_EVT_ENTER:
10682                 /* free mailbox buffer and send alloc ok to physical sport */
10683                 ocs_free(hw->os, data, SLI4_BMBX_SIZE);
10684                 ocs_sm_post_event(&domain->sport->ctx, OCS_EVT_HW_PORT_ALLOC_OK, NULL);
10685 
10686                 ocs_hw_domain_add(hw, domain);
10687 
10688                 /* now inform registered callbacks */
10689                 if (hw->callback.domain != NULL) {
10690                         hw->callback.domain(hw->args.domain,
10691                                         OCS_HW_DOMAIN_ALLOC_OK,
10692                                         domain);
10693                 }
10694                 break;
10695         case OCS_EVT_HW_DOMAIN_REQ_ATTACH:
10696                 ocs_sm_transition(ctx, __ocs_hw_domain_attach_reg_vfi, data);
10697                 break;
10698         case OCS_EVT_HW_DOMAIN_REQ_FREE:
10699                 /* unreg_fcfi/vfi */
10700                 if (SLI4_IF_TYPE_BE3_SKH_PF == sli_get_if_type(&hw->sli)) {
10701                         ocs_sm_transition(ctx, __ocs_hw_domain_free_unreg_fcfi, NULL);
10702                 } else {
10703                         ocs_sm_transition(ctx, __ocs_hw_domain_free_unreg_vfi, NULL);
10704                 }
10705                 break;
10706         default:
10707                 __ocs_hw_domain_common(__func__, ctx, evt, data);
10708                 break;
10709         }
10710 
10711         return NULL;
10712 }
10713 
10714 static void *
10715 __ocs_hw_domain_alloc_read_sparm64(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
10716 {
10717         ocs_domain_t    *domain = ctx->app;
10718         ocs_hw_t        *hw = domain->hw;
10719 
10720         smtrace("domain");
10721 
10722         switch (evt) {
10723         case OCS_EVT_ENTER:
10724                 if (0 == sli_cmd_read_sparm64(&hw->sli, data, SLI4_BMBX_SIZE,
10725                                         &domain->dma, SLI4_READ_SPARM64_VPI_DEFAULT)) {
10726                         ocs_log_err(hw->os, "READ_SPARM64 format failure\n");
10727                         ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
10728                         break;
10729                 }
10730 
10731                 if (ocs_hw_command(hw, data, OCS_CMD_NOWAIT, __ocs_hw_domain_cb, domain)) {
10732                         ocs_log_err(hw->os, "READ_SPARM64 command failure\n");
10733                         ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
10734                         break;
10735                 }
10736                 break;
10737         case OCS_EVT_EXIT:
10738                 break;
10739         case OCS_EVT_RESPONSE:
10740                 ocs_display_sparams(domain->display_name, "domain sparm64", 0, NULL, domain->dma.virt);
10741 
10742                 ocs_sm_transition(ctx, __ocs_hw_domain_allocated, data);
10743                 break;
10744         case OCS_EVT_ERROR:
10745                 ocs_sm_transition(ctx, __ocs_hw_domain_alloc_report_fail, data);
10746                 break;
10747         default:
10748                 __ocs_hw_domain_common(__func__, ctx, evt, data);
10749                 break;
10750         }
10751 
10752         return NULL;
10753 }
10754 
10755 static void *
10756 __ocs_hw_domain_alloc_init_vfi(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
10757 {
10758         ocs_domain_t    *domain = ctx->app;
10759         ocs_sli_port_t  *sport = domain->sport;
10760         ocs_hw_t        *hw = domain->hw;
10761 
10762         smtrace("domain");
10763 
10764         switch (evt) {
10765         case OCS_EVT_ENTER:
10766                 if (0 == sli_cmd_init_vfi(&hw->sli, data, SLI4_BMBX_SIZE, domain->indicator,
10767                                         domain->fcf_indicator, sport->indicator)) {
10768                         ocs_log_err(hw->os, "INIT_VFI format failure\n");
10769                         ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
10770                         break;
10771                 }
10772                 if (ocs_hw_command(hw, data, OCS_CMD_NOWAIT, __ocs_hw_domain_cb, domain)) {
10773                         ocs_log_err(hw->os, "INIT_VFI command failure\n");
10774                         ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
10775                         break;
10776                 }
10777                 break;
10778         case OCS_EVT_EXIT:
10779                 break;
10780         case OCS_EVT_RESPONSE:
10781                 ocs_sm_transition(ctx, __ocs_hw_domain_alloc_read_sparm64, data);
10782                 break;
10783         case OCS_EVT_ERROR:
10784                 ocs_sm_transition(ctx, __ocs_hw_domain_alloc_report_fail, data);
10785                 break;
10786         default:
10787                 __ocs_hw_domain_common(__func__, ctx, evt, data);
10788                 break;
10789         }
10790 
10791         return NULL;
10792 }
10793 
10794 static void *
10795 __ocs_hw_domain_alloc_reg_fcfi(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
10796 {
10797         ocs_domain_t    *domain = ctx->app;
10798         ocs_hw_t        *hw = domain->hw;
10799 
10800         smtrace("domain");
10801 
10802         switch (evt) {
10803         case OCS_EVT_ENTER: {
10804                 sli4_cmd_rq_cfg_t rq_cfg[SLI4_CMD_REG_FCFI_NUM_RQ_CFG];
10805                 uint32_t i;
10806 
10807                 /* Set the filter match/mask values from hw's filter_def values */
10808                 for (i = 0; i < SLI4_CMD_REG_FCFI_NUM_RQ_CFG; i++) {
10809                         rq_cfg[i].rq_id = 0xffff;
10810                         rq_cfg[i].r_ctl_mask = (uint8_t) hw->config.filter_def[i];
10811                         rq_cfg[i].r_ctl_match = (uint8_t) (hw->config.filter_def[i] >> 8);
10812                         rq_cfg[i].type_mask = (uint8_t) (hw->config.filter_def[i] >> 16);
10813                         rq_cfg[i].type_match = (uint8_t) (hw->config.filter_def[i] >> 24);
10814                 }
10815 
10816                 /* Set the rq_id for each, in order of RQ definition */
10817                 for (i = 0; i < hw->hw_rq_count; i++) {
10818                         if (i >= ARRAY_SIZE(rq_cfg)) {
10819                                 ocs_log_warn(hw->os, "more RQs than REG_FCFI filter entries\n");
10820                                 break;
10821                         }
10822                         rq_cfg[i].rq_id = hw->hw_rq[i]->hdr->id;
10823                 }
10824 
10825                 if (!data) {
10826                         ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
10827                         break;
10828                 }
10829 
10830                 if (hw->hw_mrq_count) {
10831                         if (OCS_HW_RTN_SUCCESS != ocs_hw_config_mrq(hw, SLI4_CMD_REG_FCFI_SET_FCFI_MODE,
10832                                  domain->vlan_id, domain->fcf)) {
10833                                 ocs_log_err(hw->os, "REG_FCFI_MRQ format failure\n");
10834                                 ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
10835                                 break;
10836                         }
10837 
10838                 } else {
10839                         if (0 == sli_cmd_reg_fcfi(&hw->sli, data, SLI4_BMBX_SIZE, domain->fcf,
10840                                                 rq_cfg, domain->vlan_id)) {
10841                                 ocs_log_err(hw->os, "REG_FCFI format failure\n");
10842                                 ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
10843                                 break;
10844                         }
10845                 }
10846 
10847                 if (ocs_hw_command(hw, data, OCS_CMD_NOWAIT, __ocs_hw_domain_cb, domain)) {
10848                         ocs_log_err(hw->os, "REG_FCFI command failure\n");
10849                         ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
10850                         break;
10851                 }
10852                 break;
10853         }
10854         case OCS_EVT_EXIT:
10855                 break;
10856         case OCS_EVT_RESPONSE:
10857                 if (!data) {
10858                         ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
10859                         break;
10860                 }
10861 
10862                 domain->fcf_indicator = ((sli4_cmd_reg_fcfi_t *)data)->fcfi;
10863 
10864                 /*
10865                  * IF_TYPE 0 devices do not support explicit VFI and VPI initialization
10866                  * and instead rely on implicit initialization during VFI registration.
10867                  * Short circuit normal processing here for those devices.
10868                  */
10869                 if (SLI4_IF_TYPE_BE3_SKH_PF == sli_get_if_type(&hw->sli)) {
10870                         ocs_sm_transition(ctx, __ocs_hw_domain_alloc_read_sparm64, data);
10871                 } else {
10872                         ocs_sm_transition(ctx, __ocs_hw_domain_alloc_init_vfi, data);
10873                 }
10874                 break;
10875         case OCS_EVT_ERROR:
10876                 ocs_sm_transition(ctx, __ocs_hw_domain_alloc_report_fail, data);
10877                 break;
10878         default:
10879                 __ocs_hw_domain_common(__func__, ctx, evt, data);
10880                 break;
10881         }
10882 
10883         return NULL;
10884 }
10885 
10886 static void *
10887 __ocs_hw_domain_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
10888 {
10889         ocs_domain_t    *domain = ctx->app;
10890         ocs_hw_t        *hw = domain->hw;
10891 
10892         smtrace("domain");
10893 
10894         switch (evt) {
10895         case OCS_EVT_ENTER:
10896                 if (sli_get_medium(&hw->sli) == SLI_LINK_MEDIUM_FC) {
10897                         /*
10898                          * For FC, the HW alread registered a FCFI
10899                          * Copy FCF information into the domain and jump to INIT_VFI
10900                          */
10901                         domain->fcf_indicator = hw->fcf_indicator;
10902                         ocs_sm_transition(&domain->sm, __ocs_hw_domain_alloc_init_vfi, data);
10903                 } else {
10904                         ocs_sm_transition(&domain->sm, __ocs_hw_domain_alloc_reg_fcfi, data);
10905                 }
10906                 break;
10907         default:
10908                 __ocs_hw_domain_common(__func__, ctx, evt, data);
10909                 break;
10910         }
10911 
10912         return NULL;
10913 }
10914 
10915 static void *
10916 __ocs_hw_domain_free_report_fail(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
10917 {
10918         ocs_domain_t    *domain = ctx->app;
10919 
10920         smtrace("domain");
10921 
10922         switch (evt) {
10923         case OCS_EVT_ENTER:
10924                 if (domain != NULL) {
10925                         ocs_hw_t        *hw = domain->hw;
10926 
10927                         ocs_hw_domain_del(hw, domain);
10928 
10929                         if (hw->callback.domain != NULL) {
10930                                 hw->callback.domain(hw->args.domain,
10931                                                      OCS_HW_DOMAIN_FREE_FAIL,
10932                                                      domain);
10933                         }
10934                 }
10935 
10936                 /* free command buffer */
10937                 if (data != NULL) {
10938                         ocs_free(domain != NULL ? domain->hw->os : NULL, data, SLI4_BMBX_SIZE);
10939                 }
10940                 break;
10941         case OCS_EVT_EXIT:
10942                 break;
10943         default:
10944                 __ocs_hw_domain_common(__func__, ctx, evt, data);
10945                 break;
10946         }
10947 
10948         return NULL;
10949 }
10950 
10951 static void *
10952 __ocs_hw_domain_freed(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
10953 {
10954         ocs_domain_t    *domain = ctx->app;
10955 
10956         smtrace("domain");
10957 
10958         switch (evt) {
10959         case OCS_EVT_ENTER:
10960                 /* Free DMA and mailbox buffer */
10961                 if (domain != NULL) {
10962                         ocs_hw_t *hw = domain->hw;
10963 
10964                         /* free VFI resource */
10965                         sli_resource_free(&hw->sli, SLI_RSRC_FCOE_VFI,
10966                                           domain->indicator);
10967 
10968                         ocs_hw_domain_del(hw, domain);
10969 
10970                         /* inform registered callbacks */
10971                         if (hw->callback.domain != NULL) {
10972                                 hw->callback.domain(hw->args.domain,
10973                                                      OCS_HW_DOMAIN_FREE_OK,
10974                                                      domain);
10975                         }
10976                 }
10977                 if (data != NULL) {
10978                         ocs_free(NULL, data, SLI4_BMBX_SIZE);
10979                 }
10980                 break;
10981         case OCS_EVT_EXIT:
10982                 break;
10983         default:
10984                 __ocs_hw_domain_common(__func__, ctx, evt, data);
10985                 break;
10986         }
10987 
10988         return NULL;
10989 }
10990 
10991 static void *
10992 __ocs_hw_domain_free_redisc_fcf(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
10993 {
10994         ocs_domain_t    *domain = ctx->app;
10995         ocs_hw_t        *hw = domain->hw;
10996 
10997         smtrace("domain");
10998 
10999         switch (evt) {
11000         case OCS_EVT_ENTER:
11001                 /* if we're in the middle of a teardown, skip sending rediscover */
11002                 if (hw->state == OCS_HW_STATE_TEARDOWN_IN_PROGRESS) {
11003                         ocs_sm_transition(ctx, __ocs_hw_domain_freed, data);
11004                         break;
11005                 }
11006                 if (0 == sli_cmd_fcoe_rediscover_fcf(&hw->sli, data, SLI4_BMBX_SIZE, domain->fcf)) {
11007                         ocs_log_err(hw->os, "REDISCOVER_FCF format failure\n");
11008                         ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
11009                         break;
11010                 }
11011 
11012                 if (ocs_hw_command(hw, data, OCS_CMD_NOWAIT, __ocs_hw_domain_cb, domain)) {
11013                         ocs_log_err(hw->os, "REDISCOVER_FCF command failure\n");
11014                         ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
11015                 }
11016                 break;
11017         case OCS_EVT_RESPONSE:
11018         case OCS_EVT_ERROR:
11019                 /* REDISCOVER_FCF can fail if none exist */
11020                 ocs_sm_transition(ctx, __ocs_hw_domain_freed, data);
11021                 break;
11022         case OCS_EVT_EXIT:
11023                 break;
11024         default:
11025                 __ocs_hw_domain_common(__func__, ctx, evt, data);
11026                 break;
11027         }
11028 
11029         return NULL;
11030 }
11031 
11032 static void *
11033 __ocs_hw_domain_free_unreg_fcfi(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
11034 {
11035         ocs_domain_t    *domain = ctx->app;
11036         ocs_hw_t        *hw = domain->hw;
11037 
11038         smtrace("domain");
11039 
11040         switch (evt) {
11041         case OCS_EVT_ENTER:
11042                 if (data == NULL) {
11043                         data = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
11044                         if (!data) {
11045                                 ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
11046                                 break;
11047                         }
11048                 }
11049 
11050                 if (0 == sli_cmd_unreg_fcfi(&hw->sli, data, SLI4_BMBX_SIZE, domain->fcf_indicator)) {
11051                         ocs_log_err(hw->os, "UNREG_FCFI format failure\n");
11052                         ocs_free(hw->os, data, SLI4_BMBX_SIZE);
11053                         ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
11054                         break;
11055                 }
11056 
11057                 if (ocs_hw_command(hw, data, OCS_CMD_NOWAIT, __ocs_hw_domain_cb, domain)) {
11058                         ocs_log_err(hw->os, "UNREG_FCFI command failure\n");
11059                         ocs_free(hw->os, data, SLI4_BMBX_SIZE);
11060                         ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
11061                         break;
11062                 }
11063                 break;
11064         case OCS_EVT_RESPONSE:
11065                 if (domain->req_rediscover_fcf) {
11066                         domain->req_rediscover_fcf = FALSE;
11067                         ocs_sm_transition(ctx, __ocs_hw_domain_free_redisc_fcf, data);
11068                 } else {
11069                         ocs_sm_transition(ctx, __ocs_hw_domain_freed, data);
11070                 }
11071                 break;
11072         case OCS_EVT_ERROR:
11073                 ocs_sm_transition(ctx, __ocs_hw_domain_free_report_fail, data);
11074                 break;
11075         case OCS_EVT_EXIT:
11076                 break;
11077         default:
11078                 __ocs_hw_domain_common(__func__, ctx, evt, data);
11079                 break;
11080         }
11081 
11082         return NULL;
11083 }
11084 
11085 static void *
11086 __ocs_hw_domain_free_unreg_vfi(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
11087 {
11088         ocs_domain_t    *domain = ctx->app;
11089         ocs_hw_t        *hw = domain->hw;
11090         uint8_t         is_fc = FALSE;
11091 
11092         smtrace("domain");
11093 
11094         is_fc = (sli_get_medium(&hw->sli) == SLI_LINK_MEDIUM_FC);
11095 
11096         switch (evt) {
11097         case OCS_EVT_ENTER:
11098                 if (data == NULL) {
11099                         data = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
11100                         if (!data) {
11101                                 ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
11102                                 break;
11103                         }
11104                 }
11105 
11106                 if (0 == sli_cmd_unreg_vfi(&hw->sli, data, SLI4_BMBX_SIZE, domain,
11107                                         SLI4_UNREG_TYPE_DOMAIN)) {
11108                         ocs_log_err(hw->os, "UNREG_VFI format failure\n");
11109                         ocs_free(hw->os, data, SLI4_BMBX_SIZE);
11110                         ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
11111                         break;
11112                 }
11113 
11114                 if (ocs_hw_command(hw, data, OCS_CMD_NOWAIT, __ocs_hw_domain_cb, domain)) {
11115                         ocs_log_err(hw->os, "UNREG_VFI command failure\n");
11116                         ocs_free(hw->os, data, SLI4_BMBX_SIZE);
11117                         ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
11118                         break;
11119                 }
11120                 break;
11121         case OCS_EVT_ERROR:
11122                 if (is_fc) {
11123                         ocs_sm_transition(ctx, __ocs_hw_domain_free_report_fail, data);
11124                 } else {
11125                         ocs_sm_transition(ctx, __ocs_hw_domain_free_unreg_fcfi, data);
11126                 }
11127                 break;
11128         case OCS_EVT_RESPONSE:
11129                 if (is_fc) {
11130                         ocs_sm_transition(ctx, __ocs_hw_domain_freed, data);
11131                 } else {
11132                         ocs_sm_transition(ctx, __ocs_hw_domain_free_unreg_fcfi, data);
11133                 }
11134                 break;
11135         default:
11136                 __ocs_hw_domain_common(__func__, ctx, evt, data);
11137                 break;
11138         }
11139 
11140         return NULL;
11141 }
11142 
11143 /* callback for domain alloc/attach/free */
11144 static int32_t
11145 __ocs_hw_domain_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
11146 {
11147         ocs_domain_t    *domain = arg;
11148         sli4_mbox_command_header_t      *hdr = (sli4_mbox_command_header_t *)mqe;
11149         ocs_sm_event_t  evt;
11150 
11151         if (status || hdr->status) {
11152                 ocs_log_debug(hw->os, "bad status vfi=%#x st=%x hdr=%x\n",
11153                               domain->indicator, status, hdr->status);
11154                 evt = OCS_EVT_ERROR;
11155         } else {
11156                 evt = OCS_EVT_RESPONSE;
11157         }
11158 
11159         ocs_sm_post_event(&domain->sm, evt, mqe);
11160 
11161         return 0;
11162 }
11163 
11164 static int32_t
11165 target_wqe_timer_nop_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
11166 {
11167         ocs_hw_io_t *io = NULL;
11168         ocs_hw_io_t *io_next = NULL;
11169         uint64_t ticks_current = ocs_get_os_ticks();
11170         uint32_t sec_elapsed;
11171         ocs_hw_rtn_e rc;
11172 
11173         sli4_mbox_command_header_t      *hdr = (sli4_mbox_command_header_t *)mqe;
11174 
11175         if (status || hdr->status) {
11176                 ocs_log_debug(hw->os, "bad status st=%x hdr=%x\n",
11177                               status, hdr->status);
11178                 /* go ahead and proceed with wqe timer checks... */
11179         }
11180 
11181         /* loop through active WQE list and check for timeouts */
11182         ocs_lock(&hw->io_lock);
11183         ocs_list_foreach_safe(&hw->io_timed_wqe, io, io_next) {
11184                 sec_elapsed = ((ticks_current - io->submit_ticks) / ocs_get_os_tick_freq());
11185 
11186                 /*
11187                  * If elapsed time > timeout, abort it. No need to check type since
11188                  * it wouldn't be on this list unless it was a target WQE
11189                  */
11190                 if (sec_elapsed > io->tgt_wqe_timeout) {
11191                         ocs_log_test(hw->os, "IO timeout xri=0x%x tag=0x%x type=%d\n",
11192                                      io->indicator, io->reqtag, io->type);
11193 
11194                         /* remove from active_wqe list so won't try to abort again */
11195                         ocs_list_remove(&hw->io_timed_wqe, io);
11196 
11197                         /* save status of "timed out" for when abort completes */
11198                         io->status_saved = 1;
11199                         io->saved_status = SLI4_FC_WCQE_STATUS_TARGET_WQE_TIMEOUT;
11200                         io->saved_ext = 0;
11201                         io->saved_len = 0;
11202 
11203                         /* now abort outstanding IO */
11204                         rc = ocs_hw_io_abort(hw, io, FALSE, NULL, NULL);
11205                         if (rc) {
11206                                 ocs_log_test(hw->os,
11207                                         "abort failed xri=%#x tag=%#x rc=%d\n",
11208                                         io->indicator, io->reqtag, rc);
11209                         }
11210                 }
11211                 /*
11212                  * need to go through entire list since each IO could have a
11213                  * different timeout value
11214                  */
11215         }
11216         ocs_unlock(&hw->io_lock);
11217 
11218         /* if we're not in the middle of shutting down, schedule next timer */
11219         if (!hw->active_wqe_timer_shutdown) {
11220                 ocs_setup_timer(hw->os, &hw->wqe_timer, target_wqe_timer_cb, hw, OCS_HW_WQ_TIMER_PERIOD_MS);
11221         }
11222         hw->in_active_wqe_timer = FALSE;
11223         return 0;
11224 }
11225 
11226 static void
11227 target_wqe_timer_cb(void *arg)
11228 {
11229         ocs_hw_t *hw = (ocs_hw_t *)arg;
11230 
11231         /* delete existing timer; will kick off new timer after checking wqe timeouts */
11232         hw->in_active_wqe_timer = TRUE;
11233         ocs_del_timer(&hw->wqe_timer);
11234 
11235         /* Forward timer callback to execute in the mailbox completion processing context */
11236         if (ocs_hw_async_call(hw, target_wqe_timer_nop_cb, hw)) {
11237                 ocs_log_test(hw->os, "ocs_hw_async_call failed\n");
11238         }
11239 }
11240 
11241 static void
11242 shutdown_target_wqe_timer(ocs_hw_t *hw)
11243 {
11244         uint32_t        iters = 100;
11245 
11246         if (hw->config.emulate_tgt_wqe_timeout) {
11247                 /* request active wqe timer shutdown, then wait for it to complete */
11248                 hw->active_wqe_timer_shutdown = TRUE;
11249 
11250                 /* delete WQE timer and wait for timer handler to complete (if necessary) */
11251                 ocs_del_timer(&hw->wqe_timer);
11252 
11253                 /* now wait for timer handler to complete (if necessary) */
11254                 while (hw->in_active_wqe_timer && iters) {
11255                         /*
11256                          * if we happen to have just sent NOP mailbox command, make sure
11257                          * completions are being processed
11258                          */
11259                         ocs_hw_flush(hw);
11260                         iters--;
11261                 }
11262 
11263                 if (iters == 0) {
11264                         ocs_log_test(hw->os, "Failed to shutdown active wqe timer\n");
11265                 }
11266         }
11267 }
11268 
11269 /**
11270  * @brief Determine if HW IO is owned by the port.
11271  *
11272  * @par Description
11273  * Determines if the given HW IO has been posted to the chip.
11274  *
11275  * @param hw Hardware context allocated by the caller.
11276  * @param io HW IO.
11277  *
11278  * @return Returns TRUE if given HW IO is port-owned.
11279  */
11280 uint8_t
11281 ocs_hw_is_io_port_owned(ocs_hw_t *hw, ocs_hw_io_t *io)
11282 {
11283         /* Check to see if this is a port owned XRI */
11284         return io->is_port_owned;
11285 }
11286 
11287 /**
11288  * @brief Return TRUE if exchange is port-owned.
11289  *
11290  * @par Description
11291  * Test to see if the xri is a port-owned xri.
11292  *
11293  * @param hw Hardware context.
11294  * @param xri Exchange indicator.
11295  *
11296  * @return Returns TRUE if XRI is a port owned XRI.
11297  */
11298 
11299 uint8_t
11300 ocs_hw_is_xri_port_owned(ocs_hw_t *hw, uint32_t xri)
11301 {
11302         ocs_hw_io_t *io = ocs_hw_io_lookup(hw, xri);
11303         return (io == NULL ? FALSE : io->is_port_owned);
11304 }
11305 
11306 /**
11307  * @brief Returns an XRI from the port owned list to the host.
11308  *
11309  * @par Description
11310  * Used when the POST_XRI command fails as well as when the RELEASE_XRI completes.
11311  *
11312  * @param hw Hardware context.
11313  * @param xri_base The starting XRI number.
11314  * @param xri_count The number of XRIs to free from the base.
11315  */
11316 static void
11317 ocs_hw_reclaim_xri(ocs_hw_t *hw, uint16_t xri_base, uint16_t xri_count)
11318 {
11319         ocs_hw_io_t     *io;
11320         uint32_t i;
11321 
11322         for (i = 0; i < xri_count; i++) {
11323                 io = ocs_hw_io_lookup(hw, xri_base + i);
11324 
11325                 /*
11326                  * if this is an auto xfer rdy XRI, then we need to release any
11327                  * buffer attached to the XRI before moving the XRI back to the free pool.
11328                  */
11329                 if (hw->auto_xfer_rdy_enabled) {
11330                         ocs_hw_rqpair_auto_xfer_rdy_move_to_host(hw, io);
11331                 }
11332 
11333                 ocs_lock(&hw->io_lock);
11334                         ocs_list_remove(&hw->io_port_owned, io);
11335                         io->is_port_owned = 0;
11336                         ocs_list_add_tail(&hw->io_free, io);
11337                 ocs_unlock(&hw->io_lock);
11338         }
11339 }
11340 
11341 /**
11342  * @brief Called when the POST_XRI command completes.
11343  *
11344  * @par Description
11345  * Free the mailbox command buffer and reclaim the XRIs on failure.
11346  *
11347  * @param hw Hardware context.
11348  * @param status Status field from the mbox completion.
11349  * @param mqe Mailbox response structure.
11350  * @param arg Pointer to a callback function that signals the caller that the command is done.
11351  *
11352  * @return Returns 0.
11353  */
11354 static int32_t
11355 ocs_hw_cb_post_xri(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void  *arg)
11356 {
11357         sli4_cmd_post_xri_t     *post_xri = (sli4_cmd_post_xri_t*)mqe;
11358 
11359         /* Reclaim the XRIs as host owned if the command fails */
11360         if (status != 0) {
11361                 ocs_log_debug(hw->os, "Status 0x%x for XRI base 0x%x, cnt =x%x\n",
11362                               status, post_xri->xri_base, post_xri->xri_count);
11363                 ocs_hw_reclaim_xri(hw, post_xri->xri_base, post_xri->xri_count);
11364         }
11365 
11366         ocs_free(hw->os, mqe, SLI4_BMBX_SIZE);
11367         return 0;
11368 }
11369 
11370 /**
11371  * @brief Issues a mailbox command to move XRIs from the host-controlled pool to the port.
11372  *
11373  * @param hw Hardware context.
11374  * @param xri_start The starting XRI to post.
11375  * @param num_to_post The number of XRIs to post.
11376  *
11377  * @return Returns OCS_HW_RTN_NO_MEMORY, OCS_HW_RTN_ERROR, or OCS_HW_RTN_SUCCESS.
11378  */
11379 
11380 static ocs_hw_rtn_e
11381 ocs_hw_post_xri(ocs_hw_t *hw, uint32_t xri_start, uint32_t num_to_post)
11382 {
11383         uint8_t *post_xri;
11384         ocs_hw_rtn_e rc = OCS_HW_RTN_ERROR;
11385 
11386         /* Since we need to allocate for mailbox queue, just always allocate */
11387         post_xri = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
11388         if (post_xri == NULL) {
11389                 ocs_log_err(hw->os, "no buffer for command\n");
11390                 return OCS_HW_RTN_NO_MEMORY;
11391         }
11392 
11393         /* Register the XRIs */
11394         if (sli_cmd_post_xri(&hw->sli, post_xri, SLI4_BMBX_SIZE,
11395                              xri_start, num_to_post)) {
11396                 rc = ocs_hw_command(hw, post_xri, OCS_CMD_NOWAIT, ocs_hw_cb_post_xri, NULL);
11397                 if (rc != OCS_HW_RTN_SUCCESS) {
11398                         ocs_free(hw->os, post_xri, SLI4_BMBX_SIZE);
11399                         ocs_log_err(hw->os, "post_xri failed\n");
11400                 }
11401         }
11402         return rc;
11403 }
11404 
11405 /**
11406  * @brief Move XRIs from the host-controlled pool to the port.
11407  *
11408  * @par Description
11409  * Removes IOs from the free list and moves them to the port.
11410  *
11411  * @param hw Hardware context.
11412  * @param num_xri The number of XRIs being requested to move to the chip.
11413  *
11414  * @return Returns the number of XRIs that were moved.
11415  */
11416 
11417 uint32_t
11418 ocs_hw_xri_move_to_port_owned(ocs_hw_t *hw, uint32_t num_xri)
11419 {
11420         ocs_hw_io_t     *io;
11421         uint32_t i;
11422         uint32_t num_posted = 0;
11423 
11424         /*
11425          * Note: We cannot use ocs_hw_io_alloc() because that would place the
11426          *       IO on the io_inuse list. We need to move from the io_free to
11427          *       the io_port_owned list.
11428          */
11429         ocs_lock(&hw->io_lock);
11430 
11431         for (i = 0; i < num_xri; i++) {
11432                 if (NULL != (io = ocs_list_remove_head(&hw->io_free))) {
11433                         ocs_hw_rtn_e rc;
11434 
11435                         /*
11436                          * if this is an auto xfer rdy XRI, then we need to attach a
11437                          * buffer to the XRI before submitting it to the chip. If a
11438                          * buffer is unavailable, then we cannot post it, so return it
11439                          * to the free pool.
11440                          */
11441                         if (hw->auto_xfer_rdy_enabled) {
11442                                 /* Note: uses the IO lock to get the auto xfer rdy buffer */
11443                                 ocs_unlock(&hw->io_lock);
11444                                 rc = ocs_hw_rqpair_auto_xfer_rdy_move_to_port(hw, io);
11445                                 ocs_lock(&hw->io_lock);
11446                                 if (rc != OCS_HW_RTN_SUCCESS) {
11447                                         ocs_list_add_head(&hw->io_free, io);
11448                                         break;
11449                                 }
11450                         }
11451                         ocs_lock_init(hw->os, &io->axr_lock, "HW_axr_lock[%d]", io->indicator);
11452                         io->is_port_owned = 1;
11453                         ocs_list_add_tail(&hw->io_port_owned, io);
11454 
11455                         /* Post XRI */
11456                         if (ocs_hw_post_xri(hw, io->indicator, 1) != OCS_HW_RTN_SUCCESS ) {
11457                                 ocs_hw_reclaim_xri(hw, io->indicator, i);
11458                                 break;
11459                         }
11460                         num_posted++;
11461                 } else {
11462                         /* no more free XRIs */
11463                         break;
11464                 }
11465         }
11466         ocs_unlock(&hw->io_lock);
11467 
11468         return num_posted;
11469 }
11470 
11471 /**
11472  * @brief Called when the RELEASE_XRI command completes.
11473  *
11474  * @par Description
11475  * Move the IOs back to the free pool on success.
11476  *
11477  * @param hw Hardware context.
11478  * @param status Status field from the mbox completion.
11479  * @param mqe Mailbox response structure.
11480  * @param arg Pointer to a callback function that signals the caller that the command is done.
11481  *
11482  * @return Returns 0.
11483  */
11484 static int32_t
11485 ocs_hw_cb_release_xri(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void  *arg)
11486 {
11487         sli4_cmd_release_xri_t  *release_xri = (sli4_cmd_release_xri_t*)mqe;
11488         uint8_t i;
11489 
11490         /* Reclaim the XRIs as host owned if the command fails */
11491         if (status != 0) {
11492                 ocs_log_err(hw->os, "Status 0x%x\n", status);
11493         } else {
11494                 for (i = 0; i < release_xri->released_xri_count; i++) {
11495                         uint16_t xri = ((i & 1) == 0 ? release_xri->xri_tbl[i/2].xri_tag0 :
11496                                         release_xri->xri_tbl[i/2].xri_tag1);
11497                         ocs_hw_reclaim_xri(hw, xri, 1);
11498                 }
11499         }
11500 
11501         ocs_free(hw->os, mqe, SLI4_BMBX_SIZE);
11502         return 0;
11503 }
11504 
11505 /**
11506  * @brief Move XRIs from the port-controlled pool to the host.
11507  *
11508  * Requests XRIs from the FW to return to the host-owned pool.
11509  *
11510  * @param hw Hardware context.
11511  * @param num_xri The number of XRIs being requested to moved from the chip.
11512  *
11513  * @return Returns 0 for success, or a negative error code value for failure.
11514  */
11515 
11516 ocs_hw_rtn_e
11517 ocs_hw_xri_move_to_host_owned(ocs_hw_t *hw, uint8_t num_xri)
11518 {
11519         uint8_t *release_xri;
11520         ocs_hw_rtn_e rc = OCS_HW_RTN_ERROR;
11521 
11522         /* non-local buffer required for mailbox queue */
11523         release_xri = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
11524         if (release_xri == NULL) {
11525                 ocs_log_err(hw->os, "no buffer for command\n");
11526                 return OCS_HW_RTN_NO_MEMORY;
11527         }
11528 
11529         /* release the XRIs */
11530         if (sli_cmd_release_xri(&hw->sli, release_xri, SLI4_BMBX_SIZE, num_xri)) {
11531                 rc = ocs_hw_command(hw, release_xri, OCS_CMD_NOWAIT, ocs_hw_cb_release_xri, NULL);
11532                 if (rc != OCS_HW_RTN_SUCCESS) {
11533                         ocs_log_err(hw->os, "release_xri failed\n");
11534                 }
11535         }
11536         /* If we are polling or an error occurred, then free the mailbox buffer */
11537         if (release_xri != NULL && rc != OCS_HW_RTN_SUCCESS) {
11538                 ocs_free(hw->os, release_xri, SLI4_BMBX_SIZE);
11539         }
11540         return rc;
11541 }
11542 
11543 /**
11544  * @brief Allocate an ocs_hw_rx_buffer_t array.
11545  *
11546  * @par Description
11547  * An ocs_hw_rx_buffer_t array is allocated, along with the required DMA memory.
11548  *
11549  * @param hw Pointer to HW object.
11550  * @param rqindex RQ index for this buffer.
11551  * @param count Count of buffers in array.
11552  * @param size Size of buffer.
11553  *
11554  * @return Returns the pointer to the allocated ocs_hw_rq_buffer_t array.
11555  */
11556 static ocs_hw_rq_buffer_t *
11557 ocs_hw_rx_buffer_alloc(ocs_hw_t *hw, uint32_t rqindex, uint32_t count, uint32_t size)
11558 {
11559         ocs_t *ocs = hw->os;
11560         ocs_hw_rq_buffer_t *rq_buf = NULL;
11561         ocs_hw_rq_buffer_t *prq;
11562         uint32_t i;
11563 
11564         if (count != 0) {
11565                 rq_buf = ocs_malloc(hw->os, sizeof(*rq_buf) * count, OCS_M_NOWAIT | OCS_M_ZERO);
11566                 if (rq_buf == NULL) {
11567                         ocs_log_err(hw->os, "Failure to allocate unsolicited DMA trackers\n");
11568                         return NULL;
11569                 }
11570 
11571                 for (i = 0, prq = rq_buf; i < count; i ++, prq++) {
11572                         prq->rqindex = rqindex;
11573                         if (ocs_dma_alloc(ocs, &prq->dma, size, OCS_MIN_DMA_ALIGNMENT)) {
11574                                 ocs_log_err(hw->os, "DMA allocation failed\n");
11575                                 ocs_free(hw->os, rq_buf, sizeof(*rq_buf) * count);
11576                                 rq_buf = NULL;
11577                                 break;
11578                         }
11579                 }
11580         }
11581         return rq_buf;
11582 }
11583 
11584 /**
11585  * @brief Free an ocs_hw_rx_buffer_t array.
11586  *
11587  * @par Description
11588  * The ocs_hw_rx_buffer_t array is freed, along with allocated DMA memory.
11589  *
11590  * @param hw Pointer to HW object.
11591  * @param rq_buf Pointer to ocs_hw_rx_buffer_t array.
11592  * @param count Count of buffers in array.
11593  *
11594  * @return None.
11595  */
11596 static void
11597 ocs_hw_rx_buffer_free(ocs_hw_t *hw, ocs_hw_rq_buffer_t *rq_buf, uint32_t count)
11598 {
11599         ocs_t *ocs = hw->os;
11600         uint32_t i;
11601         ocs_hw_rq_buffer_t *prq;
11602 
11603         if (rq_buf != NULL) {
11604                 for (i = 0, prq = rq_buf; i < count; i++, prq++) {
11605                         ocs_dma_free(ocs, &prq->dma);
11606                 }
11607                 ocs_free(hw->os, rq_buf, sizeof(*rq_buf) * count);
11608         }
11609 }
11610 
11611 /**
11612  * @brief Allocate the RQ data buffers.
11613  *
11614  * @param hw Pointer to HW object.
11615  *
11616  * @return Returns 0 on success, or a non-zero value on failure.
11617  */
11618 ocs_hw_rtn_e
11619 ocs_hw_rx_allocate(ocs_hw_t *hw)
11620 {
11621         ocs_t *ocs = hw->os;
11622         uint32_t i;
11623         int32_t rc = OCS_HW_RTN_SUCCESS;
11624         uint32_t rqindex = 0;
11625         hw_rq_t *rq;
11626         uint32_t hdr_size = OCS_HW_RQ_SIZE_HDR;
11627         uint32_t payload_size = hw->config.rq_default_buffer_size;
11628 
11629         rqindex = 0;
11630 
11631         for (i = 0; i < hw->hw_rq_count; i++) {
11632                 rq = hw->hw_rq[i];
11633 
11634                 /* Allocate header buffers */
11635                 rq->hdr_buf = ocs_hw_rx_buffer_alloc(hw, rqindex, rq->entry_count, hdr_size);
11636                 if (rq->hdr_buf == NULL) {
11637                         ocs_log_err(ocs, "ocs_hw_rx_buffer_alloc hdr_buf failed\n");
11638                         rc = OCS_HW_RTN_ERROR;
11639                         break;
11640                 }
11641 
11642                 ocs_log_debug(hw->os, "rq[%2d] rq_id %02d header  %4d by %4d bytes\n", i, rq->hdr->id,
11643                               rq->entry_count, hdr_size);
11644 
11645                 rqindex++;
11646 
11647                 /* Allocate payload buffers */
11648                 rq->payload_buf = ocs_hw_rx_buffer_alloc(hw, rqindex, rq->entry_count, payload_size);
11649                 if (rq->payload_buf == NULL) {
11650                         ocs_log_err(ocs, "ocs_hw_rx_buffer_alloc fb_buf failed\n");
11651                         rc = OCS_HW_RTN_ERROR;
11652                         break;
11653                 }
11654                 ocs_log_debug(hw->os, "rq[%2d] rq_id %02d default %4d by %4d bytes\n", i, rq->data->id,
11655                               rq->entry_count, payload_size);
11656                 rqindex++;
11657         }
11658 
11659         return rc ? OCS_HW_RTN_ERROR : OCS_HW_RTN_SUCCESS;
11660 }
11661 
11662 /**
11663  * @brief Post the RQ data buffers to the chip.
11664  *
11665  * @param hw Pointer to HW object.
11666  *
11667  * @return Returns 0 on success, or a non-zero value on failure.
11668  */
11669 ocs_hw_rtn_e
11670 ocs_hw_rx_post(ocs_hw_t *hw)
11671 {
11672         uint32_t i;
11673         uint32_t idx;
11674         uint32_t rq_idx;
11675         int32_t rc = 0;
11676 
11677         /*
11678          * In RQ pair mode, we MUST post the header and payload buffer at the
11679          * same time.
11680          */
11681         for (rq_idx = 0, idx = 0; rq_idx < hw->hw_rq_count; rq_idx++) {
11682                 hw_rq_t *rq = hw->hw_rq[rq_idx];
11683 
11684                 for (i = 0; i < rq->entry_count-1; i++) {
11685                         ocs_hw_sequence_t *seq = ocs_array_get(hw->seq_pool, idx++);
11686                         ocs_hw_assert(seq != NULL);
11687 
11688                         seq->header = &rq->hdr_buf[i];
11689 
11690                         seq->payload = &rq->payload_buf[i];
11691 
11692                         rc = ocs_hw_sequence_free(hw, seq);
11693                         if (rc) {
11694                                 break;
11695                         }
11696                 }
11697                 if (rc) {
11698                         break;
11699                 }
11700         }
11701 
11702         return rc;
11703 }
11704 
11705 /**
11706  * @brief Free the RQ data buffers.
11707  *
11708  * @param hw Pointer to HW object.
11709  *
11710  */
11711 void
11712 ocs_hw_rx_free(ocs_hw_t *hw)
11713 {
11714         hw_rq_t *rq;
11715         uint32_t i;
11716 
11717         /* Free hw_rq buffers */
11718         for (i = 0; i < hw->hw_rq_count; i++) {
11719                 rq = hw->hw_rq[i];
11720                 if (rq != NULL) {
11721                         ocs_hw_rx_buffer_free(hw, rq->hdr_buf, rq->entry_count);
11722                         rq->hdr_buf = NULL;
11723                         ocs_hw_rx_buffer_free(hw, rq->payload_buf, rq->entry_count);
11724                         rq->payload_buf = NULL;
11725                 }
11726         }
11727 }
11728 
11729 /**
11730  * @brief HW async call context structure.
11731  */
11732 typedef struct {
11733         ocs_hw_async_cb_t callback;
11734         void *arg;
11735         uint8_t cmd[SLI4_BMBX_SIZE];
11736 } ocs_hw_async_call_ctx_t;
11737 
11738 /**
11739  * @brief HW async callback handler
11740  *
11741  * @par Description
11742  * This function is called when the NOP mailbox command completes.  The callback stored
11743  * in the requesting context is invoked.
11744  *
11745  * @param hw Pointer to HW object.
11746  * @param status Completion status.
11747  * @param mqe Pointer to mailbox completion queue entry.
11748  * @param arg Caller-provided argument.
11749  *
11750  * @return None.
11751  */
11752 static void
11753 ocs_hw_async_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
11754 {
11755         ocs_hw_async_call_ctx_t *ctx = arg;
11756 
11757         if (ctx != NULL) {
11758                 if (ctx->callback != NULL) {
11759                         (*ctx->callback)(hw, status, mqe, ctx->arg);
11760                 }
11761                 ocs_free(hw->os, ctx, sizeof(*ctx));
11762         }
11763 }
11764 
11765 /**
11766  * @brief Make an async callback using NOP mailbox command
11767  *
11768  * @par Description
11769  * Post a NOP mailbox command; the callback with argument is invoked upon completion
11770  * while in the event processing context.
11771  *
11772  * @param hw Pointer to HW object.
11773  * @param callback Pointer to callback function.
11774  * @param arg Caller-provided callback.
11775  *
11776  * @return Returns 0 on success, or a negative error code value on failure.
11777  */
11778 int32_t
11779 ocs_hw_async_call(ocs_hw_t *hw, ocs_hw_async_cb_t callback, void *arg)
11780 {
11781         int32_t rc = 0;
11782         ocs_hw_async_call_ctx_t *ctx;
11783 
11784         /*
11785          * Allocate a callback context (which includes the mailbox command buffer), we need
11786          * this to be persistent as the mailbox command submission may be queued and executed later
11787          * execution.
11788          */
11789         ctx = ocs_malloc(hw->os, sizeof(*ctx), OCS_M_ZERO | OCS_M_NOWAIT);
11790         if (ctx == NULL) {
11791                 ocs_log_err(hw->os, "failed to malloc async call context\n");
11792                 return OCS_HW_RTN_NO_MEMORY;
11793         }
11794         ctx->callback = callback;
11795         ctx->arg = arg;
11796 
11797         /* Build and send a NOP mailbox command */
11798         if (sli_cmd_common_nop(&hw->sli, ctx->cmd, sizeof(ctx->cmd), 0) == 0) {
11799                 ocs_log_err(hw->os, "COMMON_NOP format failure\n");
11800                 ocs_free(hw->os, ctx, sizeof(*ctx));
11801                 rc = -1;
11802         }
11803 
11804         if (ocs_hw_command(hw, ctx->cmd, OCS_CMD_NOWAIT, ocs_hw_async_cb, ctx)) {
11805                 ocs_log_err(hw->os, "COMMON_NOP command failure\n");
11806                 ocs_free(hw->os, ctx, sizeof(*ctx));
11807                 rc = -1;
11808         }
11809         return rc;
11810 }
11811 
11812 /**
11813  * @brief Initialize the reqtag pool.
11814  *
11815  * @par Description
11816  * The WQ request tag pool is initialized.
11817  *
11818  * @param hw Pointer to HW object.
11819  *
11820  * @return Returns 0 on success, or a negative error code value on failure.
11821  */
11822 ocs_hw_rtn_e
11823 ocs_hw_reqtag_init(ocs_hw_t *hw)
11824 {
11825         if (hw->wq_reqtag_pool == NULL) {
11826                 hw->wq_reqtag_pool = ocs_pool_alloc(hw->os, sizeof(hw_wq_callback_t), 65536, TRUE);
11827                 if (hw->wq_reqtag_pool == NULL) {
11828                         ocs_log_err(hw->os, "ocs_pool_alloc hw_wq_callback_t failed\n");
11829                         return OCS_HW_RTN_NO_MEMORY;
11830                 }
11831         }
11832         ocs_hw_reqtag_reset(hw);
11833         return OCS_HW_RTN_SUCCESS;
11834 }
11835 
11836 /**
11837  * @brief Allocate a WQ request tag.
11838  *
11839  * Allocate and populate a WQ request tag from the WQ request tag pool.
11840  *
11841  * @param hw Pointer to HW object.
11842  * @param callback Callback function.
11843  * @param arg Pointer to callback argument.
11844  *
11845  * @return Returns pointer to allocated WQ request tag, or NULL if object cannot be allocated.
11846  */
11847 hw_wq_callback_t *
11848 ocs_hw_reqtag_alloc(ocs_hw_t *hw, void (*callback)(void *arg, uint8_t *cqe, int32_t status), void *arg)
11849 {
11850         hw_wq_callback_t *wqcb;
11851 
11852         ocs_hw_assert(callback != NULL);
11853 
11854         wqcb = ocs_pool_get(hw->wq_reqtag_pool);
11855         if (wqcb != NULL) {
11856                 ocs_hw_assert(wqcb->callback == NULL);
11857                 wqcb->callback = callback;
11858                 wqcb->arg = arg;
11859         }
11860         return wqcb;
11861 }
11862 
11863 /**
11864  * @brief Free a WQ request tag.
11865  *
11866  * Free the passed in WQ request tag.
11867  *
11868  * @param hw Pointer to HW object.
11869  * @param wqcb Pointer to WQ request tag object to free.
11870  *
11871  * @return None.
11872  */
11873 void
11874 ocs_hw_reqtag_free(ocs_hw_t *hw, hw_wq_callback_t *wqcb)
11875 {
11876         ocs_hw_assert(wqcb->callback != NULL);
11877         wqcb->callback = NULL;
11878         wqcb->arg = NULL;
11879         ocs_pool_put(hw->wq_reqtag_pool, wqcb);
11880 }
11881 
11882 /**
11883  * @brief Return WQ request tag by index.
11884  *
11885  * @par Description
11886  * Return pointer to WQ request tag object given an index.
11887  *
11888  * @param hw Pointer to HW object.
11889  * @param instance_index Index of WQ request tag to return.
11890  *
11891  * @return Pointer to WQ request tag, or NULL.
11892  */
11893 hw_wq_callback_t *
11894 ocs_hw_reqtag_get_instance(ocs_hw_t *hw, uint32_t instance_index)
11895 {
11896         hw_wq_callback_t *wqcb;
11897 
11898         wqcb = ocs_pool_get_instance(hw->wq_reqtag_pool, instance_index);
11899         if (wqcb == NULL) {
11900                 ocs_log_err(hw->os, "wqcb for instance %d is null\n", instance_index);
11901         }
11902         return wqcb;
11903 }
11904 
11905 /**
11906  * @brief Reset the WQ request tag pool.
11907  *
11908  * @par Description
11909  * Reset the WQ request tag pool, returning all to the free list.
11910  *
11911  * @param hw pointer to HW object.
11912  *
11913  * @return None.
11914  */
11915 void
11916 ocs_hw_reqtag_reset(ocs_hw_t *hw)
11917 {
11918         hw_wq_callback_t *wqcb;
11919         uint32_t i;
11920 
11921         /* Remove all from freelist */
11922         while(ocs_pool_get(hw->wq_reqtag_pool) != NULL) {
11923                 ;
11924         }
11925 
11926         /* Put them all back */
11927         for (i = 0; ((wqcb = ocs_pool_get_instance(hw->wq_reqtag_pool, i)) != NULL); i++) {
11928                 wqcb->instance_index = i;
11929                 wqcb->callback = NULL;
11930                 wqcb->arg = NULL;
11931                 ocs_pool_put(hw->wq_reqtag_pool, wqcb);
11932         }
11933 }
11934 
11935 /**
11936  * @brief Handle HW assertion
11937  *
11938  * HW assert, display diagnostic message, and abort.
11939  *
11940  * @param cond string describing failing assertion condition
11941  * @param filename file name
11942  * @param linenum line number
11943  *
11944  * @return none
11945  */
11946 void
11947 _ocs_hw_assert(const char *cond, const char *filename, int linenum)
11948 {
11949         ocs_printf("%s(%d): HW assertion (%s) failed\n", filename, linenum, cond);
11950         ocs_abort();
11951                 /* no return */
11952 }
11953 
11954 /**
11955  * @brief Handle HW verify
11956  *
11957  * HW verify, display diagnostic message, dump stack and return.
11958  *
11959  * @param cond string describing failing verify condition
11960  * @param filename file name
11961  * @param linenum line number
11962  *
11963  * @return none
11964  */
11965 void
11966 _ocs_hw_verify(const char *cond, const char *filename, int linenum)
11967 {
11968         ocs_printf("%s(%d): HW verify (%s) failed\n", filename, linenum, cond);
11969         ocs_print_stack();
11970 }
11971 
11972 /**
11973  * @brief Reque XRI
11974  *
11975  * @par Description
11976  * Reque XRI
11977  *
11978  * @param hw Pointer to HW object.
11979  * @param io Pointer to HW IO
11980  *
11981  * @return Return 0 if successful else returns -1
11982  */
11983 int32_t 
11984 ocs_hw_reque_xri( ocs_hw_t *hw, ocs_hw_io_t *io )
11985 {
11986         int32_t rc = 0;
11987 
11988         rc = ocs_hw_rqpair_auto_xfer_rdy_buffer_post(hw, io, 1);
11989         if (rc) {
11990                 ocs_list_add_tail(&hw->io_port_dnrx, io);
11991                 rc = -1;
11992                 goto exit_ocs_hw_reque_xri;
11993         }
11994 
11995         io->auto_xfer_rdy_dnrx = 0;
11996         io->type = OCS_HW_IO_DNRX_REQUEUE;
11997         if (sli_requeue_xri_wqe(&hw->sli, io->wqe.wqebuf, hw->sli.config.wqe_size, io->indicator, OCS_HW_REQUE_XRI_REGTAG, SLI4_CQ_DEFAULT)) {
11998                 /* Clear buffer from XRI */
11999                 ocs_pool_put(hw->auto_xfer_rdy_buf_pool, io->axr_buf);
12000                 io->axr_buf = NULL;
12001 
12002                 ocs_log_err(hw->os, "requeue_xri WQE error\n");
12003                 ocs_list_add_tail(&hw->io_port_dnrx, io);
12004 
12005                 rc = -1;
12006                 goto exit_ocs_hw_reque_xri;
12007         }
12008 
12009         if (io->wq == NULL) {
12010                 io->wq = ocs_hw_queue_next_wq(hw, io);
12011                 ocs_hw_assert(io->wq != NULL);
12012         }
12013 
12014         /*
12015          * Add IO to active io wqe list before submitting, in case the
12016          * wcqe processing preempts this thread.
12017          */
12018         OCS_STAT(hw->tcmd_wq_submit[io->wq->instance]++);
12019         OCS_STAT(io->wq->use_count++);
12020 
12021         rc = hw_wq_write(io->wq, &io->wqe);
12022         if (rc < 0) {
12023                 ocs_log_err(hw->os, "sli_queue_write reque xri failed: %d\n", rc);
12024                 rc = -1;
12025         }
12026 
12027 exit_ocs_hw_reque_xri:
12028         return 0;
12029 }
12030 
12031 uint32_t
12032 ocs_hw_get_def_wwn(ocs_t *ocs, uint32_t chan, uint64_t *wwpn, uint64_t *wwnn)
12033 {
12034         sli4_t *sli4 = &ocs->hw.sli;
12035         ocs_dma_t       dma;
12036         uint8_t         *payload = NULL;
12037 
12038         int indicator = sli4->config.extent[SLI_RSRC_FCOE_VPI].base[0] + chan;
12039 
12040         /* allocate memory for the service parameters */
12041         if (ocs_dma_alloc(ocs, &dma, 112, 4)) {
12042                 ocs_log_err(ocs, "Failed to allocate DMA memory\n");
12043                 return 1;
12044         }
12045 
12046         if (0 == sli_cmd_read_sparm64(sli4, sli4->bmbx.virt, SLI4_BMBX_SIZE,
12047                                 &dma, indicator)) {
12048                 ocs_log_err(ocs, "READ_SPARM64 allocation failure\n");
12049                 ocs_dma_free(ocs, &dma);
12050                 return 1;
12051         }
12052 
12053         if (sli_bmbx_command(sli4)) {
12054                 ocs_log_err(ocs, "READ_SPARM64 command failure\n");
12055                 ocs_dma_free(ocs, &dma);
12056                 return 1;
12057         }
12058 
12059         payload = dma.virt;
12060         ocs_memcpy(wwpn, payload + SLI4_READ_SPARM64_WWPN_OFFSET, sizeof(*wwpn));
12061         ocs_memcpy(wwnn, payload + SLI4_READ_SPARM64_WWNN_OFFSET, sizeof(*wwnn));
12062         ocs_dma_free(ocs, &dma);
12063         return 0;
12064 }
12065 
12066 /**
12067  * @page fc_hw_api_overview HW APIs
12068  * - @ref devInitShutdown
12069  * - @ref domain
12070  * - @ref port
12071  * - @ref node
12072  * - @ref io
12073  * - @ref interrupt
12074  *
12075  * <div class="overview">
12076  * The Hardware Abstraction Layer (HW) insulates the higher-level code from the SLI-4
12077  * message details, but the higher level code must still manage domains, ports,
12078  * IT nexuses, and IOs. The HW API is designed to help the higher level manage
12079  * these objects.<br><br>
12080  *
12081  * The HW uses function callbacks to notify the higher-level code of events
12082  * that are received from the chip. There are currently three types of
12083  * functions that may be registered:
12084  *
12085  * <ul><li>domain – This function is called whenever a domain event is generated
12086  * within the HW. Examples include a new FCF is discovered, a connection
12087  * to a domain is disrupted, and allocation callbacks.</li>
12088  * <li>unsolicited – This function is called whenever new data is received in
12089  * the SLI-4 receive queue.</li>
12090  * <li>rnode – This function is called for remote node events, such as attach status
12091  * and  allocation callbacks.</li></ul>
12092  *
12093  * Upper layer functions may be registered by using the ocs_hw_callback() function.
12094  *
12095  * <img src="elx_fc_hw.jpg" alt="FC/FCoE HW" title="FC/FCoE HW" align="right"/>
12096  * <h2>FC/FCoE HW API</h2>
12097  * The FC/FCoE HW component builds upon the SLI-4 component to establish a flexible
12098  * interface for creating the necessary common objects and sending I/Os. It may be used
12099  * “as is” in customer implementations or it can serve as an example of typical interactions
12100  * between a driver and the SLI-4 hardware. The broad categories of functionality include:
12101  *
12102  * <ul><li>Setting-up and tearing-down of the HW.</li>
12103  * <li>Allocating and using the common objects (SLI Port, domain, remote node).</li>
12104  * <li>Sending and receiving I/Os.</li></ul>
12105  *
12106  * <h3>HW Setup</h3>
12107  * To set up the HW:
12108  *
12109  * <ol>
12110  * <li>Set up the HW object using ocs_hw_setup().<br>
12111  * This step performs a basic configuration of the SLI-4 component and the HW to
12112  * enable querying the hardware for its capabilities. At this stage, the HW is not
12113  * capable of general operations (such as, receiving events or sending I/Os).</li><br><br>
12114  * <li>Configure the HW according to the driver requirements.<br>
12115  * The HW provides functions to discover hardware capabilities (ocs_hw_get()), as
12116  * well as configures the amount of resources required (ocs_hw_set()). The driver
12117  * must also register callback functions (ocs_hw_callback()) to receive notification of
12118  * various asynchronous events.<br><br>
12119  * @b Note: Once configured, the driver must initialize the HW (ocs_hw_init()). This
12120  * step creates the underlying queues, commits resources to the hardware, and
12121  * prepares the hardware for operation. While the hardware is operational, the
12122  * port is not online, and cannot send or receive data.</li><br><br>
12123  * <br><br>
12124  * <li>Finally, the driver can bring the port online (ocs_hw_port_control()).<br>
12125  * When the link comes up, the HW determines if a domain is present and notifies the
12126  * driver using the domain callback function. This is the starting point of the driver's
12127  * interaction with the common objects.<br><br>
12128  * @b Note: For FCoE, there may be more than one domain available and, therefore,
12129  * more than one callback.</li>
12130  * </ol>
12131  *
12132  * <h3>Allocating and Using Common Objects</h3>
12133  * Common objects provide a mechanism through which the various OneCore Storage
12134  * driver components share and track information. These data structures are primarily
12135  * used to track SLI component information but can be extended by other components, if
12136  * needed. The main objects are:
12137  *
12138  * <ul><li>DMA – the ocs_dma_t object describes a memory region suitable for direct
12139  * memory access (DMA) transactions.</li>
12140  * <li>SCSI domain – the ocs_domain_t object represents the SCSI domain, including
12141  * any infrastructure devices such as FC switches and FC forwarders. The domain
12142  * object contains both an FCFI and a VFI.</li>
12143  * <li>SLI Port (sport) – the ocs_sli_port_t object represents the connection between
12144  * the driver and the SCSI domain. The SLI Port object contains a VPI.</li>
12145  * <li>Remote node – the ocs_remote_node_t represents a connection between the SLI
12146  * Port and another device in the SCSI domain. The node object contains an RPI.</li></ul>
12147  *
12148  * Before the driver can send I/Os, it must allocate the SCSI domain, SLI Port, and remote
12149  * node common objects and establish the connections between them. The goal is to
12150  * connect the driver to the SCSI domain to exchange I/Os with other devices. These
12151  * common object connections are shown in the following figure, FC Driver Common Objects:
12152  * <img src="elx_fc_common_objects.jpg"
12153  * alt="FC Driver Common Objects" title="FC Driver Common Objects" align="center"/>
12154  *
12155  * The first step is to create a connection to the domain by allocating an SLI Port object.
12156  * The SLI Port object represents a particular FC ID and must be initialized with one. With
12157  * the SLI Port object, the driver can discover the available SCSI domain(s). On identifying
12158  * a domain, the driver allocates a domain object and attaches to it using the previous SLI
12159  * port object.<br><br>
12160  *
12161  * @b Note: In some cases, the driver may need to negotiate service parameters (that is,
12162  * FLOGI) with the domain before attaching.<br><br>
12163  *
12164  * Once attached to the domain, the driver can discover and attach to other devices
12165  * (remote nodes). The exact discovery method depends on the driver, but it typically
12166  * includes using a position map, querying the fabric name server, or an out-of-band
12167  * method. In most cases, it is necessary to log in with devices before performing I/Os.
12168  * Prior to sending login-related ELS commands (ocs_hw_srrs_send()), the driver must
12169  * allocate a remote node object (ocs_hw_node_alloc()). If the login negotiation is
12170  * successful, the driver must attach the nodes (ocs_hw_node_attach()) to the SLI Port
12171  * before exchanging FCP I/O.<br><br>
12172  *
12173  * @b Note: The HW manages both the well known fabric address and the name server as
12174  * nodes in the domain. Therefore, the driver must allocate node objects prior to
12175  * communicating with either of these entities.
12176  *
12177  * <h3>Sending and Receiving I/Os</h3>
12178  * The HW provides separate interfaces for sending BLS/ ELS/ FC-CT and FCP, but the
12179  * commands are conceptually similar. Since the commands complete asynchronously,
12180  * the caller must provide a HW I/O object that maintains the I/O state, as well as
12181  * provide a callback function. The driver may use the same callback function for all I/O
12182  * operations, but each operation must use a unique HW I/O object. In the SLI-4
12183  * architecture, there is a direct association between the HW I/O object and the SGL used
12184  * to describe the data. Therefore, a driver typically performs the following operations:
12185  *
12186  * <ul><li>Allocates a HW I/O object (ocs_hw_io_alloc()).</li>
12187  * <li>Formats the SGL, specifying both the HW I/O object and the SGL.
12188  * (ocs_hw_io_init_sges() and ocs_hw_io_add_sge()).</li>
12189  * <li>Sends the HW I/O (ocs_hw_io_send()).</li></ul>
12190  *
12191  * <h3>HW Tear Down</h3>
12192  * To tear-down the HW:
12193  *
12194  * <ol><li>Take the port offline (ocs_hw_port_control()) to prevent receiving further
12195  * data andevents.</li>
12196  * <li>Destroy the HW object (ocs_hw_teardown()).</li>
12197  * <li>Free any memory used by the HW, such as buffers for unsolicited data.</li></ol>
12198  * <br>
12199  * </div><!-- overview -->
12200  *
12201  */
12202 
12203 /**
12204  * This contains all hw runtime workaround code.  Based on the asic type,
12205  * asic revision, and range of fw revisions, a particular workaround may be enabled.
12206  *
12207  * A workaround may consist of overriding a particular HW/SLI4 value that was initialized
12208  * during ocs_hw_setup() (for example the MAX_QUEUE overrides for mis-reported queue
12209  * sizes). Or if required, elements of the ocs_hw_workaround_t structure may be set to
12210  * control specific runtime behavior.
12211  *
12212  * It is intended that the controls in ocs_hw_workaround_t be defined functionally.  So we
12213  * would have the driver look like:  "if (hw->workaround.enable_xxx) then ...", rather than
12214  * what we might previously see as "if this is a BE3, then do xxx"
12215  *
12216  */
12217 
12218 #define HW_FWREV_ZERO           (0ull)
12219 #define HW_FWREV_MAX            (~0ull)
12220 
12221 #define SLI4_ASIC_TYPE_ANY      0
12222 #define SLI4_ASIC_REV_ANY       0
12223 
12224 /**
12225  * @brief Internal definition of workarounds
12226  */
12227 
12228 typedef enum {
12229         HW_WORKAROUND_TEST = 1,
12230         HW_WORKAROUND_MAX_QUEUE,        /**< Limits all queues */
12231         HW_WORKAROUND_MAX_RQ,           /**< Limits only the RQ */
12232         HW_WORKAROUND_RETAIN_TSEND_IO_LENGTH,
12233         HW_WORKAROUND_WQE_COUNT_METHOD,
12234         HW_WORKAROUND_RQE_COUNT_METHOD,
12235         HW_WORKAROUND_USE_UNREGISTERD_RPI,
12236         HW_WORKAROUND_DISABLE_AR_TGT_DIF, /**< Disable of auto-response target DIF */
12237         HW_WORKAROUND_DISABLE_SET_DUMP_LOC,
12238         HW_WORKAROUND_USE_DIF_QUARANTINE,
12239         HW_WORKAROUND_USE_DIF_SEC_XRI,          /**< Use secondary xri for multiple data phases */
12240         HW_WORKAROUND_OVERRIDE_FCFI_IN_SRB,     /**< FCFI reported in SRB not correct, use "first" registered domain */
12241         HW_WORKAROUND_FW_VERSION_TOO_LOW,       /**< The FW version is not the min version supported by this driver */
12242         HW_WORKAROUND_SGLC_MISREPORTED, /**< Chip supports SGL Chaining but SGLC is not set in SLI4_PARAMS */
12243         HW_WORKAROUND_IGNORE_SEND_FRAME_CAPABLE,        /**< Don't use SEND_FRAME capable if FW version is too old */
12244 } hw_workaround_e;
12245 
12246 /**
12247  * @brief Internal workaround structure instance
12248  */
12249 
12250 typedef struct {
12251         sli4_asic_type_e asic_type;
12252         sli4_asic_rev_e asic_rev;
12253         uint64_t fwrev_low;
12254         uint64_t fwrev_high;
12255 
12256         hw_workaround_e workaround;
12257         uint32_t value;
12258 } hw_workaround_t;
12259 
12260 static hw_workaround_t hw_workarounds[] = {
12261         {SLI4_ASIC_TYPE_ANY,    SLI4_ASIC_REV_ANY, HW_FWREV_ZERO, HW_FWREV_MAX,
12262                 HW_WORKAROUND_TEST, 999},
12263 
12264         /* Bug: 127585: if_type == 2 returns 0 for total length placed on
12265          * FCP_TSEND64_WQE completions.   Note, original driver code enables this
12266          * workaround for all asic types
12267          */
12268         {SLI4_ASIC_TYPE_ANY,    SLI4_ASIC_REV_ANY, HW_FWREV_ZERO, HW_FWREV_MAX,
12269                 HW_WORKAROUND_RETAIN_TSEND_IO_LENGTH, 0},
12270 
12271         /* Bug: unknown, Lancer A0 has mis-reported max queue depth */
12272         {SLI4_ASIC_TYPE_LANCER, SLI4_ASIC_REV_A0, HW_FWREV_ZERO, HW_FWREV_MAX,
12273                 HW_WORKAROUND_MAX_QUEUE, 2048},
12274 
12275         /* Bug: 143399, BE3 has mis-reported max RQ queue depth */
12276         {SLI4_ASIC_TYPE_BE3,    SLI4_ASIC_REV_ANY, HW_FWREV_ZERO, HW_FWREV(4,6,293,0),
12277                 HW_WORKAROUND_MAX_RQ, 2048},
12278 
12279         /* Bug: 143399, skyhawk has mis-reported max RQ queue depth */
12280         {SLI4_ASIC_TYPE_SKYHAWK, SLI4_ASIC_REV_ANY, HW_FWREV_ZERO, HW_FWREV(10,0,594,0),
12281                 HW_WORKAROUND_MAX_RQ, 2048},
12282 
12283         /* Bug: 103487, BE3 before f/w 4.2.314.0 has mis-reported WQE count method */
12284         {SLI4_ASIC_TYPE_BE3,    SLI4_ASIC_REV_ANY, HW_FWREV_ZERO, HW_FWREV(4,2,314,0),
12285                 HW_WORKAROUND_WQE_COUNT_METHOD, 1},
12286 
12287         /* Bug: 103487, BE3 before f/w 4.2.314.0 has mis-reported RQE count method */
12288         {SLI4_ASIC_TYPE_BE3,    SLI4_ASIC_REV_ANY, HW_FWREV_ZERO, HW_FWREV(4,2,314,0),
12289                 HW_WORKAROUND_RQE_COUNT_METHOD, 1},
12290 
12291         /* Bug: 142968, BE3 UE with RPI == 0xffff */
12292         {SLI4_ASIC_TYPE_BE3,    SLI4_ASIC_REV_ANY, HW_FWREV_ZERO, HW_FWREV_MAX,
12293                 HW_WORKAROUND_USE_UNREGISTERD_RPI, 0},
12294 
12295         /* Bug: unknown, Skyhawk won't support auto-response on target T10-PI  */
12296         {SLI4_ASIC_TYPE_SKYHAWK, SLI4_ASIC_REV_ANY, HW_FWREV_ZERO, HW_FWREV_MAX,
12297                 HW_WORKAROUND_DISABLE_AR_TGT_DIF, 0},
12298 
12299         {SLI4_ASIC_TYPE_LANCER, SLI4_ASIC_REV_ANY, HW_FWREV_ZERO, HW_FWREV(1,1,65,0),
12300                 HW_WORKAROUND_DISABLE_SET_DUMP_LOC, 0},
12301 
12302         /* Bug: 160124, Skyhawk quarantine DIF XRIs  */
12303         {SLI4_ASIC_TYPE_SKYHAWK, SLI4_ASIC_REV_ANY, HW_FWREV_ZERO, HW_FWREV_MAX,
12304                 HW_WORKAROUND_USE_DIF_QUARANTINE, 0},
12305 
12306         /* Bug: 161832, Skyhawk use secondary XRI for multiple data phase TRECV */
12307         {SLI4_ASIC_TYPE_SKYHAWK, SLI4_ASIC_REV_ANY, HW_FWREV_ZERO, HW_FWREV_MAX,
12308                 HW_WORKAROUND_USE_DIF_SEC_XRI, 0},
12309 
12310         /* Bug: xxxxxx, FCFI reported in SRB not corrrect */
12311         {SLI4_ASIC_TYPE_LANCER, SLI4_ASIC_REV_ANY, HW_FWREV_ZERO, HW_FWREV_MAX,
12312                 HW_WORKAROUND_OVERRIDE_FCFI_IN_SRB, 0},
12313 #if 0
12314         /* Bug: 165642, FW version check for driver */
12315         {SLI4_ASIC_TYPE_LANCER, SLI4_ASIC_REV_ANY, HW_FWREV_ZERO, HW_FWREV_1(OCS_MIN_FW_VER_LANCER),
12316                 HW_WORKAROUND_FW_VERSION_TOO_LOW, 0},
12317 #endif
12318         {SLI4_ASIC_TYPE_SKYHAWK, SLI4_ASIC_REV_ANY, HW_FWREV_ZERO, HW_FWREV_1(OCS_MIN_FW_VER_SKYHAWK),
12319                 HW_WORKAROUND_FW_VERSION_TOO_LOW, 0},
12320 
12321         /* Bug 177061, Lancer FW does not set the SGLC bit */
12322         {SLI4_ASIC_TYPE_LANCER, SLI4_ASIC_REV_ANY, HW_FWREV_ZERO, HW_FWREV_MAX,
12323                 HW_WORKAROUND_SGLC_MISREPORTED, 0},
12324 
12325         /* BZ 181208/183914, enable this workaround for ALL revisions */
12326         {SLI4_ASIC_TYPE_ANY, SLI4_ASIC_REV_ANY, HW_FWREV_ZERO, HW_FWREV_MAX,
12327                 HW_WORKAROUND_IGNORE_SEND_FRAME_CAPABLE, 0},
12328 };
12329 
12330 /**
12331  * @brief Function prototypes
12332  */
12333 
12334 static int32_t ocs_hw_workaround_match(ocs_hw_t *hw, hw_workaround_t *w);
12335 
12336 /**
12337  * @brief Parse the firmware version (name)
12338  *
12339  * Parse a string of the form a.b.c.d, returning a uint64_t packed as defined
12340  * by the HW_FWREV() macro
12341  *
12342  * @param fwrev_string pointer to the firmware string
12343  *
12344  * @return packed firmware revision value
12345  */
12346 
12347 static uint64_t
12348 parse_fw_version(const char *fwrev_string)
12349 {
12350         int v[4] = {0};
12351         const char *p;
12352         int i;
12353 
12354         for (p = fwrev_string, i = 0; *p && (i < 4); i ++) {
12355                 v[i] = ocs_strtoul(p, 0, 0);
12356                 while(*p && *p != '.') {
12357                         p ++;
12358                 }
12359                 if (*p) {
12360                         p ++;
12361                 }
12362         }
12363 
12364         /* Special case for bootleg releases with f/w rev 0.0.9999.0, set to max value */
12365         if (v[2] == 9999) {
12366                 return HW_FWREV_MAX;
12367         } else {
12368                 return HW_FWREV(v[0], v[1], v[2], v[3]);
12369         }
12370 }
12371 
12372 /**
12373  * @brief Test for a workaround match
12374  *
12375  * Looks at the asic type, asic revision, and fw revision, and returns TRUE if match.
12376  *
12377  * @param hw Pointer to the HW structure
12378  * @param w Pointer to a workaround structure entry
12379  *
12380  * @return Return TRUE for a match
12381  */
12382 
12383 static int32_t
12384 ocs_hw_workaround_match(ocs_hw_t *hw, hw_workaround_t *w)
12385 {
12386         return (((w->asic_type == SLI4_ASIC_TYPE_ANY) || (w->asic_type == hw->sli.asic_type)) &&
12387                     ((w->asic_rev == SLI4_ASIC_REV_ANY) || (w->asic_rev == hw->sli.asic_rev)) &&
12388                     (w->fwrev_low <= hw->workaround.fwrev) &&
12389                     ((w->fwrev_high == HW_FWREV_MAX) || (hw->workaround.fwrev < w->fwrev_high)));
12390 }
12391 
12392 /**
12393  * @brief Setup HW runtime workarounds
12394  *
12395  * The function is called at the end of ocs_hw_setup() to setup any runtime workarounds
12396  * based on the HW/SLI setup.
12397  *
12398  * @param hw Pointer to HW structure
12399  *
12400  * @return none
12401  */
12402 
12403 void
12404 ocs_hw_workaround_setup(struct ocs_hw_s *hw)
12405 {
12406         hw_workaround_t *w;
12407         sli4_t *sli4 = &hw->sli;
12408         uint32_t i;
12409 
12410         /* Initialize the workaround settings */
12411         ocs_memset(&hw->workaround, 0, sizeof(hw->workaround));
12412 
12413         /* If hw_war_version is non-null, then its a value that was set by a module parameter
12414          * (sorry for the break in abstraction, but workarounds are ... well, workarounds)
12415          */
12416 
12417         if (hw->hw_war_version) {
12418                 hw->workaround.fwrev = parse_fw_version(hw->hw_war_version);
12419         } else {
12420                 hw->workaround.fwrev = parse_fw_version((char*) sli4->config.fw_name[0]);
12421         }
12422 
12423         /* Walk the workaround list, if a match is found, then handle it */
12424         for (i = 0, w = hw_workarounds; i < ARRAY_SIZE(hw_workarounds); i++, w++) {
12425                 if (ocs_hw_workaround_match(hw, w)) {
12426                         switch(w->workaround) {
12427                         case HW_WORKAROUND_TEST: {
12428                                 ocs_log_debug(hw->os, "Override: test: %d\n", w->value);
12429                                 break;
12430                         }
12431 
12432                         case HW_WORKAROUND_RETAIN_TSEND_IO_LENGTH: {
12433                                 ocs_log_debug(hw->os, "HW Workaround: retain TSEND IO length\n");
12434                                 hw->workaround.retain_tsend_io_length = 1;
12435                                 break;
12436                         }
12437                         case HW_WORKAROUND_MAX_QUEUE: {
12438                                 sli4_qtype_e q;
12439 
12440                                 ocs_log_debug(hw->os, "HW Workaround: override max_qentries: %d\n", w->value);
12441                                 for (q = SLI_QTYPE_EQ; q < SLI_QTYPE_MAX; q++) {
12442                                         if (hw->num_qentries[q] > w->value) {
12443                                                 hw->num_qentries[q] = w->value;
12444                                         }
12445                                 }
12446                                 break;
12447                         }
12448                         case HW_WORKAROUND_MAX_RQ: {
12449                                 ocs_log_debug(hw->os, "HW Workaround: override RQ max_qentries: %d\n", w->value);
12450                                 if (hw->num_qentries[SLI_QTYPE_RQ] > w->value) {
12451                                         hw->num_qentries[SLI_QTYPE_RQ] = w->value;
12452                                 }
12453                                 break;
12454                         }
12455                         case HW_WORKAROUND_WQE_COUNT_METHOD: {
12456                                 ocs_log_debug(hw->os, "HW Workaround: set WQE count method=%d\n", w->value);
12457                                 sli4->config.count_method[SLI_QTYPE_WQ] = w->value;
12458                                 sli_calc_max_qentries(sli4);
12459                                 break;
12460                         }
12461                         case HW_WORKAROUND_RQE_COUNT_METHOD: {
12462                                 ocs_log_debug(hw->os, "HW Workaround: set RQE count method=%d\n", w->value);
12463                                 sli4->config.count_method[SLI_QTYPE_RQ] = w->value;
12464                                 sli_calc_max_qentries(sli4);
12465                                 break;
12466                         }
12467                         case HW_WORKAROUND_USE_UNREGISTERD_RPI:
12468                                 ocs_log_debug(hw->os, "HW Workaround: use unreg'd RPI if rnode->indicator == 0xFFFF\n");
12469                                 hw->workaround.use_unregistered_rpi = TRUE;
12470                                 /*
12471                                  * Allocate an RPI that is never registered, to be used in the case where
12472                                  * a node has been unregistered, and its indicator (RPI) value is set to 0xFFFF
12473                                  */
12474                                 if (sli_resource_alloc(&hw->sli, SLI_RSRC_FCOE_RPI, &hw->workaround.unregistered_rid,
12475                                         &hw->workaround.unregistered_index)) {
12476                                         ocs_log_err(hw->os, "sli_resource_alloc unregistered RPI failed\n");
12477                                         hw->workaround.use_unregistered_rpi = FALSE;
12478                                 }
12479                                 break;
12480                         case HW_WORKAROUND_DISABLE_AR_TGT_DIF:
12481                                 ocs_log_debug(hw->os, "HW Workaround: disable AR on T10-PI TSEND\n");
12482                                 hw->workaround.disable_ar_tgt_dif = TRUE;
12483                                 break;
12484                         case HW_WORKAROUND_DISABLE_SET_DUMP_LOC:
12485                                 ocs_log_debug(hw->os, "HW Workaround: disable set_dump_loc\n");
12486                                 hw->workaround.disable_dump_loc = TRUE;
12487                                 break;
12488                         case HW_WORKAROUND_USE_DIF_QUARANTINE:
12489                                 ocs_log_debug(hw->os, "HW Workaround: use DIF quarantine\n");
12490                                 hw->workaround.use_dif_quarantine = TRUE;
12491                                 break;
12492                         case HW_WORKAROUND_USE_DIF_SEC_XRI:
12493                                 ocs_log_debug(hw->os, "HW Workaround: use DIF secondary xri\n");
12494                                 hw->workaround.use_dif_sec_xri = TRUE;
12495                                 break;
12496                         case HW_WORKAROUND_OVERRIDE_FCFI_IN_SRB:
12497                                 ocs_log_debug(hw->os, "HW Workaround: override FCFI in SRB\n");
12498                                 hw->workaround.override_fcfi = TRUE;
12499                                 break;
12500 
12501                         case HW_WORKAROUND_FW_VERSION_TOO_LOW:
12502                                 ocs_log_debug(hw->os, "HW Workaround: fw version is below the minimum for this driver\n");
12503                                 hw->workaround.fw_version_too_low = TRUE;
12504                                 break;
12505                         case HW_WORKAROUND_SGLC_MISREPORTED:
12506                                 ocs_log_debug(hw->os, "HW Workaround: SGLC misreported - chaining is enabled\n");
12507                                 hw->workaround.sglc_misreported = TRUE;
12508                                 break;
12509                         case HW_WORKAROUND_IGNORE_SEND_FRAME_CAPABLE:
12510                                 ocs_log_debug(hw->os, "HW Workaround: not SEND_FRAME capable - disabled\n");
12511                                 hw->workaround.ignore_send_frame = TRUE;
12512                                 break;
12513                         } /* switch(w->workaround) */
12514                 }
12515         }
12516 }

Cache object: 24e127203df58fd888e1e82e18019af4


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