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