Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ocs_hal.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011-2018, Emulex
3  * All rights reserved.
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 /**
34  * @file
35  * Defines and implements the Hardware Abstraction Layer (HAL).
36  * All interaction with the hardware is performed through the HAL, which abstracts
37  * the details of the underlying SLI-4 implementation.
38  */
39 
40 /**
41  * @defgroup devInitShutdown Device Initialization and Shutdown
42  * @defgroup domain Domain Functions
43  * @defgroup port Port Functions
44  * @defgroup node Remote Node Functions
45  * @defgroup io IO Functions
46  * @defgroup interrupt Interrupt handling
47  * @defgroup os OS Required Functions
48  */
49 
50 #include "ocs.h"
51 #include "ocs_os.h"
52 #include "ocs_hal.h"
53 #include "ocs_hal_queues.h"
54 #include "ocs_ras.h"
55 
56 #define OCS_HAL_READ_FCF_SIZE 4096
57 #define OCS_HAL_DEFAULT_AUTO_XFER_RDY_IOS 256
58 #define OCS_HAL_WQ_TIMER_PERIOD_MS 500
59 
60 /* Values used for setting the optimized write parameters */
61 #define OCS_HAL_TOW_BLK_SIZE_DEFAULT 0 /* 512 bytes */
62 #define OCS_HAL_TOW_REF_TAG_LBA_DEFAULT TRUE
63 #define OCS_HAL_TOW_APP_TAG_VALID_DEFAULT FALSE
64 #define OCS_HAL_TOW_APP_TAG_VALUE_DEFAULT 0
65 
66 /* By design driver elects not to receive completion CQE for REQUEUE_XRI WQE.
67  * However FW will still generate a CQE if it encounters an error while processing
68  * REQUEUE_XRI request. In order to handle completion CQE with error status,
69  * driver pre-allocates & sets aside a completion context for REQUEUE_XRI WQE.
70  */
71 #define OCS_HAL_REQUE_XRI_REGTAG 65534
72 
73 /* max command and response buffer lengths -- arbitrary at the moment */
74 #define OCS_HAL_DMTF_CLP_CMD_MAX 256
75 #define OCS_HAL_DMTF_CLP_RSP_MAX 256
76 
77 /* HAL global data */
79 
80 static void ocs_hal_queue_hash_add(ocs_queue_hash_t *, uint16_t, uint16_t);
81 static void ocs_hal_adjust_wqs(ocs_hal_t *hal);
82 static uint32_t ocs_hal_get_num_chutes(ocs_hal_t *hal);
83 static int32_t ocs_hal_cb_link(void *, void *);
84 static int32_t ocs_hal_cb_fip(void *, void *);
85 static int32_t ocs_hal_command_process(ocs_hal_t *, int32_t, uint8_t *, size_t);
86 static int32_t ocs_hal_mq_process(ocs_hal_t *, int32_t, sli4_queue_t *);
87 static int32_t ocs_hal_cb_read_fcf(ocs_hal_t *, int32_t, uint8_t *, void *);
88 static int32_t ocs_hal_cb_node_attach(ocs_hal_t *, int32_t, uint8_t *, void *);
89 static int32_t ocs_hal_cb_node_free(ocs_hal_t *, int32_t, uint8_t *, void *);
90 static int32_t ocs_hal_cb_unreg_rpi_all(ocs_hal_t *, int32_t, uint8_t *, void *);
91 static ocs_hal_rtn_e ocs_hal_setup_io(ocs_hal_t *);
92 static ocs_hal_rtn_e ocs_hal_init_io(ocs_hal_t *);
93 static int32_t ocs_hal_command_cancel(ocs_hal_t *);
94 static void ocs_hal_io_quarantine(ocs_hal_t *hal, hal_wq_t *wq, ocs_hal_io_t *io);
95 static void ocs_hal_io_restore_sgl(ocs_hal_t *, ocs_hal_io_t *);
96 static int32_t ocs_hal_io_ini_sge(ocs_hal_t *, ocs_hal_io_t *, ocs_dma_t *, uint32_t, ocs_dma_t *);
97 static ocs_hal_rtn_e ocs_hal_firmware_write_lancer(ocs_hal_t *hal, ocs_dma_t *dma, uint32_t size, uint32_t offset, int last, ocs_hal_fw_cb_t cb, void *arg);
98 static int32_t ocs_hal_cb_fw_write(ocs_hal_t *, int32_t, uint8_t *, void *);
99 static int32_t ocs_hal_cb_sfp(ocs_hal_t *, int32_t, uint8_t *, void *);
100 static int32_t ocs_hal_cb_temp(ocs_hal_t *, int32_t, uint8_t *, void *);
101 static int32_t ocs_hal_cb_link_stat(ocs_hal_t *, int32_t, uint8_t *, void *);
102 static int32_t ocs_hal_cb_host_stat(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg);
103 static void ocs_hal_dmtf_clp_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg);
104 static int32_t ocs_hal_clp_resp_get_value(ocs_hal_t *hal, const char *keyword, char *value, uint32_t value_len, const char *resp, uint32_t resp_len);
105 typedef void (*ocs_hal_dmtf_clp_cb_t)(ocs_hal_t *hal, int32_t status, uint32_t result_len, void *arg);
106 static ocs_hal_rtn_e ocs_hal_exec_dmtf_clp_cmd(ocs_hal_t *hal, ocs_dma_t *dma_cmd, ocs_dma_t *dma_resp, uint32_t opts, ocs_hal_dmtf_clp_cb_t cb, void *arg);
107 static void ocs_hal_linkcfg_dmtf_clp_cb(ocs_hal_t *hal, int32_t status, uint32_t result_len, void *arg);
108 
109 static int32_t __ocs_read_topology_cb(ocs_hal_t *, int32_t, uint8_t *, void *);
110 static int32_t __ocs_read_fec_cb(ocs_hal_t *, int32_t, uint8_t *, void *);
111 static void __ocs_hal_read_lmt_cb(ocs_hal_t *, int32_t, uint8_t *, void *);
112 static ocs_hal_rtn_e ocs_hal_get_linkcfg(ocs_hal_t *, uint32_t, ocs_hal_port_control_cb_t, void *);
113 static ocs_hal_rtn_e ocs_hal_get_linkcfg_lancer(ocs_hal_t *, uint32_t, ocs_hal_port_control_cb_t, void *);
114 static ocs_hal_rtn_e ocs_hal_get_linkcfg_skyhawk(ocs_hal_t *, uint32_t, ocs_hal_port_control_cb_t, void *);
115 static ocs_hal_rtn_e ocs_hal_set_linkcfg(ocs_hal_t *, ocs_hal_linkcfg_e, uint32_t, ocs_hal_port_control_cb_t, void *);
118 static void ocs_hal_init_linkcfg_cb(int32_t status, uintptr_t value, void *arg);
119 static ocs_hal_rtn_e ocs_hal_set_eth_license(ocs_hal_t *hal, uint32_t license);
120 static ocs_hal_rtn_e ocs_hal_set_dif_seed(ocs_hal_t *hal);
121 static ocs_hal_rtn_e ocs_hal_set_dif_mode(ocs_hal_t *hal);
122 static void ocs_hal_io_free_internal(void *arg);
123 static void ocs_hal_io_free_port_owned(void *arg);
124 static ocs_hal_rtn_e ocs_hal_config_axr_t10pi(ocs_hal_t *hal);
125 static ocs_hal_rtn_e ocs_hal_config_tow_t10pi(ocs_hal_t *hal);
126 static ocs_hal_rtn_e ocs_hal_config_set_fdt_xfer_hint(ocs_hal_t *hal, uint32_t fdt_xfer_hint);
127 static void ocs_hal_wq_process_abort(void *arg, uint8_t *cqe, int32_t status);
128 static int32_t ocs_hal_config_mrq(ocs_hal_t *hal, uint8_t, uint16_t, uint16_t);
129 static ocs_hal_rtn_e ocs_hal_config_watchdog_timer(ocs_hal_t *hal);
130 static ocs_hal_rtn_e ocs_hal_config_sli_port_health_check(ocs_hal_t *hal, uint8_t query, uint8_t enable);
131 static ocs_hal_rtn_e ocs_hal_config_fec(ocs_hal_t *hal, uint8_t enable);
132 static ocs_hal_rtn_e ocs_hal_config_fw_ag_rsp(ocs_hal_t *hal, uint8_t enable);
133 static ocs_hal_rtn_e ocs_hal_config_sliport_pause(ocs_hal_t *hal, uint8_t enable);
134 
135 /* HAL domain database operations */
136 static int32_t ocs_hal_domain_add(ocs_hal_t *, ocs_domain_t *);
137 static int32_t ocs_hal_domain_del(ocs_hal_t *, ocs_domain_t *);
138 
139 
140 /* Port state machine */
141 static void *__ocs_hal_port_alloc_init(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
142 static void *__ocs_hal_port_alloc_read_sparm64(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
143 static void *__ocs_hal_port_alloc_init_vpi(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
144 static void *__ocs_hal_port_done(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
145 static void *__ocs_hal_port_free_unreg_vpi(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
146 
147 /* Domain state machine */
148 static void *__ocs_hal_domain_init(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
149 static void *__ocs_hal_domain_alloc_reg_fcfi(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
150 static void * __ocs_hal_domain_alloc_init_vfi(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
151 static void *__ocs_hal_domain_free_unreg_vfi(ocs_sm_ctx_t *, ocs_sm_event_t, void *);
152 static void *__ocs_hal_domain_free_unreg_fcfi(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data);
153 static int32_t __ocs_hal_domain_cb(ocs_hal_t *, int32_t, uint8_t *, void *);
154 static int32_t __ocs_hal_port_cb(ocs_hal_t *, int32_t, uint8_t *, void *);
155 static int32_t __ocs_hal_port_realloc_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg);
156 
157 /* BZ 161832 */
158 static void ocs_hal_check_sec_hio_list(ocs_hal_t *hal);
159 
160 /* WQE timeouts */
161 static void target_wqe_timer_cb(void *arg);
162 static void shutdown_target_wqe_timer(ocs_hal_t *hal);
163 
164 /* Adapter firmware diagnostic logging (RAS) */
165 static ocs_hal_rtn_e ocs_hal_config_fw_diagnostic_logging(ocs_hal_t *hal, int32_t log_size, int32_t log_level);
167 
168 static void
170 {
171  ocs_log_err(hal->os, "SLI4_RSP: cmd_opcode: %#x, cmd_subsystem: %#x, status: %#x, addl_status: %#x\n",
172  hdr->opcode, hdr->subsystem, hdr->status, hdr->additional_status);
173  ocs_log_err(hal->os, " %08X %08X %08X %08X\n", ((uint32_t *)hdr)[0],
174  ((uint32_t *)hdr)[1], ((uint32_t *)hdr)[2], ((uint32_t *)hdr)[3]);
175 }
176 
177 static ocs_hal_rtn_e ocs_hal_init_tow_esoc(ocs_hal_t *hal, uint32_t tow_feature)
178 {
179  uint32_t ramdisc_blocksize = 512;
180  uint8_t buf[SLI4_BMBX_SIZE];
181  int32_t len = 0;
182  char prop_buf[32];
184 
185  if (ocs_get_property("ramdisc_blocksize", prop_buf, sizeof(prop_buf)) == 0) {
186  ramdisc_blocksize = ocs_strtoul(prop_buf, 0, 0);
187  }
188 
189  if (sli_get_auto_xfer_rdy_capable(&hal->sli)) {
190  len = sli_cmd_config_auto_xfer_rdy_hp(&hal->sli, buf, SLI4_BMBX_SIZE,
191  hal->config.tow_io_size,
192  ramdisc_blocksize);
193  } else if (sli_get_tow_capable(&hal->sli)) {
195  hal->config.tow_io_size,
196  hal->config.tow_xri_cnt,
197  ramdisc_blocksize, tow_feature);
198  }
199 
200  if (len <= 0) {
201  ocs_log_err(hal->os, "Failed to populate TOW ESOC command\n");
202  return rc;
203  }
204 
205  rc = ocs_hal_command(hal, buf, OCS_CMD_POLL, NULL, NULL);
206  if (rc || ((sli4_mbox_command_header_t *)buf)->status)
207  return OCS_HAL_RTN_ERROR;
208 
209  return rc;
210 }
211 
212 static ocs_hal_rtn_e ocs_hal_init_tow(ocs_hal_t *hal, uint32_t tow_feature)
213 {
214  uint8_t buf[SLI4_BMBX_SIZE];
215  int32_t len = 0;
217 
218  if (sli_get_auto_xfer_rdy_capable(&hal->sli)) {
219  len = sli_cmd_config_auto_xfer_rdy(&hal->sli, buf, SLI4_BMBX_SIZE,
220  hal->config.tow_io_size);
221  } else if (sli_get_tow_capable(&hal->sli)) {
222  len = sli_cmd_config_optimized_write(&hal->sli, buf, SLI4_BMBX_SIZE,
223  hal->config.tow_io_size,
224  hal->config.tow_xri_cnt,
225  tow_feature);
226  }
227 
228  if (len <= 0) {
229  ocs_log_err(hal->os, "Failed to populate TOW comamnd\n");
230  return rc;
231  }
232 
233  rc = ocs_hal_command(hal, buf, OCS_CMD_POLL, NULL, NULL);
234  if (rc || ((sli4_mbox_command_header_t *)buf)->status)
235  return OCS_HAL_RTN_ERROR;
236 
237  return rc;
238 }
239 
240 static ocs_hal_rtn_e ocs_hal_init_tow_t10pi(ocs_hal_t *hal)
241 {
243 
244  if (sli_get_auto_xfer_rdy_capable(&hal->sli)) {
245  rc = ocs_hal_config_axr_t10pi(hal);
246  if (rc != OCS_HAL_RTN_SUCCESS) {
247  ocs_log_err(hal->os, "Failed to config AXR T10 PI\n");
248  }
249  } else if (sli_get_tow_capable(&hal->sli)) {
250  rc = ocs_hal_config_tow_t10pi(hal);
251  if (rc != OCS_HAL_RTN_SUCCESS) {
252  ocs_log_err(hal->os, "Failed to config tow T10 PI\n");
253  }
254  }
255 
256  return rc;
257 }
258 
259 /**
260  * @brief Initialize TOW feature for AXR/FB
261  */
263 {
264  uint32_t tow_feature = 0;
265  int32_t rc = OCS_HAL_RTN_ERROR;
266 
267  hal->tow_enabled = FALSE;
268 
269  ocs_hal_get(hal, OCS_HAL_TOW_FEATURE, &tow_feature);
270  if (!tow_feature)
271  return OCS_HAL_RTN_SUCCESS;
272 
273  if (hal->config.esoc) {
274  rc = ocs_hal_init_tow_esoc(hal, tow_feature);
275  } else {
276  rc = ocs_hal_init_tow(hal, tow_feature);
277  }
278 
279  if (rc) {
280  ocs_log_err(hal->os, "Failed to enable TOW feature\n");
281  return rc;
282  }
283 
284  if (hal->config.tow_t10_enable) {
285  rc = ocs_hal_init_tow_t10pi(hal);
286  if (rc != OCS_HAL_RTN_SUCCESS) {
287  ocs_log_err(hal->os, "Failed to config optimized write T10 PI\n");
288  return rc;
289  }
290  }
291 
292  hal->tow_enabled = TRUE;
293  ocs_log_info(hal->os, "TOW feature is successfully enabled\n");
294  return rc;
295 }
296 
297 static inline void
298 ocs_hal_add_io_timed_wqe(ocs_hal_t *hal, ocs_hal_io_t *io)
299 {
300  if (hal->config.emulate_tgt_wqe_timeout && io->tgt_wqe_timeout) {
301  /*
302  * Active WQE list currently only used for
303  * target WQE timeouts.
304  */
305  ocs_lock(&hal->io_lock);
306  ocs_list_add_tail(&hal->io_timed_wqe, io);
307  io->submit_ticks = ocs_get_os_ticks();
308  ocs_unlock(&hal->io_lock);
309  }
310 }
311 
312 static inline void
313 ocs_hal_remove_io_timed_wqe(ocs_hal_t *hal, ocs_hal_io_t *io)
314 {
315  if (hal->config.emulate_tgt_wqe_timeout) {
316  /*
317  * If target wqe timeouts are enabled,
318  * remove from active wqe list.
319  */
320  ocs_lock(&hal->io_lock);
321  if (ocs_list_on_list(&io->wqe_link)) {
322  ocs_list_remove(&hal->io_timed_wqe, io);
323  }
324  ocs_unlock(&hal->io_lock);
325  }
326 }
327 
328 static uint8_t ocs_hal_iotype_is_originator(uint16_t io_type)
329 {
330  switch (io_type) {
334  case OCS_HAL_FC_CT:
335  case OCS_HAL_ELS_REQ:
336  return 1;
337  default:
338  return 0;
339  }
340 }
341 
342 static uint8_t ocs_hal_wcqe_abort_needed(uint16_t status, uint8_t ext, uint8_t xb)
343 {
344  /* if exchange not active, nothing to abort */
345  if (!xb) {
346  return FALSE;
347  }
348  if (status == SLI4_FC_WCQE_STATUS_LOCAL_REJECT) {
349  switch (ext) {
350  /* exceptions where abort is not needed */
351  case SLI4_FC_LOCAL_REJECT_INVALID_RPI: /* lancer returns this after unreg_rpi */
352  case SLI4_FC_LOCAL_REJECT_ABORT_REQUESTED: /* abort already in progress */
353  /* WQE failed because link went down. Depending on the timing, FW will complete pending WQEs
354  * with extended status as either RPI_SUSPENDED or LINK_DOWN */
357  return FALSE;
358  default:
359  break;
360  }
361  }
362  return TRUE;
363 }
364 
365 /**
366  * @brief Determine the number of chutes on the device.
367  *
368  * @par Description
369  * Some devices require queue resources allocated per protocol processor
370  * (chute). This function returns the number of chutes on this device.
371  *
372  * @param hal Hardware context allocated by the caller.
373  *
374  * @return Returns the number of chutes on the device for protocol.
375  */
376 static uint32_t
377 ocs_hal_get_num_chutes(ocs_hal_t *hal)
378 {
379  uint32_t num_chutes = 1;
380 
381  if (sli_get_is_dual_ulp_capable(&hal->sli) &&
382  sli_get_is_ulp_enabled(&hal->sli, 0) &&
383  sli_get_is_ulp_enabled(&hal->sli, 1)) {
384  num_chutes = 2;
385  }
386  return num_chutes;
387 }
388 
389 static ocs_hal_rtn_e
390 ocs_hal_link_event_init(ocs_hal_t *hal)
391 {
392  if (hal == NULL) {
393  ocs_log_err(NULL, "bad parameter hal=%p\n", hal);
394  return OCS_HAL_RTN_ERROR;
395  }
396 
397  hal->link.status = SLI_LINK_STATUS_MAX;
398  hal->link.topology = SLI_LINK_TOPO_NONE;
399  hal->link.medium = SLI_LINK_MEDIUM_MAX;
400  hal->link.speed = 0;
401  hal->link.logical_link_speed = 0;
402  hal->link.loop_map = NULL;
403  hal->link.fc_id = UINT32_MAX;
404 
405  return OCS_HAL_RTN_SUCCESS;
406 }
407 
408 /**
409  * @ingroup devInitShutdown
410  * @brief Read the max dump size for this port
411  *
412  * @par Description
413  * Queries the FW for the maximum dump size
414  *
415  * @param hal Hardware context allocated by the caller.
416  *
417  * @return Returns 0 on success, or a non-zero value on failure.
418  */
419 static ocs_hal_rtn_e
421 {
422  uint8_t buf[SLI4_BMBX_SIZE];
423  int rc;
424 
425  /* lancer only */
426  if ((SLI4_IF_TYPE_LANCER_FC_ETH != sli_get_if_type(&hal->sli)) &&
427  (SLI4_IF_TYPE_LANCER_G7 != sli_get_if_type(&hal->sli))) {
428  ocs_log_debug(hal->os, "Function only supported for I/F type 2/6\n");
429  return OCS_HAL_RTN_ERROR;
430  }
431 
432  /*
433  * Make sure the FW is new enough to support this command. If the FW
434  * is too old, the FW will UE.
435  */
436  if (hal->workaround.disable_dump_loc) {
437  ocs_log_test(hal->os, "FW version is too old for this feature\n");
438  return OCS_HAL_RTN_ERROR;
439  }
440 
441  sli_cmd_common_set_dump_location(&hal->sli, buf, SLI4_BMBX_SIZE, 1, 0, NULL, 0);
442  rc = ocs_hal_command(hal, buf, OCS_CMD_POLL, NULL, NULL);
443  if (OCS_HAL_RTN_SUCCESS == rc) {
444  sli4_cmd_sli_config_t *mbox_rsp = (sli4_cmd_sli_config_t *)buf;
447 
448  if ((0 == mbox_rsp->hdr.status) && (0 == sli4_rsp->hdr.status)) {
449  hal->dump_size = sli4_rsp->buffer_length;
450  ocs_log_debug(hal->os, "Dump size: %x\n", sli4_rsp->buffer_length);
451  } else {
452  rc = OCS_HAL_RTN_ERROR;
453  }
454  }
455 
456  return rc;
457 }
458 
459 static void
460 ocs_hal_sli_queue_free(ocs_hal_t *hal)
461 {
462  uint32_t i;
463 
464  for (i = 0; i < OCS_HAL_MAX_NUM_WQ && hal->wq[i]; i++) {
465  ocs_free(hal->os, hal->wq[i], sizeof(sli4_queue_t));
466  hal->wq[i] = NULL;
467  }
468 
469  for (i = 0; i < OCS_HAL_MAX_NUM_RQ && hal->rq[i]; i++) {
470  ocs_free(hal->os, hal->rq[i], sizeof(sli4_queue_t));
471  hal->rq[i] = NULL;
472  }
473 
474  for (i = 0; i < OCS_HAL_MAX_NUM_MQ && hal->mq[i]; i++) {
475  ocs_free(hal->os, hal->mq[i], sizeof(sli4_queue_t));
476  hal->mq[i] = NULL;
477  }
478 
479  for (i = 0; i < OCS_HAL_MAX_NUM_CQ && hal->cq[i]; i++) {
480  ocs_free(hal->os, hal->cq[i], sizeof(sli4_queue_t));
481  hal->cq[i] = NULL;
482  }
483 
484  for (i = 0; i < OCS_HAL_MAX_NUM_EQ && hal->eq[i]; i++) {
485  ocs_free(hal->os, hal->eq[i], sizeof(sli4_queue_t));
486  hal->eq[i] = NULL;
487  }
488 }
489 
490 static ocs_hal_rtn_e
491 ocs_hal_sli_queue_alloc(ocs_hal_t *hal)
492 {
493  uint32_t i;
494 
495  for (i = 0; i < OCS_HAL_MAX_NUM_WQ; i++) {
496  hal->wq[i] = ocs_malloc(hal->os, sizeof(sli4_queue_t), OCS_M_ZERO);
497  if (!hal->wq[i]) {
498  ocs_log_err(hal->os, "Failed to allocate memory for SLI WQ[%d]\n", i);
499  goto free_sli_queues;
500  }
501  }
502 
503  for (i = 0; i < OCS_HAL_MAX_NUM_RQ; i++) {
504  hal->rq[i] = ocs_malloc(hal->os, sizeof(sli4_queue_t), OCS_M_ZERO);
505  if (!hal->rq[i]) {
506  ocs_log_err(hal->os, "Failed to allocate memory for SLI RQ[%d]\n", i);
507  goto free_sli_queues;
508  }
509  }
510 
511  for (i = 0; i < OCS_HAL_MAX_NUM_MQ; i++) {
512  hal->mq[i] = ocs_malloc(hal->os, sizeof(sli4_queue_t), OCS_M_ZERO);
513  if (!hal->mq[i]) {
514  ocs_log_err(hal->os, "Failed to allocate memory for SLI MQ[%d]\n", i);
515  goto free_sli_queues;
516  }
517  }
518 
519  for (i = 0; i < OCS_HAL_MAX_NUM_CQ; i++) {
520  hal->cq[i] = ocs_malloc(hal->os, sizeof(sli4_queue_t), OCS_M_ZERO);
521  if (!hal->cq[i]) {
522  ocs_log_err(hal->os, "Failed to allocate memory for SLI CQ[%d]\n", i);
523  goto free_sli_queues;
524  }
525  }
526 
527  for (i = 0; i < OCS_HAL_MAX_NUM_EQ; i++) {
528  hal->eq[i] = ocs_malloc(hal->os, sizeof(sli4_queue_t), OCS_M_ZERO);
529  if (!hal->eq[i]) {
530  ocs_log_err(hal->os, "Failed to allocate memory for SLI EQ[%d]\n", i);
531  goto free_sli_queues;
532  }
533  }
534 
535  return OCS_HAL_RTN_SUCCESS;
536 
537 free_sli_queues:
539  return OCS_HAL_RTN_NO_MEMORY;
540 }
541 
542 static void
543 ocs_hal_queue_hash_free(ocs_hal_t *hal)
544 {
545  if (hal->cq_hash) {
546  ocs_free(hal->os, hal->cq_hash, OCS_HAL_Q_HASH_SIZE * sizeof(ocs_queue_hash_t));
547  hal->cq_hash = NULL;
548  }
549 
550  if (hal->rq_hash) {
551  ocs_free(hal->os, hal->rq_hash, OCS_HAL_Q_HASH_SIZE * sizeof(ocs_queue_hash_t));
552  hal->rq_hash = NULL;
553  }
554 
555  if (hal->wq_hash) {
556  ocs_free(hal->os, hal->wq_hash, OCS_HAL_Q_HASH_SIZE * sizeof(ocs_queue_hash_t));
557  hal->wq_hash = NULL;
558  }
559 }
560 
561 static ocs_hal_rtn_e
563 {
564  hal->cq_hash = ocs_malloc(hal->os, OCS_HAL_Q_HASH_SIZE * sizeof(ocs_queue_hash_t), OCS_M_ZERO);
565  if (!hal->cq_hash) {
566  ocs_log_err(hal->os, "CQ hash allocation failed\n");
567  goto free_queue_hash;
568  }
569 
570  hal->rq_hash = ocs_malloc(hal->os, OCS_HAL_Q_HASH_SIZE * sizeof(ocs_queue_hash_t), OCS_M_ZERO);
571  if (!hal->rq_hash) {
572  ocs_log_err(hal->os, "RQ hash allocation failed\n");
573  goto free_queue_hash;
574  }
575 
576  hal->wq_hash = ocs_malloc(hal->os, OCS_HAL_Q_HASH_SIZE * sizeof(ocs_queue_hash_t), OCS_M_ZERO);
577  if (!hal->wq_hash) {
578  ocs_log_err(hal->os, "WQ hash allocation failed\n");
579  goto free_queue_hash;
580  }
581 
582  return OCS_HAL_RTN_SUCCESS;
583 
584 free_queue_hash:
587  return OCS_HAL_RTN_NO_MEMORY;
588 }
589 
590 /**
591  * @ingroup devInitShutdown
592  * @brief Set up the Hardware Abstraction Layer module.
593  *
594  * @par Description
595  * Calls set up to configure the hardware.
596  *
597  * @param hal Hardware context allocated by the caller.
598  * @param os Device abstraction.
599  * @param port_type Protocol type of port, such as FC and NIC.
600  *
601  * @todo Why is port_type a parameter?
602  *
603  * @return Returns 0 on success, or a non-zero value on failure.
604  */
606 ocs_hal_setup(ocs_hal_t *hal, ocs_os_handle_t os, sli4_port_type_e port_type)
607 {
608  uint32_t i;
609 
610  if (hal == NULL) {
611  ocs_log_err(os, "bad parameter(s) hal=%p\n", hal);
612  return OCS_HAL_RTN_ERROR;
613  }
614 
615  if (hal->hal_setup_called) {
616  /* Setup run-time workarounds.
617  * Call for each setup, to allow for hal_war_version
618  */
620  return OCS_HAL_RTN_SUCCESS;
621  }
622 
623  /*
624  * ocs_hal_init() relies on NULL pointers indicating that a structure
625  * needs allocation. If a structure is non-NULL, ocs_hal_init() won't
626  * free/realloc that memory
627  */
628  ocs_memset(hal, 0, sizeof(ocs_hal_t));
629 
630  hal->hal_setup_called = TRUE;
631 
632  hal->os = os;
633 
634  ocs_sem_init(&hal->bmbx_sem, 1, "hal_bmbx_sem");
635 
636  ocs_lock_init(hal->os, &hal->cmd_lock, "HAL_cmd_lock[%d]", ocs_instance(hal->os));
637  ocs_list_init(&hal->cmd_head, ocs_command_ctx_t, link);
638  ocs_list_init(&hal->cmd_pending, ocs_command_ctx_t, link);
639  hal->cmd_head_count = 0;
640 
641  ocs_lock_init(hal->os, &hal->io_lock, "HAL_io_lock[%d]", ocs_instance(hal->os));
642  ocs_lock_init(hal->os, &hal->io_abort_lock, "HAL_io_abort_lock[%d]", ocs_instance(hal->os));
643 
644  ocs_atomic_init(&hal->io_alloc_failed_count, 0);
645 
646  hal->config.speed = FC_LINK_SPEED_AUTO_16_8_4;
647  hal->config.dif_seed = 0;
648  hal->config.tow_blksize_chip = OCS_HAL_TOW_BLK_SIZE_DEFAULT;
649  hal->config.tow_ref_tag_lba = OCS_HAL_TOW_REF_TAG_LBA_DEFAULT;
650  hal->config.tow_app_tag_valid = OCS_HAL_TOW_APP_TAG_VALID_DEFAULT;
651  hal->config.tow_app_tag_value = OCS_HAL_TOW_APP_TAG_VALUE_DEFAULT;
652 
653  /* Allocate storage for SLI queue objects */
654  if (ocs_hal_sli_queue_alloc(hal)) {
655  return OCS_HAL_RTN_NO_MEMORY;
656  }
657 
658  /* Allocate memory for queue hashes */
659  if (ocs_hal_queue_hash_alloc(hal)) {
660  return OCS_HAL_RTN_NO_MEMORY;
661  }
662 
663  if (sli_setup(&hal->sli, hal->os, port_type)) {
664  ocs_log_err(hal->os, "SLI setup failed\n");
665  return OCS_HAL_RTN_ERROR;
666  }
667 
668  ocs_memset(hal->domains, 0, sizeof(hal->domains));
669 
670  ocs_memset(hal->fcf_index_fcfi, 0, sizeof(hal->fcf_index_fcfi));
671 
673 
674  sli_callback(&hal->sli, SLI4_CB_LINK, ocs_hal_cb_link, hal);
675  sli_callback(&hal->sli, SLI4_CB_FIP, ocs_hal_cb_fip, hal);
676 
677  /*
678  * Set all the queue sizes to the maximum allowed. These values may
679  * be changes later by the adjust and workaround functions.
680  */
681  for (i = 0; i < ARRAY_SIZE(hal->num_qentries); i++) {
682  hal->num_qentries[i] = sli_get_max_qentries(&hal->sli, i);
683  }
684 
685  /*
686  * The RQ assignment for RQ pair mode.
687  */
688  hal->config.rq_default_buffer_size = OCS_HAL_RQ_SIZE_PAYLOAD;
689  hal->config.n_io = sli_get_max_rsrc(&hal->sli, SLI_RSRC_FCOE_XRI);
690 
691  /* by default, enable initiator-only auto-ABTS emulation */
692  hal->config.i_only_aab = TRUE;
693 
694  /* Setup run-time workarounds */
696 
697  /* HAL_WORKAROUND_OVERRIDE_FCFI_IN_SRB */
698  if (hal->workaround.override_fcfi) {
699  hal->first_domain_idx = -1;
700  }
701 
702  /* Must be done after the workaround setup */
703  if ((SLI4_IF_TYPE_LANCER_FC_ETH == sli_get_if_type(&hal->sli)) ||
704  (SLI4_IF_TYPE_LANCER_G7 == sli_get_if_type(&hal->sli))) {
705  (void)ocs_hal_read_max_dump_size(hal);
706  }
707 
708  /* calculate the number of WQs required. */
709  ocs_hal_adjust_wqs(hal);
710 
711  /* Set the default dif mode */
712  if (! sli_is_dif_inline_capable(&hal->sli)) {
713  ocs_log_test(hal->os, "not inline capable, setting mode to seperate\n");
714  hal->config.dif_mode = OCS_HAL_DIF_MODE_SEPARATE;
715  }
716  /* Workaround: BZ 161832 */
717  if (hal->workaround.use_dif_sec_xri) {
718  ocs_list_init(&hal->sec_hio_wait_list, ocs_hal_io_t, link);
719  }
720 
721  /*
722  * Figure out the starting and max ULP to spread the WQs across the
723  * ULPs.
724  */
725  if (sli_get_is_dual_ulp_capable(&hal->sli)) {
726  if (sli_get_is_ulp_enabled(&hal->sli, 0) &&
727  sli_get_is_ulp_enabled(&hal->sli, 1)) {
728  hal->ulp_start = 0;
729  hal->ulp_max = 1;
730  } else if (sli_get_is_ulp_enabled(&hal->sli, 0)) {
731  hal->ulp_start = 0;
732  hal->ulp_max = 0;
733  } else {
734  hal->ulp_start = 1;
735  hal->ulp_max = 1;
736  }
737  } else {
738  if (sli_get_is_ulp_enabled(&hal->sli, 0)) {
739  hal->ulp_start = 0;
740  hal->ulp_max = 0;
741  } else {
742  hal->ulp_start = 1;
743  hal->ulp_max = 1;
744  }
745  }
746  ocs_log_debug(hal->os, "ulp_start %d, ulp_max %d\n",
747  hal->ulp_start, hal->ulp_max);
748  hal->config.queue_topology = hal_global.queue_topology_string;
749 
750  hal->qtop = ocs_hal_qtop_parse(hal, hal->config.queue_topology);
751  if (hal->qtop == NULL) {
752  ocs_log_crit(hal->os, "Queue topology string is invalid\n");
753  return OCS_HAL_RTN_ERROR;
754  }
755 
756  hal->config.n_eq = hal->qtop->entry_counts[QTOP_EQ];
757  hal->config.n_cq = hal->qtop->entry_counts[QTOP_CQ];
758  hal->config.n_rq = hal->qtop->entry_counts[QTOP_RQ];
759  hal->config.n_wq = hal->qtop->entry_counts[QTOP_WQ];
760  hal->config.n_mq = hal->qtop->entry_counts[QTOP_MQ];
761 
762  /* Verify qtop configuration against driver supported configuration */
763  /* TODO - Verify how to sanity check num rqs */
764 /* if (hal->config.n_rq > OCE_HAL_MAX_NUM_MRQ_PAIRS) {
765  ocs_log_crit(hal->os, "Max supported MRQ pairs = %d\n",
766  OCE_HAL_MAX_NUM_MRQ_PAIRS);
767  return OCS_HAL_RTN_ERROR;
768  } */
769 
770  if (hal->config.n_eq > OCS_HAL_MAX_NUM_EQ) {
771  ocs_log_crit(hal->os, "Max supported EQs = %d\n",
773  return OCS_HAL_RTN_ERROR;
774  }
775 
776  if (hal->config.n_cq > OCS_HAL_MAX_NUM_CQ) {
777  ocs_log_crit(hal->os, "Max supported CQs = %d\n",
779  return OCS_HAL_RTN_ERROR;
780  }
781 
782  if (hal->config.n_wq > OCS_HAL_MAX_NUM_WQ) {
783  ocs_log_crit(hal->os, "Max supported WQs = %d\n",
785  return OCS_HAL_RTN_ERROR;
786  }
787 
788  if (hal->config.n_mq > OCS_HAL_MAX_NUM_MQ) {
789  ocs_log_crit(hal->os, "Max supported MQs = %d\n",
791  return OCS_HAL_RTN_ERROR;
792  }
793 
794  return OCS_HAL_RTN_SUCCESS;
795 }
796 
797 /**
798  * @ingroup devInitShutdown
799  * @brief Allocate memory structures to prepare for the device operation.
800  *
801  * @par Description
802  * Allocates memory structures needed by the device and prepares the device
803  * for operation.
804  * @n @n @b Note: This function may be called more than once (for example, at
805  * initialization and then after a reset), but the size of the internal resources
806  * may not be changed without tearing down the HAL (ocs_hal_teardown()).
807  *
808  * @param hal Hardware context allocated by the caller.
809  *
810  * @return Returns 0 on success, or a non-zero value on failure.
811  */
813 ocs_hal_init(ocs_hal_t *hal)
814 {
815  ocs_hal_rtn_e rc;
816  uint32_t i = 0;
817  uint8_t buf[SLI4_BMBX_SIZE];
818  uint32_t max_rpi;
819  int rem_count;
820  uint32_t count;
821  uint32_t q_count = 0;
822  /*
823  * Make sure the command lists are empty. If this is start-of-day,
824  * they'll be empty since they were just initialized in ocs_hal_setup.
825  * If we've just gone through a reset, the command and command pending
826  * lists should have been cleaned up as part of the reset (ocs_hal_reset()).
827  */
828  ocs_lock(&hal->cmd_lock);
829  if (!ocs_list_empty(&hal->cmd_head)) {
830  ocs_log_test(hal->os, "command found on cmd list\n");
831  ocs_unlock(&hal->cmd_lock);
832  return OCS_HAL_RTN_ERROR;
833  }
834  if (!ocs_list_empty(&hal->cmd_pending)) {
835  ocs_log_test(hal->os, "command found on pending list\n");
836  ocs_unlock(&hal->cmd_lock);
837  return OCS_HAL_RTN_ERROR;
838  }
839  ocs_unlock(&hal->cmd_lock);
840 
841  /* Free RQ buffers if prevously allocated */
842  ocs_hal_rx_free(hal);
843 
844  /*
845  * The IO queues must be initialized here for the reset case. The
846  * ocs_hal_init_io() function will re-add the IOs to the free list.
847  * The cmd_head list should be OK since we free all entries in
848  * ocs_hal_command_cancel() that is called in the ocs_hal_reset().
849  */
850 
851  /* If we are in this function due to a reset, there may be stale items
852  * on lists that need to be removed. Clean them up.
853  */
854  rem_count=0;
855  if (ocs_list_valid(&hal->io_wait_free)) {
856  while ((!ocs_list_empty(&hal->io_wait_free))) {
857  rem_count++;
858  ocs_list_remove_head(&hal->io_wait_free);
859  }
860  if (rem_count > 0) {
861  ocs_log_debug(hal->os, "removed %d items from io_wait_free list\n", rem_count);
862  }
863  }
864  rem_count=0;
865  if (ocs_list_valid(&hal->io_inuse)) {
866  while ((!ocs_list_empty(&hal->io_inuse))) {
867  rem_count++;
868  ocs_list_remove_head(&hal->io_inuse);
869  }
870  if (rem_count > 0) {
871  ocs_log_debug(hal->os, "removed %d items from io_inuse list\n", rem_count);
872  }
873  }
874  rem_count=0;
875  if (ocs_list_valid(&hal->io_free)) {
876  while ((!ocs_list_empty(&hal->io_free))) {
877  rem_count++;
878  ocs_list_remove_head(&hal->io_free);
879  }
880  if (rem_count > 0) {
881  ocs_log_debug(hal->os, "removed %d items from io_free list\n", rem_count);
882  }
883  }
884  if (ocs_list_valid(&hal->io_port_owned)) {
885  while ((!ocs_list_empty(&hal->io_port_owned))) {
886  ocs_list_remove_head(&hal->io_port_owned);
887  }
888  }
889  ocs_list_init(&hal->io_inuse, ocs_hal_io_t, link);
890  ocs_list_init(&hal->io_free, ocs_hal_io_t, link);
891  ocs_list_init(&hal->io_port_owned, ocs_hal_io_t, link);
892  ocs_list_init(&hal->io_wait_free, ocs_hal_io_t, link);
893  ocs_list_init(&hal->io_timed_wqe, ocs_hal_io_t, wqe_link);
894  ocs_list_init(&hal->io_port_dnrx, ocs_hal_io_t, dnrx_link);
895 
896  /* If MRQ not required, Make sure we dont request feature. */
897  if (hal->config.n_rq == 1) {
898  hal->sli.config.features.flag.mrqp = FALSE;
899  }
900 
901  if (sli_init(&hal->sli)) {
902  ocs_log_err(hal->os, "SLI failed to initialize\n");
903  return OCS_HAL_RTN_ERROR;
904  }
905 
907  hal_global.fw_diag_log_level)) {
908  ocs_log_err(hal->os, "Failed to enable RAS firmware logging\n");
909  }
910 
911  /*
912  * Enable the target optimized write feature if requested.
913  */
914  rc = ocs_hal_init_tow_feature(hal);
915  if (rc) {
916  ocs_log_err(hal->os, "Failed to initialize optimized write feature\n");
917  return rc;
918  }
919 
920  if(hal->sliport_healthcheck) {
921  rc = ocs_hal_config_sli_port_health_check(hal, 0, 1);
922  if (rc != OCS_HAL_RTN_SUCCESS) {
923  ocs_log_err(hal->os, "Enabling Sliport Health check failed \n");
924  return rc;
925  }
926  }
927 
928  if ((sli_get_if_type(&hal->sli) == SLI4_IF_TYPE_LANCER_FC_ETH) ||
929  (hal->sli.if_type == SLI4_IF_TYPE_LANCER_G7)) {
930  rc = ocs_hal_config_fec(hal, !hal->disable_fec);
931  if (rc != OCS_HAL_RTN_SUCCESS) {
932  ocs_log_err(hal->os, "Config FEC failed \n");
933  return rc;
934  }
935  }
936 
937  if (sli_get_if_type(&hal->sli) == SLI4_IF_TYPE_LANCER_FC_ETH) {
938  rc = ocs_hal_config_fw_ag_rsp(hal, hal->enable_fw_ag_rsp);
939  if (rc != OCS_HAL_RTN_SUCCESS) {
940  ocs_log_err(hal->os, "Setting FW Auto-good response configuration not supproted \n");
941  }
942  }
943 
944  if (hal->sliport_pause_errors && (ocs_strcmp(hal->sliport_pause_errors, "disabled")) &&
946  rc = ocs_hal_config_sliport_pause(hal, 1);
947  if (rc != OCS_HAL_RTN_SUCCESS) {
948  ocs_log_err(hal->os, "Sliport pause state enable failed\n");
949  return rc;
950  }
951  }
952 
953  /*
954  * Set FDT transfer hint, only works on Lancer
955  */
956  if ((hal->sli.if_type == SLI4_IF_TYPE_LANCER_FC_ETH) && (OCS_HAL_FDT_XFER_HINT != 0)) {
957  /*
958  * Non-fatal error. In particular, we can disregard failure to set OCS_HAL_FDT_XFER_HINT on
959  * devices with legacy firmware that do not support OCS_HAL_FDT_XFER_HINT feature.
960  */
962  }
963 
964 #if !defined(OCSU_FC_RAMD) && !defined(OCSU_FC_WORKLOAD) && !defined(OCS_USPACE_SPDK)
965  /*
966  * Set dump to host buffers every time when hal is reset
967  */
969  if (rc) {
970  ocs_log_err(hal->os, "Set FW dump location failed\n");
971  return rc;
972  }
973 #endif
974 
975  /*
976  * Verify that we have not exceeded any queue sizes
977  */
978  q_count = MIN(sli_get_max_queue(&hal->sli, SLI_QTYPE_EQ),
980  if (hal->config.n_eq > q_count) {
981  ocs_log_err(hal->os, "requested %d EQ but %d allowed\n",
982  hal->config.n_eq, q_count);
983  return OCS_HAL_RTN_ERROR;
984  }
985 
986  q_count = MIN(sli_get_max_queue(&hal->sli, SLI_QTYPE_CQ),
988  if (hal->config.n_cq > q_count) {
989  ocs_log_err(hal->os, "requested %d CQ but %d allowed\n",
990  hal->config.n_cq, q_count);
991  return OCS_HAL_RTN_ERROR;
992  }
993 
994  q_count = MIN(sli_get_max_queue(&hal->sli, SLI_QTYPE_MQ),
996  if (hal->config.n_mq > q_count) {
997  ocs_log_err(hal->os, "requested %d MQ but %d allowed\n",
998  hal->config.n_mq, q_count);
999  return OCS_HAL_RTN_ERROR;
1000  }
1001 
1002  q_count = MIN(sli_get_max_queue(&hal->sli, SLI_QTYPE_RQ),
1004  if (hal->config.n_rq > q_count) {
1005  ocs_log_err(hal->os, "requested %d RQ but %d allowed\n",
1006  hal->config.n_rq, q_count);
1007  return OCS_HAL_RTN_ERROR;
1008  }
1009 
1010  q_count = MIN(sli_get_max_queue(&hal->sli, SLI_QTYPE_WQ),
1012  if (hal->config.n_wq > q_count) {
1013  ocs_log_err(hal->os, "requested %d WQ but %d allowed\n",
1014  hal->config.n_wq, q_count);
1015  return OCS_HAL_RTN_ERROR;
1016  }
1017 
1018  /* zero the hashes */
1019  ocs_memset(hal->cq_hash, 0, OCS_HAL_Q_HASH_SIZE * sizeof(ocs_queue_hash_t));
1020  ocs_log_debug(hal->os, "Max CQs %d, hash size = %d\n",
1022 
1023  ocs_memset(hal->rq_hash, 0, OCS_HAL_Q_HASH_SIZE * sizeof(ocs_queue_hash_t));
1024  ocs_log_debug(hal->os, "Max RQs %d, hash size = %d\n",
1026 
1027  ocs_memset(hal->wq_hash, 0, OCS_HAL_Q_HASH_SIZE * sizeof(ocs_queue_hash_t));
1028  ocs_log_debug(hal->os, "Max WQs %d, hash size = %d\n",
1030 
1031  rc = ocs_hal_init_queues(hal, hal->qtop);
1032  if (rc != OCS_HAL_RTN_SUCCESS) {
1033  return rc;
1034  }
1035 
1036  max_rpi = sli_get_max_rsrc(&hal->sli, SLI_RSRC_FCOE_RPI);
1037  i = sli_fc_get_rpi_requirements(&hal->sli, max_rpi);
1038  if (i) {
1039  ocs_dma_t payload_memory;
1040 
1041  rc = OCS_HAL_RTN_ERROR;
1042 
1043  if (hal->rnode_mem.size) {
1044  ocs_dma_free(hal->os, &hal->rnode_mem);
1045  }
1046 
1047  if (ocs_dma_alloc(hal->os, &hal->rnode_mem, i, 4096)) {
1048  ocs_log_err(hal->os, "remote node memory allocation fail\n");
1049  return OCS_HAL_RTN_NO_MEMORY;
1050  }
1051 
1052  payload_memory.size = 0;
1053  if (sli_cmd_fcoe_post_hdr_templates(&hal->sli, buf, SLI4_BMBX_SIZE,
1054  &hal->rnode_mem, UINT16_MAX, &payload_memory)) {
1055  rc = ocs_hal_command(hal, buf, OCS_CMD_POLL, NULL, NULL);
1056 
1057  if (payload_memory.size) {
1058  /* The command was non-embedded - need to free the dma buffer */
1059  ocs_dma_free(hal->os, &payload_memory);
1060  }
1061  }
1062 
1063  if (rc || ((sli4_mbox_command_header_t *)buf)->status) {
1064  ocs_log_err(hal->os, "header template registration failed\n");
1065  return OCS_HAL_RTN_ERROR;
1066  }
1067  }
1068 
1069  /* Allocate and post RQ buffers */
1070  rc = ocs_hal_rx_allocate(hal);
1071  if (rc) {
1072  ocs_log_err(hal->os, "rx_allocate failed\n");
1073  return rc;
1074  }
1075 
1076  /* Populate hal->seq_free_list */
1077  if (hal->seq_pool == NULL) {
1078  uint32_t count = 0;
1079  uint32_t i;
1080 
1081  /* Sum up the total number of RQ entries, to use to allocate the sequence object pool */
1082  for (i = 0; i < hal->hal_rq_count; i++) {
1083  count += hal->hal_rq[i]->entry_count;
1084  }
1085 
1086  hal->seq_pool = ocs_array_alloc(hal->os, sizeof(ocs_hal_sequence_t), count);
1087  if (hal->seq_pool == NULL) {
1088  ocs_log_err(hal->os, "malloc seq_pool failed\n");
1089  return OCS_HAL_RTN_NO_MEMORY;
1090  }
1091  }
1092 
1093  if(ocs_hal_rx_post(hal)) {
1094  ocs_log_err(hal->os, "WARNING - error posting RQ buffers\n");
1095  }
1096 
1097  /* Allocate rpi_ref if not previously allocated */
1098  if (hal->rpi_ref == NULL) {
1099  hal->rpi_ref = ocs_malloc(hal->os, max_rpi * sizeof(*hal->rpi_ref),
1100  OCS_M_ZERO | OCS_M_NOWAIT);
1101  if (hal->rpi_ref == NULL) {
1102  ocs_log_err(hal->os, "rpi_ref allocation failure (%d)\n", i);
1103  return OCS_HAL_RTN_NO_MEMORY;
1104  }
1105  }
1106 
1107  for (i = 0; i < max_rpi; i ++) {
1108  ocs_atomic_init(&hal->rpi_ref[i].rpi_count, 0);
1109  ocs_atomic_init(&hal->rpi_ref[i].rpi_attached, 0);
1110  }
1111 
1112  ocs_memset(hal->domains, 0, sizeof(hal->domains));
1113 
1114  /* HAL_WORKAROUND_OVERRIDE_FCFI_IN_SRB */
1115  if (hal->workaround.override_fcfi) {
1116  hal->first_domain_idx = -1;
1117  }
1118 
1119  ocs_memset(hal->fcf_index_fcfi, 0, sizeof(hal->fcf_index_fcfi));
1120 
1121  /* Register a FCFI to allow unsolicited frames to be routed to the driver */
1122  if (sli_get_medium(&hal->sli) == SLI_LINK_MEDIUM_FC) {
1123 
1124  if (hal->hal_mrq_used) {
1125  ocs_log_info(hal->os, "using REG_FCFI MRQ\n");
1126 
1128  if (rc != OCS_HAL_RTN_SUCCESS) {
1129  ocs_log_err(hal->os, "REG_FCFI_MRQ FCFI registration failed\n");
1130  return rc;
1131  }
1132 
1134  if (rc != OCS_HAL_RTN_SUCCESS) {
1135  ocs_log_err(hal->os, "REG_FCFI_MRQ MRQ registration failed\n");
1136  return rc;
1137  }
1138  } else {
1140 
1141  ocs_log_info(hal->os, "using REG_FCFI standard\n");
1142 
1143  /* Set the filter match/mask values from hal's filter_def values */
1144  for (i = 0; i < SLI4_CMD_REG_FCFI_NUM_RQ_CFG; i++) {
1145  rq_cfg[i].rq_id = 0xffff;
1146  rq_cfg[i].r_ctl_mask = (uint8_t) hal->config.filter_def[i];
1147  rq_cfg[i].r_ctl_match = (uint8_t) (hal->config.filter_def[i] >> 8);
1148  rq_cfg[i].type_mask = (uint8_t) (hal->config.filter_def[i] >> 16);
1149  rq_cfg[i].type_match = (uint8_t) (hal->config.filter_def[i] >> 24);
1150  }
1151 
1152  /*
1153  * Update the rq_id's of the FCF configuration (don't update more than the number
1154  * of rq_cfg elements)
1155  */
1156  for (i = 0; i < OCS_MIN(hal->hal_rq_count, SLI4_CMD_REG_FCFI_NUM_RQ_CFG); i++) {
1157  hal_rq_t *rq = hal->hal_rq[i];
1158  uint32_t j;
1159  for (j = 0; j < SLI4_CMD_REG_FCFI_NUM_RQ_CFG; j++) {
1160  uint32_t mask = (rq->filter_mask != 0) ? rq->filter_mask : 1;
1161  if (mask & (1U << j)) {
1162  rq_cfg[j].rq_id = rq->hdr->id;
1163  ocs_log_info(hal->os, "REG_FCFI: filter[%d] %08X -> RQ[%d] id=%d\n",
1164  j, hal->config.filter_def[j], i, rq->hdr->id);
1165  }
1166  }
1167  }
1168 
1169  sli_cmd_reg_fcfi(&hal->sli, buf, SLI4_BMBX_SIZE, 0, rq_cfg, 0);
1170  rc = ocs_hal_command(hal, buf, OCS_CMD_POLL, NULL, NULL);
1171  if (rc || ((sli4_mbox_command_header_t *)buf)->status)
1172  return OCS_HAL_RTN_ERROR;
1173 
1174  hal->fcf_indicator = ((sli4_cmd_reg_fcfi_t *)buf)->fcfi;
1175  }
1176  }
1177 
1178  /*
1179  * Allocate the WQ request tag pool, if not previously allocated (the request tag value is 16 bits,
1180  * thus the pool allocation size of 64k)
1181  */
1182  rc = ocs_hal_reqtag_init(hal);
1183  if (rc) {
1184  ocs_log_err(hal->os, "ocs_pool_alloc hal_wq_callback_t failed: %d\n", rc);
1185  return rc;
1186  }
1187 
1188  rc = ocs_hal_setup_io(hal);
1189  if (rc) {
1190  ocs_log_err(hal->os, "IO allocation failure\n");
1191  return rc;
1192  }
1193 
1194  rc = ocs_hal_init_io(hal);
1195  if (rc) {
1196  ocs_log_err(hal->os, "IO initialization failure\n");
1197  return rc;
1198  }
1199 
1200  ocs_queue_history_init(hal->os, &hal->q_hist);
1201 
1202  /* get hw link config; polling, so callback will be called immediately */
1203  hal->linkcfg = OCS_HAL_LINKCFG_NA;
1205 
1206  /* if lancer ethernet, ethernet ports need to be enabled */
1207  if ((hal->sli.if_type == SLI4_IF_TYPE_LANCER_FC_ETH) &&
1208  (sli_get_medium(&hal->sli) == SLI_LINK_MEDIUM_ETHERNET)) {
1209  if (ocs_hal_set_eth_license(hal, hal->eth_license)) {
1210  /* log warning but continue */
1211  ocs_log_err(hal->os, "Failed to set ethernet license\n");
1212  }
1213  }
1214 
1215  /* Set the DIF seed - only for lancer right now */
1216  if (SLI4_IF_TYPE_LANCER_FC_ETH == sli_get_if_type(&hal->sli) &&
1218  ocs_log_err(hal->os, "Failed to set DIF seed value\n");
1219  return rc;
1220  }
1221 
1222  /* Set the DIF mode - skyhawk only */
1223  if (SLI4_IF_TYPE_BE3_SKH_PF == sli_get_if_type(&hal->sli) &&
1224  sli_get_dif_capable(&hal->sli)) {
1225  rc = ocs_hal_set_dif_mode(hal);
1226  if (rc != OCS_HAL_RTN_SUCCESS) {
1227  ocs_log_err(hal->os, "Failed to set DIF mode value\n");
1228  return rc;
1229  }
1230  }
1231 
1232  /*
1233  * Arming the EQ allows (e.g.) interrupts when CQ completions write EQ entries
1234  */
1235  for (i = 0; i < hal->eq_count; i++) {
1236  sli_queue_arm(&hal->sli, hal->eq[i], TRUE);
1237  }
1238 
1239  /*
1240  * Initialize RQ hash
1241  */
1242  for (i = 0; i < hal->rq_count; i++) {
1243  ocs_hal_queue_hash_add(hal->rq_hash, hal->rq[i]->id, i);
1244  }
1245 
1246  /*
1247  * Initialize WQ hash
1248  */
1249  for (i = 0; i < hal->wq_count; i++) {
1250  ocs_hal_queue_hash_add(hal->wq_hash, hal->wq[i]->id, i);
1251  }
1252 
1253  /*
1254  * Arming the CQ allows (e.g.) MQ completions to write CQ entries
1255  */
1256  for (i = 0; i < hal->cq_count; i++) {
1257  ocs_hal_queue_hash_add(hal->cq_hash, hal->cq[i]->id, i);
1258  sli_queue_arm(&hal->sli, hal->cq[i], TRUE);
1259  }
1260 
1261  /* record the fact that the queues are functional */
1262  hal->state = OCS_HAL_STATE_ACTIVE;
1263 
1264  /* Note: Must be after the IOs are setup and the state is active */
1265  if (ocs_hal_rqpair_init(hal)) {
1266  ocs_log_err(hal->os, "WARNING - error initializing RQ pair\n");
1267  }
1268 
1269  /* finally kick off periodic timer to check for timed out target WQEs */
1270  if (hal->config.emulate_tgt_wqe_timeout) {
1271  ocs_setup_timer(hal->os, &hal->wqe_timer, target_wqe_timer_cb, hal,
1273  }
1274 
1275  /*
1276  * Allocate a HAL IOs for send frame. Allocate one for each Class 1 WQ, or if there
1277  * are none of those, allocate one for WQ[0]
1278  */
1279  if ((count = ocs_varray_get_count(hal->wq_class_array[1])) > 0) {
1280  for (i = 0; i < count; i++) {
1281  hal_wq_t *wq = ocs_varray_iter_next(hal->wq_class_array[1]);
1282  wq->send_frame_io = ocs_hal_io_alloc(hal);
1283  if (wq->send_frame_io == NULL) {
1284  ocs_log_err(hal->os, "ocs_hal_io_alloc for send_frame_io failed\n");
1285  }
1286  }
1287  } else {
1288  hal->hal_wq[0]->send_frame_io = ocs_hal_io_alloc(hal);
1289  if (hal->hal_wq[0]->send_frame_io == NULL) {
1290  ocs_log_err(hal->os, "ocs_hal_io_alloc for send_frame_io failed\n");
1291  }
1292  }
1293 
1294  /* Initialize send frame frame sequence id */
1295  ocs_atomic_init(&hal->send_frame_seq_id, 0);
1296 
1297  /* Initialize watchdog timer if enabled by user */
1298  hal->expiration_logged = 0;
1299  if(hal->watchdog_timeout) {
1300  if((hal->watchdog_timeout < 1) || (hal->watchdog_timeout > 65534)) {
1301  ocs_log_err(hal->os, "watchdog_timeout out of range: Valid range is 1 - 65534\n");
1302  }else if(!ocs_hal_config_watchdog_timer(hal)) {
1303  ocs_log_info(hal->os, "watchdog timer configured with timeout = %d seconds \n", hal->watchdog_timeout);
1304  }
1305  }
1306 
1307  return OCS_HAL_RTN_SUCCESS;
1308 }
1309 
1310 /**
1311  * @brief Configure Multi-RQ
1312  *
1313  * @param hal Hardware context allocated by the caller.
1314  * @param mode 1 to set MRQ filters and 0 to set FCFI index
1315  * @param vlanid valid in mode 0
1316  * @param fcf_index valid in mode 0
1317  *
1318  * @return Returns 0 on success, or a non-zero value on failure.
1319  */
1320 static int32_t
1321 ocs_hal_config_mrq(ocs_hal_t *hal, uint8_t mode, uint16_t vlanid, uint16_t fcf_index)
1322 {
1323  uint8_t buf[SLI4_BMBX_SIZE];
1324  hal_rq_t *rq;
1325  sli4_cmd_reg_fcfi_mrq_t *rsp = NULL;
1326  uint32_t i, j;
1328  int32_t rc;
1329  ocs_t *ocs = (ocs_t *)hal->os;
1330 
1331  if (mode == SLI4_CMD_REG_FCFI_SET_FCFI_MODE) {
1332  goto issue_cmd;
1333  }
1334 
1335  /* Set the filter match/mask values from hal's filter_def values */
1336  for (i = 0; i < SLI4_CMD_REG_FCFI_NUM_RQ_CFG; i++) {
1337  rq_filter[i].rq_id = 0xffff;
1338  rq_filter[i].is_mrq = FALSE;
1339  rq_filter[i].r_ctl_mask = (uint8_t) hal->config.filter_def[i];
1340  rq_filter[i].r_ctl_match = (uint8_t) (hal->config.filter_def[i] >> 8);
1341  rq_filter[i].type_mask = (uint8_t) (hal->config.filter_def[i] >> 16);
1342  rq_filter[i].type_match = (uint8_t) (hal->config.filter_def[i] >> 24);
1343  rq_filter[i].protocol_valid = 0;
1344  rq_filter[i].protocol = 0;
1345  }
1346 
1347  /* Accumulate counts for each filter type used, build rq_ids[] list */
1348  for (i = 0; i < hal->hal_rq_count; i++) {
1349  rq = hal->hal_rq[i];
1350  for (j = 0; j < SLI4_CMD_REG_FCFI_NUM_RQ_CFG; j++) {
1351  if (rq->filter_mask & (1U << j)) {
1352  if (rq_filter[j].rq_id != 0xffff) {
1353  /* Already used. Bailout ifts not RQset case */
1354  if (!rq->is_mrq || (rq_filter[j].rq_id != rq->base_mrq_id)) {
1355  ocs_log_err(hal->os, "Wrong queue topology.\n");
1356  return OCS_HAL_RTN_ERROR;
1357  }
1358  continue;
1359  } else {
1360  if (rq->is_mrq) {
1361  rq_filter[j].rq_id = rq->base_mrq_id;
1362  rq_filter[j].filtermask = rq->filter_mask;
1363  rq_filter[j].is_mrq = TRUE;
1364  rq_filter[j].mrq_set_count = rq->mrq_set_count;
1365  rq_filter[j].mrq_set_num = rq->mrq_set_num;
1366  rq_filter[j].mrq_policy = rq->policy;
1367  if (rq->policy == 3) {
1368  rq_filter[j].protocol_valid = TRUE;
1369  rq_filter[j].protocol = 1;
1370  } else if (ocs->enable_nvme_tgt) {
1371  /*
1372  * When NVME MRQ is used, SCSI MRQ also should use protocol.
1373  * This is Prism asic expectation.
1374  */
1375  rq_filter[j].protocol_valid = TRUE;
1376  rq_filter[j].protocol = 0;
1377  }
1378  } else {
1379  rq_filter[j].rq_id = rq->hdr->id;
1380  }
1381  }
1382  }
1383  }
1384  }
1385 
1386 issue_cmd:
1387  /* Invoke REG_FCFI_MRQ */
1388  rc = sli_cmd_reg_fcfi_mrq(&hal->sli,
1389  buf, /* buf */
1390  SLI4_BMBX_SIZE, /* size */
1391  mode, /* mode 1 */
1392  fcf_index, /* fcf_index */
1393  vlanid, /* vlan_id */
1394  rq_filter); /* RQ filter */
1395  if (rc == 0) {
1396  ocs_log_err(hal->os, "sli_cmd_reg_fcfi_mrq() failed: %d\n", rc);
1397  return OCS_HAL_RTN_ERROR;
1398  }
1399 
1400  rc = ocs_hal_command(hal, buf, OCS_CMD_POLL, NULL, NULL);
1401  if (rc || ((sli4_mbox_command_header_t *)buf)->status)
1402  return OCS_HAL_RTN_ERROR;
1403 
1404  if (mode == SLI4_CMD_REG_FCFI_SET_FCFI_MODE) {
1405  rsp = (sli4_cmd_reg_fcfi_mrq_t *)buf;
1406  hal->fcf_indicator = rsp->fcfi;
1407  }
1408 
1409  return rc;
1410 }
1411 
1412 /**
1413  * @brief Callback function for getting linkcfg during HAL initialization.
1414  *
1415  * @param status Status of the linkcfg get operation.
1416  * @param value Link configuration enum to which the link configuration is set.
1417  * @param arg Callback argument (ocs_hal_t *).
1418  *
1419  * @return None.
1420  */
1421 static void
1422 ocs_hal_init_linkcfg_cb(int32_t status, uintptr_t value, void *arg)
1423 {
1424  ocs_hal_t *hal = (ocs_hal_t *)arg;
1425  if (status == 0) {
1426  hal->linkcfg = (ocs_hal_linkcfg_e)value;
1427  } else {
1428  hal->linkcfg = OCS_HAL_LINKCFG_NA;
1429  }
1430  ocs_log_debug(hal->os, "linkcfg=%d\n", hal->linkcfg);
1431 }
1432 
1433 /**
1434  * @ingroup devInitShutdown
1435  * @brief Tear down the Hardware Abstraction Layer module.
1436  *
1437  * @par Description
1438  * Frees memory structures needed by the device, and shuts down the device. Does
1439  * not free the HAL context memory (which is done by the caller).
1440  *
1441  * @param hal Hardware context allocated by the caller.
1442  *
1443  * @return Returns 0 on success, or a non-zero value on failure.
1444  */
1446 ocs_hal_teardown(ocs_hal_t *hal)
1447 {
1448  uint32_t i = 0;
1449  uint32_t iters = 10;/*XXX*/
1450  uint32_t max_rpi;
1451  uint32_t destroy_queues;
1452  uint32_t free_memory;
1453 
1454  if (!hal) {
1455  ocs_log_err(NULL, "bad parameter(s) hal=%p\n", hal);
1456  return OCS_HAL_RTN_ERROR;
1457  }
1458 
1459  destroy_queues = (hal->state == OCS_HAL_STATE_ACTIVE);
1460  free_memory = (hal->state != OCS_HAL_STATE_UNINITIALIZED);
1461 
1462  /* shutdown target wqe timer */
1464 
1465  /* Cancel watchdog timer if enabled */
1466  if(hal->watchdog_timeout) {
1467  hal->watchdog_timeout = 0;
1469  }
1470 
1471  /* Cancel Sliport Healthcheck */
1472  if(hal->sliport_healthcheck) {
1473  hal->sliport_healthcheck = 0;
1475  }
1476 
1477  if (hal->state != OCS_HAL_STATE_QUEUES_ALLOCATED) {
1478 
1480 
1481  ocs_hal_flush(hal);
1482 
1483  /* If there are outstanding commands, wait for them to complete */
1484  while (!ocs_list_empty(&hal->cmd_head) && iters) {
1485  ocs_delay_usec(10000);
1486  ocs_hal_flush(hal);
1487  iters--;
1488  }
1489 
1490  if (ocs_list_empty(&hal->cmd_head)) {
1491  ocs_log_debug(hal->os, "All commands completed on MQ queue\n");
1492  } else {
1493  ocs_log_debug(hal->os, "Some commands still pending on MQ queue\n");
1494  }
1495 
1496  // Cancel any remaining commands
1498  } else {
1500  }
1501 
1502  ocs_lock_free(&hal->cmd_lock);
1503 
1504  /* Free unregistered RPI if workaround is in force */
1505  if (hal->workaround.use_unregistered_rpi) {
1506  if (sli_resource_free(&hal->sli, SLI_RSRC_FCOE_RPI, hal->workaround.unregistered_rid)) {
1507  ocs_log_err(hal->os, "FCOE_RPI (%d) free failed\n", hal->workaround.unregistered_rid);
1508  }
1509  }
1510 
1511  max_rpi = sli_get_max_rsrc(&hal->sli, SLI_RSRC_FCOE_RPI);
1512  if (hal->rpi_ref) {
1513  for (i = 0; i < max_rpi; i++) {
1514  if (ocs_atomic_read(&hal->rpi_ref[i].rpi_count)) {
1515  ocs_log_debug(hal->os, "non-zero ref [%d]=%d\n",
1516  i, ocs_atomic_read(&hal->rpi_ref[i].rpi_count));
1517  }
1518  }
1519  ocs_free(hal->os, hal->rpi_ref, max_rpi * sizeof(*hal->rpi_ref));
1520  hal->rpi_ref = NULL;
1521  }
1522 
1523  ocs_dma_free(hal->os, &hal->rnode_mem);
1524 
1525  if (hal->io) {
1526  for (i = 0; i < hal->config.n_io; i++) {
1527  if (!hal->io[i]) {
1528  continue;
1529  }
1530 
1531  if (hal->io[i]->sgl && hal->io[i]->sgl->virt) {
1532  if (hal->io[i]->is_port_owned) {
1533  ocs_lock_free(&hal->io[i]->tow_lock);
1534  }
1535  ocs_dma_free(hal->os, hal->io[i]->sgl);
1536  }
1537 
1538  ocs_free(hal->os, hal->io[i], sizeof(ocs_hal_io_t));
1539  hal->io[i] = NULL;
1540  }
1541 
1542  ocs_free(hal->os, hal->wqe_buffs, hal->config.n_io * hal->sli.config.wqe_size);
1543  hal->wqe_buffs = NULL;
1544  ocs_free(hal->os, hal->io, hal->config.n_io * sizeof(ocs_hal_io_t *));
1545  hal->io = NULL;
1546  }
1547 
1548  ocs_dma_free(hal->os, &hal->xfer_rdy);
1549  ocs_dma_free(hal->os, &hal->chip_dump_sges);
1550  ocs_dma_free(hal->os, &hal->func_dump_sges);
1551  ocs_dma_free(hal->os, &hal->loop_map);
1552 
1553  ocs_lock_free(&hal->io_lock);
1554  ocs_lock_free(&hal->io_abort_lock);
1555 
1556 
1557  for (i = 0; i < hal->wq_count; i++) {
1558  sli_queue_free(&hal->sli, hal->wq[i], destroy_queues, free_memory);
1559  }
1560 
1561 
1562  for (i = 0; i < hal->rq_count; i++) {
1563  sli_queue_free(&hal->sli, hal->rq[i], destroy_queues, free_memory);
1564  }
1565 
1566  for (i = 0; i < hal->mq_count; i++) {
1567  sli_queue_free(&hal->sli, hal->mq[i], destroy_queues, free_memory);
1568  }
1569 
1570  for (i = 0; i < hal->cq_count; i++) {
1571  sli_queue_free(&hal->sli, hal->cq[i], destroy_queues, free_memory);
1572  }
1573 
1574  for (i = 0; i < hal->eq_count; i++) {
1575  sli_queue_free(&hal->sli, hal->eq[i], destroy_queues, free_memory);
1576  }
1577 
1578  ocs_hal_qtop_free(hal->qtop);
1579 
1580  /* Free rq buffers */
1581  ocs_hal_rx_free(hal);
1582 
1583  hal_queue_teardown(hal);
1584 
1586 
1588 
1589  if (sli_teardown(&hal->sli)) {
1590  ocs_log_err(hal->os, "SLI teardown failed\n");
1591  }
1592 
1593  /* Free the queue hashes */
1595 
1596  /* Free the SLI queue objects */
1598 
1599  ocs_queue_history_free(&hal->q_hist);
1600 
1601  /* record the fact that the queues are non-functional */
1602  hal->state = OCS_HAL_STATE_UNINITIALIZED;
1603 
1604  /* free sequence free pool */
1605  ocs_array_free(hal->seq_pool);
1606  hal->seq_pool = NULL;
1607 
1608  /* free hal_wq_callback pool */
1609  ocs_pool_free(hal->wq_reqtag_pool);
1610 
1611  /* Mark HAL setup as not having been called */
1612  hal->hal_setup_called = FALSE;
1613 
1614  return OCS_HAL_RTN_SUCCESS;
1615 }
1616 
1617 static ocs_hal_rtn_e
1618 ocs_hal_sli_reset(ocs_hal_t *hal, ocs_hal_reset_e reset, ocs_hal_state_e prev_state)
1619 {
1621 
1622  switch(reset) {
1624  ocs_log_debug(hal->os, "issuing function level reset\n");
1625  if (sli_reset(&hal->sli)) {
1626  ocs_log_err(hal->os, "sli_reset failed\n");
1627  rc = OCS_HAL_RTN_ERROR;
1628  }
1629  break;
1631  ocs_log_debug(hal->os, "issuing firmware reset\n");
1632  if (sli_fw_reset(&hal->sli)) {
1633  ocs_log_err(hal->os, "sli_soft_reset failed\n");
1634  rc = OCS_HAL_RTN_ERROR;
1635  }
1636  /*
1637  * Because the FW reset leaves the FW in a non-running state,
1638  * follow that with a regular reset.
1639  */
1640  ocs_log_debug(hal->os, "issuing function level reset\n");
1641  if (sli_reset(&hal->sli)) {
1642  ocs_log_err(hal->os, "sli_reset failed\n");
1643  rc = OCS_HAL_RTN_ERROR;
1644  }
1645  break;
1646  default:
1647  ocs_log_err(hal->os, "unknown reset type - no reset performed\n");
1648  hal->state = prev_state;
1650  break;
1651  }
1652 
1653  return rc;
1654 }
1655 
1657 ocs_hal_port_migration(ocs_hal_t *hal)
1658 {
1660 
1661  ocs_log_debug(hal->os, "issuing Port migration\n");
1662  if (sli_port_migration(&hal->sli)) {
1663  ocs_log_err(hal->os, "sli_port_migration failed\n");
1664  rc = OCS_HAL_RTN_ERROR;
1665  }
1666 
1667  return rc;
1668 }
1670 ocs_hal_reset(ocs_hal_t *hal, ocs_hal_reset_e reset)
1671 {
1672  uint32_t i, iters;
1674  ocs_hal_state_e prev_state = hal->state;
1675  uint32_t destroy_queues, free_memory;
1676  ocs_domain_t *domain;
1677  ocs_t *ocs = (ocs_t *)hal->os;
1678 
1679  if (hal->state != OCS_HAL_STATE_ACTIVE) {
1680  ocs_log_test(hal->os, "HAL state %d is not active\n", hal->state);
1681  }
1682 
1683  destroy_queues = (hal->state == OCS_HAL_STATE_ACTIVE);
1684  free_memory = (hal->state != OCS_HAL_STATE_UNINITIALIZED);
1685  hal->state = OCS_HAL_STATE_RESET_IN_PROGRESS;
1686 
1687  /* If the prev_state is already reset/teardown in progress, don't continue further */
1688  if (prev_state == OCS_HAL_STATE_RESET_IN_PROGRESS ||
1689  prev_state == OCS_HAL_STATE_TEARDOWN_IN_PROGRESS) {
1690  return ocs_hal_sli_reset(hal, reset, prev_state);
1691  }
1692 
1693  /* shutdown target wqe timer */
1695 
1696  /* Cancel watchdog timer if enabled */
1697  if(hal->watchdog_timeout) {
1698  hal->watchdog_timeout = 0;
1700  }
1701 
1702  if (prev_state != OCS_HAL_STATE_UNINITIALIZED) {
1703  ocs_hal_flush(hal);
1704 
1705  /*
1706  * If an mailbox command requiring a DMA is outstanding (i.e. SFP/DDM),
1707  * then the FW will UE when the reset is issued. So attempt to complete
1708  * all mailbox commands.
1709  */
1710  iters = 10;
1711  while (!ocs_list_empty(&hal->cmd_head) && iters) {
1712  ocs_delay_usec(10000);
1713  ocs_hal_flush(hal);
1714  iters--;
1715  }
1716 
1717  if (ocs_list_empty(&hal->cmd_head)) {
1718  ocs_log_debug(hal->os, "All commands completed on MQ queue\n");
1719  } else {
1720  ocs_log_debug(hal->os, "Some commands still pending on MQ queue\n");
1721  }
1722  }
1723 
1724  /* Reset the chip */
1725  rc = ocs_hal_sli_reset(hal, reset, prev_state);
1726  if (rc == OCS_HAL_RTN_INVALID_ARG) {
1727  return OCS_HAL_RTN_ERROR;
1728  }
1729 
1730  /* Not safe to walk command/io lists unless they've been initialized */
1731  if (prev_state != OCS_HAL_STATE_UNINITIALIZED) {
1733 
1734  /* Try to clean up the io_inuse list */
1735  ocs_hal_io_cancel(hal);
1736 
1737  ocs_memset(hal->domains, 0, sizeof(hal->domains));
1738  ocs_memset(hal->fcf_index_fcfi, 0, sizeof(hal->fcf_index_fcfi));
1739 
1741 
1742  ocs_lock(&hal->io_lock);
1743  /* The io lists should be empty, but remove any that didn't get cleaned up. */
1744  /* Clean up the timed wqe list, the free list, and the wait free list */
1745  while (!ocs_list_empty(&hal->io_timed_wqe)) {
1746  ocs_list_remove_head(&hal->io_timed_wqe);
1747  }
1748 
1749  while (!ocs_list_empty(&hal->io_free)) {
1750  ocs_list_remove_head(&hal->io_free);
1751  }
1752 
1753  while (!ocs_list_empty(&hal->io_wait_free)) {
1754  ocs_list_remove_head(&hal->io_wait_free);
1755  }
1756  ocs_unlock(&hal->io_lock);
1757  }
1758 
1759  /*
1760  * IO inuse has been cleaned-up and now call domain force free
1761  * before queue reset and RX buffer free.
1762  */
1763  while ((domain = ocs_list_get_head(&(ocs->domain_list))) != NULL) {
1764  ocs_log_debug(ocs, "free domain %p\n", domain);
1765  ocs_domain_force_free(domain);
1766  }
1767 
1768  if (prev_state != OCS_HAL_STATE_UNINITIALIZED) {
1769  for (i = 0; i < hal->wq_count; i++) {
1770  sli_queue_free(&hal->sli, hal->wq[i], destroy_queues, free_memory);
1771  }
1772 
1773  for (i = 0; i < hal->rq_count; i++) {
1774  sli_queue_free(&hal->sli, hal->rq[i], destroy_queues, free_memory);
1775  }
1776 
1777  for (i = 0; i < hal->hal_rq_count; i++) {
1778  hal_rq_t *rq = hal->hal_rq[i];
1779  if (rq->rq_tracker != NULL) {
1780  uint32_t j;
1781 
1782  for (j = 0; j < rq->entry_count; j++) {
1783  rq->rq_tracker[j] = NULL;
1784  }
1785  }
1786  }
1787 
1788  for (i = 0; i < hal->mq_count; i++) {
1789  sli_queue_free(&hal->sli, hal->mq[i], destroy_queues, free_memory);
1790  }
1791 
1792  for (i = 0; i < hal->cq_count; i++) {
1793  sli_queue_free(&hal->sli, hal->cq[i], destroy_queues, free_memory);
1794  }
1795 
1796  for (i = 0; i < hal->eq_count; i++) {
1797  sli_queue_free(&hal->sli, hal->eq[i], destroy_queues, free_memory);
1798  }
1799 
1800  /* Free rq buffers */
1801  ocs_hal_rx_free(hal);
1802 
1803  /* Teardown the HAL queue topology */
1804  hal_queue_teardown(hal);
1805 
1806  /* Reset the request tag pool, the HAL IO request tags are reassigned in ocs_hal_setup_io() */
1807  ocs_hal_reqtag_reset(hal);
1808  } else {
1809 
1810  /* Free rq buffers */
1811  ocs_hal_rx_free(hal);
1812  }
1813 
1814  /*
1815  * Re-apply the run-time workarounds after clearing the SLI config
1816  * fields in sli_reset.
1817  */
1819  return rc;
1820 }
1821 
1822 int32_t
1823 ocs_hal_get_num_eq(ocs_hal_t *hal)
1824 {
1825  return hal->eq_count;
1826 }
1827 
1828 static int32_t
1830 {
1831  /* The error values below are taken from LOWLEVEL_SET_WATCHDOG_TIMER_rev1.pdf
1832  * No further explanation is given in the document.
1833  * */
1834  return (sli_reg_read(&hal->sli, SLI4_REG_SLIPORT_ERROR1) == 0x2 &&
1835  sli_reg_read(&hal->sli, SLI4_REG_SLIPORT_ERROR2) == 0x10);
1836 }
1837 
1838 
1840 ocs_hal_get(ocs_hal_t *hal, ocs_hal_property_e prop, uint32_t *value)
1841 {
1843  int32_t tmp;
1844 
1845  if (!value) {
1846  return OCS_HAL_RTN_ERROR;
1847  }
1848 
1849  *value = 0;
1850 
1851  switch (prop) {
1852  case OCS_HAL_N_IO:
1853  *value = hal->config.n_io;
1854  break;
1855  case OCS_HAL_N_SGL:
1856  *value = (hal->config.n_sgl - SLI4_SGE_MAX_RESERVED);
1857  break;
1858  case OCS_HAL_MAX_IO:
1859  *value = sli_get_max_rsrc(&hal->sli, SLI_RSRC_FCOE_XRI);
1860  break;
1861  case OCS_HAL_MAX_NODES:
1862  *value = sli_get_max_rsrc(&hal->sli, SLI_RSRC_FCOE_RPI);
1863  break;
1865  *value = hal->num_qentries[SLI_QTYPE_RQ];
1866  break;
1868  *value = hal->config.rq_default_buffer_size;
1869  break;
1871  *value = sli_get_auto_xfer_rdy_capable(&hal->sli);
1872  break;
1873  case OCS_HAL_TOW_CAPABLE:
1874  *value = sli_get_tow_capable(&hal->sli);
1875  break;
1876  case OCS_HAL_TOW_XRIS_MAX:
1877  *value = sli_get_tow_xris_max(&hal->sli);
1878  break;
1879  case OCS_HAL_TOW_BLK_SIZE:
1880  switch (hal->config.tow_blksize_chip) {
1881  case 0:
1882  *value = 512;
1883  break;
1884  case 1:
1885  *value = 1024;
1886  break;
1887  case 2:
1888  *value = 2048;
1889  break;
1890  case 3:
1891  *value = 4096;
1892  break;
1893  case 4:
1894  *value = 520;
1895  break;
1896  default:
1897  *value = 0;
1898  rc = OCS_HAL_RTN_ERROR;
1899  break;
1900  }
1901  break;
1903  *value = hal->config.tow_t10_enable;
1904  break;
1905  case OCS_HAL_TOW_P_TYPE:
1906  *value = hal->config.tow_p_type;
1907  break;
1909  *value = hal->config.tow_ref_tag_lba;
1910  break;
1912  *value = hal->config.tow_app_tag_valid;
1913  break;
1915  *value = hal->config.tow_app_tag_value;
1916  break;
1917  case OCS_HAL_TOW_FEATURE:
1918  *value = hal->config.tow_feature;
1919  break;
1920  case OCS_HAL_TOW_XRI_CNT:
1921  *value = hal->config.tow_xri_cnt;
1922  break;
1923  case OCS_HAL_TOW_IO_SIZE:
1924  *value = hal->config.tow_io_size;
1925  break;
1926  case OCS_HAL_MAX_SGE:
1927  *value = sli_get_max_sge(&hal->sli);
1928  break;
1929  case OCS_HAL_MAX_SGL:
1930  *value = sli_get_max_sgl(&hal->sli);
1931  break;
1932  case OCS_HAL_TOPOLOGY:
1933  /*
1934  * Infer link.status based on link.speed.
1935  * Report OCS_HAL_TOPOLOGY_NONE if the link is down.
1936  */
1937  if (hal->link.speed == 0) {
1938  *value = OCS_HAL_TOPOLOGY_NONE;
1939  break;
1940  }
1941  switch (hal->link.topology) {
1942  case SLI_LINK_TOPO_NPORT:
1943  *value = OCS_HAL_TOPOLOGY_NPORT;
1944  break;
1945  case SLI_LINK_TOPO_LOOP:
1946  *value = OCS_HAL_TOPOLOGY_LOOP;
1947  break;
1948  case SLI_LINK_TOPO_NONE:
1949  *value = OCS_HAL_TOPOLOGY_NONE;
1950  break;
1951  default:
1952  ocs_log_test(hal->os, "unsupported topology %#x\n", hal->link.topology);
1953  rc = OCS_HAL_RTN_ERROR;
1954  break;
1955  }
1956  break;
1958  *value = hal->config.topology;
1959  break;
1960  case OCS_HAL_LINK_SPEED:
1961  *value = hal->link.speed;
1962  break;
1964  *value = hal->link.logical_link_speed;
1965  break;
1967  *value = hal->link.aggregate_link_speed;
1968  break;
1970  switch (hal->config.speed) {
1971  case FC_LINK_SPEED_10G:
1972  *value = 10000;
1973  break;
1975  *value = 0;
1976  break;
1977  case FC_LINK_SPEED_2G:
1978  *value = 2000;
1979  break;
1980  case FC_LINK_SPEED_4G:
1981  *value = 4000;
1982  break;
1983  case FC_LINK_SPEED_8G:
1984  *value = 8000;
1985  break;
1986  case FC_LINK_SPEED_16G:
1987  *value = 16000;
1988  break;
1989  case FC_LINK_SPEED_32G:
1990  *value = 32000;
1991  break;
1992  default:
1993  ocs_log_test(hal->os, "unsupported speed %#x\n", hal->config.speed);
1994  rc = OCS_HAL_RTN_ERROR;
1995  break;
1996  }
1997  break;
1998  case OCS_HAL_IF_TYPE:
1999  *value = sli_get_if_type(&hal->sli);
2000  break;
2001  case OCS_HAL_SLI_REV:
2002  *value = sli_get_sli_rev(&hal->sli);
2003  break;
2004  case OCS_HAL_SLI_FAMILY:
2005  *value = sli_get_sli_family(&hal->sli);
2006  break;
2007  case OCS_HAL_DIF_CAPABLE:
2008  *value = sli_get_dif_capable(&hal->sli);
2009  break;
2010  case OCS_HAL_DIF_SEED:
2011  *value = hal->config.dif_seed;
2012  break;
2013  case OCS_HAL_DIF_MODE:
2014  *value = hal->config.dif_mode;
2015  break;
2017  /* Lancer supports multiple DIF separates */
2018  if (hal->sli.if_type == SLI4_IF_TYPE_LANCER_FC_ETH) {
2019  *value = TRUE;
2020  } else {
2021  *value = FALSE;
2022  }
2023  break;
2024  case OCS_HAL_DUMP_MAX_SIZE:
2025  *value = hal->dump_size;
2026  break;
2027  case OCS_HAL_DUMP_READY:
2028  *value = sli_dump_is_ready(&hal->sli);
2029  break;
2030  case OCS_HAL_DUMP_PRESENT:
2031  {
2032  ocs_t *ocs = (ocs_t *)hal->os;
2033 
2034  if (ocs->enable_auto_recovery) {
2035  /**
2036  * If auto recovery is enabled, SLIPort flag will be cleared by the
2037  * set_dump_location mbox cmd in the hal reset path. So, we have to
2038  * rely on OCS dump_state flag to validate the presence of FW dumps.
2039  *
2040  * Check only for FDD, and return if a dump exists on this PCI func.
2041  * This can even return the presence of CLD on PCI func 0 since we
2042  * really don't care about the type of dump that exists in OCS buffers.
2043  */
2045  } else {
2046  /* Since auto recovery is disabled, SLIPort flag will be valid */
2047  *value = sli_dump_is_present(&hal->sli);
2048  }
2049 
2050  /* If FW dump is present, set the appropriate fw_dump_type */
2051  if (*value) {
2052  *value = ocs->fw_dump.type;
2053  }
2054  break;
2055  }
2057  tmp = sli_reset_required(&hal->sli);
2058  if(tmp < 0) {
2059  rc = OCS_HAL_RTN_ERROR;
2060  } else {
2061  *value = tmp;
2062  }
2063  break;
2064  case OCS_HAL_FW_ERROR:
2065  *value = sli_fw_error_status(&hal->sli);
2066  break;
2067  case OCS_HAL_FW_READY:
2068  *value = sli_fw_ready(&hal->sli);
2069  break;
2070  case OCS_HAL_FW_TIMED_OUT:
2071  *value = ocs_hal_get_fw_timed_out(hal);
2072  break;
2074  *value = sli_get_hlm_capable(&hal->sli);
2075  break;
2076  case OCS_HAL_DPP_MODE:
2077  *value = sli_get_dpp_capable(&hal->sli);
2078  break;
2080  *value = sli_get_sgl_preregister_required(&hal->sli);
2081  break;
2082  case OCS_HAL_HW_REV1:
2083  *value = sli_get_hw_revision(&hal->sli, 0);
2084  break;
2085  case OCS_HAL_HW_REV2:
2086  *value = sli_get_hw_revision(&hal->sli, 1);
2087  break;
2088  case OCS_HAL_HW_REV3:
2089  *value = sli_get_hw_revision(&hal->sli, 2);
2090  break;
2091  case OCS_HAL_LINKCFG:
2092  *value = hal->linkcfg;
2093  break;
2094  case OCS_HAL_ETH_LICENSE:
2095  *value = hal->eth_license;
2096  break;
2098  *value = sli_get_link_module_type(&hal->sli);
2099  break;
2100  case OCS_HAL_NUM_CHUTES:
2101  *value = ocs_hal_get_num_chutes(hal);
2102  break;
2104  *value = hal->workaround.disable_ar_tgt_dif;
2105  break;
2107  *value = hal->config.i_only_aab;
2108  break;
2110  *value = hal->config.emulate_tgt_wqe_timeout;
2111  break;
2112  case OCS_HAL_VPD_LEN:
2113  *value = sli_get_vpd_len(&hal->sli);
2114  break;
2116  *value = sli_get_is_sgl_chaining_capable(&hal->sli) || hal->workaround.sglc_misreported;
2117  break;
2119  /*
2120  * SGL Chaining is allowed in the following cases:
2121  * 1. Lancer with host SGL Lists
2122  * 2. Skyhawk with pre-registered SGL Lists
2123  */
2124  *value = FALSE;
2125  if ((sli_get_is_sgl_chaining_capable(&hal->sli) || hal->workaround.sglc_misreported) &&
2126  !sli_get_sgl_preregister(&hal->sli) &&
2128  *value = TRUE;
2129  }
2130 
2131  if ((sli_get_is_sgl_chaining_capable(&hal->sli) || hal->workaround.sglc_misreported) &&
2132  sli_get_sgl_preregister(&hal->sli) &&
2133  ((SLI4_IF_TYPE_BE3_SKH_PF == sli_get_if_type(&hal->sli)) ||
2134  (SLI4_IF_TYPE_BE3_SKH_VF == sli_get_if_type(&hal->sli)))) {
2135  *value = TRUE;
2136  }
2137  break;
2139  /* Only lancer supports host allocated SGL Chaining buffers. */
2140  *value = ((sli_get_is_sgl_chaining_capable(&hal->sli) || hal->workaround.sglc_misreported) &&
2142  break;
2144  if (hal->workaround.ignore_send_frame) {
2145  *value = 0;
2146  } else {
2147  /* Only lancer is capable */
2148  *value = sli_get_if_type(&hal->sli) == SLI4_IF_TYPE_LANCER_FC_ETH;
2149  }
2150  break;
2152  *value = hal->config.rq_selection_policy;
2153  break;
2154  case OCS_HAL_RR_QUANTA:
2155  *value = hal->config.rr_quanta;
2156  break;
2157  case OCS_HAL_MAX_VPORTS:
2158  *value = sli_get_max_rsrc(&hal->sli, SLI_RSRC_FCOE_VPI);
2159  break;
2160  case OCS_HAL_PORTNUM:
2161  *value = sli_get_portnum(&hal->sli);
2162  break;
2164  *value = hal->config.suppress_rsp_capable;
2165  break;
2166  default:
2167  ocs_log_test(hal->os, "unsupported property %#x\n", prop);
2168  rc = OCS_HAL_RTN_ERROR;
2169  }
2170 
2171  return rc;
2172 }
2173 
2174 void *
2176 {
2177  void *rc = NULL;
2178 
2179  switch (prop) {
2180  case OCS_HAL_WWN_NODE:
2181  rc = sli_get_wwn_node(&hal->sli);
2182  break;
2183  case OCS_HAL_WWN_PORT:
2184  rc = sli_get_wwn_port(&hal->sli);
2185  break;
2186  case OCS_HAL_VPD:
2187  /* make sure VPD length is non-zero */
2188  if (sli_get_vpd_len(&hal->sli)) {
2189  rc = sli_get_vpd(&hal->sli);
2190  }
2191  break;
2192  case OCS_HAL_FW_REV:
2193  rc = sli_get_fw_name(&hal->sli, 0);
2194  break;
2195  case OCS_HAL_FW_REV2:
2196  rc = sli_get_fw_name(&hal->sli, 1);
2197  break;
2198  case OCS_HAL_IPL:
2199  rc = sli_get_ipl_name(&hal->sli);
2200  break;
2202  rc = sli_get_bios_version_string(&hal->sli);
2203  break;
2204  default:
2205  ocs_log_test(hal->os, "unsupported property %#x\n", prop);
2206  }
2207 
2208  return rc;
2209 }
2210 
2211 
2212 
2214 ocs_hal_set(ocs_hal_t *hal, ocs_hal_property_e prop, uint32_t value)
2215 {
2217 
2218  switch (prop) {
2219  case OCS_HAL_N_IO:
2220  if (value > sli_get_max_rsrc(&hal->sli, SLI_RSRC_FCOE_XRI) ||
2221  value == 0) {
2222  ocs_log_test(hal->os, "IO value out of range %d vs %d\n",
2223  value, sli_get_max_rsrc(&hal->sli, SLI_RSRC_FCOE_XRI));
2224  rc = OCS_HAL_RTN_ERROR;
2225  } else {
2226  hal->config.n_io = value;
2227  }
2228  break;
2229  case OCS_HAL_N_SGL:
2230  value += SLI4_SGE_MAX_RESERVED;
2231  if (value > sli_get_max_sgl(&hal->sli)) {
2232  ocs_log_test(hal->os, "SGL value out of range %d vs %d\n",
2233  value, sli_get_max_sgl(&hal->sli));
2234  rc = OCS_HAL_RTN_ERROR;
2235  } else {
2236  hal->config.n_sgl = value;
2237  }
2238  break;
2239  case OCS_HAL_TOPOLOGY:
2240  if ((sli_get_medium(&hal->sli) != SLI_LINK_MEDIUM_FC) &&
2241  (value != OCS_HAL_TOPOLOGY_AUTO)) {
2242  ocs_log_test(hal->os, "unsupported topology=%#x medium=%#x\n",
2243  value, sli_get_medium(&hal->sli));
2244  rc = OCS_HAL_RTN_ERROR;
2245  break;
2246  }
2247 
2248  switch (value) {
2249  case OCS_HAL_TOPOLOGY_AUTO:
2250  if (sli_get_medium(&hal->sli) == SLI_LINK_MEDIUM_FC) {
2252  } else {
2254  }
2255  break;
2258  break;
2259  case OCS_HAL_TOPOLOGY_LOOP:
2261  break;
2262  default:
2263  ocs_log_test(hal->os, "unsupported topology %#x\n", value);
2264  rc = OCS_HAL_RTN_ERROR;
2265  }
2266  hal->config.topology = value;
2267  break;
2268  case OCS_HAL_LINK_SPEED:
2269  if (sli_get_medium(&hal->sli) != SLI_LINK_MEDIUM_FC) {
2270  switch (value) {
2271  case 0: /* Auto-speed negotiation */
2272  case 10000: /* FCoE speed */
2273  hal->config.speed = FC_LINK_SPEED_10G;
2274  break;
2275  default:
2276  ocs_log_test(hal->os, "unsupported speed=%#x medium=%#x\n",
2277  value, sli_get_medium(&hal->sli));
2278  rc = OCS_HAL_RTN_ERROR;
2279  }
2280  break;
2281  }
2282 
2283  switch (value) {
2284  case 0: /* Auto-speed negotiation */
2285  hal->config.speed = FC_LINK_SPEED_AUTO_16_8_4;
2286  break;
2287  case 2000: /* FC speeds */
2288  hal->config.speed = FC_LINK_SPEED_2G;
2289  break;
2290  case 4000:
2291  hal->config.speed = FC_LINK_SPEED_4G;
2292  break;
2293  case 8000:
2294  hal->config.speed = FC_LINK_SPEED_8G;
2295  break;
2296  case 16000:
2297  hal->config.speed = FC_LINK_SPEED_16G;
2298  break;
2299  case 32000:
2300  hal->config.speed = FC_LINK_SPEED_32G;
2301  break;
2302  default:
2303  ocs_log_test(hal->os, "unsupported speed %d\n", value);
2304  rc = OCS_HAL_RTN_ERROR;
2305  }
2306  break;
2307  case OCS_HAL_DIF_SEED:
2308  /* Set the DIF seed - only for lancer right now */
2309  if (SLI4_IF_TYPE_LANCER_FC_ETH != sli_get_if_type(&hal->sli)) {
2310  ocs_log_test(hal->os, "DIF seed not supported for this device\n");
2311  rc = OCS_HAL_RTN_ERROR;
2312  } else {
2313  hal->config.dif_seed = value;
2314  }
2315  break;
2316  case OCS_HAL_DIF_MODE:
2317  switch (value) {
2319  /*
2320  * Make sure we support inline DIF.
2321  *
2322  * Note: Having both bits clear means that we have old
2323  * FW that doesn't set the bits.
2324  */
2325  if (sli_is_dif_inline_capable(&hal->sli)) {
2326  hal->config.dif_mode = value;
2327  } else {
2328  ocs_log_test(hal->os, "chip does not support DIF inline\n");
2329  rc = OCS_HAL_RTN_ERROR;
2330  }
2331  break;
2333  /* Make sure we support DIF separates. */
2334  if (sli_is_dif_separate_capable(&hal->sli)) {
2335  hal->config.dif_mode = value;
2336  } else {
2337  ocs_log_test(hal->os, "chip does not support DIF separate\n");
2338  rc = OCS_HAL_RTN_ERROR;
2339  }
2340  }
2341  break;
2343  hal->config.rq_default_buffer_size = value;
2344  break;
2345  case OCS_HAL_TOW_IO_SIZE:
2346  hal->config.tow_io_size = value;
2347  break;
2348  case OCS_HAL_TOW_XRI_CNT:
2349  hal->config.tow_xri_cnt = value;
2350  break;
2351  case OCS_HAL_TOW_FEATURE:
2352  hal->config.tow_feature = value;
2353  break;
2354  case OCS_HAL_TOW_BLK_SIZE:
2355  switch (value) {
2356  case 512:
2357  hal->config.tow_blksize_chip = 0;
2358  break;
2359  case 1024:
2360  hal->config.tow_blksize_chip = 1;
2361  break;
2362  case 2048:
2363  hal->config.tow_blksize_chip = 2;
2364  break;
2365  case 4096:
2366  hal->config.tow_blksize_chip = 3;
2367  break;
2368  case 520:
2369  hal->config.tow_blksize_chip = 4;
2370  break;
2371  default:
2372  ocs_log_err(hal->os, "Invalid block size %d\n", value);
2373  rc = OCS_HAL_RTN_ERROR;
2374  }
2375  break;
2377  hal->config.tow_t10_enable = value;
2378  break;
2379  case OCS_HAL_TOW_P_TYPE:
2380  hal->config.tow_p_type = value;
2381  break;
2383  hal->config.tow_ref_tag_lba = value;
2384  break;
2386  hal->config.tow_app_tag_valid = value;
2387  break;
2389  hal->config.tow_app_tag_value = value;
2390  break;
2391  case OCS_HAL_ESOC:
2392  hal->config.esoc = value;
2393  break;
2395  rc = sli_set_hlm(&hal->sli, value);
2396  break;
2397  case OCS_HAL_DPP_MODE:
2398  rc = sli_set_dpp(&hal->sli, value);
2399  break;
2401  rc = sli_set_sgl_preregister(&hal->sli, value);
2402  break;
2403  case OCS_HAL_ETH_LICENSE:
2404  hal->eth_license = value;
2405  break;
2407  hal->config.i_only_aab = value;
2408  break;
2410  hal->config.emulate_tgt_wqe_timeout = value;
2411  break;
2412  case OCS_HAL_BOUNCE:
2413  hal->config.bounce = value;
2414  break;
2416  hal->config.rq_selection_policy = value;
2417  break;
2418  case OCS_HAL_RR_QUANTA:
2419  hal->config.rr_quanta = value;
2420  break;
2422  hal->config.cq_process_limit = value;
2423  break;
2425  hal->config.suppress_rsp_capable = value;
2426  break;
2427  default:
2428  ocs_log_test(hal->os, "unsupported property %#x\n", prop);
2429  rc = OCS_HAL_RTN_ERROR;
2430  }
2431 
2432  return rc;
2433 }
2434 
2435 
2437 ocs_hal_set_ptr(ocs_hal_t *hal, ocs_hal_property_e prop, void *value)
2438 {
2440 
2441  switch (prop) {
2442  case OCS_HAL_WAR_VERSION:
2443  hal->hal_war_version = value;
2444  break;
2445  case OCS_HAL_FILTER_DEF: {
2446  char *p = value;
2447  uint32_t idx = 0;
2448 
2449  for (idx = 0; idx < ARRAY_SIZE(hal->config.filter_def); idx++) {
2450  hal->config.filter_def[idx] = 0;
2451  }
2452 
2453  for (idx = 0; (idx < ARRAY_SIZE(hal->config.filter_def)) && (p != NULL) && *p; ) {
2454  hal->config.filter_def[idx++] = ocs_strtoul(p, 0, 0);
2455  p = ocs_strchr(p, ',');
2456  if (p != NULL) {
2457  p++;
2458  }
2459  }
2460 
2461  break;
2462  }
2463  default:
2464  ocs_log_test(hal->os, "unsupported property %#x\n", prop);
2465  rc = OCS_HAL_RTN_ERROR;
2466  break;
2467  }
2468  return rc;
2469 }
2470 /**
2471  * @ingroup interrupt
2472  * @brief Check for the events associated with the interrupt vector.
2473  *
2474  * @param hal Hardware context.
2475  * @param vector Zero-based interrupt vector number.
2476  *
2477  * @return Returns 0 on success, or a non-zero value on failure.
2478  */
2479 int32_t
2480 ocs_hal_event_check(ocs_hal_t *hal, uint32_t vector)
2481 {
2482  int32_t rc = 0;
2483 
2484  if (!hal) {
2485  ocs_log_err(NULL, "HAL context NULL?!?\n");
2486  return -1;
2487  }
2488 
2489  if (vector > hal->eq_count) {
2490  ocs_log_err(hal->os, "vector %d. max %d\n",
2491  vector, hal->eq_count);
2492  return -1;
2493  }
2494 
2495  /*
2496  * The caller should disable interrupts if they wish to prevent us
2497  * from processing during a shutdown. The following states are defined:
2498  * OCS_HAL_STATE_UNINITIALIZED - No queues allocated
2499  * OCS_HAL_STATE_QUEUES_ALLOCATED - The state after a chip reset,
2500  * queues are cleared.
2501  * OCS_HAL_STATE_ACTIVE - Chip and queues are operational
2502  * OCS_HAL_STATE_RESET_IN_PROGRESS - reset, we still want completions
2503  * OCS_HAL_STATE_TEARDOWN_IN_PROGRESS - We still want mailbox
2504  * completions.
2505  */
2506  if (hal->state != OCS_HAL_STATE_UNINITIALIZED) {
2507  rc = sli_queue_is_empty(&hal->sli, hal->eq[vector]);
2508 
2509  /* Re-arm queue if there are no entries */
2510  if (rc != 0) {
2511  sli_queue_arm(&hal->sli, hal->eq[vector], TRUE);
2512  }
2513  }
2514  return rc;
2515 }
2516 
2517 void
2519 {
2520  ocs_hal_sequence_t *seq = arg;
2521  ocs_hal_t *hal = seq->hal;
2522 
2523  ocs_hal_assert(hal != NULL);
2524  ocs_hal_assert(hal->callback.unsolicited != NULL);
2525 
2526  hal->callback.unsolicited(hal->args.unsolicited, seq);
2527 }
2528 
2529 int32_t
2530 ocs_hal_process(ocs_hal_t *hal, uint32_t vector, uint32_t max_isr_time_msec)
2531 {
2532  hal_eq_t *eq;
2533  int32_t rc = 0;
2534 
2535  CPUTRACE("");
2536 
2537  /*
2538  * The caller should disable interrupts if they wish to prevent us
2539  * from processing during a shutdown. The following states are defined:
2540  * OCS_HAL_STATE_UNINITIALIZED - No queues allocated
2541  * OCS_HAL_STATE_QUEUES_ALLOCATED - The state after a chip reset,
2542  * queues are cleared.
2543  * OCS_HAL_STATE_ACTIVE - Chip and queues are operational
2544  * OCS_HAL_STATE_RESET_IN_PROGRESS - reset, we still want completions
2545  * OCS_HAL_STATE_TEARDOWN_IN_PROGRESS - We still want mailbox
2546  * completions.
2547  */
2548  if (hal->state == OCS_HAL_STATE_UNINITIALIZED) {
2549  return 0;
2550  }
2551 
2552  /* Get pointer to hal_eq_t */
2553  eq = hal->hal_eq[vector];
2554  if (!eq) {
2555  return 0;
2556  }
2557 
2558  OCS_STAT(eq->use_count++);
2559 
2560  rc = ocs_hal_eq_process(hal, eq, max_isr_time_msec);
2561 
2562  eq->queue->last_processed_time = ocs_ticks_to_ms(ocs_get_os_ticks());
2563  return rc;
2564 }
2565 
2566 /**
2567  * @ingroup interrupt
2568  * @brief Process events associated with an EQ.
2569  *
2570  * @par Description
2571  * Loop termination:
2572  * @n @n Without a mechanism to terminate the completion processing loop, it
2573  * is possible under some workload conditions for the loop to never terminate
2574  * (or at least take longer than the OS is happy to have an interrupt handler
2575  * or kernel thread context hold a CPU without yielding).
2576  * @n @n The approach taken here is to periodically check how much time
2577  * we have been in this
2578  * processing loop, and if we exceed a predetermined time (multiple seconds), the
2579  * loop is terminated, and ocs_hal_process() returns.
2580  *
2581  * @param hal Hardware context.
2582  * @param eq Pointer to HAL EQ object.
2583  * @param max_isr_time_msec Maximum time in msec to stay in this function.
2584  *
2585  * @return Returns 0 on success, or a non-zero value on failure.
2586  */
2587 int32_t
2588 ocs_hal_eq_process(ocs_hal_t *hal, hal_eq_t *eq, uint32_t max_isr_time_msec)
2589 {
2590  uint8_t eqe[sizeof(sli4_eqe_t)] = { 0 };
2591  uint32_t done = FALSE;
2592  uint64_t tstart;
2593  uint64_t telapsed;
2594  tstart = ocs_get_os_ticks();
2595 
2596  CPUTRACE("");
2597 
2598  while (!done && !sli_queue_read(&hal->sli, eq->queue, eqe)) {
2599  uint16_t cq_id = 0;
2600  int32_t rc;
2601 
2602  rc = sli_eq_parse(&hal->sli, eqe, &cq_id);
2603  if (unlikely(rc)) {
2604  if (rc > 0) {
2605  uint32_t i;
2606 
2607  /*
2608  * Received a sentinel EQE indicating the EQ is full.
2609  * Process all CQs
2610  */
2611  for (i = 0; i < hal->cq_count; i++) {
2612  ocs_hal_cq_process(hal, hal->hal_cq[i], hal->config.cq_process_limit);
2613  }
2614  continue;
2615  } else {
2616  return rc;
2617  }
2618  } else {
2619  int32_t index = ocs_hal_queue_hash_find(hal->cq_hash, cq_id);
2620  if (likely(index >= 0)) {
2621  //ocs_log_err(hal->os, "Recevied CQ Event %d : %d\n", cq_id, index);
2622  ocs_hal_cq_process(hal, hal->hal_cq[index], hal->config.cq_process_limit);
2623  } else {
2624  ocs_log_err(hal->os, "bad CQ_ID %#06x\n", cq_id);
2625  }
2626  }
2627 
2628 
2629  if (eq->queue->n_posted > (eq->queue->posted_limit)) {
2630  sli_queue_arm(&hal->sli, eq->queue, FALSE);
2631  }
2632 
2633  telapsed = ocs_get_os_ticks() - tstart;
2634  if (ocs_ticks_to_ms(telapsed) >= max_isr_time_msec) {
2635  done = TRUE;
2636  }
2637  }
2638  sli_queue_eq_arm(&hal->sli, eq->queue, TRUE);
2639 
2640  return 0;
2641 }
2642 
2643 static ocs_hal_rtn_e
2644 ocs_hal_bmbx_command(ocs_hal_t *hal, uint8_t *cmd)
2645 {
2646  sli4_mbox_command_header_t *hdr = NULL;
2647  void *bmbx = hal->sli.bmbx.virt;
2649  int32_t mcqe_status;
2650 
2651  ocs_memset(bmbx, 0, SLI4_BMBX_SIZE);
2652  ocs_memcpy(bmbx, cmd, SLI4_BMBX_SIZE);
2653 
2654  mcqe_status = sli_bmbx_command(&hal->sli);
2655  if (mcqe_status < 0) {
2656  ocs_log_err(hal->os, "BMBX submission failed\n");
2657  return rc;
2658  }
2659 
2660  ocs_memcpy(cmd, bmbx, SLI4_BMBX_SIZE);
2661  hdr = (sli4_mbox_command_header_t *)cmd;
2662  if (!hdr->status) {
2663  rc = OCS_HAL_RTN_SUCCESS;
2664  } else {
2665  ocs_log_err(hal->os, "BMBX failed; bmbx_hdr: %08x, bmbx_cmd: %#x, bmbx_status: %#x\n",
2666  (uint32_t *)hdr, hdr->command, hdr->status);
2667  if (mcqe_status == SLI4_MGMT_STATUS_FEATURE_NOT_SUPPORTED)
2669  }
2670 
2671  return rc;
2672 }
2673 
2674 /**
2675  * @brief Submit queued (pending) mbx commands.
2676  *
2677  * @par Description
2678  * Submit queued mailbox commands.
2679  * --- Assumes that hal->cmd_lock is held ---
2680  *
2681  * @param hal Hardware context.
2682  *
2683  * @return Returns 0 on success, or a negative error code value on failure.
2684  */
2685 static int32_t
2687 {
2688  ocs_command_ctx_t *ctx;
2689  int32_t rc = -1;
2690 
2691  /* Submit MQE only if there's room */
2692  while (hal->cmd_head_count < (hal->mq[0]->length - 1U)) {
2693  ctx = ocs_list_remove_head(&hal->cmd_pending);
2694  if (ctx == NULL) {
2695  break;
2696  }
2697 
2698  ocs_list_add_tail(&hal->cmd_head, ctx);
2699  hal->cmd_head_count++;
2700 
2701  rc = sli_queue_write(&hal->sli, hal->mq[0], ctx->buf);
2702  ocs_assert((rc >= 0), -1);
2703  }
2704 
2705  return 0;
2706 }
2707 
2708 /**
2709  * @ingroup io
2710  * @brief Issue a SLI command.
2711  *
2712  * @par Description
2713  * Send a mailbox command to the hardware, and either wait for a completion
2714  * (OCS_CMD_POLL) or get an optional asynchronous completion (OCS_CMD_NOWAIT).
2715  *
2716  * @param hal Hardware context.
2717  * @param cmd Buffer containing a formatted command and results.
2718  * @param opts Command options:
2719  * - OCS_CMD_POLL - Command executes synchronously and busy-waits for the completion.
2720  * - OCS_CMD_NOWAIT - Command executes asynchronously. Uses callback.
2721  * @param cb Function callback used for asynchronous mode. May be NULL.
2722  * @n Prototype is <tt>(*cb)(void *arg, uint8_t *cmd)</tt>.
2723  * @n @n @b Note: If the
2724  * callback function pointer is NULL, the results of the command are silently
2725  * discarded, allowing this pointer to exist solely on the stack.
2726  * @param arg Argument passed to an asynchronous callback.
2727  *
2728  * @return Returns 0 on success, or a non-zero value on failure.
2729  */
2731 ocs_hal_command(ocs_hal_t *hal, uint8_t *cmd, uint32_t opts, void *cb, void *arg)
2732 {
2734 
2735  /*
2736  * If the chip is in an error state (UE'd) then reject this mailbox
2737  * command.
2738  */
2739  if (sli_fw_error_status(&hal->sli) > 0) {
2740  uint32_t err1 = sli_reg_read(&hal->sli, SLI4_REG_SLIPORT_ERROR1);
2741  uint32_t err2 = sli_reg_read(&hal->sli, SLI4_REG_SLIPORT_ERROR2);
2742 
2743  if (hal->expiration_logged == 0 && err1 == 0x2 && err2 == 0x10) {
2744  hal->expiration_logged = 1;
2745  ocs_log_crit(hal->os,"Emulex: Heartbeat expired after %d seconds\n",
2746  hal->watchdog_timeout);
2747  }
2748 
2749  ocs_log_crit(hal->os, "Chip is in an error state - reset needed\n");
2750  ocs_log_crit(hal->os, "status=%#x error1=%#x error2=%#x\n",
2751  sli_reg_read(&hal->sli, SLI4_REG_SLIPORT_STATUS), err1, err2);
2752  goto log_err;
2753  }
2754 
2755  if (OCS_CMD_POLL == opts) {
2756  if (hal->mq[0]->length && !sli_queue_is_empty(&hal->sli, hal->mq[0])) {
2757  /*
2758  * Can't issue Boot-strap mailbox command with other
2759  * mail-queue commands pending as this interaction is
2760  * undefined
2761  */
2762  ocs_log_err(hal->os, "MQ is not empty\n");
2763  } else {
2764  ocs_sem_p(&hal->bmbx_sem, OCS_SEM_FOREVER);
2765  rc = ocs_hal_bmbx_command(hal, cmd);
2766  ocs_sem_v(&hal->bmbx_sem);
2767  }
2768  } else if (OCS_CMD_NOWAIT == opts) {
2769  ocs_command_ctx_t *ctx = NULL;
2770 
2771  ctx = ocs_malloc(hal->os, sizeof(*ctx), OCS_M_ZERO | OCS_M_NOWAIT);
2772  if (!ctx) {
2773  ocs_log_err(hal->os, "Can't allocate the command context\n");
2775  goto log_err;
2776  }
2777 
2778  if (OCS_HAL_STATE_ACTIVE != hal->state) {
2779  ocs_log_err(hal->os, "HAL state (%d) is not active\n", hal->state);
2780  ocs_free(hal->os, ctx, sizeof(*ctx));
2781  goto log_err;
2782  }
2783 
2784  if (cb) {
2785  ctx->cb = cb;
2786  ctx->arg = arg;
2787  }
2788  ctx->buf = cmd;
2789  ctx->ctx = hal;
2790 
2791  ocs_lock(&hal->cmd_lock);
2792  /* Add to pending list */
2793  ocs_list_add_tail(&hal->cmd_pending, ctx);
2794 
2795  /* Submit as much of the pending list as we can */
2796  rc = ocs_hal_cmd_submit_pending(hal);
2797  if (rc) {
2798  ocs_log_err(hal->os, "MQE submission failed\n");
2799  ocs_free(hal->os, ctx, sizeof(*ctx));
2800  }
2801  ocs_unlock(&hal->cmd_lock);
2802  }
2803 
2804 log_err:
2805  if (rc)
2806  ocs_log_err(hal->os, "MBOX command: %#x failed, rc: %d\n",
2807  ((sli4_mbox_command_header_t *)cmd)->command, rc);
2808 
2809  return rc;
2810 }
2811 
2812 /**
2813  * @ingroup devInitShutdown
2814  * @brief Register a callback for the given event.
2815  *
2816  * @param hal Hardware context.
2817  * @param which Event of interest.
2818  * @param func Function to call when the event occurs.
2819  * @param arg Argument passed to the callback function.
2820  *
2821  * @return Returns 0 on success, or a non-zero value on failure.
2822  */
2824 ocs_hal_callback(ocs_hal_t *hal, ocs_hal_callback_e which, void *func, void *arg)
2825 {
2826 
2827  if (!hal || !func || (which >= OCS_HAL_CB_MAX)) {
2828  ocs_log_err(NULL, "bad parameter hal=%p which=%#x func=%p\n",
2829  hal, which, func);
2830  return OCS_HAL_RTN_ERROR;
2831  }
2832 
2833  switch (which) {
2834  case OCS_HAL_CB_DOMAIN:
2835  hal->callback.domain = func;
2836  hal->args.domain = arg;
2837  break;
2838  case OCS_HAL_CB_PORT:
2839  hal->callback.port = func;
2840  hal->args.port = arg;
2841  break;
2843  hal->callback.unsolicited = func;
2844  hal->args.unsolicited = arg;
2845  break;
2847  hal->callback.rnode = func;
2848  hal->args.rnode = arg;
2849  break;
2850  case OCS_HAL_CB_BOUNCE:
2851  hal->callback.bounce = func;
2852  hal->args.bounce = arg;
2853  break;
2854  case OCS_HAL_CB_XPORT:
2855  hal->callback.xport = func;
2856  hal->args.xport = arg;
2857  break;
2858  default:
2859  ocs_log_test(hal->os, "unknown callback %#x\n", which);
2860  return OCS_HAL_RTN_ERROR;
2861  }
2862 
2863  return OCS_HAL_RTN_SUCCESS;
2864 }
2865 
2866 /**
2867  * @ingroup port
2868  * @brief Allocate a port object.
2869  *
2870  * @par Description
2871  * This function allocates a VPI object for the port and stores it in the
2872  * indicator field of the port object.
2873  *
2874  * @param hal Hardware context.
2875  * @param sport SLI port object used to connect to the domain.
2876  * @param domain Domain object associated with this port (may be NULL).
2877  * @param wwpn Port's WWPN in big-endian order, or NULL to use default.
2878  *
2879  * @return Returns 0 on success, or a non-zero value on failure.
2880  */
2882 ocs_hal_port_alloc(ocs_hal_t *hal, ocs_sli_port_t *sport, ocs_domain_t *domain,
2883  uint8_t *wwpn)
2884 {
2885  uint8_t *cmd = NULL;
2887  uint32_t index;
2888 
2889  sport->indicator = UINT32_MAX;
2890  sport->hal = hal;
2891  sport->ctx.app = sport;
2892  sport->sm_free_req_pending = 0;
2893 
2894  /*
2895  * Check if the chip is in an error state (UE'd) before proceeding.
2896  */
2897  if (sli_fw_error_status(&hal->sli) > 0) {
2898  ocs_log_crit(hal->os, "Chip is in an error state - reset needed\n");
2899  return OCS_HAL_RTN_ERROR;
2900  }
2901 
2902  if (wwpn) {
2903  ocs_memcpy(&sport->sli_wwpn, wwpn, sizeof(sport->sli_wwpn));
2904  }
2905 
2906  if (sli_resource_alloc(&hal->sli, SLI_RSRC_FCOE_VPI, &sport->indicator, &index)) {
2907  ocs_log_err(hal->os, "FCOE_VPI allocation failure\n");
2908  return OCS_HAL_RTN_ERROR;
2909  }
2910 
2911  if (domain != NULL) {
2912  ocs_sm_function_t next = NULL;
2913 
2914  cmd = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
2915  if (!cmd) {
2916  ocs_log_err(hal->os, "command memory allocation failed\n");
2917  rc = OCS_HAL_RTN_NO_MEMORY;
2918  goto ocs_hal_port_alloc_out;
2919  }
2920 
2921  // If the WWPN is NULL, fetch the default WWPN and WWNN before
2922  // initializing the VPI
2923  if (!wwpn) {
2925  } else {
2927  }
2928 
2929  ocs_sm_transition(&sport->ctx, next, cmd);
2930  } else if (!wwpn) {
2931  // This is the convention for the HAL, not SLI
2932  ocs_log_test(hal->os, "need WWN for physical port\n");
2933  rc = OCS_HAL_RTN_ERROR;
2934  } else {
2935  /* domain NULL and wwpn non-NULL */
2936  ocs_sm_transition(&sport->ctx, __ocs_hal_port_alloc_init, NULL);
2937  }
2938 
2939 ocs_hal_port_alloc_out:
2940  if (rc != OCS_HAL_RTN_SUCCESS) {
2941  ocs_free(hal->os, cmd, SLI4_BMBX_SIZE);
2942 
2943  if (sli_resource_free(&hal->sli, SLI_RSRC_FCOE_VPI, sport->indicator)) {
2944  ocs_log_err(hal->os, "FCOE_VPI (%d) free failed, addr=%#x\n", sport->indicator, sport->fc_id);
2945  }
2946  }
2947 
2948  return rc;
2949 }
2950 
2951 /**
2952  * @ingroup port
2953  * @brief Attach a physical/virtual SLI port to a domain.
2954  *
2955  * @par Description
2956  * This function registers a previously-allocated VPI with the
2957  * device.
2958  *
2959  * @param hal Hardware context.
2960  * @param sport Pointer to the SLI port object.
2961  * @param fc_id Fibre Channel ID to associate with this port.
2962  *
2963  * @return Returns OCS_HAL_RTN_SUCCESS on success, or an error code on failure.
2964  */
2966 ocs_hal_port_attach(ocs_hal_t *hal, ocs_sli_port_t *sport, uint32_t fc_id)
2967 {
2968  uint8_t *buf = NULL;
2970 
2971  if (!hal || !sport) {
2972  ocs_log_err(hal ? hal->os : NULL,
2973  "bad parameter(s) hal=%p sport=%p\n", hal,
2974  sport);
2975  return OCS_HAL_RTN_ERROR;
2976  }
2977 
2978  /*
2979  * Check if the chip is in an error state (UE'd) before proceeding.
2980  */
2981  if (sli_fw_error_status(&hal->sli) > 0) {
2982  ocs_log_crit(hal->os, "Chip is in an error state - reset needed\n");
2983  return OCS_HAL_RTN_ERROR;
2984  }
2985 
2986  buf = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
2987  if (!buf) {
2988  ocs_log_err(hal->os, "no buffer for command\n");
2989  return OCS_HAL_RTN_NO_MEMORY;
2990  }
2991 
2992  sport->fc_id = fc_id;
2994  return rc;
2995 }
2996 
2997 /**
2998  * @brief Called when the port control command completes.
2999  *
3000  * @par Description
3001  * We only need to free the mailbox command buffer.
3002  *
3003  * @param hal Hardware context.
3004  * @param status Status field from the mbox completion.
3005  * @param mqe Mailbox response structure.
3006  * @param arg Pointer to a callback function that signals the caller that the command is done.
3007  *
3008  * @return Returns 0.
3009  */
3010 static int32_t
3011 ocs_hal_cb_port_control(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
3012 {
3013  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
3014  return 0;
3015 }
3016 
3017 /**
3018  * @ingroup port
3019  * @brief Control a port (initialize, shutdown, or set link configuration).
3020  *
3021  * @par Description
3022  * This function controls a port depending on the @c ctrl parameter:
3023  * - @b OCS_HAL_PORT_INIT -
3024  * Issues the CONFIG_LINK and INIT_LINK commands for the specified port.
3025  * The HAL generates an OCS_HAL_DOMAIN_FOUND event when the link comes up.
3026  * .
3027  * - @b OCS_HAL_PORT_SHUTDOWN -
3028  * Issues the DOWN_LINK command for the specified port.
3029  * The HAL generates an OCS_HAL_DOMAIN_LOST event when the link is down.
3030  * .
3031  * - @b OCS_HAL_PORT_SET_LINK_CONFIG -
3032  * Sets the link configuration.
3033  *
3034  * @param hal Hardware context.
3035  * @param ctrl Specifies the operation:
3036  * - OCS_HAL_PORT_INIT
3037  * - OCS_HAL_PORT_SHUTDOWN
3038  * - OCS_HAL_PORT_SET_LINK_CONFIG
3039  *
3040  * @param value Operation-specific value.
3041  * - OCS_HAL_PORT_INIT - Selective reset AL_PA
3042  * - OCS_HAL_PORT_SHUTDOWN - N/A
3043  * - OCS_HAL_PORT_SET_LINK_CONFIG - An enum #ocs_hal_linkcfg_e value.
3044  *
3045  * @param cb Callback function to invoke the following operation.
3046  * - OCS_HAL_PORT_INIT/OCS_HAL_PORT_SHUTDOWN - NULL (link events
3047  * are handled by the OCS_HAL_CB_DOMAIN callbacks).
3048  * - OCS_HAL_PORT_SET_LINK_CONFIG - Invoked after linkcfg mailbox command
3049  * completes.
3050  *
3051  * @param arg Callback argument invoked after the command completes.
3052  * - OCS_HAL_PORT_INIT/OCS_HAL_PORT_SHUTDOWN - NULL (link events
3053  * are handled by the OCS_HAL_CB_DOMAIN callbacks).
3054  * - OCS_HAL_PORT_SET_LINK_CONFIG - Invoked after linkcfg mailbox command
3055  * completes.
3056  *
3057  * @return Returns 0 on success, or a non-zero value on failure.
3058  */
3060 ocs_hal_port_control(ocs_hal_t *hal, ocs_hal_port_e ctrl, uintptr_t value, ocs_hal_port_control_cb_t cb, void *arg)
3061 {
3063 
3064  switch (ctrl) {
3065  case OCS_HAL_PORT_INIT:
3066  {
3067  uint8_t *init_link;
3068  uint32_t speed = 0;
3069  uint8_t reset_alpa = 0;
3070 
3071  if (SLI_LINK_MEDIUM_FC == sli_get_medium(&hal->sli)) {
3072  uint8_t *cfg_link;
3073 
3074  cfg_link = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
3075  if (cfg_link == NULL) {
3076  ocs_log_err(hal->os, "no buffer for command\n");
3077  return OCS_HAL_RTN_NO_MEMORY;
3078  }
3079 
3080  sli_cmd_config_link(&hal->sli, cfg_link, SLI4_BMBX_SIZE);
3081  rc = ocs_hal_command(hal, cfg_link, OCS_CMD_NOWAIT, ocs_hal_cb_port_control, NULL);
3082  if (rc) {
3083  ocs_free(hal->os, cfg_link, SLI4_BMBX_SIZE);
3084  break;
3085  }
3086 
3087  speed = hal->config.speed;
3088  reset_alpa = (uint8_t)(value & 0xff);
3089  } else {
3090  speed = FC_LINK_SPEED_10G;
3091  }
3092 
3093  /*
3094  * Bring link up, unless FW version is not supported
3095  */
3096  if (hal->workaround.fw_version_too_low) {
3097  if ((SLI4_IF_TYPE_LANCER_FC_ETH == hal->sli.if_type) ||
3098  (SLI4_IF_TYPE_LANCER_G7 == hal->sli.if_type)) {
3099  ocs_log_err(hal->os, "Cannot bring up link. Please update firmware to %s or later (current version is %s)\n",
3100  OCS_FW_VER_STR(OCS_MIN_FW_VER_LANCER), (char *) sli_get_fw_name(&hal->sli,0));
3101  } else {
3102  ocs_log_err(hal->os, "Cannot bring up link. Please update firmware to %s or later (current version is %s)\n",
3103  OCS_FW_VER_STR(OCS_MIN_FW_VER_SKYHAWK), (char *) sli_get_fw_name(&hal->sli, 0));
3104  }
3105 
3106  return OCS_HAL_RTN_ERROR;
3107  }
3108 
3109  /* Allocate a new buffer for the init_link command */
3110  init_link = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
3111  if (init_link == NULL) {
3112  ocs_log_err(hal->os, "no buffer for command\n");
3113  return OCS_HAL_RTN_NO_MEMORY;
3114  }
3115 
3116  rc = OCS_HAL_RTN_ERROR;
3117  if (sli_cmd_init_link(&hal->sli, init_link, SLI4_BMBX_SIZE, speed, reset_alpa)) {
3118  rc = ocs_hal_command(hal, init_link, OCS_CMD_NOWAIT, ocs_hal_cb_port_control, NULL);
3119  }
3120 
3121  /* Free buffer on error, since no callback is coming */
3122  if (rc) {
3123  ocs_free(hal->os, init_link, SLI4_BMBX_SIZE);
3124  ocs_log_err(hal->os, "INIT_LINK failed\n");
3125  }
3126 
3127  break;
3128  }
3129  case OCS_HAL_PORT_SHUTDOWN:
3130  {
3131  uint8_t *down_link;
3132 
3133  down_link = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
3134  if (down_link == NULL) {
3135  ocs_log_err(hal->os, "no buffer for command\n");
3136  return OCS_HAL_RTN_NO_MEMORY;
3137  }
3138 
3139  sli_cmd_down_link(&hal->sli, down_link, SLI4_BMBX_SIZE);
3140  rc = ocs_hal_command(hal, down_link, OCS_CMD_NOWAIT, ocs_hal_cb_port_control, NULL);
3141  /* Free buffer on error, since no callback is coming */
3142  if (rc)
3143  ocs_free(hal->os, down_link, SLI4_BMBX_SIZE);
3144 
3145  break;
3146  }
3148  rc = ocs_hal_set_linkcfg(hal, (ocs_hal_linkcfg_e)value, OCS_CMD_NOWAIT, cb, arg);
3149  break;
3150  default:
3151  ocs_log_test(hal->os, "unhandled control %#x\n", ctrl);
3152  break;
3153  }
3154 
3155  return rc;
3156 }
3157 
3158 
3159 /**
3160  * @ingroup port
3161  * @brief Free port resources.
3162  *
3163  * @par Description
3164  * Issue the UNREG_VPI command to free the assigned VPI context.
3165  *
3166  * @param hal Hardware context.
3167  * @param sport SLI port object used to connect to the domain.
3168  *
3169  * @return Returns 0 on success, or a non-zero value on failure.
3170  */
3172 ocs_hal_port_free(ocs_hal_t *hal, ocs_sli_port_t *sport)
3173 {
3175 
3176  if (!hal || !sport) {
3177  ocs_log_err(hal ? hal->os : NULL,
3178  "bad parameter(s) hal=%p sport=%p\n", hal,
3179  sport);
3180  return OCS_HAL_RTN_ERROR;
3181  }
3182 
3183  /*
3184  * Check if the chip is in an error state (UE'd) before proceeding.
3185  */
3186  if (sli_fw_error_status(&hal->sli) > 0) {
3187  ocs_log_crit(hal->os, "Chip is in an error state - reset needed\n");
3188  return OCS_HAL_RTN_ERROR;
3189  }
3190 
3191  ocs_sm_post_event(&sport->ctx, OCS_EVT_HAL_PORT_REQ_FREE, NULL);
3192  return rc;
3193 }
3194 
3195 /**
3196  * @ingroup domain
3197  * @brief Allocate a fabric domain object.
3198  *
3199  * @par Description
3200  * This function starts a series of commands needed to connect to the domain, including
3201  * - REG_FCFI
3202  * - INIT_VFI
3203  * - READ_SPARMS
3204  * .
3205  * @b Note: Not all SLI interface types use all of the above commands.
3206  * @n @n Upon successful allocation, the HAL generates a OCS_HAL_DOMAIN_ALLOC_OK
3207  * event. On failure, it generates a OCS_HAL_DOMAIN_ALLOC_FAIL event.
3208  *
3209  * @param hal Hardware context.
3210  * @param domain Pointer to the domain object.
3211  * @param fcf FCF index.
3212  * @param vlan VLAN ID.
3213  *
3214  * @return Returns 0 on success, or a non-zero value on failure.
3215  */
3217 ocs_hal_domain_alloc(ocs_hal_t *hal, ocs_domain_t *domain, uint32_t fcf, uint32_t vlan)
3218 {
3219  uint8_t *cmd = NULL;
3220  uint32_t index;
3221 
3222  if (!hal || !domain || !domain->sport) {
3223  ocs_log_err(NULL, "bad parameter(s) hal=%p domain=%p sport=%p\n",
3224  hal, domain, domain ? domain->sport : NULL);
3225  return OCS_HAL_RTN_ERROR;
3226  }
3227 
3228  /*
3229  * Check if the chip is in an error state (UE'd) before proceeding.
3230  */
3231  if (sli_fw_error_status(&hal->sli) > 0) {
3232  ocs_log_crit(hal->os, "Chip is in an error state - reset needed\n");
3233  return OCS_HAL_RTN_ERROR;
3234  }
3235 
3236  cmd = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
3237  if (!cmd) {
3238  ocs_log_err(hal->os, "command memory allocation failed\n");
3239  return OCS_HAL_RTN_NO_MEMORY;
3240  }
3241 
3242  // allocate memory for the service parameters
3243  if (ocs_dma_alloc(hal->os, &domain->dma, 112, 4)) {
3244  ocs_log_err(hal->os, "Failed to allocate DMA memory\n");
3245  ocs_free(hal->os, cmd, SLI4_BMBX_SIZE);
3246  return OCS_HAL_RTN_NO_MEMORY;
3247  }
3248 
3249  domain->hal = hal;
3250  domain->sm.app = domain;
3251  domain->fcf = fcf;
3252  domain->fcf_indicator = UINT32_MAX;
3253  domain->vlan_id = vlan;
3254  domain->indicator = UINT32_MAX;
3255 
3256  if (sli_resource_alloc(&hal->sli, SLI_RSRC_FCOE_VFI, &domain->indicator, &index)) {
3257  ocs_log_err(hal->os, "FCOE_VFI allocation failure\n");
3258 
3259  ocs_free(hal->os, cmd, SLI4_BMBX_SIZE);
3260  ocs_dma_free(hal->os, &domain->dma);
3261 
3262  return OCS_HAL_RTN_ERROR;
3263  }
3264 
3265  ocs_sm_transition(&domain->sm, __ocs_hal_domain_init, cmd);
3266  return OCS_HAL_RTN_SUCCESS;
3267 }
3268 
3269 /**
3270  * @ingroup domain
3271  * @brief Attach a SLI port to a domain.
3272  *
3273  * @param hal Hardware context.
3274  * @param domain Pointer to the domain object.
3275  * @param fc_id Fibre Channel ID to associate with this port.
3276  *
3277  * @return Returns 0 on success, or a non-zero value on failure.
3278  */
3280 ocs_hal_domain_attach(ocs_hal_t *hal, ocs_domain_t *domain, uint32_t fc_id)
3281 {
3282  uint8_t *buf = NULL;
3284 
3285  if (!hal || !domain) {
3286  ocs_log_err(hal ? hal->os : NULL,
3287  "bad parameter(s) hal=%p domain=%p\n",
3288  hal, domain);
3289  return OCS_HAL_RTN_ERROR;
3290  }
3291 
3292  /*
3293  * Check if the chip is in an error state (UE'd) before proceeding.
3294  */
3295  if (sli_fw_error_status(&hal->sli) > 0) {
3296  ocs_log_crit(hal->os, "Chip is in an error state - reset needed\n");
3297  return OCS_HAL_RTN_ERROR;
3298  }
3299 
3300  buf = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
3301  if (!buf) {
3302  ocs_log_err(hal->os, "no buffer for command\n");
3303  return OCS_HAL_RTN_NO_MEMORY;
3304  }
3305 
3306  domain->sport->fc_id = fc_id;
3308  return rc;
3309 }
3310 
3311 /**
3312  * @ingroup domain
3313  * @brief Free a fabric domain object.
3314  *
3315  * @par Description
3316  * Free both the driver and SLI port resources associated with the domain.
3317  *
3318  * @param hal Hardware context.
3319  * @param domain Pointer to the domain object.
3320  *
3321  * @return Returns 0 on success, or a non-zero value on failure.
3322  */
3324 ocs_hal_domain_free(ocs_hal_t *hal, ocs_domain_t *domain)
3325 {
3327 
3328  if (!hal || !domain) {
3329  ocs_log_err(hal ? hal->os : NULL,
3330  "bad parameter(s) hal=%p domain=%p\n",
3331  hal, domain);
3332  return OCS_HAL_RTN_ERROR;
3333  }
3334 
3335  /*
3336  * Check if the chip is in an error state (UE'd) before proceeding.
3337  */
3338  if (sli_fw_error_status(&hal->sli) > 0) {
3339  ocs_log_crit(hal->os, "Chip is in an error state - reset needed\n");
3340  return OCS_HAL_RTN_ERROR;
3341  }
3342 
3343  ocs_sm_post_event(&domain->sm, OCS_EVT_HAL_DOMAIN_REQ_FREE, NULL);
3344  return rc;
3345 }
3346 
3347 /**
3348  * @ingroup domain
3349  * @brief Free a fabric domain object.
3350  *
3351  * @par Description
3352  * Free the driver resources associated with the domain. The difference between
3353  * this call and ocs_hal_domain_free() is that this call assumes resources no longer
3354  * exist on the SLI port, due to a reset or after some error conditions.
3355  *
3356  * @param hal Hardware context.
3357  * @param domain Pointer to the domain object.
3358  *
3359  * @return Returns 0 on success, or a non-zero value on failure.
3360  */
3362 ocs_hal_domain_force_free(ocs_hal_t *hal, ocs_domain_t *domain)
3363 {
3364  if (!hal || !domain) {
3365  ocs_log_err(NULL, "bad parameter(s) hal=%p domain=%p\n", hal, domain);
3366  return OCS_HAL_RTN_ERROR;
3367  }
3368 
3369  ocs_dma_free(hal->os, &domain->dma);
3370  if (sli_resource_free(&hal->sli, SLI_RSRC_FCOE_VFI, domain->indicator)) {
3371  ocs_log_err(hal->os, "FCOE_VFI (%d) free failed\n", domain->indicator);
3372  }
3373 
3374  return OCS_HAL_RTN_SUCCESS;
3375 }
3376 
3377 /**
3378  * @ingroup node
3379  * @brief Allocate a remote node object.
3380  *
3381  * @param hal Hardware context.
3382  * @param rnode Allocated remote node object to initialize.
3383  * @param fc_addr FC address of the remote node.
3384  * @param sport SLI port used to connect to remote node.
3385  *
3386  * @return Returns 0 on success, or a non-zero value on failure.
3387  */
3389 ocs_hal_node_alloc(ocs_hal_t *hal, ocs_remote_node_t *rnode, uint32_t fc_addr,
3390  ocs_sli_port_t *sport)
3391 {
3392  /* Check for invalid indicator */
3393  if (UINT32_MAX != rnode->indicator) {
3394  ocs_log_err(hal->os, "FCOE_RPI allocation failure addr=%#x rpi=%#x\n",
3395  fc_addr, rnode->indicator);
3396  return OCS_HAL_RTN_ERROR;
3397  }
3398 
3399  /*
3400  * Check if the chip is in an error state (UE'd) before proceeding.
3401  */
3402  if (sli_fw_error_status(&hal->sli) > 0) {
3403  ocs_log_crit(hal->os, "Chip is in an error state - reset needed\n");
3404  return OCS_HAL_RTN_ERROR;
3405  }
3406 
3407  // NULL SLI port indicates an unallocated remote node
3408  rnode->sport = NULL;
3409 
3410  if (sli_resource_alloc(&hal->sli, SLI_RSRC_FCOE_RPI, &rnode->indicator, &rnode->index)) {
3411  ocs_log_err(hal->os, "FCOE_RPI allocation failure addr=%#x\n",
3412  fc_addr);
3413  return OCS_HAL_RTN_ERROR;
3414  }
3415 
3416  rnode->fc_id = fc_addr;
3417  rnode->sport = sport;
3418 
3419  return OCS_HAL_RTN_SUCCESS;
3420 }
3421 
3422 /**
3423  * @ingroup node
3424  * @brief Update a remote node object with the remote port's service parameters.
3425  *
3426  * @param hal Hardware context.
3427  * @param rnode Allocated remote node object to initialize.
3428  * @param sparms DMA buffer containing the remote port's service parameters.
3429  *
3430  * @return Returns 0 on success, or a non-zero value on failure.
3431  */
3433 ocs_hal_node_attach(ocs_hal_t *hal, ocs_remote_node_t *rnode, ocs_dma_t *sparms)
3434 {
3436  uint8_t *buf = NULL;
3437  uint32_t count = 0;
3438  uint8_t hlm = FALSE;
3439 
3440  if (!hal || !rnode || !sparms) {
3441  ocs_log_err(NULL, "bad parameter(s) hal=%p rnode=%p sparms=%p\n",
3442  hal, rnode, sparms);
3443  return OCS_HAL_RTN_ERROR;
3444  }
3445 
3446  /*
3447  * Check if the chip is in an error state (UE'd) before proceeding.
3448  */
3449  if (sli_fw_error_status(&hal->sli) > 0) {
3450  ocs_log_crit(hal->os, "Chip is in an error state - reset needed\n");
3451  return OCS_HAL_RTN_ERROR;
3452  }
3453 
3454  buf = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
3455  if (!buf) {
3456  ocs_log_err(hal->os, "no buffer for command\n");
3457  return OCS_HAL_RTN_NO_MEMORY;
3458  }
3459 
3460  /*
3461  * If the attach count is non-zero, this RPI has already been registered.
3462  * Otherwise, register the RPI
3463  */
3464  if (rnode->index == UINT32_MAX) {
3465  ocs_log_err(NULL, "bad parameter rnode->index invalid\n");
3466  ocs_free(hal->os, buf, SLI4_BMBX_SIZE);
3467  return OCS_HAL_RTN_ERROR;
3468  }
3469  count = ocs_atomic_add_return(&hal->rpi_ref[rnode->index].rpi_count, 1);
3470  if (count) {
3471  /*
3472  * Can't attach multiple FC_ID's to a node unless High Login
3473  * Mode is enabled
3474  */
3475  if (sli_get_hlm(&hal->sli) == FALSE) {
3476  ocs_log_test(hal->os, "attach to already attached node HLM=%d count=%d\n",
3477  sli_get_hlm(&hal->sli), count);
3478  rc = OCS_HAL_RTN_SUCCESS;
3479  } else {
3480  rnode->node_group = TRUE;
3481  rnode->attached = ocs_atomic_read(&hal->rpi_ref[rnode->index].rpi_attached);
3482  rc = rnode->attached ? OCS_HAL_RTN_SUCCESS_SYNC : OCS_HAL_RTN_SUCCESS;
3483  }
3484  } else {
3485  rnode->node_group = FALSE;
3486  hlm = sli_get_hlm(&hal->sli);
3487 
3488  ocs_display_sparams("", "reg rpi", 0, NULL, sparms->virt);
3489  sli_cmd_reg_rpi(&hal->sli, buf, SLI4_BMBX_SIZE, rnode->fc_id,
3490  rnode->indicator, rnode->sport->indicator, sparms, 0,
3491  (hal->tow_enabled && hal->config.tow_t10_enable), hlm);
3492  rc = ocs_hal_command(hal, buf, OCS_CMD_NOWAIT, ocs_hal_cb_node_attach, rnode);
3493  }
3494 
3495  if (count || rc) {
3496  if (rc < OCS_HAL_RTN_SUCCESS) {
3497  ocs_atomic_sub_return(&hal->rpi_ref[rnode->index].rpi_count, 1);
3498  ocs_log_err(hal->os, "%s error\n", count ? "HLM" : "REG_RPI");
3499  }
3500  ocs_free(hal->os, buf, SLI4_BMBX_SIZE);
3501  }
3502 
3503  return rc;
3504 }
3505 
3506 /**
3507  * @ingroup node
3508  * @brief Free a remote node resource.
3509  *
3510  * @param hal Hardware context.
3511  * @param rnode Remote node object to free.
3512  *
3513  * @return Returns 0 on success, or a non-zero value on failure.
3514  */
3516 ocs_hal_node_free_resources(ocs_hal_t *hal, ocs_remote_node_t *rnode)
3517 {
3519 
3520  if (!hal || !rnode) {
3521  ocs_log_err(NULL, "bad parameter(s) hal=%p rnode=%p\n",
3522  hal, rnode);
3523  return OCS_HAL_RTN_ERROR;
3524  }
3525 
3526  if (rnode->sport) {
3527  if (!rnode->attached) {
3528  if (rnode->indicator != UINT32_MAX) {
3529  if (ocs_atomic_read(&hal->rpi_ref[rnode->index].rpi_count) > 0)
3530  return rc;
3531 
3532  if (sli_resource_free(&hal->sli, SLI_RSRC_FCOE_RPI, rnode->indicator)) {
3533  ocs_log_err(hal->os, "FCOE_RPI (%d) free failed, addr=%#x\n",
3534  rnode->indicator, rnode->fc_id);
3535  rc = OCS_HAL_RTN_ERROR;
3536  } else {
3537  rnode->node_group = FALSE;
3538  rnode->indicator = UINT32_MAX;
3539  rnode->index = UINT32_MAX;
3540  rnode->free_group = FALSE;
3541  }
3542  }
3543  } else {
3544  ocs_log_err(hal->os, "Error: rnode is still attached\n");
3545  rc = OCS_HAL_RTN_ERROR;
3546  }
3547  }
3548 
3549  return rc;
3550 }
3551 
3552 /**
3553  * @ingroup node
3554  * @brief Free a remote node object.
3555  *
3556  * @param hal Hardware context.
3557  * @param rnode Remote node object to free.
3558  *
3559  * @return Returns 0 on success, or a non-zero value on failure.
3560  */
3562 ocs_hal_node_detach(ocs_hal_t *hal, ocs_remote_node_t *rnode)
3563 {
3564  uint8_t *buf = NULL;
3566  uint32_t index = UINT32_MAX;
3567  uint32_t indicator;
3568  ocs_node_t *node;
3569 
3570  if (!hal || !rnode) {
3571  ocs_log_err(NULL, "bad parameter(s) hal=%p rnode=%p\n", hal, rnode);
3572  return OCS_HAL_RTN_ERROR;
3573  }
3574 
3575  node = (ocs_node_t *)rnode->node;
3576  if (!node) {
3577  ocs_log_err(hal->os, "bad parameter node=%p\n", node);
3578  return OCS_HAL_RTN_ERROR;
3579  }
3580 
3581  /*
3582  * Check if the chip is in an error state (UE'd) before proceeding.
3583  */
3584  if (sli_fw_error_status(&hal->sli) > 0) {
3585  ocs_log_crit(hal->os, "Chip is in an error state - reset needed\n");
3586  return OCS_HAL_RTN_ERROR;
3587  }
3588 
3589  index = rnode->index;
3590 
3591  if (rnode->sport) {
3592  uint32_t count = 0;
3593  uint32_t fc_id;
3594 
3595  if (!rnode->attached)
3596  return OCS_HAL_RTN_SUCCESS_SYNC;
3597 
3598  buf = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
3599  if (!buf) {
3600  ocs_log_err(hal->os, "no buffer for command\n");
3601  return OCS_HAL_RTN_NO_MEMORY;
3602  }
3603 
3604  indicator = rnode->indicator;
3605  count = ocs_atomic_sub_return(&hal->rpi_ref[index].rpi_count, 1);
3606 
3607  if (count <= 1) {
3608  /* There are no other references to this RPI; so unregister it and free the resource */
3609  fc_id = UINT32_MAX;
3610  rnode->node_group = FALSE;
3611  rnode->free_group = TRUE;
3612 
3613  ocs_atomic_set(&hal->rpi_ref[index].rpi_attached, 0);
3614  } else {
3615  if (sli_get_hlm(&hal->sli) == FALSE)
3616  ocs_log_err(hal->os, "Invalid count with HLM disabled, count=%d\n", count);
3617 
3618  fc_id = rnode->fc_id & 0x00ffffff;
3619  rnode->free_group = FALSE;
3620 
3621  /*
3622  * In HLM, RPI will be free'd only when the last initiator's unreg_rpi gets completed.
3623  * Mark the other rnode indicators as invalid, except the last rnode's indicator.
3624  */
3625  rnode->indicator = UINT32_MAX;
3626  }
3627 
3628  if (!node->unreg_rpi) {
3629  node->unreg_rpi = TRUE;
3630  rc = OCS_HAL_RTN_ERROR;
3631 
3632  if (sli_cmd_unreg_rpi(&hal->sli, buf, SLI4_BMBX_SIZE, indicator,
3633  SLI_RSRC_FCOE_RPI, fc_id)) {
3634  rc = ocs_hal_command(hal, buf, OCS_CMD_NOWAIT, ocs_hal_cb_node_free, rnode);
3635  }
3636 
3637  if (rc)
3638  ocs_free(hal->os, buf, SLI4_BMBX_SIZE);
3639  } else {
3640  /* We already called unreg_rpi_all, skipping unreg_rpi */
3641  ocs_free(hal->os, buf, SLI4_BMBX_SIZE);
3642  rc = OCS_HAL_RTN_SUCCESS;
3643  }
3644  }
3645 
3646  return rc;
3647 }
3648 
3649 /**
3650  * @ingroup node
3651  * @brief Free all remote node objects.
3652  *
3653  * @param hal Hardware context.
3654  *
3655  * @return Returns 0 on success, or a non-zero value on failure.
3656  */
3658 ocs_hal_unreg_rpi_all(ocs_hal_t *hal, ocs_sport_t *sport)
3659 {
3660  uint8_t *buf = NULL;
3662 
3663  if (!hal) {
3664  ocs_log_err(NULL, "bad parameter hal=%p\n", hal);
3665  return OCS_HAL_RTN_ERROR;
3666  }
3667 
3668  /*
3669  * Check if the chip is in an error state (UE'd) before proceeding.
3670  */
3671  if (sli_fw_error_status(&hal->sli) > 0) {
3672  ocs_log_crit(hal->os, "Chip is in an error state - reset needed\n");
3673  return OCS_HAL_RTN_ERROR;
3674  }
3675 
3676  buf = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
3677  if (!buf) {
3678  ocs_log_err(hal->os, "no buffer for command\n");
3679  return OCS_HAL_RTN_NO_MEMORY;
3680  }
3681 
3682  if (sli_cmd_unreg_rpi(&hal->sli, buf, SLI4_BMBX_SIZE, sport->indicator,
3683  SLI_RSRC_FCOE_VPI, UINT32_MAX)) {
3685  }
3686 
3687  if (rc)
3688  ocs_free(hal->os, buf, SLI4_BMBX_SIZE);
3689 
3690  return rc;
3691 }
3692 
3694 ocs_hal_node_group_alloc(ocs_hal_t *hal, ocs_remote_node_group_t *ngroup)
3695 {
3696 
3697  if (!hal || !ngroup) {
3698  ocs_log_err(NULL, "bad parameter hal=%p ngroup=%p\n",
3699  hal, ngroup);
3700  return OCS_HAL_RTN_ERROR;
3701  }
3702 
3703  if (sli_resource_alloc(&hal->sli, SLI_RSRC_FCOE_RPI, &ngroup->indicator,
3704  &ngroup->index)) {
3705  ocs_log_err(hal->os, "FCOE_RPI allocation failure addr=%#x\n",
3706  ngroup->indicator);
3707  return OCS_HAL_RTN_ERROR;
3708  }
3709 
3710  return OCS_HAL_RTN_SUCCESS;
3711 }
3712 
3714 ocs_hal_node_group_attach(ocs_hal_t *hal, ocs_remote_node_group_t *ngroup, ocs_remote_node_t *rnode)
3715 {
3716  if (!hal || !ngroup || !rnode) {
3717  ocs_log_err(NULL, "bad parameter hal=%p ngroup=%p rnode=%p\n",
3718  hal, ngroup, rnode);
3719  return OCS_HAL_RTN_ERROR;
3720  }
3721 
3722  if (rnode->attached) {
3723  ocs_log_err(hal->os, "node already attached RPI=%#x addr=%#x\n",
3724  rnode->indicator, rnode->fc_id);
3725  return OCS_HAL_RTN_ERROR;
3726  }
3727 
3728  if (rnode->indicator != UINT32_MAX &&
3729  ocs_atomic_read(&hal->rpi_ref[rnode->index].rpi_count) == 0) {
3730  if (sli_resource_free(&hal->sli, SLI_RSRC_FCOE_RPI, rnode->indicator)) {
3731  ocs_log_err(hal->os, "FCOE_RPI (%d) free failed, addr=%#x\n", rnode->indicator, rnode->fc_id);
3732  return OCS_HAL_RTN_ERROR;
3733  }
3734  }
3735 
3736  rnode->indicator = ngroup->indicator;
3737  rnode->index = ngroup->index;
3738 
3739  return OCS_HAL_RTN_SUCCESS;
3740 }
3741 
3743 ocs_hal_node_group_free(ocs_hal_t *hal, ocs_remote_node_group_t *ngroup)
3744 {
3745  if (!hal || !ngroup) {
3746  ocs_log_err(NULL, "bad parameter hal=%p ngroup=%p\n",
3747  hal, ngroup);
3748  return OCS_HAL_RTN_ERROR;
3749  }
3750 
3751  ocs_assert(ocs_atomic_read(&hal->rpi_ref[ngroup->index].rpi_count) == 0, -1);
3752 
3753  if (sli_resource_free(&hal->sli, SLI_RSRC_FCOE_RPI, ngroup->indicator)) {
3754  ocs_log_err(hal->os, "FCOE_RPI (%d) free failed\n", ngroup->indicator);
3755  return OCS_HAL_RTN_ERROR;
3756  }
3757 
3758  ngroup->indicator = UINT32_MAX;
3759  ngroup->index = UINT32_MAX;
3760 
3761  return OCS_HAL_RTN_SUCCESS;
3762 }
3763 
3764 /**
3765  * @brief Initialize IO fields on each free call.
3766  *
3767  * @n @b Note: This is done on each free call (as opposed to each
3768  * alloc call) because port-owned XRIs are not
3769  * allocated with ocs_hal_io_alloc() but are freed with this
3770  * function.
3771  *
3772  * @param io Pointer to HAL IO.
3773  */
3774 static inline void
3775 ocs_hal_init_free_io(ocs_hal_io_t *io)
3776 {
3777  /*
3778  * Set io->done to NULL, to avoid any callbacks, should
3779  * a completion be received for one of these IOs
3780  */
3781  io->done = NULL;
3782  io->abort_done = NULL;
3783  io->status_saved = 0;
3784  io->abort_in_progress = FALSE;
3785  io->port_owned_abort_count = 0;
3786  io->rnode = NULL;
3787  io->type = 0xFFFF;
3788  io->wq = NULL;
3789  io->ul_io = NULL;
3790  io->tgt_wqe_timeout = 0;
3791 }
3792 
3793 /**
3794  * @ingroup io
3795  * @brief Lockless allocate a HAL IO object.
3796  *
3797  * @par Description
3798  * Assume that hal->ocs_lock is held. This function is only used if
3799  * use_dif_sec_xri workaround is being used.
3800  *
3801  * @param hal Hardware context.
3802  *
3803  * @return Returns a pointer to an object on success, or NULL on failure.
3804  */
3805 static inline ocs_hal_io_t *
3806 _ocs_hal_io_alloc(ocs_hal_t *hal)
3807 {
3808  ocs_hal_io_t *io = NULL;
3809 
3810  if (NULL != (io = ocs_list_remove_head(&hal->io_free))) {
3811  ocs_list_add_tail(&hal->io_inuse, io);
3812  io->state = OCS_HAL_IO_STATE_INUSE;
3813  io->quarantine = FALSE;
3814  io->quarantine_first_phase = TRUE;
3815  io->abort_reqtag = UINT32_MAX;
3816  io->saved_status = 0;
3817  io->saved_len = 0;
3818  io->saved_ext = 0;
3819  ocs_ref_init(&io->ref, ocs_hal_io_free_internal, io);
3820  } else {
3821  ocs_atomic_add_return(&hal->io_alloc_failed_count, 1);
3822  }
3823 
3824  return io;
3825 }
3826 /**
3827  * @ingroup io
3828  * @brief Allocate a HAL IO object.
3829  *
3830  * @par Description
3831  * @n @b Note: This function applies to non-port owned XRIs
3832  * only.
3833  *
3834  * @param hal Hardware context.
3835  *
3836  * @return Returns a pointer to an object on success, or NULL on failure.
3837  */
3838 ocs_hal_io_t *
3839 ocs_hal_io_alloc(ocs_hal_t *hal)
3840 {
3841  ocs_hal_io_t *io = NULL;
3842 
3843  ocs_lock(&hal->io_lock);
3844  io = _ocs_hal_io_alloc(hal);
3845  ocs_unlock(&hal->io_lock);
3846 
3847  return io;
3848 }
3849 
3850 /**
3851  * @ingroup io
3852  * @brief Allocate/Activate a port owned HAL IO object.
3853  *
3854  * @par Description
3855  * This function is called by the transport layer when an XRI is
3856  * allocated by the SLI-Port. This will "activate" the HAL IO
3857  * associated with the XRI received from the SLI-Port to mirror
3858  * the state of the XRI.
3859  * @n @n @b Note: This function applies to port owned XRIs only.
3860  *
3861  * @param hal Hardware context.
3862  * @param io Pointer HAL IO to activate/allocate.
3863  *
3864  * @return Returns a pointer to an object on success, or NULL on failure.
3865  */
3866 ocs_hal_io_t *
3867 ocs_hal_io_activate_port_owned(ocs_hal_t *hal, ocs_hal_io_t *io)
3868 {
3869  if (ocs_ref_read_count(&io->ref) > 0) {
3870  ocs_log_err(hal->os, "Bad parameter: refcount > 0\n");
3871  return NULL;
3872  }
3873 
3874  if (io->wq != NULL) {
3875  ocs_log_err(hal->os, "xri=%#x already in use\n", io->indicator);
3876  return NULL;
3877  }
3878 
3879  ocs_ref_init(&io->ref, ocs_hal_io_free_port_owned, io);
3880  io->xbusy = TRUE;
3881 
3882  return io;
3883 }
3884 
3885 /**
3886  * @ingroup io
3887  * @brief When an IO is freed, depending on the exchange busy flag, and other
3888  * workarounds, move it to the correct list.
3889  *
3890  * @par Description
3891  * @n @b Note: Assumes that the hal->io_lock is held and the item has been removed
3892  * from the busy or wait_free list.
3893  *
3894  * @param hal Hardware context.
3895  * @param io Pointer to the IO object to move.
3896  */
3897 static void
3898 ocs_hal_io_free_move_correct_list(ocs_hal_t *hal, ocs_hal_io_t *io)
3899 {
3900  if (io->xbusy) {
3901  /* add to wait_free list and wait for XRI_ABORTED CQEs to clean up */
3902  ocs_list_add_tail(&hal->io_wait_free, io);
3903  io->state = OCS_HAL_IO_STATE_WAIT_FREE;
3904  } else {
3905  /* IO not busy, add to free list */
3906  ocs_list_add_tail(&hal->io_free, io);
3907  io->state = OCS_HAL_IO_STATE_FREE;
3908  }
3909 
3910  /* BZ 161832 workaround */
3911  if (hal->workaround.use_dif_sec_xri) {
3913  }
3914 }
3915 
3916 /**
3917  * @ingroup io
3918  * @brief Free a HAL IO object. Perform cleanup common to
3919  * port and host-owned IOs.
3920  *
3921  * @param hal Hardware context.
3922  * @param io Pointer to the HAL IO object.
3923  */
3924 static inline void
3925 ocs_hal_io_free_common(ocs_hal_t *hal, ocs_hal_io_t *io)
3926 {
3927  /* initialize IO fields */
3929 
3930  /* Restore default SGL */
3931  ocs_hal_io_restore_sgl(hal, io);
3932 }
3933 
3934 /**
3935  * @ingroup io
3936  * @brief Free a HAL IO object associated with a port-owned XRI.
3937  *
3938  * @param arg Pointer to the HAL IO object.
3939  */
3940 static void
3942 {
3943  ocs_hal_io_t *io = (ocs_hal_io_t *)arg;
3944  ocs_hal_t *hal = io->hal;
3945 
3946  /*
3947  * If the dnrx bit is set, then add it to the list of XRIs
3948  * waiting for buffers.
3949  */
3950  if (io->tow_dnrx) {
3951  ocs_lock(&hal->io_lock);
3952  /* take a reference count because we still own the IO until the buffer is posted */
3953  ocs_ref_init(&io->ref, ocs_hal_io_free_port_owned, io);
3954  ocs_list_add_tail(&hal->io_port_dnrx, io);
3955  ocs_unlock(&hal->io_lock);
3956  }
3957 
3958  /* perform common cleanup */
3959  ocs_hal_io_free_common(hal, io);
3960 }
3961 
3962 /**
3963  * @ingroup io
3964  * @brief Free a previously-allocated HAL IO object. Called when
3965  * IO refcount goes to zero (host-owned IOs only).
3966  *
3967  * @param arg Pointer to the HAL IO object.
3968  */
3969 static void
3971 {
3972  ocs_hal_io_t *io = (ocs_hal_io_t *)arg;
3973  ocs_hal_t *hal = io->hal;
3974 
3975  /* perform common cleanup */
3976  ocs_hal_io_free_common(hal, io);
3977 
3978  ocs_lock(&hal->io_lock);
3979  /* remove from in-use list */
3980  if (ocs_list_on_list(&io->link) && !ocs_list_empty(&hal->io_inuse)) {
3981  ocs_list_remove(&hal->io_inuse, io);
3983  }
3984  ocs_unlock(&hal->io_lock);
3985 }
3986 
3987 /**
3988  * @ingroup io
3989  * @brief Free a previously-allocated HAL IO object.
3990  *
3991  * @par Description
3992  * @n @b Note: This function applies to port and host owned XRIs.
3993  *
3994  * @param hal Hardware context.
3995  * @param io Pointer to the HAL IO object.
3996  *
3997  * @return Returns a non-zero value if HAL IO was freed, 0 if references
3998  * on the IO still exist, or a negative value if an error occurred.
3999  */
4000 int32_t
4001 ocs_hal_io_free(ocs_hal_t *hal, ocs_hal_io_t *io)
4002 {
4003  /* just put refcount */
4004  if (ocs_ref_read_count(&io->ref) <= 0) {
4005  ocs_log_err(hal->os, "Bad parameter: refcount <= 0 io=%p xri=%#x tag=%#x\n",
4006  io, io->indicator, io->reqtag);
4007  ocs_hal_assert(0);
4008  return -1;
4009  }
4010 
4011  return ocs_ref_put(&io->ref); /* ocs_ref_get(): ocs_hal_io_alloc() */
4012 }
4013 
4014 /**
4015  * @ingroup io
4016  * @brief Check if given HAL IO is in-use
4017  *
4018  * @par Description
4019  * This function returns TRUE if the given HAL IO has been
4020  * allocated and is in-use, and FALSE otherwise. It applies to
4021  * port and host owned XRIs.
4022  *
4023  * @param hal Hardware context.
4024  * @param io Pointer to the HAL IO object.
4025  *
4026  * @return TRUE if an IO is in use, or FALSE otherwise.
4027  */
4028 uint8_t
4029 ocs_hal_io_inuse(ocs_hal_t *hal, ocs_hal_io_t *io)
4030 {
4031  return (ocs_ref_read_count(&io->ref) > 0);
4032 }
4033 
4034 /**
4035  * @brief Write a HAL IO to a work queue.
4036  *
4037  * @par Description
4038  * A HAL IO is written to a work queue.
4039  *
4040  * @param wq Pointer to work queue.
4041  * @param wqe Pointer to WQ entry.
4042  *
4043  * @n @b Note: Assumes the SLI-4 queue lock is held.
4044  *
4045  * @return Returns 0 on success, or a negative error code value on failure.
4046  */
4047 static int32_t
4048 _hal_wq_write(hal_wq_t *wq, ocs_hal_wqe_t *wqe)
4049 {
4050  int32_t rc;
4051  int32_t queue_rc;
4052 
4053  /* Every so often, set the wqec bit to generate comsummed completions */
4054  if (wq->wqec_count) {
4055  wq->wqec_count--;
4056  }
4057  if (wq->wqec_count == 0) {
4058  sli4_generic_wqe_t *genwqe = (void*)wqe->wqebuf;
4059  genwqe->wqec = 1;
4060  wq->wqec_count = wq->wqec_set_count;
4061  }
4062 
4063  /* Decrement WQ free count */
4064  wq->free_count--;
4065 
4066  queue_rc = _sli_queue_write(&wq->hal->sli, wq->queue, wqe->wqebuf);
4067 
4068  if (queue_rc < 0) {
4069  rc = -1;
4070  } else {
4071  rc = 0;
4072  ocs_queue_history_wq(&wq->hal->q_hist, (void *) wqe->wqebuf, wq->queue->id, queue_rc);
4073  }
4074 
4075  return rc;
4076 }
4077 
4078 /**
4079  * @brief Write a HAL IO to a work queue.
4080  *
4081  * @par Description
4082  * A HAL IO is written to a work queue.
4083  *
4084  * @param wq Pointer to work queue.
4085  * @param wqe Pointer to WQE entry.
4086  *
4087  * @n @b Note: Takes the SLI-4 queue lock.
4088  *
4089  * @return Returns 0 on success, or a negative error code value on failure.
4090  */
4091 int32_t
4092 hal_wq_write(hal_wq_t *wq, ocs_hal_wqe_t *wqe)
4093 {
4094  int32_t rc = 0;
4095 
4096  sli_queue_lock(wq->queue);
4097  if ( ! ocs_list_empty(&wq->pending_list)) {
4098  ocs_list_add_tail(&wq->pending_list, wqe);
4099  OCS_STAT(wq->wq_pending_count++;)
4100  while ((wq->free_count > 0) && ((wqe = ocs_list_remove_head(&wq->pending_list)) != NULL)) {
4101  rc = _hal_wq_write(wq, wqe);
4102  if (rc < 0) {
4103  break;
4104  }
4105  if (wqe->abort_wqe_submit_needed) {
4106  wqe->abort_wqe_submit_needed = 0;
4107  sli_abort_wqe(&wq->hal->sli, wqe->wqebuf, wq->hal->sli.config.wqe_size, SLI_ABORT_XRI,
4108  wqe->send_abts, wqe->id, 0, wqe->abort_reqtag, SLI4_CQ_DEFAULT );
4109  ocs_list_add_tail(&wq->pending_list, wqe);
4110  OCS_STAT(wq->wq_pending_count++;)
4111  }
4112  }
4113  } else {
4114  if (wq->free_count > 0) {
4115  rc = _hal_wq_write(wq, wqe);
4116  } else {
4117  ocs_list_add_tail(&wq->pending_list, wqe);
4118  OCS_STAT(wq->wq_pending_count++;)
4119  }
4120  }
4121 
4122  sli_queue_unlock(wq->queue);
4123 
4124  return rc;
4125 
4126 }
4127 
4128 /**
4129  * @brief Update free count and submit any pending HAL IOs
4130  *
4131  * @par Description
4132  * The WQ free count is updated, and any pending HAL IOs are submitted that
4133  * will fit in the queue.
4134  *
4135  * @param wq Pointer to work queue.
4136  * @param update_free_count Value added to WQs free count.
4137  *
4138  * @return None.
4139  */
4140 static void
4141 hal_wq_submit_pending(hal_wq_t *wq, uint32_t update_free_count)
4142 {
4143  ocs_hal_wqe_t *wqe;
4144 
4145  sli_queue_lock(wq->queue);
4146 
4147  /* Update free count with value passed in */
4148  wq->free_count += update_free_count;
4149 
4150  while ((wq->free_count > 0) && ((wqe = ocs_list_remove_head(&wq->pending_list)) != NULL)) {
4151  _hal_wq_write(wq, wqe);
4152 
4153  if (wqe->abort_wqe_submit_needed) {
4154  wqe->abort_wqe_submit_needed = 0;
4155  sli_abort_wqe(&wq->hal->sli, wqe->wqebuf, wq->hal->sli.config.wqe_size, SLI_ABORT_XRI,
4156  wqe->send_abts, wqe->id, 0, wqe->abort_reqtag, SLI4_CQ_DEFAULT);
4157  ocs_list_add_tail(&wq->pending_list, wqe);
4158  OCS_STAT(wq->wq_pending_count++;)
4159  }
4160  }
4161 
4162  sli_queue_unlock(wq->queue);
4163 }
4164 
4165 /**
4166  * @brief Check to see if there are any BZ 161832 workaround waiting IOs
4167  *
4168  * @par Description
4169  * Checks hal->sec_hio_wait_list, if an IO is waiting for a HAL IO, then try
4170  * to allocate a secondary HAL io, and dispatch it.
4171  *
4172  * @n @b Note: hal->io_lock MUST be taken when called.
4173  *
4174  * @param hal pointer to HAL object
4175  *
4176  * @return none
4177  */
4178 static void
4180 {
4181  ocs_hal_io_t *io;
4182  ocs_hal_io_t *sec_io;
4183  int rc = 0;
4184 
4185  while (!ocs_list_empty(&hal->sec_hio_wait_list)) {
4186  uint16_t flags;
4187 
4188  sec_io = _ocs_hal_io_alloc(hal);
4189  if (sec_io == NULL) {
4190  break;
4191  }
4192 
4193  io = ocs_list_remove_head(&hal->sec_hio_wait_list);
4194  ocs_list_add_tail(&hal->io_inuse, io);
4195  io->state = OCS_HAL_IO_STATE_INUSE;
4196  io->sec_hio = sec_io;
4197 
4198  /* mark secondary XRI for second and subsequent data phase as quarantine */
4199  if (io->xbusy) {
4200  sec_io->quarantine = TRUE;
4201  }
4202 
4203  flags = io->sec_iparam.fcp_tgt.flags;
4204  if (io->xbusy) {
4205  flags |= SLI4_IO_CONTINUATION;
4206  } else {
4207  flags &= ~SLI4_IO_CONTINUATION;
4208  }
4209 
4210  io->tgt_wqe_timeout = io->sec_iparam.fcp_tgt.timeout;
4211 
4212  /* Complete (continue) TRECV IO */
4213  if (io->xbusy) {
4214  if (sli_fcp_cont_treceive64_wqe(&hal->sli, io->wqe.wqebuf, hal->sli.config.wqe_size, &io->def_sgl,
4215  io->first_data_sge,
4216  io->sec_iparam.fcp_tgt.offset, io->sec_len, io->indicator, io->sec_hio->indicator,
4217  io->reqtag, SLI4_CQ_DEFAULT,
4218  io->sec_iparam.fcp_tgt.ox_id, io->rnode->indicator, io->rnode,
4219  flags,
4220  io->sec_iparam.fcp_tgt.dif_oper, io->sec_iparam.fcp_tgt.blk_size, io->sec_iparam.fcp_tgt.cs_ctl,
4221  io->sec_iparam.fcp_tgt.app_id, io->sec_iparam.fcp_tgt.wqe_timer)) {
4222  ocs_log_test(hal->os, "TRECEIVE WQE error\n");
4223  break;
4224  }
4225  } else {
4226  if (sli_fcp_treceive64_wqe(&hal->sli, io->wqe.wqebuf, hal->sli.config.wqe_size, &io->def_sgl,
4227  io->first_data_sge,
4228  io->sec_iparam.fcp_tgt.offset, io->sec_len, io->indicator,
4229  io->reqtag, SLI4_CQ_DEFAULT,
4230  io->sec_iparam.fcp_tgt.ox_id, io->rnode->indicator, io->rnode,
4231  flags,
4232  io->sec_iparam.fcp_tgt.dif_oper, io->sec_iparam.fcp_tgt.blk_size,
4233  io->sec_iparam.fcp_tgt.cs_ctl, io->sec_iparam.fcp_tgt.app_id, io->sec_iparam.fcp_tgt.wqe_timer)) {
4234  ocs_log_test(hal->os, "TRECEIVE WQE error\n");
4235  break;
4236  }
4237  }
4238 
4239  if (io->wq == NULL) {
4240  io->wq = ocs_hal_queue_next_wq(hal, io);
4241  ocs_hal_assert(io->wq != NULL);
4242  }
4243  io->xbusy = TRUE;
4244 
4245  /*
4246  * Add IO to active io wqe list before submitting, in case the
4247  * wcqe processing preempts this thread.
4248  */
4249  ocs_hal_add_io_timed_wqe(hal, io);
4250  rc = hal_wq_write(io->wq, &io->wqe);
4251  if (rc >= 0) {
4252  /* non-negative return is success */
4253  rc = 0;
4254  } else {
4255  /* failed to write wqe, remove from active wqe list */
4256  ocs_log_err(hal->os, "sli_queue_write failed: %d\n", rc);
4257  io->xbusy = FALSE;
4258  ocs_hal_remove_io_timed_wqe(hal, io);
4259  }
4260  }
4261 }
4262 
4263 /**
4264  * @ingroup io
4265  * @brief Send a Single Request/Response Sequence (SRRS).
4266  *
4267  * @par Description
4268  * This routine supports communication sequences consisting of a single
4269  * request and single response between two endpoints. Examples include:
4270  * - Sending an ELS request.
4271  * - Sending an ELS response - To send an ELS reponse, the caller must provide
4272  * the OX_ID from the received request.
4273  * - Sending a FC Common Transport (FC-CT) request - To send a FC-CT request,
4274  * the caller must provide the R_CTL, TYPE, and DF_CTL
4275  * values to place in the FC frame header.
4276  * .
4277  * @n @b Note: The caller is expected to provide both send and receive
4278  * buffers for requests. In the case of sending a response, no receive buffer
4279  * is necessary and the caller may pass in a NULL pointer.
4280  *
4281  * @param hal Hardware context.
4282  * @param type Type of sequence (ELS request/response, FC-CT).
4283  * @param io Previously-allocated HAL IO object.
4284  * @param send DMA memory holding data to send (for example, ELS request, BLS response).
4285  * @param len Length, in bytes, of data to send.
4286  * @param receive Optional DMA memory to hold a response.
4287  * @param rnode Destination of data (that is, a remote node).
4288  * @param iparam IO parameters (ELS response and FC-CT).
4289  * @param cb Function call upon completion of sending the data (may be NULL).
4290  * @param arg Argument to pass to IO completion function.
4291  *
4292  * @return Returns 0 on success, or a non-zero on failure.
4293  */
4295 ocs_hal_srrs_send(ocs_hal_t *hal, ocs_hal_io_type_e type, ocs_hal_io_t *io,
4296  ocs_dma_t *send, uint32_t len, ocs_dma_t *receive,
4297  ocs_remote_node_t *rnode, ocs_hal_io_param_t *iparam,
4298  ocs_hal_srrs_cb_t cb, void *arg)
4299 {
4300  sli4_sge_t *sge = NULL;
4302  uint16_t local_flags = 0;
4303 
4304  if (!hal || !io || !rnode || !iparam) {
4305  ocs_log_err(NULL, "bad parm hal=%p io=%p send=%p receive=%p rnode=%p iparam=%p\n",
4306  hal, io, send, receive, rnode, iparam);
4307  return OCS_HAL_RTN_ERROR;
4308  }
4309 
4310  if (hal->state != OCS_HAL_STATE_ACTIVE) {
4311  ocs_log_test(hal->os, "cannot send SRRS, HAL state=%d\n", hal->state);
4312  return OCS_HAL_RTN_ERROR;
4313  }
4314 
4315  if (ocs_hal_is_xri_port_owned(hal, io->indicator)) {
4316  /* We must set the XC bit for port owned XRIs */
4317  local_flags |= SLI4_IO_CONTINUATION;
4318  }
4319  io->rnode = rnode;
4320  io->type = type;
4321  io->done = cb;
4322  io->arg = arg;
4323 
4324  sge = io->sgl->virt;
4325 
4326  // clear both SGE
4327  ocs_memset(io->sgl->virt, 0, 2 * sizeof(sli4_sge_t));
4328 
4329  if (send) {
4330  sge[0].buffer_address_high = ocs_addr32_hi(send->phys);
4331  sge[0].buffer_address_low = ocs_addr32_lo(send->phys);
4332  sge[0].sge_type = SLI4_SGE_TYPE_DATA;
4333  sge[0].buffer_length = len;
4334  }
4335 
4336  if ((OCS_HAL_ELS_REQ == type) || (OCS_HAL_FC_CT == type)) {
4337  sge[1].buffer_address_high = ocs_addr32_hi(receive->phys);
4338  sge[1].buffer_address_low = ocs_addr32_lo(receive->phys);
4339  sge[1].sge_type = SLI4_SGE_TYPE_DATA;
4340  sge[1].buffer_length = receive->size;
4341  sge[1].last = TRUE;
4342  } else {
4343  sge[0].last = TRUE;
4344  }
4345 
4346  switch (type) {
4347  case OCS_HAL_ELS_REQ:
4348  if ( (!send) || sli_els_request64_wqe(&hal->sli, io->wqe.wqebuf, hal->sli.config.wqe_size, io->sgl,
4349  *((uint8_t *)(send->virt)), /* req_type */
4350  len, receive->size,
4351  iparam->els.timeout, io->indicator, io->reqtag, SLI4_CQ_DEFAULT, rnode)) {
4352  ocs_log_err(hal->os, "REQ WQE error\n");
4353  rc = OCS_HAL_RTN_ERROR;
4354  }
4355  break;
4356  case OCS_HAL_ELS_RSP:
4357  if ( (!send) || sli_xmit_els_rsp64_wqe(&hal->sli, io->wqe.wqebuf, hal->sli.config.wqe_size, send, len,
4358  io->indicator, io->reqtag, SLI4_CQ_DEFAULT,
4359  iparam->els.ox_id,
4360  rnode, local_flags, UINT32_MAX)) {
4361  ocs_log_err(hal->os, "RSP WQE error\n");
4362  rc = OCS_HAL_RTN_ERROR;
4363  }
4364  break;
4365  case OCS_HAL_ELS_RSP_SID:
4366  if ( (!send) || sli_xmit_els_rsp64_wqe(&hal->sli, io->wqe.wqebuf, hal->sli.config.wqe_size, send, len,
4367  io->indicator, io->reqtag, SLI4_CQ_DEFAULT,
4368  iparam->els_sid.ox_id,
4369  rnode, local_flags, iparam->els_sid.s_id)) {
4370  ocs_log_err(hal->os, "RSP (SID) WQE error\n");
4371  rc = OCS_HAL_RTN_ERROR;
4372  }
4373  break;
4374  case OCS_HAL_FC_CT:
4375  if ( (!send) || sli_gen_request64_wqe(&hal->sli, io->wqe.wqebuf, hal->sli.config.wqe_size, io->sgl, len,
4376  receive->size, iparam->fc_ct.timeout, io->indicator,
4377  io->reqtag, SLI4_CQ_DEFAULT, rnode, iparam->fc_ct.r_ctl,
4378  iparam->fc_ct.type, iparam->fc_ct.df_ctl)) {
4379  ocs_log_err(hal->os, "GEN WQE error\n");
4380  rc = OCS_HAL_RTN_ERROR;
4381  }
4382  break;
4383  case OCS_HAL_FC_CT_RSP:
4384  if ( (!send) || sli_xmit_sequence64_wqe(&hal->sli, io->wqe.wqebuf, hal->sli.config.wqe_size, io->sgl, len,
4385  iparam->fc_ct_rsp.timeout, iparam->fc_ct_rsp.ox_id, io->indicator,
4386  io->reqtag, rnode, iparam->fc_ct_rsp.r_ctl,
4387  iparam->fc_ct_rsp.type, iparam->fc_ct_rsp.df_ctl)) {
4388  ocs_log_err(hal->os, "XMIT SEQ WQE error\n");
4389  rc = OCS_HAL_RTN_ERROR;
4390  }
4391  break;
4392  case OCS_HAL_BLS_ACC:
4393  case OCS_HAL_BLS_RJT:
4394  {
4395  sli_bls_payload_t bls;
4396 
4397  if (OCS_HAL_BLS_ACC == type) {
4398  bls.type = SLI_BLS_ACC;
4399  ocs_memcpy(&bls.u.acc, iparam->bls.payload, sizeof(bls.u.acc));
4400  } else {
4401  bls.type = SLI_BLS_RJT;
4402  ocs_memcpy(&bls.u.rjt, iparam->bls.payload, sizeof(bls.u.rjt));
4403  }
4404 
4405  bls.ox_id = iparam->bls.ox_id;
4406  bls.rx_id = iparam->bls.rx_id;
4407 
4408  if (sli_xmit_bls_rsp64_wqe(&hal->sli, io->wqe.wqebuf, hal->sli.config.wqe_size, &bls,
4409  io->indicator, io->reqtag,
4411  rnode, UINT32_MAX)) {
4412  ocs_log_err(hal->os, "XMIT_BLS_RSP64 WQE error\n");
4413  rc = OCS_HAL_RTN_ERROR;
4414  }
4415  break;
4416  }
4417  case OCS_HAL_BLS_ACC_SID:
4418  {
4419  sli_bls_payload_t bls;
4420 
4421  bls.type = SLI_BLS_ACC;
4422  ocs_memcpy(&bls.u.acc, iparam->bls_sid.payload, sizeof(bls.u.acc));
4423 
4424  bls.ox_id = iparam->bls_sid.ox_id;
4425  bls.rx_id = iparam->bls_sid.rx_id;
4426 
4427  if (sli_xmit_bls_rsp64_wqe(&hal->sli, io->wqe.wqebuf, hal->sli.config.wqe_size, &bls,
4428  io->indicator, io->reqtag,
4430  rnode, iparam->bls_sid.s_id)) {
4431  ocs_log_err(hal->os, "XMIT_BLS_RSP64 WQE SID error\n");
4432  rc = OCS_HAL_RTN_ERROR;
4433  }
4434  break;
4435  }
4436  case OCS_HAL_BCAST:
4437  if ( (!send) || sli_xmit_bcast64_wqe(&hal->sli, io->wqe.wqebuf, hal->sli.config.wqe_size, send, len,
4438  iparam->bcast.timeout, io->indicator, io->reqtag,
4439  SLI4_CQ_DEFAULT, rnode,
4440  iparam->bcast.r_ctl, iparam->bcast.type, iparam->bcast.df_ctl)) {
4441  ocs_log_err(hal->os, "XMIT_BCAST64 WQE error\n");
4442  rc = OCS_HAL_RTN_ERROR;
4443  }
4444  break;
4445  default:
4446  ocs_log_err(hal->os, "bad SRRS type %#x\n", type);
4447  rc = OCS_HAL_RTN_ERROR;
4448  }
4449 
4450  if (OCS_HAL_RTN_SUCCESS == rc) {
4451  if (io->wq == NULL) {
4452  io->wq = ocs_hal_queue_next_wq(hal, io);
4453  ocs_hal_assert(io->wq != NULL);
4454  }
4455  io->xbusy = TRUE;
4456 
4457  /*
4458  * Add IO to active io wqe list before submitting, in case the
4459  * wcqe processing preempts this thread.
4460  */
4461  OCS_STAT(io->wq->use_count++);
4462  ocs_hal_add_io_timed_wqe(hal, io);
4463  rc = hal_wq_write(io->wq, &io->wqe);
4464  if (rc >= 0) {
4465  /* non-negative return is success */
4466  rc = 0;
4467  } else {
4468  /* failed to write wqe, remove from active wqe list */
4469  ocs_log_err(hal->os, "sli_queue_write failed: %d\n", rc);
4470  io->xbusy = FALSE;
4471  ocs_hal_remove_io_timed_wqe(hal, io);
4472  }
4473  }
4474 
4475  return rc;
4476 }
4477 
4478 /**
4479  * @ingroup io
4480  * @brief Send a read, write, or response IO.
4481  *
4482  * @par Description
4483  * This routine supports sending a higher-level IO (for example, FCP) between two endpoints
4484  * as a target or initiator. Examples include:
4485  * - Sending read data and good response (target).
4486  * - Sending a response (target with no data or after receiving write data).
4487  * .
4488  * This routine assumes all IOs use the SGL associated with the HAL IO. Prior to
4489  * calling this routine, the data should be loaded using ocs_hal_io_add_sge().
4490  *
4491  * @param hal Hardware context.
4492  * @param type Type of IO (target read, target response, and so on).
4493  * @param io Previously-allocated HAL IO object.
4494  * @param len Length, in bytes, of data to send.
4495  * @param iparam IO parameters.
4496  * @param rnode Destination of data (that is, a remote node).
4497  * @param cb Function call upon completion of sending data (may be NULL).
4498  * @param arg Argument to pass to IO completion function.
4499  *
4500  * @return Returns 0 on success, or a non-zero value on failure.
4501  *
4502  * @todo
4503  * - Support specifiying relative offset.
4504  * - Use a WQ other than 0.
4505  */
4507 ocs_hal_io_send(ocs_hal_t *hal, ocs_hal_io_type_e type, ocs_hal_io_t *io,
4508  uint32_t len, ocs_hal_io_param_t *iparam, ocs_remote_node_t *rnode,
4509  void *cb, void *arg)
4510 {
4512  uint32_t rpi;
4513  uint8_t send_wqe = TRUE;
4514 
4515  CPUTRACE("");
4516 
4517  if (!hal || !io || !rnode || !iparam) {
4518  ocs_log_err(NULL, "bad parm hal=%p io=%p iparam=%p rnode=%p\n",
4519  hal, io, iparam, rnode);
4520  return OCS_HAL_RTN_ERROR;
4521  }
4522 
4523  if (hal->state != OCS_HAL_STATE_ACTIVE) {
4524  ocs_log_err(hal->os, "cannot send IO, HAL state=%d\n", hal->state);
4525  return OCS_HAL_RTN_ERROR;
4526  }
4527 
4528  rpi = rnode->indicator;
4529 
4530  if (hal->workaround.use_unregistered_rpi && (rpi == UINT32_MAX)) {
4531  rpi = hal->workaround.unregistered_rid;
4532  ocs_log_test(hal->os, "using unregistered RPI: %d\n", rpi);
4533  }
4534 
4535  /*
4536  * Save state needed during later stages
4537  */
4538  io->rnode = rnode;
4539  io->type = type;
4540  io->done = cb;
4541  io->arg = arg;
4542 
4543  /*
4544  * Format the work queue entry used to send the IO
4545  */
4546  switch (type) {
4548  /*
4549  * If use_dif_quarantine workaround is in effect, and dif_separates then mark the
4550  * initiator read IO for quarantine
4551  */
4552  if (hal->workaround.use_dif_quarantine && (hal->config.dif_mode == OCS_HAL_DIF_MODE_SEPARATE) &&
4554  io->quarantine = TRUE;
4555  }
4556 
4557  ocs_hal_io_ini_sge(hal, io, iparam->fcp_ini.cmnd, iparam->fcp_ini.cmnd_size,
4558  iparam->fcp_ini.rsp);
4559 
4560  if (sli_fcp_iread64_wqe(&hal->sli, io->wqe.wqebuf, hal->sli.config.wqe_size, &io->def_sgl, io->first_data_sge, len,
4561  io->indicator, io->reqtag, SLI4_CQ_DEFAULT, rpi, rnode,
4562  iparam->fcp_ini.dif_oper, iparam->fcp_ini.blk_size,
4563  iparam->fcp_ini.timeout)) {
4564  ocs_log_err(hal->os, "IREAD WQE error\n");
4565  rc = OCS_HAL_RTN_ERROR;
4566  }
4567  break;
4569  ocs_hal_io_ini_sge(hal, io, iparam->fcp_ini.cmnd, iparam->fcp_ini.cmnd_size,
4570  iparam->fcp_ini.rsp);
4571 
4572  if (sli_fcp_iwrite64_wqe(&hal->sli, io->wqe.wqebuf, hal->sli.config.wqe_size, &io->def_sgl, io->first_data_sge,
4573  len, iparam->fcp_ini.first_burst,
4574  io->indicator, io->reqtag,
4575  SLI4_CQ_DEFAULT, rpi, rnode,
4576  iparam->fcp_ini.dif_oper, iparam->fcp_ini.blk_size,
4577  iparam->fcp_ini.timeout)) {
4578  ocs_log_err(hal->os, "IWRITE WQE error\n");
4579  rc = OCS_HAL_RTN_ERROR;
4580  }
4581  break;
4583  ocs_hal_io_ini_sge(hal, io, iparam->fcp_ini.cmnd, iparam->fcp_ini.cmnd_size,
4584  iparam->fcp_ini.rsp);
4585 
4586  if (sli_fcp_icmnd64_wqe(&hal->sli, io->wqe.wqebuf, hal->sli.config.wqe_size, &io->def_sgl,
4587  io->indicator, io->reqtag, SLI4_CQ_DEFAULT,
4588  rpi, rnode, iparam->fcp_ini.timeout)) {
4589  ocs_log_err(hal->os, "ICMND WQE error\n");
4590  rc = OCS_HAL_RTN_ERROR;
4591  }
4592  break;
4593  case OCS_HAL_IO_TARGET_WRITE: {
4594  uint16_t flags = iparam->fcp_tgt.flags;
4595  fcp_xfer_rdy_iu_t *xfer = io->xfer_rdy.virt;
4596 
4597  /*
4598  * Fill in the XFER_RDY for IF_TYPE 0 devices
4599  */
4600  *((uint32_t *)xfer->fcp_data_ro) = ocs_htobe32(iparam->fcp_tgt.offset);
4601  *((uint32_t *)xfer->fcp_burst_len) = ocs_htobe32(len);
4602  *((uint32_t *)xfer->rsvd) = 0;
4603 
4604  if (io->xbusy) {
4605  flags |= SLI4_IO_CONTINUATION;
4606  } else {
4607  flags &= ~SLI4_IO_CONTINUATION;
4608  }
4609 
4610  io->tgt_wqe_timeout = iparam->fcp_tgt.timeout;
4611 
4612  /*
4613  * If use_dif_quarantine workaround is in effect, and this is a DIF enabled IO
4614  * then mark the target write IO for quarantine
4615  */
4616  if (hal->workaround.use_dif_quarantine && (hal->config.dif_mode == OCS_HAL_DIF_MODE_SEPARATE) &&
4618  io->quarantine = TRUE;
4619  }
4620 
4621  /*
4622  * BZ 161832 Workaround:
4623  * Check for use_dif_sec_xri workaround. Note, even though the first dataphase
4624  * doesn't really need a secondary XRI, we allocate one anyway, as this avoids the
4625  * potential for deadlock where all XRI's are allocated as primaries to IOs that
4626  * are on hal->sec_hio_wait_list. If this secondary XRI is not for the first
4627  * data phase, it is marked for quarantine.
4628  */
4629  if (hal->workaround.use_dif_sec_xri && (iparam->fcp_tgt.dif_oper != OCS_HAL_DIF_OPER_DISABLED)) {
4630 
4631  /*
4632  * If we have allocated a chained SGL for skyhawk, then
4633  * we can re-use this for the sec_hio.
4634  */
4635  if (io->ovfl_io != NULL) {
4636  io->sec_hio = io->ovfl_io;
4637  io->sec_hio->quarantine = TRUE;
4638  } else {
4639  io->sec_hio = ocs_hal_io_alloc(hal);
4640  }
4641  if (io->sec_hio == NULL) {
4642  /* Failed to allocate, so save full request context and put
4643  * this IO on the wait list
4644  */
4645  io->sec_iparam = *iparam;
4646  io->sec_len = len;
4647  ocs_lock(&hal->io_lock);
4648  ocs_list_remove(&hal->io_inuse, io);
4649  ocs_list_add_tail(&hal->sec_hio_wait_list, io);
4650  io->state = OCS_HAL_IO_STATE_WAIT_SEC_HIO;
4651  hal->sec_hio_wait_count++;
4652  ocs_unlock(&hal->io_lock);
4653  send_wqe = FALSE;
4654  /* Done */
4655  break;
4656  }
4657  /* We quarantine the secondary IO if this is the second or subsequent data phase */
4658  if (io->xbusy) {
4659  io->sec_hio->quarantine = TRUE;
4660  }
4661  }
4662 
4663  /*
4664  * If not the first data phase, and io->sec_hio has been allocated, then issue
4665  * FCP_CONT_TRECEIVE64 WQE, otherwise use the usual FCP_TRECEIVE64 WQE
4666  */
4667  if (io->xbusy && (io->sec_hio != NULL)) {
4668  if (sli_fcp_cont_treceive64_wqe(&hal->sli, io->wqe.wqebuf, hal->sli.config.wqe_size, &io->def_sgl, io->first_data_sge,
4669  iparam->fcp_tgt.offset, len, io->indicator, io->sec_hio->indicator,
4670  io->reqtag, SLI4_CQ_DEFAULT,
4671  iparam->fcp_tgt.ox_id, rpi, rnode,
4672  flags,
4673  iparam->fcp_tgt.dif_oper, iparam->fcp_tgt.blk_size,
4674  iparam->fcp_tgt.cs_ctl, iparam->fcp_tgt.app_id, iparam->fcp_tgt.wqe_timer)) {
4675  ocs_log_err(hal->os, "TRECEIVE WQE error\n");
4676  rc = OCS_HAL_RTN_ERROR;
4677  }
4678  } else {
4679  if (sli_fcp_treceive64_wqe(&hal->sli, io->wqe.wqebuf, hal->sli.config.wqe_size, &io->def_sgl, io->first_data_sge,
4680  iparam->fcp_tgt.offset, len, io->indicator, io->reqtag,
4682  iparam->fcp_tgt.ox_id, rpi, rnode,
4683  flags,
4684  iparam->fcp_tgt.dif_oper, iparam->fcp_tgt.blk_size,
4685  iparam->fcp_tgt.cs_ctl, iparam->fcp_tgt.app_id, iparam->fcp_tgt.wqe_timer)) {
4686  ocs_log_err(hal->os, "TRECEIVE WQE error\n");
4687  rc = OCS_HAL_RTN_ERROR;
4688  }
4689  }
4690  break;
4691  }
4692  case OCS_HAL_IO_TARGET_READ: {
4693  uint16_t flags = iparam->fcp_tgt.flags;
4694  uint32_t suppress_rsp = false;
4695 
4696  if (io->xbusy) {
4697  flags |= SLI4_IO_CONTINUATION;
4698  } else {
4699  flags &= ~SLI4_IO_CONTINUATION;
4700  }
4701 
4702  /*
4703  * Suppress the response when following conditions are met.
4704  * 1. HAL suppress resp is capable
4705  * 2. Remote node is negotiated for suppress resp.
4706  * 3. Auto response is enabled.
4707  */
4708  ocs_hal_get(hal, OCS_HAL_SUPPRESS_RSP_CAPABLE, &suppress_rsp);
4709  if ((flags & SLI4_IO_AUTO_GOOD_RESPONSE) &&
4710  suppress_rsp && ocs_node_suppress_resp(rnode)) {
4711  flags |= SLI4_IO_SUPPRESS_RESPONSE;
4712  }
4713 
4714  io->tgt_wqe_timeout = iparam->fcp_tgt.timeout;
4715  if (sli_fcp_tsend64_wqe(&hal->sli, io->wqe.wqebuf, hal->sli.config.wqe_size, &io->def_sgl, io->first_data_sge,
4716  iparam->fcp_tgt.offset, len, io->indicator, io->reqtag,
4718  iparam->fcp_tgt.ox_id, rpi, rnode,
4719  flags,
4720  iparam->fcp_tgt.dif_oper,
4721  iparam->fcp_tgt.blk_size,
4722  iparam->fcp_tgt.cs_ctl,
4723  iparam->fcp_tgt.app_id)) {
4724  ocs_log_err(hal->os, "TSEND WQE error\n");
4725  rc = OCS_HAL_RTN_ERROR;
4726  } else if (hal->workaround.retain_tsend_io_length) {
4727  io->length = len;
4728  }
4729  break;
4730  }
4731  case OCS_HAL_IO_TARGET_RSP: {
4732  uint16_t flags = iparam->fcp_tgt.flags;
4733 
4734  if (io->xbusy) {
4735  flags |= SLI4_IO_CONTINUATION;
4736  } else {
4737  flags &= ~SLI4_IO_CONTINUATION;
4738  }
4739 
4740  /* Attach buffer for port_owned XRI */
4741  if (hal->tow_enabled && io->is_port_owned) {
4742  if ((io->tow_dnrx = ocs_hal_rqpair_tow_xri_buffer_attach(hal, io, TRUE))) {
4743  flags |= SLI4_IO_DNRX;
4744  }
4745  }
4746 
4747  io->tgt_wqe_timeout = iparam->fcp_tgt.timeout;
4748  if (sli_fcp_trsp64_wqe(&hal->sli, io->wqe.wqebuf, hal->sli.config.wqe_size,
4749  &io->def_sgl,
4750  len,
4751  io->indicator, io->reqtag,
4753  iparam->fcp_tgt.ox_id,
4754  rpi, rnode,
4755  flags, iparam->fcp_tgt.cs_ctl,
4756  io->is_port_owned,
4757  iparam->fcp_tgt.app_id)) {
4758  ocs_log_err(hal->os, "TRSP WQE error\n");
4759  rc = OCS_HAL_RTN_ERROR;
4760  }
4761 
4762  break;
4763  }
4764  default:
4765  ocs_log_err(hal->os, "unsupported IO type %#x\n", type);
4766  rc = OCS_HAL_RTN_ERROR;
4767  }
4768 
4769  if (send_wqe && (OCS_HAL_RTN_SUCCESS == rc)) {
4770  if (io->wq == NULL) {
4771  io->wq = ocs_hal_queue_next_wq(hal, io);
4772  ocs_hal_assert(io->wq != NULL);
4773  }
4774 
4775  io->xbusy = TRUE;
4776 
4777  /*
4778  * Add IO to active io wqe list before submitting, in case the
4779  * wcqe processing preempts this thread.
4780  */
4781  OCS_STAT(hal->tcmd_wq_submit[io->wq->instance]++);
4782  OCS_STAT(io->wq->use_count++);
4783  ocs_hal_add_io_timed_wqe(hal, io);
4784  rc = hal_wq_write(io->wq, &io->wqe);
4785  if (rc >= 0) {
4786  /* non-negative return is success */
4787  rc = 0;
4788  } else {
4789  /* failed to write wqe, remove from active wqe list */
4790  ocs_log_err(hal->os, "sli_queue_write failed: %d\n", rc);
4791  io->xbusy = FALSE;
4792  ocs_hal_remove_io_timed_wqe(hal, io);
4793  }
4794  }
4795 
4796  return rc;
4797 }
4798 
4799 /**
4800  * @brief Send a raw frame
4801  *
4802  * @par Description
4803  * Using the SEND_FRAME_WQE, a frame consisting of header and payload is sent.
4804  *
4805  * @param hal Pointer to HAL object.
4806  * @param hdr Pointer to a little endian formatted FC header.
4807  * @param sof Value to use as the frame SOF.
4808  * @param eof Value to use as the frame EOF.
4809  * @param payload Pointer to payload DMA buffer.
4810  * @param ctx Pointer to caller provided send frame context.
4811  * @param callback Callback function.
4812  * @param arg Callback function argument.
4813  *
4814  * @return Returns 0 on success, or a negative error code value on failure.
4815  */
4817 ocs_hal_send_frame(ocs_hal_t *hal, fc_header_le_t *hdr, uint8_t sof, uint8_t eof, ocs_dma_t *payload,
4818  ocs_hal_send_frame_context_t *ctx, void (*callback)(void *arg, uint8_t *cqe, int32_t status), void *arg)
4819 {
4820  int32_t rc;
4821  ocs_hal_wqe_t *wqe;
4822  uint32_t xri;
4823  hal_wq_t *wq;
4824 
4825  wqe = &ctx->wqe;
4826 
4827  /* populate the callback object */
4828  ctx->hal = hal;
4829 
4830  /* Fetch and populate request tag */
4831  ctx->wqcb = ocs_hal_reqtag_alloc(hal, callback, arg);
4832  if (ctx->wqcb == NULL) {
4833  ocs_log_err(hal->os, "can't allocate request tag\n");
4834  return OCS_HAL_RTN_NO_RESOURCES;
4835  }
4836 
4837  /* Choose a work queue, first look for a class[1] wq, otherwise just use wq[0] */
4838  wq = ocs_varray_iter_next(hal->wq_class_array[1]);
4839  if (wq == NULL) {
4840  wq = hal->hal_wq[0];
4841  }
4842 
4843  /* Set XRI and RX_ID in the header based on which WQ, and which send_frame_io we are using */
4844  xri = wq->send_frame_io->indicator;
4845 
4846  /* Build the send frame WQE */
4847  rc = sli_send_frame_wqe(&hal->sli, wqe->wqebuf, hal->sli.config.wqe_size, sof, eof, (uint32_t*) hdr, payload,
4848  payload->len, OCS_HAL_SEND_FRAME_TIMEOUT, xri, ctx->wqcb->instance_index);
4849  if (rc) {
4850  ocs_log_err(hal->os, "sli_send_frame_wqe failed: %d\n", rc);
4851  return OCS_HAL_RTN_ERROR;
4852  }
4853 
4854  /* Write to WQ */
4855  rc = hal_wq_write(wq, wqe);
4856  if (rc) {
4857  ocs_log_err(hal->os, "hal_wq_write failed: %d\n", rc);
4858  return OCS_HAL_RTN_ERROR;
4859  }
4860 
4861  OCS_STAT(wq->use_count++);
4862 
4863  return OCS_HAL_RTN_SUCCESS;
4864 }
4865 
4867 ocs_hal_io_register_sgl(ocs_hal_t *hal, ocs_hal_io_t *io, ocs_dma_t *sgl, uint32_t sgl_count)
4868 {
4869  if (sli_get_sgl_preregister(&hal->sli)) {
4870  ocs_log_err(hal->os, "can't use temporary SGL with pre-registered SGLs\n");
4871  return OCS_HAL_RTN_ERROR;
4872  }
4873  io->ovfl_sgl = sgl;
4874  io->ovfl_sgl_count = sgl_count;
4875  io->ovfl_io = NULL;
4876 
4877  return OCS_HAL_RTN_SUCCESS;
4878 }
4879 
4880 static void
4881 ocs_hal_io_restore_sgl(ocs_hal_t *hal, ocs_hal_io_t *io)
4882 {
4883  /* Restore the default */
4884  io->sgl = &io->def_sgl;
4885  io->sgl_count = io->def_sgl_count;
4886 
4887  /*
4888  * For skyhawk, we need to free the IO allocated for the chained
4889  * SGL. For all devices, clear the overflow fields on the IO.
4890  *
4891  * Note: For DIF IOs, we may be using the same XRI for the sec_hio and
4892  * the chained SGLs. If so, then we clear the ovfl_io field
4893  * when the sec_hio is freed.
4894  */
4895  if (io->ovfl_io != NULL) {
4896  ocs_hal_io_free(hal, io->ovfl_io);
4897  io->ovfl_io = NULL;
4898  }
4899 
4900  /* Clear the overflow SGL */
4901  io->ovfl_sgl = NULL;
4902  io->ovfl_sgl_count = 0;
4903  io->ovfl_lsp = NULL;
4904 }
4905 
4906 /**
4907  * @ingroup io
4908  * @brief Initialize the scatter gather list entries of an IO.
4909  *
4910  * @param hal Hardware context.
4911  * @param io Previously-allocated HAL IO object.
4912  * @param type Type of IO (target read, target response, and so on).
4913  *
4914  * @return Returns 0 on success, or a non-zero value on failure.
4915  */
4917 ocs_hal_io_init_sges(ocs_hal_t *hal, ocs_hal_io_t *io, ocs_hal_io_type_e type)
4918 {
4919  sli4_sge_t *data = NULL;
4920  uint32_t i = 0;
4921  uint32_t skips = 0;
4922 
4923  if (!hal || !io) {
4924  ocs_log_err(hal ? hal->os : NULL, "bad parameter hal=%p io=%p\n",
4925  hal, io);
4926  return OCS_HAL_RTN_ERROR;
4927  }
4928 
4929  // Clear / reset the scatter-gather list
4930  io->sgl = &io->def_sgl;
4931  io->sgl_count = io->def_sgl_count;
4932  io->first_data_sge = 0;
4933 
4934  ocs_memset(io->sgl->virt, 0, 2 * sizeof(sli4_sge_t));
4935  io->n_sge = 0;
4936  io->sge_offset = 0;
4937 
4938  io->type = type;
4939 
4940  data = io->sgl->virt;
4941 
4942  /*
4943  * Some IO types have underlying hardware requirements on the order
4944  * of SGEs. Process all special entries here.
4945  */
4946  switch (type) {
4950  /*
4951  * No skips, 2 special for initiator I/Os
4952  * The addresses and length are written later
4953  */
4954  // setup command pointer
4955  data->sge_type = SLI4_SGE_TYPE_DATA;
4956  data++;
4957 
4958  // setup response pointer
4959  data->sge_type = SLI4_SGE_TYPE_DATA;
4960 
4961  if (OCS_HAL_IO_INITIATOR_NODATA == type) {
4962  data->last = TRUE;
4963  }
4964  data++;
4965 
4966  io->n_sge = 2;
4967  break;
4969 #define OCS_TARGET_WRITE_SKIPS 2
4970  skips = OCS_TARGET_WRITE_SKIPS;
4971 
4972  /* populate host resident XFER_RDY buffer */
4973  data->sge_type = SLI4_SGE_TYPE_DATA;
4974  data->buffer_address_high = ocs_addr32_hi(io->xfer_rdy.phys);
4975  data->buffer_address_low = ocs_addr32_lo(io->xfer_rdy.phys);
4976  data->buffer_length = io->xfer_rdy.size;
4977  data++;
4978 
4979  skips--;
4980 
4981  io->n_sge = 1;
4982  break;
4984  /*
4985  * For FCP_TSEND64, the first 2 entries are SKIP SGE's
4986  */
4987 #define OCS_TARGET_READ_SKIPS 2
4988  skips = OCS_TARGET_READ_SKIPS;
4989  break;
4990  case OCS_HAL_IO_TARGET_RSP:
4991  /*
4992  * No skips, etc. for FCP_TRSP64
4993  */
4994  break;
4995  default:
4996  ocs_log_err(hal->os, "unsupported IO type %#x\n", type);
4997  return OCS_HAL_RTN_ERROR;
4998  }
4999 
5000  /*
5001  * Write skip entries
5002  */
5003  for (i = 0; i < skips; i++) {
5004  data->sge_type = SLI4_SGE_TYPE_SKIP;
5005  data++;
5006  }
5007 
5008  io->n_sge += skips;
5009 
5010  /*
5011  * Set last
5012  */
5013  data->last = TRUE;
5014 
5015  return OCS_HAL_RTN_SUCCESS;
5016 }
5017 
5018 /**
5019  * @ingroup io
5020  * @brief Add a T10 PI seed scatter gather list entry.
5021  *
5022  * @param hal Hardware context.
5023  * @param io Previously-allocated HAL IO object.
5024  * @param dif_info Pointer to T10 DIF fields, or NULL if no DIF.
5025  *
5026  * @return Returns 0 on success, or a non-zero value on failure.
5027  */
5029 ocs_hal_io_add_seed_sge(ocs_hal_t *hal, ocs_hal_io_t *io, ocs_hal_dif_info_t *dif_info)
5030 {
5031  sli4_sge_t *data = NULL;
5032  sli4_diseed_sge_t *dif_seed;
5033 
5034  /* If no dif_info, or dif_oper is disabled, then just return success */
5035  if ((dif_info == NULL) || (dif_info->dif_oper == OCS_HAL_DIF_OPER_DISABLED)) {
5036  return OCS_HAL_RTN_SUCCESS;
5037  }
5038 
5039  if (!hal || !io) {
5040  ocs_log_err(hal ? hal->os : NULL, "bad parameter hal=%p io=%p dif_info=%p\n",
5041  hal, io, dif_info);
5042  return OCS_HAL_RTN_ERROR;
5043  }
5044 
5045  data = io->sgl->virt;
5046  data += io->n_sge;
5047 
5048  /* If we are doing T10 DIF add the DIF Seed SGE */
5049  ocs_memset(data, 0, sizeof(sli4_diseed_sge_t));
5050  dif_seed = (sli4_diseed_sge_t *)data;
5051  dif_seed->ref_tag_cmp = dif_info->ref_tag_cmp;
5052  dif_seed->ref_tag_repl = dif_info->ref_tag_repl;
5053  dif_seed->app_tag_repl = dif_info->app_tag_repl;
5054  dif_seed->repl_app_tag = dif_info->repl_app_tag;
5055  if (SLI4_IF_TYPE_LANCER_FC_ETH != hal->sli.if_type) {
5056  dif_seed->atrt = dif_info->disable_app_ref_ffff;
5057  dif_seed->at = dif_info->disable_app_ffff;
5058  }
5059  dif_seed->sge_type = SLI4_SGE_TYPE_DISEED;
5060  /* Workaround for SKH (BZ157233) */
5061  if (((io->type == OCS_HAL_IO_TARGET_WRITE) || (io->type == OCS_HAL_IO_INITIATOR_READ)) &&
5062  (SLI4_IF_TYPE_LANCER_FC_ETH != hal->sli.if_type) && dif_info->dif_separate) {
5063  dif_seed->sge_type = SLI4_SGE_TYPE_SKIP;
5064  }
5065 
5066  dif_seed->app_tag_cmp = dif_info->app_tag_cmp;
5067  dif_seed->dif_blk_size = dif_info->blk_size;
5068  dif_seed->auto_incr_ref_tag = dif_info->auto_incr_ref_tag;
5069  dif_seed->check_app_tag = dif_info->check_app_tag;
5070  dif_seed->check_ref_tag = dif_info->check_ref_tag;
5071  dif_seed->check_crc = dif_info->check_guard;
5072  dif_seed->new_ref_tag = dif_info->repl_ref_tag;
5073 
5074  switch(dif_info->dif_oper) {
5078  break;
5082  break;
5086  break;
5090  break;
5094  break;
5098  break;
5102  break;
5106  break;
5110  break;
5111  default:
5112  ocs_log_err(hal->os, "unsupported DIF operation %#x\n",
5113  dif_info->dif_oper);
5114  return OCS_HAL_RTN_ERROR;
5115  }
5116 
5117  /*
5118  * Set last, clear previous last
5119  */
5120  data->last = TRUE;
5121  if (io->n_sge) {
5122  data[-1].last = FALSE;
5123  }
5124 
5125  io->n_sge++;
5126 
5127  return OCS_HAL_RTN_SUCCESS;
5128 }
5129 
5130 static ocs_hal_rtn_e
5131 ocs_hal_io_overflow_sgl(ocs_hal_t *hal, ocs_hal_io_t *io)
5132 {
5133  sli4_lsp_sge_t *lsp;
5134 
5135  /* fail if we're already pointing to the overflow SGL */
5136  if (io->sgl == io->ovfl_sgl) {
5137  return OCS_HAL_RTN_ERROR;
5138  }
5139 
5140  /*
5141  * For skyhawk, we can use another SGL to extend the SGL list. The
5142  * Chained entry must not be in the first 4 entries.
5143  *
5144  * Note: For DIF enabled IOs, we will use the ovfl_io for the sec_hio.
5145  */
5146  if (sli_get_sgl_preregister(&hal->sli) &&
5147  io->def_sgl_count > 4 &&
5148  io->ovfl_io == NULL &&
5149  ((SLI4_IF_TYPE_BE3_SKH_PF == sli_get_if_type(&hal->sli)) ||
5150  (SLI4_IF_TYPE_BE3_SKH_VF == sli_get_if_type(&hal->sli)))) {
5151  io->ovfl_io = ocs_hal_io_alloc(hal);
5152  if (io->ovfl_io != NULL) {
5153  /*
5154  * Note: We can't call ocs_hal_io_register_sgl() here
5155  * because it checks that SGLs are not pre-registered
5156  * and for shyhawk, preregistered SGLs are required.
5157  */
5158  io->ovfl_sgl = &io->ovfl_io->def_sgl;
5159  io->ovfl_sgl_count = io->ovfl_io->def_sgl_count;
5160  }
5161  }
5162 
5163  /* fail if we don't have an overflow SGL registered */
5164  if (io->ovfl_io == NULL || io->ovfl_sgl == NULL) {
5165  return OCS_HAL_RTN_ERROR;
5166  }
5167 
5168  /*
5169  * Overflow, we need to put a link SGE in the last location of the current SGL, after
5170  * copying the the last SGE to the overflow SGL
5171  */
5172 
5173  ((sli4_sge_t*)io->ovfl_sgl->virt)[0] = ((sli4_sge_t*)io->sgl->virt)[io->n_sge - 1];
5174 
5175  lsp = &((sli4_lsp_sge_t*)io->sgl->virt)[io->n_sge - 1];
5176  ocs_memset(lsp, 0, sizeof(*lsp));
5177 
5178  if ((SLI4_IF_TYPE_BE3_SKH_PF == sli_get_if_type(&hal->sli)) ||
5179  (SLI4_IF_TYPE_BE3_SKH_VF == sli_get_if_type(&hal->sli))) {
5180  sli_skh_chain_sge_build(&hal->sli,
5181  (sli4_sge_t*)lsp,
5182  io->ovfl_io->indicator,
5183  0, /* frag_num */
5184  0); /* offset */
5185  } else {
5186  lsp->buffer_address_high = ocs_addr32_hi(io->ovfl_sgl->phys);
5187  lsp->buffer_address_low = ocs_addr32_lo(io->ovfl_sgl->phys);
5188  lsp->sge_type = SLI4_SGE_TYPE_LSP;
5189  lsp->last = 0;
5190  io->ovfl_lsp = lsp;
5191  io->ovfl_lsp->segment_length = sizeof(sli4_sge_t);
5192  }
5193 
5194  /* Update the current SGL pointer, and n_sgl */
5195  io->sgl = io->ovfl_sgl;
5196  io->sgl_count = io->ovfl_sgl_count;
5197  io->n_sge = 1;
5198 
5199  return OCS_HAL_RTN_SUCCESS;
5200 }
5201 
5202 /**
5203  * @ingroup io
5204  * @brief Add a scatter gather list entry to an IO.
5205  *
5206  * @param hal Hardware context.
5207  * @param io Previously-allocated HAL IO object.
5208  * @param addr Physical address.
5209  * @param length Length of memory pointed to by @c addr.
5210  *
5211  * @return Returns 0 on success, or a non-zero value on failure.
5212  */
5214 ocs_hal_io_add_sge(ocs_hal_t *hal, ocs_hal_io_t *io, uintptr_t addr, uint32_t length)
5215 {
5216  sli4_sge_t *data = NULL;
5217 
5218  if (!hal || !io || !addr || !length) {
5219  ocs_log_err(hal ? hal->os : NULL,
5220  "bad parameter hal=%p io=%p addr=%lx length=%u\n",
5221  hal, io, addr, length);
5222  return OCS_HAL_RTN_ERROR;
5223  }
5224 
5225  if ((length != 0) && (io->n_sge + 1) > io->sgl_count) {
5226  if (ocs_hal_io_overflow_sgl(hal, io) != OCS_HAL_RTN_SUCCESS) {
5227  ocs_log_err(hal->os, "SGL full (%d)\n", io->n_sge);
5228  return OCS_HAL_RTN_ERROR;
5229  }
5230  }
5231 
5232  if (length > sli_get_max_sge(&hal->sli)) {
5233  ocs_log_err(hal->os, "length of SGE %d bigger than allowed %d\n",
5234  length, sli_get_max_sge(&hal->sli));
5235  return OCS_HAL_RTN_ERROR;
5236  }
5237 
5238  data = io->sgl->virt;
5239  data += io->n_sge;
5240 
5241  data->sge_type = SLI4_SGE_TYPE_DATA;
5242  data->buffer_address_high = ocs_addr32_hi(addr);
5243  data->buffer_address_low = ocs_addr32_lo(addr);
5244  data->buffer_length = length;
5245  data->data_offset = io->sge_offset;
5246  /*
5247  * Always assume this is the last entry and mark as such.
5248  * If this is not the first entry unset the "last SGE"
5249  * indication for the previous entry
5250  */
5251  data->last = TRUE;
5252  if (io->n_sge) {
5253  data[-1].last = FALSE;
5254  }
5255 
5256  /* Set first_data_bde if not previously set */
5257  if (io->first_data_sge == 0) {
5258  io->first_data_sge = io->n_sge;
5259  }
5260 
5261  io->sge_offset += length;
5262  io->n_sge++;
5263 
5264  /* Update the linked segment length (only executed after overflow has begun) */
5265  if (io->ovfl_lsp != NULL) {
5266  io->ovfl_lsp->segment_length = io->n_sge * sizeof(sli4_sge_t);
5267  }
5268 
5269  return OCS_HAL_RTN_SUCCESS;
5270 }
5271 
5272 /**
5273  * @ingroup io
5274  * @brief Add a T10 DIF scatter gather list entry to an IO.
5275  *
5276  * @param hal Hardware context.
5277  * @param io Previously-allocated HAL IO object.
5278  * @param addr DIF physical address.
5279  *
5280  * @return Returns 0 on success, or a non-zero value on failure.
5281  */
5283 ocs_hal_io_add_dif_sge(ocs_hal_t *hal, ocs_hal_io_t *io, uintptr_t addr)
5284 {
5285  sli4_dif_sge_t *data = NULL;
5286 
5287  if (!hal || !io || !addr) {
5288  ocs_log_err(hal ? hal->os : NULL,
5289  "bad parameter hal=%p io=%p addr=%lx\n",
5290  hal, io, addr);
5291  return OCS_HAL_RTN_ERROR;
5292  }
5293 
5294  if ((io->n_sge + 1) > hal->config.n_sgl) {
5295  if (ocs_hal_io_overflow_sgl(hal, io) != OCS_HAL_RTN_ERROR) {
5296  ocs_log_err(hal->os, "SGL full (%d)\n", io->n_sge);
5297  return OCS_HAL_RTN_ERROR;
5298  }
5299  }
5300 
5301  data = io->sgl->virt;
5302  data += io->n_sge;
5303 
5304  data->sge_type = SLI4_SGE_TYPE_DIF;
5305  /* Workaround for SKH (BZ157233) */
5306  if (((io->type == OCS_HAL_IO_TARGET_WRITE) || (io->type == OCS_HAL_IO_INITIATOR_READ)) &&
5307  (SLI4_IF_TYPE_LANCER_FC_ETH != hal->sli.if_type)) {
5308  data->sge_type = SLI4_SGE_TYPE_SKIP;
5309  }
5310 
5311  data->buffer_address_high = ocs_addr32_hi(addr);
5312  data->buffer_address_low = ocs_addr32_lo(addr);
5313 
5314  /*
5315  * Always assume this is the last entry and mark as such.
5316  * If this is not the first entry unset the "last SGE"
5317  * indication for the previous entry
5318  */
5319  data->last = TRUE;
5320  if (io->n_sge) {
5321  data[-1].last = FALSE;
5322  }
5323 
5324  io->n_sge++;
5325 
5326  return OCS_HAL_RTN_SUCCESS;
5327 }
5328 
5329 /**
5330  * @ingroup io
5331  * @brief Abort a previously-started IO.
5332  *
5333  * @param hal Hardware context.
5334  * @param io_to_abort The IO to abort.
5335  * @param send_abts Boolean to have the hardware automatically
5336  * generate an ABTS.
5337  * @param cb Function call upon completion of the abort (may be NULL).
5338  * @param arg Argument to pass to abort completion function.
5339  *
5340  * @return Returns 0 on success, or a non-zero value on failure.
5341  */
5343 ocs_hal_io_abort(ocs_hal_t *hal, ocs_hal_io_t *io_to_abort, uint32_t send_abts, void *cb, void *arg)
5344 {
5346  uint32_t id = 0, mask = 0;
5348  hal_wq_callback_t *wqcb;
5349 
5350  if (!hal || !io_to_abort) {
5351  ocs_log_err(hal ? hal->os : NULL,
5352  "bad parameter hal=%p io=%p\n",
5353  hal, io_to_abort);
5354  return OCS_HAL_RTN_ERROR;
5355  }
5356 
5357  if (hal->state != OCS_HAL_STATE_ACTIVE) {
5358  ocs_log_err(hal->os, "cannot send IO abort, HAL state=%d\n",
5359  hal->state);
5360  return OCS_HAL_RTN_ERROR;
5361  }
5362 
5363  /* take a reference on IO being aborted */
5364  if (ocs_ref_get_unless_zero(&io_to_abort->ref) == 0) {
5365  /* command no longer active */
5366  ocs_log_test(hal ? hal->os : NULL,
5367  "io not active xri=0x%x tag=0x%x\n",
5368  io_to_abort->indicator, io_to_abort->reqtag);
5370  }
5371 
5372  /* non-port owned XRI checks */
5373  /* Must have a valid WQ reference */
5374  if (!ocs_hal_is_io_port_owned(hal, io_to_abort) && (io_to_abort->wq == NULL)) {
5375  ocs_log_test(hal->os, "is_port_owned %d io_to_abort xri=0x%x not active on WQ %p\n",
5376  io_to_abort->is_port_owned, io_to_abort->indicator, io_to_abort->wq);
5377  ocs_ref_put(&io_to_abort->ref); /* ocs_ref_get(): same function */
5379  }
5380 
5381  /* Validation checks complete; now check to see if already being aborted */
5382  ocs_lock(&hal->io_abort_lock);
5383  if (io_to_abort->abort_in_progress) {
5384  ocs_unlock(&hal->io_abort_lock);
5385  ocs_ref_put(&io_to_abort->ref); /* ocs_ref_get(): same function */
5386  ocs_log_debug(hal ? hal->os : NULL,
5387  "io already being aborted xri=0x%x tag=0x%x\n",
5388  io_to_abort->indicator, io_to_abort->reqtag);
5390  }
5391 
5392  /*
5393  * This IO is not already being aborted. Set flag so we won't try to
5394  * abort it again. After all, we only have one abort_done callback.
5395  */
5396  io_to_abort->abort_in_progress = 1;
5397  ocs_unlock(&hal->io_abort_lock);
5398 
5399  /*
5400  * If we got here, the possibilities are:
5401  * - host owned xri
5402  * - io_to_abort->wq_index != UINT32_MAX
5403  * - submit ABORT_WQE to same WQ
5404  * - port owned xri:
5405  * - rxri: io_to_abort->wq_index == UINT32_MAX
5406  * - submit ABORT_WQE to any WQ
5407  * - non-rxri
5408  * - io_to_abort->index != UINT32_MAX
5409  * - submit ABORT_WQE to same WQ
5410  * - io_to_abort->index == UINT32_MAX
5411  * - submit ABORT_WQE to any WQ
5412  */
5413  io_to_abort->abort_done = cb;
5414  io_to_abort->abort_arg = arg;
5415 
5416  atype = SLI_ABORT_XRI;
5417  id = io_to_abort->indicator;
5418 
5419  /* Allocate a request tag for the abort portion of this IO */
5420  wqcb = ocs_hal_reqtag_alloc(hal, ocs_hal_wq_process_abort, io_to_abort);
5421  if (wqcb == NULL) {
5422  ocs_log_err(hal->os, "can't allocate request tag\n");
5423  return OCS_HAL_RTN_NO_RESOURCES;
5424  }
5425  io_to_abort->abort_reqtag = wqcb->instance_index;
5426 
5427  /*
5428  * If the wqe is on the pending list, then set this wqe to be
5429  * aborted when the IO's wqe is removed from the list.
5430  */
5431  if (io_to_abort->wq != NULL) {
5432  sli_queue_lock(io_to_abort->wq->queue);
5433  if (ocs_list_on_list(&io_to_abort->wqe.link)) {
5434  io_to_abort->wqe.abort_wqe_submit_needed = 1;
5435  io_to_abort->wqe.send_abts = send_abts;
5436  io_to_abort->wqe.id = id;
5437  io_to_abort->wqe.abort_reqtag = io_to_abort->abort_reqtag;
5438  sli_queue_unlock(io_to_abort->wq->queue);
5439  return 0;
5440  }
5441  sli_queue_unlock(io_to_abort->wq->queue);
5442  }
5443 
5444  if (sli_abort_wqe(&hal->sli, io_to_abort->wqe.wqebuf, hal->sli.config.wqe_size, atype, send_abts, id, mask,
5445  io_to_abort->abort_reqtag, SLI4_CQ_DEFAULT)) {
5446  ocs_log_err(hal->os, "ABORT WQE error\n");
5447  io_to_abort->abort_reqtag = UINT32_MAX;
5448  ocs_hal_reqtag_free(hal, wqcb);
5449  rc = OCS_HAL_RTN_ERROR;
5450  }
5451 
5452  if (OCS_HAL_RTN_SUCCESS == rc) {
5453  if (io_to_abort->wq == NULL) {
5454  io_to_abort->wq = ocs_hal_queue_next_wq(hal, io_to_abort);
5455  ocs_hal_assert(io_to_abort->wq != NULL);
5456  }
5457  /* ABORT_WQE does not actually utilize an XRI on the Port,
5458  * therefore, keep xbusy as-is to track the exchange's state,
5459  * not the ABORT_WQE's state
5460  */
5461  rc = hal_wq_write(io_to_abort->wq, &io_to_abort->wqe);
5462  if (rc > 0) {
5463  /* non-negative return is success */
5464  rc = 0;
5465  /* can't abort an abort so skip adding to timed wqe list */
5466  }
5467  }
5468 
5469  if (OCS_HAL_RTN_SUCCESS != rc) {
5470  ocs_lock(&hal->io_abort_lock);
5471  io_to_abort->abort_in_progress = 0;
5472  ocs_unlock(&hal->io_abort_lock);
5473  ocs_ref_put(&io_to_abort->ref); /* ocs_ref_get(): same function */
5474  }
5475  return rc;
5476 }
5477 
5478 /**
5479  * @ingroup io
5480  * @brief Return the OX_ID/RX_ID of the IO.
5481  *
5482  * @param hal Hardware context.
5483  * @param io HAL IO object.
5484  *
5485  * @return Returns X_ID on success, or -1 on failure.
5486  */
5487 int32_t
5488 ocs_hal_io_get_xid(ocs_hal_t *hal, ocs_hal_io_t *io)
5489 {
5490  if (!hal || !io) {
5491  ocs_log_err(hal ? hal->os : NULL,
5492  "bad parameter hal=%p io=%p\n", hal, io);
5493  return -1;
5494  }
5495 
5496  return io->indicator;
5497 }
5498 
5499 
5500 typedef struct ocs_hal_fw_write_cb_arg {
5502  void *arg;
5504 
5505 typedef struct ocs_hal_sfp_cb_arg {
5507  void *arg;
5508  ocs_dma_t payload;
5510 
5511 typedef struct ocs_hal_temp_cb_arg {
5513  void *arg;
5515 
5516 typedef struct ocs_hal_link_stat_cb_arg {
5518  void *arg;
5520 
5521 typedef struct ocs_hal_host_stat_cb_arg {
5523  void *arg;
5525 
5526 typedef struct ocs_hal_parity_stat_cb_arg {
5528  void *arg;
5530 
5531 typedef struct ocs_hal_dump_get_cb_arg {
5533  void *arg;
5534  void *mbox_cmd;
5536 
5537 typedef struct ocs_hal_dump_clear_cb_arg {
5539  void *arg;
5540  void *mbox_cmd;
5542 
5543 typedef struct ocs_hal_fw_dump_location_results_s {
5544  ocs_sem_t sem;
5545  uint8_t status;
5546  ocs_atomic_t refcnt;
5548 
5549 /**
5550  * @brief Write a portion of a firmware image to the device.
5551  *
5552  * @par Description
5553  * Calls the correct firmware write function based on the device type.
5554  *
5555  * @param hal Hardware context.
5556  * @param dma DMA structure containing the firmware image chunk.
5557  * @param size Size of the firmware image chunk.
5558  * @param offset Offset, in bytes, from the beginning of the firmware image.
5559  * @param last True if this is the last chunk of the image.
5560  * Causes the image to be committed to flash.
5561  * @param cb Pointer to a callback function that is called when the command completes.
5562  * The callback function prototype is
5563  * <tt>void cb(int32_t status, uint32_t bytes_written, void *arg)</tt>.
5564  * @param arg Pointer to be passed to the callback function.
5565  *
5566  * @return Returns 0 on success, or a non-zero value on failure.
5567  */
5569 ocs_hal_firmware_write(ocs_hal_t *hal, ocs_dma_t *dma, uint32_t size, uint32_t offset, int last, ocs_hal_fw_cb_t cb, void *arg)
5570 {
5571  if ((hal->sli.if_type == SLI4_IF_TYPE_LANCER_FC_ETH) ||
5572  (hal->sli.if_type == SLI4_IF_TYPE_LANCER_G7)) {
5573  return ocs_hal_firmware_write_lancer(hal, dma, size, offset, last, cb, arg);
5574  } else {
5575  // TODO: Write firmware_write for BE3/Skyhawk
5576  return -1;
5577  }
5578 }
5579 
5580 /**
5581  * @brief Write a portion of a firmware image to the Emulex XE201 ASIC (Lancer).
5582  *
5583  * @par Description
5584  * Creates a SLI_CONFIG mailbox command, fills it with the correct values to write a
5585  * firmware image chunk, and then sends the command with ocs_hal_command(). On completion,
5586  * the callback function ocs_hal_fw_write_cb() gets called to free the mailbox
5587  * and to signal the caller that the write has completed.
5588  *
5589  * @param hal Hardware context.
5590  * @param dma DMA structure containing the firmware image chunk.
5591  * @param size Size of the firmware image chunk.
5592  * @param offset Offset, in bytes, from the beginning of the firmware image.
5593  * @param last True if this is the last chunk of the image. Causes the image to be committed to flash.
5594  * @param cb Pointer to a callback function that is called when the command completes.
5595  * The callback function prototype is
5596  * <tt>void cb(int32_t status, uint32_t bytes_written, void *arg)</tt>.
5597  * @param arg Pointer to be passed to the callback function.
5598  *
5599  * @return Returns 0 on success, or a non-zero value on failure.
5600  */
5602 ocs_hal_firmware_write_lancer(ocs_hal_t *hal, ocs_dma_t *dma, uint32_t size, uint32_t offset, int last, ocs_hal_fw_cb_t cb, void *arg)
5603 {
5605  uint8_t *mbxdata;
5606  ocs_hal_fw_write_cb_arg_t *cb_arg;
5607  int noc=0; // No Commit bit - set to 1 for testing
5608 
5609  if ((SLI4_IF_TYPE_LANCER_FC_ETH != sli_get_if_type(&hal->sli)) &&
5610  (SLI4_IF_TYPE_LANCER_G7 != sli_get_if_type(&hal->sli))) {
5611  ocs_log_test(hal->os, "Function only supported for I/F type 2/6\n");
5612  return OCS_HAL_RTN_ERROR;
5613  }
5614 
5615  mbxdata = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
5616  if (mbxdata == NULL) {
5617  ocs_log_err(hal->os, "failed to malloc mbox\n");
5618  return OCS_HAL_RTN_NO_MEMORY;
5619  }
5620 
5621  cb_arg = ocs_malloc(hal->os, sizeof(ocs_hal_fw_write_cb_arg_t), OCS_M_NOWAIT);
5622  if (cb_arg == NULL) {
5623  ocs_log_err(hal->os, "failed to malloc cb_arg\n");
5624  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
5625  return OCS_HAL_RTN_NO_MEMORY;
5626  }
5627 
5628  cb_arg->cb = cb;
5629  cb_arg->arg = arg;
5630 
5631  /* Send the HAL command */
5632  sli_cmd_common_write_object(&hal->sli, mbxdata, SLI4_BMBX_SIZE, noc, last, size, offset, "/prg/", dma);
5633  rc = ocs_hal_command(hal, mbxdata, OCS_CMD_NOWAIT, ocs_hal_cb_fw_write, cb_arg);
5634  if (rc) {
5635  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
5636  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
5637  }
5638 
5639  return rc;
5640 }
5641 
5642 /**
5643  * @brief Called when the WRITE OBJECT command completes.
5644  *
5645  * @par Description
5646  * Get the number of bytes actually written out of the response, free the mailbox
5647  * that was malloc'd by ocs_hal_firmware_write(),
5648  * then call the callback and pass the status and bytes written.
5649  *
5650  * @param hal Hardware context.
5651  * @param status Status field from the mbox completion.
5652  * @param mqe Mailbox response structure.
5653  * @param arg Pointer to a callback function that signals the caller that the command is done.
5654  * The callback function prototype is <tt>void cb(int32_t status, uint32_t bytes_written)</tt>.
5655  *
5656  * @return Returns 0.
5657  */
5658 static int32_t
5659 ocs_hal_cb_fw_write(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
5660 {
5661  sli4_cmd_sli_config_t *mbox_rsp = (sli4_cmd_sli_config_t *)mqe;
5663  ocs_hal_fw_write_cb_arg_t *cb_arg = arg;
5664  uint32_t bytes_written;
5665  uint32_t change_status;
5666 
5667  if (wr_obj_rsp->hdr.status)
5668  ocs_hal_log_sli4_rsp_hdr(hal, &wr_obj_rsp->hdr);
5669 
5670  if (!cb_arg || !cb_arg->cb)
5671  goto ocs_hal_cb_fw_write_done;
5672 
5673  bytes_written = wr_obj_rsp->actual_write_length;
5674  change_status = wr_obj_rsp->change_status;
5675 
5676  if (0 == status) {
5677  if (mbox_rsp->hdr.status)
5678  status = mbox_rsp->hdr.status;
5679  else if (wr_obj_rsp->hdr.status)
5680  status = wr_obj_rsp->hdr.status;
5681  }
5682 
5683  cb_arg->cb(status, wr_obj_rsp->hdr.additional_status, bytes_written, change_status, cb_arg->arg);
5684 
5685 ocs_hal_cb_fw_write_done:
5686  if (cb_arg)
5687  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
5688 
5689  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
5690  return 0;
5691 }
5692 
5693 /**
5694  * @brief Called when the READ_TRANSCEIVER_DATA command completes.
5695  *
5696  * @par Description
5697  * Get the number of bytes read out of the response, free the mailbox that was malloc'd
5698  * by ocs_hal_get_sfp(), then call the callback and pass the status and bytes written.
5699  *
5700  * @param hal Hardware context.
5701  * @param status Status field from the mbox completion.
5702  * @param mqe Mailbox response structure.
5703  * @param arg Pointer to a callback function that signals the caller that the command is done.
5704  * The callback function prototype is
5705  * <tt>void cb(int32_t status, uint32_t bytes_written, uint32_t *data, void *arg)</tt>.
5706  *
5707  * @return Returns 0.
5708  */
5709 static int32_t
5710 ocs_hal_cb_sfp(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
5711 {
5712  sli4_cmd_sli_config_t *mbox_rsp = (sli4_cmd_sli_config_t *)mqe;
5713  sli4_res_common_read_transceiver_data_t *sli4_rsp = NULL;
5714  ocs_hal_sfp_cb_arg_t *cb_arg = arg;
5715  ocs_dma_t *payload = NULL;
5716  uint32_t bytes_written;
5717 
5718  if (!cb_arg || !cb_arg->cb)
5719  goto ocs_hal_cb_sfp_done;
5720 
5721  payload = &cb_arg->payload;
5722  sli4_rsp = (sli4_res_common_read_transceiver_data_t *)payload->virt;
5723  if (sli4_rsp->hdr.status)
5724  ocs_hal_log_sli4_rsp_hdr(hal, &sli4_rsp->hdr);
5725 
5726  bytes_written = sli4_rsp->hdr.response_length;
5727 
5728  if (0 == status) {
5729  if (mbox_rsp->hdr.status)
5730  status = mbox_rsp->hdr.status;
5731  else if (sli4_rsp->hdr.status)
5732  status = sli4_rsp->hdr.status;
5733  }
5734 
5735  cb_arg->cb(hal->os, status, bytes_written, sli4_rsp->page_data, cb_arg->arg);
5736 
5737 ocs_hal_cb_sfp_done:
5738  if (cb_arg) {
5739  ocs_dma_free(hal->os, &cb_arg->payload);
5740  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
5741  }
5742 
5743  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
5744  return 0;
5745 }
5746 
5747 /**
5748  * @ingroup io
5749  * @brief Function to retrieve the SFP information.
5750  *
5751  * @param hal Hardware context.
5752  * @param page The page of SFP data to retrieve (0xa0 or 0xa2).
5753  * @param cb Function call upon completion of sending the data (may be NULL).
5754  * @param arg Argument to pass to IO completion function.
5755  *
5756  * @return Returns OCS_HAL_RTN_SUCCESS, OCS_HAL_RTN_ERROR, or OCS_HAL_RTN_NO_MEMORY.
5757  */
5759 ocs_hal_get_sfp(ocs_hal_t *hal, uint16_t page, ocs_hal_sfp_cb_t cb, void *arg)
5760 {
5762  ocs_hal_sfp_cb_arg_t *cb_arg;
5763  uint8_t *mbxdata;
5764 
5765  /* mbxdata holds the header of the command */
5766  mbxdata = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
5767  if (mbxdata == NULL) {
5768  ocs_log_err(hal->os, "failed to malloc mbox\n");
5769  return OCS_HAL_RTN_NO_MEMORY;
5770  }
5771 
5772  /* cb_arg holds the data that will be passed to the callback on completion */
5773  cb_arg = ocs_malloc(hal->os, sizeof(ocs_hal_sfp_cb_arg_t), OCS_M_NOWAIT);
5774  if (cb_arg == NULL) {
5775  ocs_log_err(hal->os, "failed to malloc cb_arg\n");
5776  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
5777  return OCS_HAL_RTN_NO_MEMORY;
5778  }
5779 
5780  cb_arg->cb = cb;
5781  cb_arg->arg = arg;
5782 
5783  /* payload holds the non-embedded portion */
5784  if (ocs_dma_alloc(hal->os, &cb_arg->payload, sizeof(sli4_res_common_read_transceiver_data_t),
5785  OCS_MIN_DMA_ALIGNMENT)) {
5786  ocs_log_err(hal->os, "Failed to allocate DMA buffer\n");
5787  ocs_free(hal->os, cb_arg, sizeof(ocs_hal_sfp_cb_arg_t));
5788  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
5789  return OCS_HAL_RTN_NO_MEMORY;
5790  }
5791 
5792  /* Send the HAL command */
5793  sli_cmd_common_read_transceiver_data(&hal->sli, mbxdata, SLI4_BMBX_SIZE, page, &cb_arg->payload);
5794  rc = ocs_hal_command(hal, mbxdata, OCS_CMD_NOWAIT, ocs_hal_cb_sfp, cb_arg);
5795  if (rc) {
5796  ocs_dma_free(hal->os, &cb_arg->payload);
5797  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
5798  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
5799  }
5800 
5801  return rc;
5802 }
5803 
5804 /**
5805  * @brief Function to retrieve the temperature information.
5806  *
5807  * @param hal Hardware context.
5808  * @param cb Function call upon completion of sending the data (may be NULL).
5809  * @param arg Argument to pass to IO completion function.
5810  *
5811  * @return Returns OCS_HAL_RTN_SUCCESS, OCS_HAL_RTN_ERROR, or OCS_HAL_RTN_NO_MEMORY.
5812  */
5814 ocs_hal_get_temperature(ocs_hal_t *hal, ocs_hal_temp_cb_t cb, void *arg)
5815 {
5817  ocs_hal_temp_cb_arg_t *cb_arg;
5818  uint8_t *mbxdata;
5819 
5820  mbxdata = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
5821  if (mbxdata == NULL) {
5822  ocs_log_err(hal->os, "failed to malloc mbox");
5823  return OCS_HAL_RTN_NO_MEMORY;
5824  }
5825 
5826  cb_arg = ocs_malloc(hal->os, sizeof(ocs_hal_temp_cb_arg_t), OCS_M_NOWAIT);
5827  if (cb_arg == NULL) {
5828  ocs_log_err(hal->os, "failed to malloc cb_arg");
5829  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
5830  return OCS_HAL_RTN_NO_MEMORY;
5831  }
5832 
5833  cb_arg->cb = cb;
5834  cb_arg->arg = arg;
5835 
5836  /* Send the HAL command */
5838  rc = ocs_hal_command(hal, mbxdata, OCS_CMD_NOWAIT, ocs_hal_cb_temp, cb_arg);
5839  if (rc) {
5840  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
5841  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
5842  }
5843 
5844  return rc;
5845 }
5846 
5847 /**
5848  * @brief Called when the DUMP command completes.
5849  *
5850  * @par Description
5851  * Get the temperature data out of the response, free the mailbox that was malloc'd
5852  * by ocs_hal_get_temperature(), then call the callback and pass the status and data.
5853  *
5854  * @param hal Hardware context.
5855  * @param status Status field from the mbox completion.
5856  * @param mqe Mailbox response structure.
5857  * @param arg Pointer to a callback function that signals the caller that the command is done.
5858  * The callback function prototype is defined by ocs_hal_temp_cb_t.
5859  *
5860  * @return Returns 0.
5861  */
5862 static int32_t
5863 ocs_hal_cb_temp(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
5864 {
5865  sli4_cmd_dump4_t *mbox_rsp = (sli4_cmd_dump4_t *)mqe;
5866  ocs_hal_temp_cb_arg_t *cb_arg = arg;
5867  uint32_t curr_temp = mbox_rsp->resp_data[0]; /* word 5 */
5868  uint32_t crit_temp_thrshld = mbox_rsp->resp_data[1]; /* word 6*/
5869  uint32_t warn_temp_thrshld = mbox_rsp->resp_data[2]; /* word 7 */
5870  uint32_t norm_temp_thrshld = mbox_rsp->resp_data[3]; /* word 8 */
5871  uint32_t fan_off_thrshld = mbox_rsp->resp_data[4]; /* word 9 */
5872  uint32_t fan_on_thrshld = mbox_rsp->resp_data[5]; /* word 10 */
5873 
5874  ocs_log_debug(hal->os, "CB status %08x, curr_temp=%d crit_temp_thr=%d "\
5875  "warn_temp_thr %d norm_temp_thr %d foff_thr %d fon_thr %d\n",
5876  status, curr_temp, crit_temp_thrshld, warn_temp_thrshld,
5877  norm_temp_thrshld, fan_off_thrshld, fan_on_thrshld);
5878 
5879  if (!cb_arg || !cb_arg->cb)
5880  goto ocs_hal_cb_temp_done;
5881 
5882  if ((0 == status) && mbox_rsp->hdr.status)
5883  status = mbox_rsp->hdr.status;
5884 
5885  cb_arg->cb(status, curr_temp, crit_temp_thrshld, warn_temp_thrshld,
5886  norm_temp_thrshld, fan_off_thrshld, fan_on_thrshld, cb_arg->arg);
5887 
5888 ocs_hal_cb_temp_done:
5889  if (cb_arg)
5890  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
5891 
5892  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
5893  return 0;
5894 }
5895 
5896 /**
5897  * @brief Function to retrieve the link statistics.
5898  *
5899  * @param hal Hardware context.
5900  * @param req_ext_counters If TRUE, then the extended counters will be requested.
5901  * @param clear_overflow_flags If TRUE, then overflow flags will be cleared.
5902  * @param clear_all_counters If TRUE, the counters will be cleared.
5903  * @param cb Function call upon completion of sending the data (may be NULL).
5904  * @param arg Argument to pass to IO completion function.
5905  *
5906  * @return Returns OCS_HAL_RTN_SUCCESS, OCS_HAL_RTN_ERROR, or OCS_HAL_RTN_NO_MEMORY.
5907  */
5909 ocs_hal_get_link_stats(ocs_hal_t *hal,
5910  uint8_t req_ext_counters,
5911  uint8_t clear_overflow_flags,
5912  uint8_t clear_all_counters,
5914  void *arg)
5915 {
5918  uint8_t *mbxdata;
5919 
5920  mbxdata = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
5921  if (mbxdata == NULL) {
5922  ocs_log_err(hal->os, "failed to malloc mbox");
5923  return OCS_HAL_RTN_NO_MEMORY;
5924  }
5925 
5926  cb_arg = ocs_malloc(hal->os, sizeof(ocs_hal_link_stat_cb_arg_t), OCS_M_NOWAIT);
5927  if (cb_arg == NULL) {
5928  ocs_log_err(hal->os, "failed to malloc cb_arg");
5929  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
5930  return OCS_HAL_RTN_NO_MEMORY;
5931  }
5932 
5933  cb_arg->cb = cb;
5934  cb_arg->arg = arg;
5935 
5936  /* Send the HAL command */
5937  sli_cmd_read_link_stats(&hal->sli, mbxdata, SLI4_BMBX_SIZE, req_ext_counters,
5938  clear_overflow_flags, clear_all_counters);
5939  rc = ocs_hal_command(hal, mbxdata, OCS_CMD_NOWAIT, ocs_hal_cb_link_stat, cb_arg);
5940  if (rc) {
5941  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
5942  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
5943  }
5944 
5945  return rc;
5946 }
5947 
5948 /**
5949  * @brief Called when the READ_LINK_STAT command completes.
5950  *
5951  * @par Description
5952  * Get the counters out of the response, free the mailbox that was malloc'd
5953  * by ocs_hal_get_link_stats(), then call the callback and pass the status and data.
5954  *
5955  * @param hal Hardware context.
5956  * @param status Status field from the mbox completion.
5957  * @param mqe Mailbox response structure.
5958  * @param arg Pointer to a callback function that signals the caller that the command is done.
5959  * The callback function prototype is defined by ocs_hal_link_stat_cb_t.
5960  *
5961  * @return Returns 0.
5962  */
5963 static int32_t
5964 ocs_hal_cb_link_stat(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
5965 {
5967  ocs_hal_link_stat_cb_arg_t *cb_arg = arg;
5969  uint32_t num_counters = (mbox_rsp->gec ? 20 : 13);
5970 
5971  if (!cb_arg || !cb_arg->cb)
5972  goto ocs_hal_cb_link_stat_done;
5973 
5974  ocs_memset(counts, 0, sizeof(ocs_hal_link_stat_counts_t) * OCS_HAL_LINK_STAT_MAX);
5975 
5981  counts[OCS_HAL_LINK_STAT_CRC_COUNT].overflow = mbox_rsp->w07of;
5989  counts[OCS_HAL_LINK_STAT_RCV_EOFA_COUNT].overflow = mbox_rsp->w15of;
5991  counts[OCS_HAL_LINK_STAT_RCV_EOFNI_COUNT].overflow = mbox_rsp->w17of;
5992  counts[OCS_HAL_LINK_STAT_RCV_SOFF_COUNT].overflow = mbox_rsp->w18of;
5996 
6019 
6020  if ((0 == status) && mbox_rsp->hdr.status)
6021  status = mbox_rsp->hdr.status;
6022 
6023  cb_arg->cb(status, num_counters, counts, cb_arg->arg);
6024 
6025 ocs_hal_cb_link_stat_done:
6026  if (cb_arg)
6027  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
6028 
6029  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
6030  return 0;
6031 }
6032 
6033 /**
6034  * @brief Function to retrieve the link and host statistics.
6035  *
6036  * @param hal Hardware context.
6037  * @param cc clear counters, if TRUE all counters will be cleared.
6038  * @param cb Function call upon completion of receiving the data.
6039  * @param arg Argument to pass to pointer fc hosts statistics structure.
6040  *
6041  * @return Returns OCS_HAL_RTN_SUCCESS, OCS_HAL_RTN_ERROR, or OCS_HAL_RTN_NO_MEMORY.
6042  */
6044 ocs_hal_get_host_stats(ocs_hal_t *hal, uint8_t cc, ocs_hal_host_stat_cb_t cb, void *arg)
6045 {
6048  uint8_t *mbxdata;
6049 
6050  mbxdata = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
6051  if (mbxdata == NULL) {
6052  ocs_log_err(hal->os, "failed to malloc mbox");
6053  return OCS_HAL_RTN_NO_MEMORY;
6054  }
6055 
6056  cb_arg = ocs_malloc(hal->os, sizeof(ocs_hal_host_stat_cb_arg_t),
6057  OCS_M_ZERO | OCS_M_NOWAIT);
6058  if (cb_arg == NULL) {
6059  ocs_log_err(hal->os, "failed to malloc cb_arg");
6060  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
6061  return OCS_HAL_RTN_NO_MEMORY;
6062  }
6063 
6064  cb_arg->cb = cb;
6065  cb_arg->arg = arg;
6066 
6067  /* Send the HAL command to get the host stats */
6068  sli_cmd_read_status(&hal->sli, mbxdata, SLI4_BMBX_SIZE, cc);
6069  rc = ocs_hal_command(hal, mbxdata, OCS_CMD_NOWAIT, ocs_hal_cb_host_stat, cb_arg);
6070  if (rc) {
6071  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
6072  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
6073  }
6074 
6075  return rc;
6076 }
6077 
6078 /**
6079  * @brief Called when the READ_STATUS command completes.
6080  *
6081  * @par Description
6082  * Get the counters out of the response, free the mailbox that was malloc'd
6083  * by ocs_hal_get_host_stats(), then call the callback and pass
6084  * the status and data.
6085  *
6086  * @param hal Hardware context.
6087  * @param status Status field from the mbox completion.
6088  * @param mqe Mailbox response structure.
6089  * @param arg Pointer to a callback function that signals the caller that the command is done.
6090  * The callback function prototype is defined by
6091  * ocs_hal_host_stat_cb_t.
6092  *
6093  * @return Returns 0.
6094  */
6095 static int32_t
6096 ocs_hal_cb_host_stat(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
6097 {
6099  ocs_hal_host_stat_cb_arg_t *cb_arg = arg;
6101  uint32_t num_counters = OCS_HAL_HOST_STAT_MAX;
6102 
6103  if (!cb_arg || !cb_arg->cb)
6104  goto ocs_hal_cb_host_stat_done;
6105 
6106  ocs_memset(counts, 0, sizeof(ocs_hal_host_stat_counts_t) * OCS_HAL_HOST_STAT_MAX);
6107 
6122 
6123  if ((0 == status) && mbox_rsp->hdr.status)
6124  status = mbox_rsp->hdr.status;
6125 
6126  cb_arg->cb(status, num_counters, counts, cb_arg->arg);
6127 
6128 ocs_hal_cb_host_stat_done:
6129  if (cb_arg)
6130  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
6131 
6132  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
6133  return 0;
6134 }
6135 
6136 /**
6137  * @brief HAL link configuration enum to the CLP string value mapping.
6138  *
6139  * This structure provides a mapping from the ocs_hal_linkcfg_e
6140  * enum (enum exposed for the OCS_HAL_PORT_SET_LINK_CONFIG port
6141  * control) to the CLP string that is used
6142  * in the DMTF_CLP_CMD mailbox command.
6143  */
6144 typedef struct ocs_hal_linkcfg_map_s {
6146  const char *clp_str;
6148 
6149 /**
6150  * @brief Mapping from the HAL linkcfg enum to the CLP command value
6151  * string.
6152  */
6154  {OCS_HAL_LINKCFG_4X10G, "ELX_4x10G"},
6155  {OCS_HAL_LINKCFG_1X40G, "ELX_1x40G"},
6156  {OCS_HAL_LINKCFG_2X16G, "ELX_2x16G"},
6157  {OCS_HAL_LINKCFG_4X8G, "ELX_4x8G"},
6158  {OCS_HAL_LINKCFG_4X1G, "ELX_4x1G"},
6159  {OCS_HAL_LINKCFG_2X10G, "ELX_2x10G"},
6160  {OCS_HAL_LINKCFG_2X10G_2X8G, "ELX_2x10G_2x8G"}};
6161 
6162 /**
6163  * @brief HAL link configuration enum to Skyhawk link config ID mapping.
6164  *
6165  * This structure provides a mapping from the ocs_hal_linkcfg_e
6166  * enum (enum exposed for the OCS_HAL_PORT_SET_LINK_CONFIG port
6167  * control) to the link config ID numbers used by Skyhawk
6168  */
6169 typedef struct ocs_hal_skyhawk_linkcfg_map_s {
6171  uint32_t config_id;
6173 
6174 /**
6175  * @brief Mapping from the HAL linkcfg enum to the Skyhawk link config IDs
6176  */
6178  {OCS_HAL_LINKCFG_4X10G, 0x0a},
6179  {OCS_HAL_LINKCFG_1X40G, 0x09},
6180 };
6181 
6182 /**
6183  * @brief Helper function for getting the HAL linkcfg enum from the CLP
6184  * string value
6185  *
6186  * @param clp_str CLP string value from OEMELX_LinkConfig.
6187  *
6188  * @return Returns the HAL linkcfg enum corresponding to clp_str.
6189  */
6190 static ocs_hal_linkcfg_e
6191 ocs_hal_linkcfg_from_clp(const char *clp_str)
6192 {
6193  uint32_t i;
6194  for (i = 0; i < ARRAY_SIZE(linkcfg_map); i++) {
6195  if (ocs_strncmp(linkcfg_map[i].clp_str, clp_str, ocs_strlen(clp_str)) == 0) {
6196  return linkcfg_map[i].linkcfg;
6197  }
6198  }
6199  return OCS_HAL_LINKCFG_NA;
6200 }
6201 
6202 /**
6203  * @brief Helper function for getting the CLP string value from the HAL
6204  * linkcfg enum.
6205  *
6206  * @param linkcfg HAL linkcfg enum.
6207  *
6208  * @return Returns the OEMELX_LinkConfig CLP string value corresponding to
6209  * given linkcfg.
6210  */
6211 static const char *
6213 {
6214  uint32_t i;
6215  for (i = 0; i < ARRAY_SIZE(linkcfg_map); i++) {
6216  if (linkcfg_map[i].linkcfg == linkcfg) {
6217  return linkcfg_map[i].clp_str;
6218  }
6219  }
6220  return NULL;
6221 }
6222 
6223 /**
6224  * @brief Helper function for getting a Skyhawk link config ID from the HAL
6225  * linkcfg enum.
6226  *
6227  * @param linkcfg HAL linkcfg enum.
6228  *
6229  * @return Returns the Skyhawk link config ID corresponding to
6230  * given linkcfg.
6231  */
6232 static uint32_t
6234 {
6235  uint32_t i;
6236  for (i = 0; i < ARRAY_SIZE(skyhawk_linkcfg_map); i++) {
6237  if (skyhawk_linkcfg_map[i].linkcfg == linkcfg) {
6238  return skyhawk_linkcfg_map[i].config_id;
6239  }
6240  }
6241  return 0;
6242 }
6243 
6244 /**
6245  * @brief Helper function for getting the HAL linkcfg enum from a
6246  * Skyhawk config ID.
6247  *
6248  * @param config_id Skyhawk link config ID.
6249  *
6250  * @return Returns the HAL linkcfg enum corresponding to config_id.
6251  */
6252 static ocs_hal_linkcfg_e
6253 ocs_hal_linkcfg_from_config_id(const uint32_t config_id)
6254 {
6255  uint32_t i;
6256  for (i = 0; i < ARRAY_SIZE(skyhawk_linkcfg_map); i++) {
6257  if (skyhawk_linkcfg_map[i].config_id == config_id) {
6258  return skyhawk_linkcfg_map[i].linkcfg;
6259  }
6260  }
6261  return OCS_HAL_LINKCFG_NA;
6262 }
6263 
6264 /**
6265  * @brief Link configuration callback argument.
6266  */
6267 typedef struct ocs_hal_linkcfg_cb_arg_s {
6269  void *arg;
6270  uint32_t opts;
6271  int32_t status;
6272  ocs_dma_t dma_cmd;
6273  ocs_dma_t dma_resp;
6274  uint32_t result_len;
6276 
6277 /**
6278  * @brief Set link configuration.
6279  *
6280  * @param hal Hardware context.
6281  * @param value Link configuration enum to which the link configuration is
6282  * set.
6283  * @param opts Mailbox command options (OCS_CMD_NOWAIT/POLL).
6284  * @param cb Callback function to invoke following mbx command.
6285  * @param arg Callback argument.
6286  *
6287  * @return Returns OCS_HAL_RTN_SUCCESS on success.
6288  */
6289 static ocs_hal_rtn_e
6290 ocs_hal_set_linkcfg(ocs_hal_t *hal, ocs_hal_linkcfg_e value, uint32_t opts, ocs_hal_port_control_cb_t cb, void *arg)
6291 {
6292  if (!sli_link_is_configurable(&hal->sli)) {
6293  ocs_log_debug(hal->os, "Function not supported\n");
6294  return OCS_HAL_RTN_ERROR;
6295  }
6296 
6297  if (SLI4_IF_TYPE_LANCER_FC_ETH == sli_get_if_type(&hal->sli)) {
6298  return ocs_hal_set_linkcfg_lancer(hal, value, opts, cb, arg);
6299  } else if ((SLI4_IF_TYPE_BE3_SKH_PF == sli_get_if_type(&hal->sli)) ||
6300  (SLI4_IF_TYPE_BE3_SKH_VF == sli_get_if_type(&hal->sli))) {
6301  return ocs_hal_set_linkcfg_skyhawk(hal, value, opts, cb, arg);
6302  } else {
6303  ocs_log_test(hal->os, "Function not supported for this IF_TYPE\n");
6304  return OCS_HAL_RTN_ERROR;
6305  }
6306 }
6307 
6308 /**
6309  * @brief Set link configuration for Lancer
6310  *
6311  * @param hal Hardware context.
6312  * @param value Link configuration enum to which the link configuration is
6313  * set.
6314  * @param opts Mailbox command options (OCS_CMD_NOWAIT/POLL).
6315  * @param cb Callback function to invoke following mbx command.
6316  * @param arg Callback argument.
6317  *
6318  * @return Returns OCS_HAL_RTN_SUCCESS on success.
6319  */
6320 static ocs_hal_rtn_e
6321 ocs_hal_set_linkcfg_lancer(ocs_hal_t *hal, ocs_hal_linkcfg_e value, uint32_t opts, ocs_hal_port_control_cb_t cb, void *arg)
6322 {
6323  char cmd[OCS_HAL_DMTF_CLP_CMD_MAX];
6324  ocs_hal_linkcfg_cb_arg_t *cb_arg;
6325  const char *value_str = NULL;
6327 
6328  /* translate ocs_hal_linkcfg_e to CLP string */
6329  value_str = ocs_hal_clp_from_linkcfg(value);
6330 
6331  /* allocate memory for callback argument */
6332  cb_arg = ocs_malloc(hal->os, sizeof(*cb_arg), OCS_M_NOWAIT);
6333  if (cb_arg == NULL) {
6334  ocs_log_err(hal->os, "failed to malloc cb_arg");
6335  return OCS_HAL_RTN_NO_MEMORY;
6336  }
6337 
6338  ocs_snprintf(cmd, OCS_HAL_DMTF_CLP_CMD_MAX, "set / OEMELX_LinkConfig=%s", value_str);
6339  /* allocate DMA for command */
6340  if (ocs_dma_alloc(hal->os, &cb_arg->dma_cmd, ocs_strlen(cmd)+1, 4096)) {
6341  ocs_log_err(hal->os, "malloc failed\n");
6342  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
6343  return OCS_HAL_RTN_NO_MEMORY;
6344  }
6345  ocs_memset(cb_arg->dma_cmd.virt, 0, ocs_strlen(cmd)+1);
6346  ocs_memcpy(cb_arg->dma_cmd.virt, cmd, ocs_strlen(cmd));
6347 
6348  /* allocate DMA for response */
6349  if (ocs_dma_alloc(hal->os, &cb_arg->dma_resp, OCS_HAL_DMTF_CLP_RSP_MAX, 4096)) {
6350  ocs_log_err(hal->os, "malloc failed\n");
6351  ocs_dma_free(hal->os, &cb_arg->dma_cmd);
6352  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
6353  return OCS_HAL_RTN_NO_MEMORY;
6354  }
6355  cb_arg->cb = cb;
6356  cb_arg->arg = arg;
6357  cb_arg->opts = opts;
6358 
6359  rc = ocs_hal_exec_dmtf_clp_cmd(hal, &cb_arg->dma_cmd, &cb_arg->dma_resp,
6360  opts, ocs_hal_linkcfg_dmtf_clp_cb, cb_arg);
6361 
6362  if (opts == OCS_CMD_POLL || rc != OCS_HAL_RTN_SUCCESS) {
6363  /* if failed, or polling, free memory here; if success and not
6364  * polling, will free in callback function
6365  */
6366  if (rc) {
6367  ocs_log_test(hal->os, "CLP cmd=\"%s\" failed\n",
6368  (char *)cb_arg->dma_cmd.virt);
6369  }
6370  ocs_dma_free(hal->os, &cb_arg->dma_cmd);
6371  ocs_dma_free(hal->os, &cb_arg->dma_resp);
6372  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
6373  }
6374  return rc;
6375 }
6376 
6377 /**
6378  * @brief Callback for ocs_hal_set_linkcfg_skyhawk
6379  *
6380  * @param hal Hardware context.
6381  * @param status Status from the RECONFIG_GET_LINK_INFO command.
6382  * @param mqe Mailbox response structure.
6383  * @param arg Pointer to a callback argument.
6384  *
6385  * @return none
6386  */
6387 static void
6388 ocs_hal_set_active_link_config_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
6389 {
6390  sli4_cmd_sli_config_t *mbox_rsp = (sli4_cmd_sli_config_t *)mqe;
6391  ocs_hal_linkcfg_cb_arg_t *cb_arg = arg;
6392 
6393  if (!cb_arg || !cb_arg->cb)
6394  goto ocs_hal_set_active_link_config_cb_done;
6395 
6396  if ((0 == status) && mbox_rsp->hdr.status)
6397  status = mbox_rsp->hdr.status;
6398 
6399  cb_arg->cb(status, 0, cb_arg->arg);
6400 
6401 ocs_hal_set_active_link_config_cb_done:
6402  if (cb_arg)
6403  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
6404 
6405  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
6406 }
6407 
6408 /**
6409  * @brief Set link configuration for a Skyhawk
6410  *
6411  * @param hal Hardware context.
6412  * @param value Link configuration enum to which the link configuration is
6413  * set.
6414  * @param opts Mailbox command options (OCS_CMD_NOWAIT/POLL).
6415  * @param cb Callback function to invoke following mbx command.
6416  * @param arg Callback argument.
6417  *
6418  * @return Returns OCS_HAL_RTN_SUCCESS on success.
6419  */
6420 static ocs_hal_rtn_e
6421 ocs_hal_set_linkcfg_skyhawk(ocs_hal_t *hal, ocs_hal_linkcfg_e value, uint32_t opts, ocs_hal_port_control_cb_t cb, void *arg)
6422 {
6423  uint8_t *mbxdata;
6424  ocs_hal_linkcfg_cb_arg_t *cb_arg;
6426  uint32_t config_id;
6427 
6428  config_id = ocs_hal_config_id_from_linkcfg(value);
6429 
6430  if (config_id == 0) {
6431  ocs_log_test(hal->os, "Link config %d not supported by Skyhawk\n", value);
6432  return OCS_HAL_RTN_ERROR;
6433  }
6434 
6435  /* mbxdata holds the header of the command */
6436  mbxdata = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
6437  if (mbxdata == NULL) {
6438  ocs_log_err(hal->os, "failed to malloc mbox\n");
6439  return OCS_HAL_RTN_NO_MEMORY;
6440  }
6441 
6442  /* cb_arg holds the data that will be passed to the callback on completion */
6443  cb_arg = ocs_malloc(hal->os, sizeof(ocs_hal_linkcfg_cb_arg_t), OCS_M_NOWAIT);
6444  if (cb_arg == NULL) {
6445  ocs_log_err(hal->os, "failed to malloc cb_arg\n");
6446  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
6447  return OCS_HAL_RTN_NO_MEMORY;
6448  }
6449 
6450  cb_arg->cb = cb;
6451  cb_arg->arg = arg;
6452 
6453  /* Send the HAL command */
6454  sli_cmd_common_set_reconfig_link_id(&hal->sli, mbxdata, SLI4_BMBX_SIZE, NULL, 0, config_id);
6455  rc = ocs_hal_command(hal, mbxdata, opts, ocs_hal_set_active_link_config_cb, cb_arg);
6456  if (rc) {
6457  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
6458  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
6459  } else if (opts == OCS_CMD_POLL) {
6460  /* If we're polling, call the callback here */
6461  ocs_hal_set_active_link_config_cb(hal, 0, mbxdata, cb_arg);
6462  }
6463 
6464  return rc;
6465 }
6466 
6467 /**
6468  * @brief Get link configuration.
6469  *
6470  * @param hal Hardware context.
6471  * @param opts Mailbox command options (OCS_CMD_NOWAIT/POLL).
6472  * @param cb Callback function to invoke following mbx command.
6473  * @param arg Callback argument.
6474  *
6475  * @return Returns OCS_HAL_RTN_SUCCESS on success.
6476  */
6477 static ocs_hal_rtn_e
6478 ocs_hal_get_linkcfg(ocs_hal_t *hal, uint32_t opts, ocs_hal_port_control_cb_t cb, void *arg)
6479 {
6480  if (!sli_link_is_configurable(&hal->sli)) {
6481  ocs_log_debug(hal->os, "Function not supported\n");
6482  return OCS_HAL_RTN_ERROR;
6483  }
6484 
6485  if ((SLI4_IF_TYPE_LANCER_FC_ETH == sli_get_if_type(&hal->sli)) ||
6486  (SLI4_IF_TYPE_LANCER_G7 == sli_get_if_type(&hal->sli))) {
6487  return ocs_hal_get_linkcfg_lancer(hal, opts, cb, arg);
6488  } else if ((SLI4_IF_TYPE_BE3_SKH_PF == sli_get_if_type(&hal->sli)) ||
6489  (SLI4_IF_TYPE_BE3_SKH_VF == sli_get_if_type(&hal->sli))) {
6490  return ocs_hal_get_linkcfg_skyhawk(hal, opts, cb, arg);
6491  } else {
6492  ocs_log_test(hal->os, "Function not supported for this IF_TYPE\n");
6493  return OCS_HAL_RTN_ERROR;
6494  }
6495 }
6496 
6497 /**
6498  * @brief Get link configuration for a Lancer
6499  *
6500  * @param hal Hardware context.
6501  * @param opts Mailbox command options (OCS_CMD_NOWAIT/POLL).
6502  * @param cb Callback function to invoke following mbx command.
6503  * @param arg Callback argument.
6504  *
6505  * @return Returns OCS_HAL_RTN_SUCCESS on success.
6506  */
6507 static ocs_hal_rtn_e
6508 ocs_hal_get_linkcfg_lancer(ocs_hal_t *hal, uint32_t opts, ocs_hal_port_control_cb_t cb, void *arg)
6509 {
6510  char cmd[OCS_HAL_DMTF_CLP_CMD_MAX];
6511  ocs_hal_linkcfg_cb_arg_t *cb_arg;
6513 
6514  /* allocate memory for callback argument */
6515  cb_arg = ocs_malloc(hal->os, sizeof(*cb_arg), OCS_M_NOWAIT);
6516  if (cb_arg == NULL) {
6517  ocs_log_err(hal->os, "failed to malloc cb_arg");
6518  return OCS_HAL_RTN_NO_MEMORY;
6519  }
6520 
6521  ocs_snprintf(cmd, OCS_HAL_DMTF_CLP_CMD_MAX, "show / OEMELX_LinkConfig");
6522 
6523  /* allocate DMA for command */
6524  if (ocs_dma_alloc(hal->os, &cb_arg->dma_cmd, ocs_strlen(cmd)+1, 4096)) {
6525  ocs_log_err(hal->os, "malloc failed\n");
6526  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
6527  return OCS_HAL_RTN_NO_MEMORY;
6528  }
6529 
6530  /* copy CLP command to DMA command */
6531  ocs_memset(cb_arg->dma_cmd.virt, 0, ocs_strlen(cmd)+1);
6532  ocs_memcpy(cb_arg->dma_cmd.virt, cmd, ocs_strlen(cmd));
6533 
6534  /* allocate DMA for response */
6535  if (ocs_dma_alloc(hal->os, &cb_arg->dma_resp, OCS_HAL_DMTF_CLP_RSP_MAX, 4096)) {
6536  ocs_log_err(hal->os, "malloc failed\n");
6537  ocs_dma_free(hal->os, &cb_arg->dma_cmd);
6538  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
6539  return OCS_HAL_RTN_NO_MEMORY;
6540  }
6541  cb_arg->cb = cb;
6542  cb_arg->arg = arg;
6543  cb_arg->opts = opts;
6544 
6545  rc = ocs_hal_exec_dmtf_clp_cmd(hal, &cb_arg->dma_cmd, &cb_arg->dma_resp,
6546  opts, ocs_hal_linkcfg_dmtf_clp_cb, cb_arg);
6547 
6548  if (opts == OCS_CMD_POLL || rc != OCS_HAL_RTN_SUCCESS) {
6549  /* if failed or polling, free memory here; if not polling and success,
6550  * will free in callback function
6551  */
6552  if (rc) {
6553  ocs_log_test(hal->os, "CLP cmd=\"%s\" failed\n",
6554  (char *)cb_arg->dma_cmd.virt);
6555  }
6556  ocs_dma_free(hal->os, &cb_arg->dma_cmd);
6557  ocs_dma_free(hal->os, &cb_arg->dma_resp);
6558  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
6559  }
6560  return rc;
6561 }
6562 
6563 /**
6564  * @brief Get the link configuration callback.
6565  *
6566  * @param hal Hardware context.
6567  * @param status Status from the RECONFIG_GET_LINK_INFO command.
6568  * @param mqe Mailbox response structure.
6569  * @param arg Pointer to a callback argument.
6570  *
6571  * @return none
6572  */
6573 static void
6574 ocs_hal_get_active_link_config_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
6575 {
6576  sli4_cmd_sli_config_t *mbox_rsp = (sli4_cmd_sli_config_t *)mqe;
6578  ocs_hal_linkcfg_cb_arg_t *cb_arg = arg;
6580 
6581  if (!cb_arg || !cb_arg->cb)
6582  goto ocs_hal_get_active_link_config_cb_done;
6583 
6584  sli4_rsp = (sli4_res_common_get_reconfig_link_info_t *)cb_arg->dma_cmd.virt;
6585  if (sli4_rsp->hdr.status)
6586  ocs_hal_log_sli4_rsp_hdr(hal, &sli4_rsp->hdr);
6587 
6588  if (0 == status) {
6589  if (mbox_rsp->hdr.status)
6590  status = mbox_rsp->hdr.status;
6591  else if (sli4_rsp->hdr.status)
6592  status = sli4_rsp->hdr.status;
6593  }
6594 
6595  if (0 == status)
6597 
6598  cb_arg->cb(status, value, cb_arg->arg);
6599 
6600 ocs_hal_get_active_link_config_cb_done:
6601  if (cb_arg) {
6602  ocs_dma_free(hal->os, &cb_arg->dma_cmd);
6603  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
6604  }
6605 
6606  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
6607 }
6608 
6609 /**
6610  * @brief Get link configuration for a Skyhawk.
6611  *
6612  * @param hal Hardware context.
6613  * @param opts Mailbox command options (OCS_CMD_NOWAIT/POLL).
6614  * @param cb Callback function to invoke following mbx command.
6615  * @param arg Callback argument.
6616  *
6617  * @return Returns OCS_HAL_RTN_SUCCESS on success.
6618  */
6619 static ocs_hal_rtn_e
6620 ocs_hal_get_linkcfg_skyhawk(ocs_hal_t *hal, uint32_t opts, ocs_hal_port_control_cb_t cb, void *arg)
6621 {
6622  uint8_t *mbxdata;
6623  ocs_hal_linkcfg_cb_arg_t *cb_arg;
6625 
6626  /* mbxdata holds the header of the command */
6627  mbxdata = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
6628  if (mbxdata == NULL) {
6629  ocs_log_err(hal->os, "failed to malloc mbox\n");
6630  return OCS_HAL_RTN_NO_MEMORY;
6631  }
6632 
6633  /* cb_arg holds the data that will be passed to the callback on completion */
6634  cb_arg = ocs_malloc(hal->os, sizeof(ocs_hal_linkcfg_cb_arg_t), OCS_M_NOWAIT);
6635  if (cb_arg == NULL) {
6636  ocs_log_err(hal->os, "failed to malloc cb_arg\n");
6637  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
6638  return OCS_HAL_RTN_NO_MEMORY;
6639  }
6640 
6641  cb_arg->cb = cb;
6642  cb_arg->arg = arg;
6643  cb_arg->opts = opts;
6644 
6645  /* dma_mem holds the non-embedded portion */
6646  if (ocs_dma_alloc(hal->os, &cb_arg->dma_cmd, sizeof(sli4_res_common_get_reconfig_link_info_t), 4)) {
6647  ocs_log_err(hal->os, "Failed to allocate DMA buffer\n");
6648  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
6649  ocs_free(hal->os, cb_arg, sizeof(ocs_hal_linkcfg_cb_arg_t));
6650  return OCS_HAL_RTN_NO_MEMORY;
6651  }
6652 
6653  /* Send the HAL command */
6654  sli_cmd_common_get_reconfig_link_info(&hal->sli, mbxdata, SLI4_BMBX_SIZE, &cb_arg->dma_cmd);
6655  rc = ocs_hal_command(hal, mbxdata, opts, ocs_hal_get_active_link_config_cb, cb_arg);
6656  if (rc) {
6657  ocs_dma_free(hal->os, &cb_arg->dma_cmd);
6658  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
6659  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
6660  } else if (opts == OCS_CMD_POLL) {
6661  /* If we're polling, call the callback here */
6662  ocs_hal_get_active_link_config_cb(hal, 0, mbxdata, cb_arg);
6663  }
6664 
6665  return rc;
6666 }
6667 
6668 /**
6669  * @brief Sets the DIF seed value.
6670  *
6671  * @param hal Hardware context.
6672  *
6673  * @return Returns OCS_HAL_RTN_SUCCESS on success.
6674  */
6675 static ocs_hal_rtn_e
6676 ocs_hal_set_dif_seed(ocs_hal_t *hal)
6677 {
6679  uint8_t buf[SLI4_BMBX_SIZE];
6681 
6682  ocs_memset(&seed_param, 0, sizeof(seed_param));
6683  seed_param.seed = hal->config.dif_seed;
6684 
6685  /* send set_features command */
6687  SLI4_SET_FEATURES_DIF_SEED, 4, (uint32_t *)&seed_param);
6688 
6689  rc = ocs_hal_command(hal, buf, OCS_CMD_POLL, NULL, NULL);
6690  if (rc || ((sli4_mbox_command_header_t *)buf)->status)
6691  return OCS_HAL_RTN_ERROR;
6692 
6693  ocs_log_debug(hal->os, "DIF seed set to 0x%x\n", hal->config.dif_seed);
6694  return rc;
6695 }
6696 
6697 /**
6698  * @brief Sets the DIF mode value.
6699  *
6700  * @param hal Hardware context.
6701  *
6702  * @return Returns OCS_HAL_RTN_SUCCESS on success.
6703  */
6704 static ocs_hal_rtn_e
6705 ocs_hal_set_dif_mode(ocs_hal_t *hal)
6706 {
6708  uint8_t buf[SLI4_BMBX_SIZE];
6710 
6711  ocs_memset(&mode_param, 0, sizeof(mode_param));
6712  mode_param.tmm = (hal->config.dif_mode == OCS_HAL_DIF_MODE_INLINE ? 0 : 1);
6713 
6714  /* send set_features command */
6716  SLI4_SET_FEATURES_DIF_MEMORY_MODE, sizeof(mode_param), (uint32_t *)&mode_param);
6717 
6718  rc = ocs_hal_command(hal, buf, OCS_CMD_POLL, NULL, NULL);
6719  if (rc || ((sli4_mbox_command_header_t *)buf)->status)
6720  return OCS_HAL_RTN_ERROR;
6721 
6722  ocs_log_test(hal->os, "DIF mode set to %s\n",
6723  (hal->config.dif_mode == OCS_HAL_DIF_MODE_INLINE ? "inline" : "separate"));
6724  return rc;
6725 }
6726 
6727 static void
6729 {
6730  ocs_hal_t *hal = (ocs_hal_t *)arg;
6731 
6733 }
6734 
6735 static void
6736 ocs_hal_cb_cfg_watchdog(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
6737 {
6738  sli4_cmd_sli_config_t *mbox_rsp = (sli4_cmd_sli_config_t *)mqe;
6740  uint16_t timeout = hal->watchdog_timeout;
6741 
6742  if (sli4_rsp->hdr.status)
6743  ocs_hal_log_sli4_rsp_hdr(hal, &sli4_rsp->hdr);
6744 
6745  if (0 == status) {
6746  if (mbox_rsp->hdr.status)
6747  status = mbox_rsp->hdr.status;
6748  else if (sli4_rsp->hdr.status)
6749  status = sli4_rsp->hdr.status;
6750  }
6751 
6752  if (0 == status) {
6753  if (timeout) {
6754  /* keeping callback 500ms before timeout to keep heartbeat alive */
6755  ocs_setup_timer(hal->os, &hal->watchdog_timer, ocs_hal_watchdog_timer_cb, hal,
6756  (timeout*1000 - 500), false);
6757  } else {
6758  ocs_del_timer(&hal->watchdog_timer);
6759  }
6760  }
6761 
6762  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
6763 }
6764 
6765 /**
6766  * @brief Set configuration parameters for watchdog timer feature.
6767  *
6768  * @param hal Hardware context.
6769  * @param timeout Timeout for watchdog timer in seconds
6770  *
6771  * @return Returns OCS_HAL_RTN_SUCCESS on success.
6772  */
6773 static ocs_hal_rtn_e
6775 {
6777  uint8_t *buf = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
6778 
6779  if (!buf) {
6780  ocs_log_err(hal->os, "no buffer for command\n");
6781  return OCS_HAL_RTN_NO_MEMORY;
6782  }
6783 
6784  sli4_cmd_lowlevel_set_watchdog(&hal->sli, buf, SLI4_BMBX_SIZE, hal->watchdog_timeout);
6786  if (rc)
6787  ocs_free(hal->os, buf, SLI4_BMBX_SIZE);
6788 
6789  return rc;
6790 }
6791 
6792 static void
6793 ocs_hal_cb_itcm_parity_stats(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
6794 {
6795  sli4_cmd_sli_config_t *mbox_rsp = (sli4_cmd_sli_config_t *)mqe;
6797  ocs_hal_parity_stat_cb_arg_t *cb_arg = arg;
6798 
6800  if (sli4_rsp->hdr.status)
6801  ocs_hal_log_sli4_rsp_hdr(hal, &sli4_rsp->hdr);
6802 
6803  if (!cb_arg || !cb_arg->cb)
6804  goto ocs_hal_cb_itcm_parity_stats_done;
6805 
6806  if (0 == status) {
6807  if (mbox_rsp->hdr.status)
6808  status = mbox_rsp->hdr.status;
6809  else if (sli4_rsp->hdr.status)
6810  status = sli4_rsp->hdr.status;
6811  }
6812 
6813  cb_arg->cb(status, sli4_rsp->num_ulp, (ocs_parity_err_count_t *)sli4_rsp->counter, cb_arg->arg);
6814 
6815 ocs_hal_cb_itcm_parity_stats_done:
6816  if (cb_arg)
6817  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
6818 
6819  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
6820 }
6821 
6823 ocs_hal_get_itcm_parity_stats(ocs_hal_t *hal, bool clear_stats, ocs_hal_parity_stat_cb_t cb, void *arg)
6824 {
6825  uint8_t *buf = NULL;
6826  ocs_hal_parity_stat_cb_arg_t *cb_arg = NULL;
6828 
6829  buf = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
6830  if (!buf) {
6831  ocs_log_err(hal->os, "Failed to malloc mbox\n");
6832  return OCS_HAL_RTN_NO_MEMORY;
6833  }
6834 
6835  cb_arg = ocs_malloc(hal->os, sizeof(*cb_arg), OCS_M_NOWAIT);
6836  if (!cb_arg) {
6837  ocs_log_err(hal->os, "Failed to malloc cb_arg\n");
6838  ocs_free(hal->os, buf, SLI4_BMBX_SIZE);
6839  return OCS_HAL_RTN_NO_MEMORY;
6840  }
6841 
6842  cb_arg->cb = cb;
6843  cb_arg->arg = arg;
6844 
6845  sli4_cmd_lowlevel_get_itcm_parity_stats(&hal->sli, buf, SLI4_BMBX_SIZE, clear_stats);
6847  if (rc) {
6848  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
6849  ocs_free(hal->os, buf, SLI4_BMBX_SIZE);
6850  }
6851 
6852  return rc;
6853 }
6854 
6855 static void
6856 ocs_hal_generic_mbx_command_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
6857 {
6858  sli4_cmd_sli_config_t *mbox_rsp = (sli4_cmd_sli_config_t *)mqe;
6859  sli4_res_hdr_t *sli4_rsp_hdr;
6860  ocs_mq_mbx_results_t *results = arg;
6861 
6862  if (0 == status) {
6863  /* If Mqe write was fine, look for mbox and sli4 status */
6864  if (results->handle_sli4_rsp) {
6865  sli4_rsp_hdr = (sli4_res_hdr_t *)mbox_rsp->payload.embed;
6866  status = sli4_rsp_hdr->status;
6867  if (status != 0)
6868  ocs_hal_log_sli4_rsp_hdr(hal, sli4_rsp_hdr);
6869  }
6870 
6871  if (mbox_rsp->hdr.status)
6872  status = mbox_rsp->hdr.status;
6873  }
6874 
6875  results->status = ((0 == status) ? 0 : 1);
6876 
6877  ocs_sem_v(&results->wait_sem);
6878  if (ocs_atomic_sub_and_test(&results->refcnt, 1))
6879  ocs_free(hal->os, results, sizeof(*results));
6880 }
6881 
6882 /**
6883  * @brief Issue a blocking hal command that has generic response
6884  * handling in callback handler
6885  *
6886  * @param hal: Hardware context.
6887  * @param req_rsp_buf: The command request and response buffer
6888  *
6889  * @param handle_sli4_rsp: command response has sli header
6890  * @param timeout_usecs: Semphore wait timeout
6891  *
6892  * @return Returns OCS_HAL_RTN_SUCCESS on success.
6893  * OCS_HAL_RTN_ERROR on timeout or failure
6894  */
6895 static ocs_hal_rtn_e
6896 ocs_hal_exec_mbx_command_generic_results(ocs_hal_t *hal, uint8_t *req_rsp_buf, bool handle_sli4_rsp,
6897  int timeout_usecs)
6898 {
6899  ocs_mq_mbx_results_t *results;
6900  ocs_hal_rtn_e rc;
6901 
6902  results = ocs_malloc(hal->os, sizeof(ocs_mq_mbx_results_t), OCS_M_ZERO | OCS_M_NOWAIT);
6903  if (results == NULL) {
6904  ocs_log_err(hal->os, "Failed to allocate memory\n");
6905  return OCS_HAL_RTN_ERROR;
6906  }
6907 
6908  /* Copy command to buffer */
6909  memcpy(results->cmd_buf, req_rsp_buf, SLI4_BMBX_SIZE);
6910 
6911  ocs_sem_init(&results->wait_sem, 0, "mq_mbx_results_sem");
6912  ocs_atomic_init(&results->refcnt, 2);
6913  results->status = 0;
6914  results->handle_sli4_rsp = handle_sli4_rsp;
6915 
6917  if (rc) {
6918  ocs_atomic_sub_and_test(&results->refcnt, 1);
6919  goto exit_mbx_cmd;
6920  }
6921 
6922  if (ocs_sem_p(&results->wait_sem, timeout_usecs)) {
6923  ocs_log_err(hal->os, "ocs_sem_p failed\n");
6924  rc = OCS_HAL_RTN_ERROR;
6925  } else {
6926  ocs_memcpy(req_rsp_buf, results->cmd_buf, SLI4_BMBX_SIZE);
6927  }
6928 
6929  if (rc || results->status) {
6930  ocs_log_err(hal->os, "MBOX command failed\n");
6931  rc = OCS_HAL_RTN_ERROR;
6932  }
6933 
6934 
6935 exit_mbx_cmd:
6936  if (ocs_atomic_sub_and_test(&results->refcnt, 1))
6937  ocs_free(hal->os, results, sizeof(*results));
6938 
6939  return rc;
6940 }
6941 
6942 /**
6943  * @brief Set trunking mode
6944  *
6945  * @param hal Hardware context.
6946  * @param trunk_mode Trunk mode to set
6947  *
6948  * @return Returns OCS_HAL_RTN_SUCCESS on success.
6949  */
6951 ocs_hal_set_trunk_mode(ocs_hal_t *hal, uint32_t trunk_mode)
6952 {
6954  uint8_t buf[SLI4_BMBX_SIZE];
6955 
6956  if (hal == NULL) {
6957  ocs_log_err(NULL, "Failed to access HAL\n");
6958  return OCS_HAL_RTN_ERROR;
6959  }
6960 
6961  if (sli_cmd_fc_set_trunk_mode(&hal->sli, buf, SLI4_BMBX_SIZE, trunk_mode) == -1) {
6962  ocs_log_err(hal->os, "[ Trunk ] Invalid mode %d\n", trunk_mode);
6964  return OCS_HAL_RTN_ERROR;
6965  }
6966 
6967  rc = ocs_hal_exec_mbx_command_generic_results(hal, buf, true, 10*1000*1000);
6968  if (rc) {
6969  ocs_log_err(hal->os, "[ Trunk ] config failed, rc = %d\n", rc);
6970  } else {
6971  ocs_log_info(hal->os, "[ Trunk ] mode=%d configured successfully."
6972  "Host reboot is required for the new configuration to take effect\n",
6973  trunk_mode);
6974  }
6975  return rc;
6976 }
6977 
6978 /**
6979  * @brief Get trunking mode information
6980  *
6981  * @param hal Hardware context.
6982  * @param trunk_info Placeholder to return trunk config info
6983  *
6984  * @return Returns OCS_HAL_RTN_SUCCESS on success.
6985  */
6987 ocs_hal_get_trunk_info(ocs_hal_t *hal, uint32_t *trunk_info)
6988 {
6990  sli4_cmd_read_topology_t *read_topo;
6991  uint8_t buf[SLI4_BMBX_SIZE];
6992 
6993  read_topo = (sli4_cmd_read_topology_t *)buf;
6994  //Issue read_topology to get trunking configuration
6995  if (sli_cmd_read_topology(&hal->sli, buf, SLI4_BMBX_SIZE, NULL)) {
6996  rc = ocs_hal_exec_mbx_command_generic_results(hal, buf, false,
6997  10*1000*1000);
6998  }
6999 
7000  if (!rc) {
7001  *trunk_info = (uint32_t)read_topo->trunk_config;
7002  } else {
7003  ocs_log_err(hal->os, "[ Trunk ] READ_TOPOLOGY failed, rc = %d\n", rc);
7004  }
7005 
7006  return rc;
7007 }
7008 /**
7009  * @brief Stop firmware diagnostic logging (RAS).
7010  *
7011  * @param hal Hardware context.
7012  *
7013  * @return Returns OCS_HAL_RTN_SUCCESS on success.
7014  */
7015 int
7017 {
7019  uint8_t *buf;
7020 
7021  ocs_log_info(hal->os, "[RAS] Attempting to stop diagnostic logging\n");
7022  buf = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT | OCS_M_ZERO);
7023  if (!buf) {
7024  ocs_log_err(hal->os, "no buffer for FW diag logging command\n");
7025  return OCS_HAL_RTN_NO_MEMORY;
7026  }
7027 
7029  rc = ocs_hal_command(hal, buf, OCS_CMD_POLL, NULL, NULL);
7030  if (rc || ((sli4_mbox_command_header_t *)buf)->status)
7031  rc = OCS_HAL_RTN_ERROR;
7032  else
7033  ocs_log_info(hal->os, "[RAS] stopped diagnostic logging successfully\n");
7034 
7035  ocs_free(hal->os, buf, SLI4_BMBX_SIZE);
7036  return rc;
7037 }
7038 
7039 /**
7040  * @brief If required disable firmware diagnostic logging (RAS) and then free resources.
7041  *
7042  * @param hal Hardware context.
7043  *
7044  * @return Returns OCS_HAL_RTN_SUCCESS on success.
7045  */
7046 static ocs_hal_rtn_e
7048 {
7049  return ocs_ras_free_resc(hal->os);
7050 }
7051 
7052 
7053 /**
7054  * @brief Set configuration parameters for adapter firmware diagnostic logging (RAS) feature.
7055  *
7056  * @param hal Hardware context.
7057  * @param log_size Host buffer size shared with the firmware to write logs.
7058  * @param log_level Firmware log level. Valid range is - 0 (least verbose) to 4 (most verbose).
7059  *
7060  * @return Returns OCS_HAL_RTN_SUCCESS on success.
7061  */
7062 static ocs_hal_rtn_e
7063 ocs_hal_config_fw_diagnostic_logging(ocs_hal_t *hal, int32_t log_size, int32_t log_level)
7064 {
7066  uint8_t *buf;
7067  uintptr_t lwpd_phys;
7068  uint32_t *buf_phys_tbl = NULL;
7069  int32_t buf_count;
7070 
7071  /* First SLI port initializes the global data structure */
7072  ocs_ras_init(log_level, log_size);
7073 
7074  ocs_log_info(hal->os, "[RAS] Setup firmware diagnostic logging\n");
7075  rc = ocs_ras_allocate_resc(hal->os);
7076  if (rc) {
7077  if (rc == -EEXIST) {
7078  // API automatically increments ref count
7079  ocs_log_info(hal->os, "[RAS] firmware diagnostic logging is active for the adapter\n");
7080  rc = OCS_HAL_RTN_SUCCESS;
7081  } else if (rc == -EPERM) {
7083  } else {
7085  }
7086  goto exit_with_err;
7087  }
7088 
7089  lwpd_phys = ocs_ras_get_lwpd_dma_addr(hal->os);
7090  buf_phys_tbl = ocs_ras_get_dma_addr_list(hal->os, &buf_count);
7091  if (!lwpd_phys || !buf_phys_tbl || !buf_count) {
7092  ocs_log_err(hal->os, "[RAS] resource error\n");
7093  rc = OCS_HAL_RTN_ERROR;
7094  goto exit_with_err;
7095  }
7096 
7097  buf = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT | OCS_M_ZERO);
7098  if (!buf) {
7099  ocs_log_err(hal->os, "[RAS] no buffer for LOWLEVEL_SET_DIAG_LOG_OPTIONS mailbox command\n");
7100  rc = OCS_HAL_RTN_NO_MEMORY;
7101  goto exit_with_err;
7102  }
7103 
7104  sli4_cmd_lowlevel_enable_ras(&hal->sli, buf, SLI4_BMBX_SIZE, log_level,
7105  log_size / buf_count, buf_count, buf_phys_tbl, lwpd_phys);
7106 
7107  rc = ocs_hal_command(hal, buf, OCS_CMD_POLL, NULL, NULL);
7108  if (rc || ((sli4_mbox_command_header_t *)buf)->status)
7109  rc = OCS_HAL_RTN_ERROR;
7110  else
7111  ocs_log_info(hal->os, "[RAS] diagnostic logging configured successfully\n");
7112 
7113  ocs_free(hal->os, buf, SLI4_BMBX_SIZE);
7114 
7115 exit_with_err:
7116  if (buf_phys_tbl) {
7117  ocs_vfree(hal->os, buf_phys_tbl, buf_count * 8);
7118  }
7119 
7120  return rc;
7121 }
7122 
7123 /**
7124  * @brief Set configuration parameters for TOW T10 PI feature.
7125  *
7126  * @param hal Hardware context.
7127  * @param buf Pointer to a mailbox buffer area.
7128  *
7129  * @return Returns OCS_HAL_RTN_SUCCESS on success.
7130  */
7132 {
7133  uint8_t buf[SLI4_BMBX_SIZE];
7136 
7137  ocs_memset(&param, 0, sizeof(param));
7138  param.scsi_diseed_sge.app_tag_repl = hal->config.tow_app_tag_value;
7142 
7143  /* build the set_features command */
7146  sizeof(param),
7147  &param);
7148  rc = ocs_hal_command(hal, buf, OCS_CMD_POLL, NULL, NULL);
7149  if (rc || ((sli4_mbox_command_header_t *)buf)->status)
7150  rc = OCS_HAL_RTN_ERROR;
7151  else
7152  ocs_log_info(hal->os, "Optimized Write T10 PI configured \n");
7153 
7154  return rc;
7155 }
7156 
7157 /**
7158  * @brief Set configuration parameters for AXR T10 PI feature.
7159  *
7160  * @param hal Hardware context.
7161  * @param buf Pointer to a mailbox buffer area.
7162  *
7163  * @return Returns OCS_HAL_RTN_SUCCESS on success.
7164  */
7166 {
7167  uint8_t buf[SLI4_BMBX_SIZE];
7170 
7171  ocs_memset(&param, 0, sizeof(param));
7172  param.rtc = (hal->config.tow_ref_tag_lba ? 0 : 1);
7173  param.atv = (hal->config.tow_app_tag_valid ? 1 : 0);
7174  param.tmm = ((hal->config.dif_mode == OCS_HAL_DIF_MODE_INLINE) ? 0 : 1);
7175  param.app_tag = hal->config.tow_app_tag_value;
7176  param.blk_size = hal->config.tow_blksize_chip;
7177 
7178  switch (hal->config.tow_p_type) {
7179  case 1:
7180  param.p_type = 0;
7181  break;
7182  case 3:
7183  param.p_type = 2;
7184  break;
7185  default:
7186  ocs_log_err(hal->os, "unsupported p_type %d\n", hal->config.tow_p_type);
7187  return OCS_HAL_RTN_ERROR;
7188  }
7189 
7190  /* build the set_features command */
7193  sizeof(param),
7194  &param);
7195  rc = ocs_hal_command(hal, buf, OCS_CMD_POLL, NULL, NULL);
7196  if (rc || ((sli4_mbox_command_header_t *)buf)->status)
7197  rc = OCS_HAL_RTN_ERROR;
7198  else
7199  ocs_log_info(hal->os, "Auto XFER RDY T10 PI configured rtc:%d atv:%d p_type:%d app_tag:%x blk_size:%d\n",
7200  param.rtc, param.atv, param.p_type,
7201  param.app_tag, param.blk_size);
7202 
7203  return rc;
7204 }
7205 
7206 
7207 /**
7208  * @brief enable sli port health check
7209  *
7210  * @param hal Hardware context.
7211  * @param buf Pointer to a mailbox buffer area.
7212  * @param query current status of the health check feature enabled/disabled
7213  * @param enable if 1: enable 0: disable
7214  * @param buf Pointer to a mailbox buffer area.
7215  *
7216  * @return Returns OCS_HAL_RTN_SUCCESS on success.
7217  */
7218 static ocs_hal_rtn_e
7219 ocs_hal_config_sli_port_health_check(ocs_hal_t *hal, uint8_t query, uint8_t enable)
7220 {
7222  uint8_t buf[SLI4_BMBX_SIZE];
7224 
7225  ocs_memset(&param, 0, sizeof(param));
7226  param.hck = enable;
7227  param.qry = query;
7228 
7229  /* build the set_features command */
7232  sizeof(param),
7233  &param);
7234 
7235  rc = ocs_hal_command(hal, buf, OCS_CMD_POLL, NULL, NULL);
7236  if (rc || ((sli4_mbox_command_header_t *)buf)->status)
7237  rc = OCS_HAL_RTN_ERROR;
7238  else
7239  ocs_log_test(hal->os, "SLI Port Health Check is enabled \n");
7240 
7241  return rc;
7242 }
7243 
7244 /**
7245  * @brief configure fec (enable/disable) on physical port
7246  * - supported only for FC at present
7247  *
7248  * @param hal Hardware context.
7249  * @param enable if 1: enable 0: disable
7250  *
7251  * @return Returns OCS_HAL_RTN_SUCCESS on success.
7252  */
7253 static ocs_hal_rtn_e
7254 ocs_hal_config_fec(ocs_hal_t *hal, uint8_t enable)
7255 {
7257  uint8_t buf[SLI4_BMBX_SIZE];
7259 
7260  ocs_memset(&param, 0, sizeof(param));
7261  param.link_number = hal->sli.physical_port;
7263  param.en = enable;
7264 
7265  /* build the set_features command */
7268  sizeof(param),
7269  &param);
7270 
7271  rc = ocs_hal_command(hal, buf, OCS_CMD_POLL, NULL, NULL);
7272  if (rc || ((sli4_mbox_command_header_t *)buf)->status)
7273  rc = OCS_HAL_RTN_ERROR;
7274  else
7275  ocs_log_test(hal->os, "FEC feature set to %d \n", enable);
7276 
7277  return rc;
7278 }
7279 
7280 /**
7281  * @brief Enable/disable firmware path to send auto-good response
7282  * - In G5/G6, The auto response mechanism does not clear the param field
7283  * in FCP/NVMe frames. This in turn causes performance issues with certain
7284  * initiators. This is a firmware workaround to force parameter field to
7285  * zero
7286  *
7287  * @param hal Hardware context.
7288  * @param enable if 1: enable 0: disable
7289  *
7290  * @return Returns OCS_HAL_RTN_SUCCESS on success.
7291  */
7292 static ocs_hal_rtn_e
7293 ocs_hal_config_fw_ag_rsp(ocs_hal_t *hal, uint8_t enable)
7294 {
7296  uint8_t buf[SLI4_BMBX_SIZE];
7298 
7299  ocs_memset(&param, 0, sizeof(param));
7300  param.pz = enable;
7301 
7302  /* build the set_features command */
7305  sizeof(param),
7306  &param);
7307 
7308  rc = ocs_hal_command(hal, buf, OCS_CMD_POLL, NULL, NULL);
7309  if (rc || ((sli4_mbox_command_header_t *)buf)->status)
7310  rc = OCS_HAL_RTN_ERROR;
7311  else
7312  ocs_log_test(hal->os, "Auto-response parameter field reset feature set to %d \n", enable);
7313 
7314  return rc;
7315 }
7316 
7317 static void
7319 {
7320  int i, token_cnt = 0;
7321  char *token = NULL;
7322  char *dup_str = ocs_strdup(hal->sliport_pause_errors);
7323  char *pause_errors = dup_str;
7324  char *errx_pair[SLI4_PAUSE_ERRX_PAIR_CNT] = { NULL };
7325 
7326  while (NULL != (token = ocs_strsep(&pause_errors, ","))) {
7327  errx_pair[token_cnt++] = token;
7328 
7329  /* Limit the # of tokens to SLI4_PAUSE_ERRX_PAIR_CNT */
7330  if (SLI4_PAUSE_ERRX_PAIR_CNT == token_cnt) {
7331  break;
7332  }
7333  }
7334 
7335  for (i = 0; i < token_cnt; i++) {
7336  char *err1 = NULL;
7337  char *err2 = NULL;
7338 
7339  /* Handle leading spaces */
7340  while (NULL != (err1 = ocs_strsep(&errx_pair[i], " "))) {
7341  if ('\0' != *err1) {
7342  break;
7343  }
7344  }
7345 
7346  /* Handle multiple spaces */
7347  while (NULL != (err2 = ocs_strsep(&errx_pair[i], " "))) {
7348  if ('\0' != *err2) {
7349  break;
7350  }
7351  }
7352 
7353  /* Handle empty tokens */
7354  if (err1) {
7355  hal->sli.pause_errx_pair[i].err1 = ocs_strtoul(err1, &token, 16);
7356  } else {
7357  continue;
7358  }
7359 
7360  /* Handle wildcard values for err2 */
7361  if (err2) {
7362  hal->sli.pause_errx_pair[i].err2 = ocs_strtoul(err2, &token, 16);
7363  } else {
7364  hal->sli.pause_errx_pair[i].err2 = 0xFFFFFFFF;
7365  }
7366 
7367  ocs_log_info(hal->os, "err1[%d]: 0x%x, err2[%d]: 0x%x\n",
7368  i, hal->sli.pause_errx_pair[i].err1,
7369  i, hal->sli.pause_errx_pair[i].err2);
7370  }
7371 
7372  ocs_free(hal->os, dup_str, ocs_strlen(hal->sliport_pause_errors) + 1);
7373 }
7374 
7375 static ocs_hal_rtn_e
7376 ocs_hal_config_sliport_pause(ocs_hal_t *hal, uint8_t enable)
7377 {
7379  uint8_t buf[SLI4_BMBX_SIZE];
7381 
7382  ocs_memset(&param, 0, sizeof(param));
7383  param.eps = enable;
7384 
7385  /* build the set_features command */
7388  sizeof(param), &param);
7389 
7390  rc = ocs_hal_command(hal, buf, OCS_CMD_POLL, NULL, NULL);
7391  if (rc || ((sli4_mbox_command_header_t *)buf)->status) {
7392  rc = OCS_HAL_RTN_ERROR;
7393  } else {
7395  ocs_log_test(hal->os, "Sliport pause state is enabled\n");
7396  }
7397 
7398  return rc;
7399 }
7400 
7401 /**
7402  * @brief Set FTD transfer hint feature
7403  *
7404  * @param hal Hardware context.
7405  * @param fdt_xfer_hint size in bytes where read requests are segmented.
7406  *
7407  * @return Returns OCS_HAL_RTN_SUCCESS on success.
7408  */
7409 static ocs_hal_rtn_e
7410 ocs_hal_config_set_fdt_xfer_hint(ocs_hal_t *hal, uint32_t fdt_xfer_hint)
7411 {
7413  uint8_t buf[SLI4_BMBX_SIZE];
7415 
7416  ocs_memset(&param, 0, sizeof(param));
7417  param.fdt_xfer_hint = fdt_xfer_hint;
7418  /* build the set_features command */
7421  sizeof(param),
7422  &param);
7423 
7424  rc = ocs_hal_command(hal, buf, OCS_CMD_POLL, NULL, NULL);
7425  if (rc || ((sli4_mbox_command_header_t *)buf)->status)
7426  rc = OCS_HAL_RTN_ERROR;
7427  else
7428  ocs_log_info(hal->os, "Set FTD transfer hint to %d\n", param.fdt_xfer_hint);
7429 
7430  return rc;
7431 }
7432 
7433 /**
7434  * @brief Get the link configuration callback.
7435  *
7436  * @param hal Hardware context.
7437  * @param status Status from the DMTF CLP command.
7438  * @param result_len Length, in bytes, of the DMTF CLP result.
7439  * @param arg Pointer to a callback argument.
7440  *
7441  * @return Returns OCS_HAL_RTN_SUCCESS on success.
7442  */
7443 static void
7444 ocs_hal_linkcfg_dmtf_clp_cb(ocs_hal_t *hal, int32_t status, uint32_t result_len, void *arg)
7445 {
7446  int32_t rval;
7447  char retdata_str[64];
7450 
7451  if (status) {
7452  ocs_log_test(hal->os, "CLP cmd failed, status=%d\n", status);
7453  } else {
7454  /* parse CLP response to get return data */
7455  rval = ocs_hal_clp_resp_get_value(hal, "retdata", retdata_str,
7456  sizeof(retdata_str),
7457  cb_arg->dma_resp.virt,
7458  result_len);
7459 
7460  if (rval <= 0) {
7461  ocs_log_err(hal->os, "failed to get retdata %d\n", result_len);
7462  } else {
7463  /* translate string into hal enum */
7464  linkcfg = ocs_hal_linkcfg_from_clp(retdata_str);
7465  }
7466  }
7467 
7468  /* invoke callback */
7469  if (cb_arg->cb) {
7470  cb_arg->cb(status, linkcfg, cb_arg->arg);
7471  }
7472 
7473  /* if polling, will free memory in calling function */
7474  if (cb_arg->opts != OCS_CMD_POLL) {
7475  ocs_dma_free(hal->os, &cb_arg->dma_cmd);
7476  ocs_dma_free(hal->os, &cb_arg->dma_resp);
7477  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
7478  }
7479 }
7480 
7481 #if !defined(OCSU_FC_RAMD) && !defined(OCSU_FC_WORKLOAD) && !defined(OCS_USPACE_SPDK)
7482 
7483 /**
7484  * @brief Set the Lancer dump location
7485  * @par Description
7486  * This function tells a Lancer chip to use a specific DMA
7487  * buffer as a dump location rather than the internal flash.
7488  *
7489  * @param hal Hardware context.
7490  * @param num_buffers The number of DMA buffers to hold the dump (1..n).
7491  * @param dump_buffers DMA buffers to hold the dump.
7492  * @fdb function specific dump
7493  *
7494  * @return Returns OCS_HAL_RTN_SUCCESS on success.
7495  */
7496 static ocs_hal_rtn_e
7497 ocs_hal_set_dump_location(ocs_hal_t *hal, uint32_t num_buffers, ocs_dma_t *dump_buffers, uint8_t fdb)
7498 {
7500  uint8_t buf[SLI4_BMBX_SIZE];
7501  ocs_dma_t *dump_sges = NULL;
7502 
7503  if (!dump_buffers || !num_buffers) {
7504  ocs_log_err(hal->os, "Dump buffers are missing\n");
7505  return rc;
7506  }
7507 
7508  /**
7509  * If a single buffer is used, then it may be passed as is to the chip. For multiple buffers,
7510  * we must allocate an SGL list and then pass the address of the list to the chip.
7511  */
7512  if (num_buffers > 1) {
7513  uint32_t sge_size = num_buffers * sizeof(sli4_sge_t);
7514  sli4_sge_t *sge;
7515  uint32_t i;
7516 
7517  dump_sges = (fdb ? &hal->func_dump_sges : &hal->chip_dump_sges);
7518  if (dump_sges->size < sge_size) {
7519  ocs_dma_free(hal->os, dump_sges);
7520  if (ocs_dma_alloc(hal->os, dump_sges, sge_size, OCS_MIN_DMA_ALIGNMENT)) {
7521  ocs_log_err(hal->os, "SGE DMA allocation failed\n");
7522  return OCS_HAL_RTN_NO_MEMORY;
7523  }
7524  }
7525 
7526  /* build the SGE list */
7527  ocs_memset(dump_sges->virt, 0, dump_sges->size);
7528  dump_sges->len = sge_size;
7529  sge = dump_sges->virt;
7530 
7531  for (i = 0; i < num_buffers; i++) {
7532  sge[i].buffer_address_high = ocs_addr32_hi(dump_buffers[i].phys);
7533  sge[i].buffer_address_low = ocs_addr32_lo(dump_buffers[i].phys);
7534  sge[i].last = (i == num_buffers - 1 ? 1 : 0);
7535  sge[i].buffer_length = dump_buffers[i].size;
7536  }
7537 
7538  sli_cmd_common_set_dump_location(&hal->sli, (void *)buf,
7539  SLI4_BMBX_SIZE, FALSE, TRUE, dump_sges, fdb);
7540  } else {
7541  dump_buffers->len = dump_buffers->size;
7542  sli_cmd_common_set_dump_location(&hal->sli, (void *)buf,
7543  SLI4_BMBX_SIZE, FALSE, FALSE, dump_buffers, fdb);
7544  }
7545 
7546  rc = ocs_hal_command(hal, buf, OCS_CMD_POLL, NULL, NULL);
7547  if (OCS_HAL_RTN_SUCCESS == rc) {
7548  ocs_log_debug(hal->os, "Set %s dump location is successful\n", fdb ? "func" : "chip");
7549  } else {
7550  if (dump_sges) {
7551  /* Free the FW dump buffer SGE's */
7552  ocs_dma_free(hal->os, dump_sges);
7553  }
7554  ocs_log_err(hal->os, "Set %s dump location command failed\n", fdb ? "func" : "chip");
7555  }
7556 
7557  return rc;
7558 }
7559 
7560 void
7562 {
7563  ocs_t *ocs = (ocs_t *)hal->os;
7564  ocs_dma_t *dump_buffers = NULL;
7565  uint32_t i, num_buffers = 0;
7566 
7567  if (ocs->fw_dump.chip_dump_buffers) {
7568  dump_buffers = ocs->fw_dump.chip_dump_buffers;
7569  num_buffers = ocs->fw_dump.num_chip_dump_buffers;
7570 
7571  for (i = 0; i < num_buffers; i++) {
7572  ocs_dma_free(ocs, &dump_buffers[i]);
7573  }
7574 
7575  ocs_free(ocs, dump_buffers, sizeof(ocs_dma_t) * num_buffers);
7576  ocs->fw_dump.chip_dump_buffers = NULL;
7577  ocs->fw_dump.num_chip_dump_buffers = 0;
7578  }
7579 
7580  if (ocs->fw_dump.func_dump_buffers) {
7581  dump_buffers = ocs->fw_dump.func_dump_buffers;
7582  num_buffers = ocs->fw_dump.num_func_dump_buffers;
7583 
7584  for (i = 0; i < num_buffers; i++) {
7585  ocs_dma_free(ocs, &dump_buffers[i]);
7586  }
7587 
7588  ocs_free(ocs, dump_buffers, sizeof(ocs_dma_t) * num_buffers);
7589  ocs->fw_dump.func_dump_buffers = NULL;
7590  ocs->fw_dump.num_func_dump_buffers = 0;
7591  }
7592 
7593  if (ocs->fw_dump.saved_buff) {
7594  ocs_free(ocs, ocs->fw_dump.saved_buff, ocs->fw_dump.size);
7595  ocs->fw_dump.saved_buff = NULL;
7596  }
7597  ocs->fw_dump.size = 0;
7598 
7599  ocs->fw_dump.state = FW_DUMP_STATE_NONE;
7600  ocs_lock_free(&ocs->fw_dump.lock);
7601 }
7602 
7603 static int32_t
7604 ocs_fw_dump_buffer_alloc(ocs_t *ocs, uint8_t dump_level)
7605 {
7606  int rc = 0;
7607  uint32_t i;
7608  uint32_t rem_bytes = 0;
7609  uint32_t num_buffers = 0;
7610  ocs_dma_t *dump_buffers = NULL;
7611 
7612  if (FW_FUNC_DESC_DUMP == dump_level) {
7613  dump_buffers = ocs->fw_dump.func_dump_buffers;
7614  num_buffers = ocs->fw_dump.num_func_dump_buffers;
7615  } else {
7616  dump_buffers = ocs->fw_dump.chip_dump_buffers;
7617  num_buffers = ocs->fw_dump.num_chip_dump_buffers;
7618  }
7619 
7620  /* If dump buffers were already allocated, return success */
7621  if ((NULL != dump_buffers) && (0 != num_buffers)) {
7622  return rc;
7623  }
7624 
7625  ocs_hal_get(&ocs->hal, OCS_HAL_DUMP_MAX_SIZE, &ocs->fw_dump.size);
7626  if (!ocs->fw_dump.saved_buff)
7627  ocs->fw_dump.saved_buff = ocs_malloc(ocs, ocs->fw_dump.size, OCS_M_ZERO);
7628 
7629  if (!ocs->fw_dump.saved_buff) {
7630  ocs_log_err(ocs, "Failed to allocated dump saved buffer\n");
7631  rc = -1;
7632  goto free_dump_buffers;
7633  }
7634 
7635  num_buffers = ((ocs->fw_dump.size + OCS_MAX_DMA_ALLOC - 1) / OCS_MAX_DMA_ALLOC);
7636  dump_buffers = ocs_malloc(ocs, sizeof(ocs_dma_t) * num_buffers, OCS_M_ZERO);
7637  if (!dump_buffers) {
7638  ocs_log_err(ocs, "Failed to allocate buffer dma objects for dump\n");
7639  rc = -1;
7640  goto free_dump_buffers;
7641  }
7642 
7643  if (FW_FUNC_DESC_DUMP == dump_level) {
7644  ocs->fw_dump.func_dump_buffers = dump_buffers;
7645  ocs->fw_dump.num_func_dump_buffers = num_buffers;
7646  } else {
7647  ocs->fw_dump.chip_dump_buffers = dump_buffers;
7648  ocs->fw_dump.num_chip_dump_buffers = num_buffers;
7649  }
7650 
7651  /* Allocate the DMA buffers to hold the dump */
7652  rem_bytes = ocs->fw_dump.size;
7653 
7654  for (i = 0; i < num_buffers; i++) {
7655  uint32_t num_bytes = OCS_MIN(rem_bytes, OCS_MAX_DMA_ALLOC);
7656  rc = ocs_dma_alloc(ocs, &dump_buffers[i], num_bytes, OCS_MIN_DMA_ALIGNMENT);
7657  if (rc) {
7658  ocs_log_err(ocs, "Failed to allocate buffer for dump\n");
7659  rc = -1;
7660  goto free_dump_buffers;
7661  }
7662  rem_bytes -= num_bytes;
7663  }
7664 
7665  ocs_log_debug(ocs, "Successfully allocated FW dump buffers\n");
7666  return rc;
7667 
7668 free_dump_buffers:
7670  return rc;
7671 }
7672 
7673 static ocs_hal_rtn_e
7674 ocs_hal_alloc_set_dump_buffers(ocs_hal_t *hal, uint8_t dump_level)
7675 {
7676  ocs_t *ocs = (ocs_t *)hal->os;
7677  uint8_t fdb_dump;
7678  uint32_t num_buffers = 0;
7679  ocs_dma_t *dump_buffers = NULL;
7681 
7682  /* Allocate dump buffers only once and re-use them in the reset path */
7683  rc = ocs_fw_dump_buffer_alloc(ocs, dump_level);
7684  if (rc) {
7685  ocs_log_err(ocs, "Failed to register FW dump buffers\n");
7686  return OCS_HAL_RTN_ERROR;
7687  }
7688 
7689  if (FW_FUNC_DESC_DUMP == dump_level) {
7690  fdb_dump = TRUE;
7691  dump_buffers = ocs->fw_dump.func_dump_buffers;
7692  num_buffers = ocs->fw_dump.num_func_dump_buffers;
7693  } else {
7694  fdb_dump = FALSE;
7695  dump_buffers = ocs->fw_dump.chip_dump_buffers;
7696  num_buffers = ocs->fw_dump.num_chip_dump_buffers;
7697  }
7698 
7699  rc = ocs_hal_set_dump_location(hal, num_buffers, dump_buffers, fdb_dump);
7700  if (rc) {
7701  ocs_log_err(hal->os, "Failed to register dump to host buffers\n");
7702  } else {
7703  ocs_log_info(hal->os, "Dump to host buffers registered with FW successfully\n");
7704  }
7705 
7706  return rc;
7707 }
7708 
7709 /**
7710  * @brief Allocates dump dma buffers, if not already allocated.
7711  * Set the Lancer dump location
7712  * @par Description
7713  * This function tells a Lancer chip to use a specific DMA
7714  * buffer as a dump location rather than the internal flash.
7715  *
7716  * @param hal Hardware context.
7717  *
7718  * @return Returns OCS_HAL_RTN_SUCCESS on success.
7719  */
7722 {
7723  ocs_t *ocs = (ocs_t *)hal->os;
7724  uint8_t bus, dev, func;
7725  ocs_hal_rtn_e rc;
7726 
7727  if (!ocs) {
7728  ocs_log_err(ocs, "ocs context is missing\n");
7729  return OCS_HAL_RTN_ERROR;
7730  }
7731 
7732  /* Don't set the dump location if 'fw_dump_to_host' is not enabled */
7733  if (FW_DUMP_TYPE_DUMPTOHOST != ocs->fw_dump.type) {
7734  return OCS_HAL_RTN_SUCCESS;
7735  }
7736 
7737  /**
7738  * Make sure the FW is new enough to support this command.
7739  * If the FW is too old, the FW will UE.
7740  */
7741  if (hal->workaround.disable_dump_loc) {
7742  ocs_log_err(hal->os, "FW version is too old for this feature\n");
7743  return OCS_HAL_RTN_ERROR;
7744  }
7745 
7746  /* Set the chip level dump location only for pci function 0 */
7747  ocs_get_bus_dev_func(ocs, &bus, &dev, &func);
7748  if (0 == func) {
7750  if (OCS_HAL_RTN_SUCCESS != rc) {
7751  return rc;
7752  }
7753  }
7754 
7755  /* For FDD, set the dump location on all pci functions */
7757 }
7758 
7759 #endif
7760 
7761 /**
7762  * @brief Set the Lancer dump location
7763  * @par Description
7764  * This function set link loopback mode
7765  *
7766  * @param hal Hardware context.
7767  * @param type loopback type to be set
7768  *
7769  * @return Returns OCS_HAL_RTN_SUCCESS on success.
7770  */
7772 ocs_hal_set_loopback_mode(ocs_hal_t *hal, uint32_t type)
7773 {
7775  uint8_t buf[SLI4_BMBX_SIZE];
7776 
7777  if (!hal) {
7778  ocs_log_err(NULL, "Failed to access HAL\n");
7779  return rc;
7780  }
7781 
7782  sli_cmd_fcoe_set_loopback_mode(&hal->sli, (void *)buf, SLI4_BMBX_SIZE, type);
7783  return ocs_hal_exec_mbx_command_generic_results(hal, buf, true,
7784  10*1000*1000);
7785 }
7786 
7787 /**
7788  * @brief Run Diagnostic PCI Loopback test
7789  * @par Description
7790  * This will run PCI loopback tests
7791  *
7792  * @param hal Hardware context.
7793  * @param TX DMA buffer address
7794  * @param TX DMA buffer size
7795  * @param RX DMA buffer address
7796  * @param RX DMA buffer size
7797  *
7798  * @return Returns OCS_HAL_RTN_SUCCESS on success.
7799  */
7801 ocs_hal_run_biu_diag(ocs_hal_t *hal, void *tx_buff, size_t tx_buff_len,
7802  void *rx_buff, size_t rx_buff_len)
7803 {
7805  uint8_t buf[SLI4_BMBX_SIZE];
7806  ocs_dma_t tx_dma_buf, rx_dma_buf;
7807 
7808  if (hal == NULL) {
7809  ocs_log_err(NULL, "Failed to access HAL\n");
7810  return OCS_HAL_RTN_ERROR;
7811  }
7812 
7813  if (ocs_dma_alloc(hal->os, &tx_dma_buf, tx_buff_len, OCS_MIN_DMA_ALIGNMENT)) {
7814  ocs_log_err(hal->os, "Failed to alloc DMA memory for TX buffer\n");
7815  return OCS_HAL_RTN_NO_MEMORY;
7816  }
7817 
7818  if (ocs_dma_alloc(hal->os, &rx_dma_buf, rx_buff_len, OCS_MIN_DMA_ALIGNMENT)) {
7819  ocs_log_err(hal->os, "Failed to alloc DMA memory for RX buffer\n");
7820  ocs_dma_free(hal->os, &tx_dma_buf);
7821  return OCS_HAL_RTN_NO_MEMORY;
7822  }
7823  ocs_memset(tx_dma_buf.virt, 0, tx_buff_len);
7824  ocs_memset(rx_dma_buf.virt, 0, rx_buff_len);
7825 
7826  ocs_memcpy(tx_dma_buf.virt, tx_buff, tx_buff_len);
7827 
7828  if (sli_cmd_config_run_biu_diag(&hal->sli, buf, SLI4_BMBX_SIZE,
7829  &tx_dma_buf, tx_buff_len,
7830  &rx_dma_buf, rx_buff_len))
7831  {
7832  rc = ocs_hal_exec_mbx_command_generic_results(hal, buf, false,
7833  10*1000*1000);
7834  if (rc)
7835  goto exit_run_biu_diag;
7836  } else {
7837  ocs_log_err(hal->os, "sli_cmd_config_run_biu_diag failed\n");
7838  rc = OCS_HAL_RTN_ERROR;
7839  goto exit_run_biu_diag;
7840  }
7841 
7842  ocs_memcpy(rx_buff, rx_dma_buf.virt, rx_buff_len);
7843 
7844 exit_run_biu_diag:
7845  ocs_dma_free(hal->os, &tx_dma_buf);
7846  ocs_dma_free(hal->os, &rx_dma_buf);
7847  return rc;
7848 }
7849 /**
7850  * @brief Set the Ethernet license.
7851  *
7852  * @par Description
7853  * This function sends the appropriate mailbox command (DMTF
7854  * CLP) to set the Ethernet license to the given license value.
7855  * Since it is used during the time of ocs_hal_init(), the mailbox
7856  * command is sent via polling (the BMBX route).
7857  *
7858  * @param hal Hardware context.
7859  * @param license 32-bit license value.
7860  *
7861  * @return Returns OCS_HAL_RTN_SUCCESS on success.
7862  */
7863 static ocs_hal_rtn_e
7864 ocs_hal_set_eth_license(ocs_hal_t *hal, uint32_t license)
7865 {
7867  char cmd[OCS_HAL_DMTF_CLP_CMD_MAX];
7868  ocs_dma_t dma_cmd;
7869  ocs_dma_t dma_resp;
7870 
7871  /* only for lancer right now */
7872  if (SLI4_IF_TYPE_LANCER_FC_ETH != sli_get_if_type(&hal->sli)) {
7873  ocs_log_test(hal->os, "Function only supported for I/F type 2\n");
7874  return OCS_HAL_RTN_ERROR;
7875  }
7876 
7877  ocs_snprintf(cmd, OCS_HAL_DMTF_CLP_CMD_MAX, "set / OEMELX_Ethernet_License=%X", license);
7878  /* allocate DMA for command */
7879  if (ocs_dma_alloc(hal->os, &dma_cmd, ocs_strlen(cmd)+1, 4096)) {
7880  ocs_log_err(hal->os, "malloc failed\n");
7881  return OCS_HAL_RTN_NO_MEMORY;
7882  }
7883  ocs_memset(dma_cmd.virt, 0, ocs_strlen(cmd)+1);
7884  ocs_memcpy(dma_cmd.virt, cmd, ocs_strlen(cmd));
7885 
7886  /* allocate DMA for response */
7887  if (ocs_dma_alloc(hal->os, &dma_resp, OCS_HAL_DMTF_CLP_RSP_MAX, 4096)) {
7888  ocs_log_err(hal->os, "malloc failed\n");
7889  ocs_dma_free(hal->os, &dma_cmd);
7890  return OCS_HAL_RTN_NO_MEMORY;
7891  }
7892 
7893  /* send DMTF CLP command mbx and poll */
7894  if (ocs_hal_exec_dmtf_clp_cmd(hal, &dma_cmd, &dma_resp, OCS_CMD_POLL, NULL, NULL)) {
7895  ocs_log_err(hal->os, "CLP cmd=\"%s\" failed\n", (char *)dma_cmd.virt);
7896  rc = OCS_HAL_RTN_ERROR;
7897  }
7898 
7899  ocs_dma_free(hal->os, &dma_cmd);
7900  ocs_dma_free(hal->os, &dma_resp);
7901  return rc;
7902 }
7903 
7904 /**
7905  * @brief Callback argument structure for the DMTF CLP commands.
7906  */
7907 typedef struct ocs_hal_clp_cb_arg_s {
7909  ocs_dma_t *dma_resp;
7910  int32_t status;
7911  uint32_t opts;
7912  void *arg;
7914 
7915 /**
7916  * @brief Execute the DMTF CLP command.
7917  *
7918  * @param hal Hardware context.
7919  * @param dma_cmd DMA buffer containing the CLP command.
7920  * @param dma_resp DMA buffer that will contain the response (if successful).
7921  * @param opts Mailbox command options (such as OCS_CMD_NOWAIT and POLL).
7922  * @param cb Callback function.
7923  * @param arg Callback argument.
7924  *
7925  * @return Returns the number of bytes written to the response
7926  * buffer on success, or a negative value if failed.
7927  */
7928 static ocs_hal_rtn_e
7929 ocs_hal_exec_dmtf_clp_cmd(ocs_hal_t *hal, ocs_dma_t *dma_cmd, ocs_dma_t *dma_resp, uint32_t opts, ocs_hal_dmtf_clp_cb_t cb, void *arg)
7930 {
7932  ocs_hal_clp_cb_arg_t *cb_arg;
7933  uint8_t *mbxdata;
7934 
7935  /* allocate DMA for mailbox */
7936  mbxdata = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
7937  if (mbxdata == NULL) {
7938  ocs_log_err(hal->os, "failed to malloc mbox\n");
7939  return OCS_HAL_RTN_NO_MEMORY;
7940  }
7941 
7942  /* allocate memory for callback argument */
7943  cb_arg = ocs_malloc(hal->os, sizeof(*cb_arg), OCS_M_NOWAIT);
7944  if (cb_arg == NULL) {
7945  ocs_log_err(hal->os, "failed to malloc cb_arg");
7946  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
7947  return OCS_HAL_RTN_NO_MEMORY;
7948  }
7949 
7950  cb_arg->cb = cb;
7951  cb_arg->arg = arg;
7952  cb_arg->dma_resp = dma_resp;
7953  cb_arg->opts = opts;
7954 
7955  /* Send the HAL command */
7956  sli_cmd_dmtf_exec_clp_cmd(&hal->sli, mbxdata, SLI4_BMBX_SIZE, dma_cmd, dma_resp);
7957  rc = ocs_hal_command(hal, mbxdata, opts, ocs_hal_dmtf_clp_cb, cb_arg);
7958  if (rc) {
7959  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
7960  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
7961  } else if (opts == OCS_CMD_POLL) {
7962  /* If we're polling, call the callback here */
7963  ocs_hal_dmtf_clp_cb(hal, 0, mbxdata, cb_arg);
7964  }
7965 
7966  return rc;
7967 }
7968 
7969 /**
7970  * @brief Clear the Lancer dump location
7971  * @par Description
7972  * This function clears existsing DMA
7973  * buffer set previously while setting dump location
7974  *
7975  * @param hal Hardware context.
7976  *
7977  * @return Returns OCS_HAL_RTN_SUCCESS on success.
7978  */
7981 {
7982  uint8_t bus, dev, func;
7984  uint8_t buf[SLI4_BMBX_SIZE];
7985 
7986  /*
7987  * Make sure the FW is new enough to support this command. If the FW
7988  * is too old, the FW will UE.
7989  */
7990  if (hal->workaround.disable_dump_loc) {
7991  ocs_log_test(hal->os, "FW version is too old for this feature\n");
7992  return OCS_HAL_RTN_ERROR;
7993  }
7994 
7995  /* This command is only valid for physical port 0 */
7996  ocs_get_bus_dev_func(hal->os, &bus, &dev, &func);
7997  if (func)
7998  return rc;
7999 
8000  /*
8001  * If a single buffer is used, then it may be passed as is to the chip. For multiple buffers,
8002  * we must allocate an SGL and then pass the address of this list to the chip.
8003  */
8004  sli_cmd_common_set_dump_location(&hal->sli, (void *)buf, SLI4_BMBX_SIZE, FALSE, FALSE, NULL, 0);
8005 
8006  rc = ocs_hal_exec_mbx_command_generic_results(hal, buf, true, 20*1000*1000);
8007 
8008  if (rc) {
8009  ocs_log_err(hal->os, "Clear dump locaton failed\n");
8010  } else {
8011  ocs_log_info(hal->os, "Dump buffers cleared with FW successfully\n");
8012  }
8013 
8014  return rc;
8015 }
8016 
8017 /**
8018  * @brief Called when the DMTF CLP command completes.
8019  *
8020  * @param hal Hardware context.
8021  * @param status Status field from the mbox completion.
8022  * @param mqe Mailbox response structure.
8023  * @param arg Pointer to a callback argument.
8024  *
8025  * @return None.
8026  *
8027  */
8028 static void
8029 ocs_hal_dmtf_clp_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
8030 {
8031  sli4_cmd_sli_config_t *mbox_rsp = (sli4_cmd_sli_config_t *)mqe;
8033  ocs_hal_clp_cb_arg_t *cb_arg = arg;
8034  char stat_str[8] = { '\0' };
8035  int32_t stat_len = 0;
8036  uint32_t result_len = 0;
8037 
8038  if (clp_rsp->hdr.status)
8039  ocs_hal_log_sli4_rsp_hdr(hal, &clp_rsp->hdr);
8040 
8041  if (!cb_arg || !cb_arg->cb)
8042  goto ocs_hal_dmtf_clp_cb_done;
8043 
8044  if (0 == status) {
8045  if (mbox_rsp->hdr.status)
8046  status = mbox_rsp->hdr.status;
8047  else if (clp_rsp->hdr.status)
8048  status = clp_rsp->hdr.status;
8049  }
8050 
8051  if (0 == status)
8052  result_len = clp_rsp->resp_length;
8053  else
8054  goto ocs_hal_dmtf_clp_invoke_cb;
8055 
8056  if (!result_len || (cb_arg->dma_resp->size < result_len)) {
8057  ocs_log_test(hal->os, "Invalid response length: resp_len=%zu result len=%d\n",
8058  cb_arg->dma_resp->size, result_len);
8059  status = -1;
8060  goto ocs_hal_dmtf_clp_invoke_cb;
8061  }
8062 
8063  /* Parse CLP response to get the status string */
8064  stat_len = ocs_hal_clp_resp_get_value(hal, "status", stat_str, sizeof(stat_str),
8065  cb_arg->dma_resp->virt, result_len);
8066  if (stat_len <= 0) {
8067  ocs_log_test(hal->os, "Failed to get status, status len=%d\n", stat_len);
8068  status = -1;
8069  goto ocs_hal_dmtf_clp_invoke_cb;
8070  }
8071 
8072  if (0 != ocs_strcmp(stat_str, "0")) {
8073  ocs_log_test(hal->os, "CLP status indicates failure=%s\n", stat_str);
8074  status = -1;
8075  }
8076 
8077 ocs_hal_dmtf_clp_invoke_cb:
8078  cb_arg->status = status;
8079  cb_arg->cb(hal, cb_arg->status, result_len, cb_arg->arg);
8080 
8081 ocs_hal_dmtf_clp_cb_done:
8082  if (cb_arg)
8083  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
8084 
8085  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
8086 }
8087 
8088 /**
8089  * @brief Parse the CLP result and get the value corresponding to the given
8090  * keyword.
8091  *
8092  * @param hal Hardware context.
8093  * @param keyword CLP keyword for which the value is returned.
8094  * @param value Location to which the resulting value is copied.
8095  * @param value_len Length of the value parameter.
8096  * @param resp Pointer to the response buffer that is searched
8097  * for the keyword and value.
8098  * @param resp_len Length of response buffer passed in.
8099  *
8100  * @return Returns the number of bytes written to the value
8101  * buffer on success, or a negative vaue on failure.
8102  */
8103 static int32_t
8104 ocs_hal_clp_resp_get_value(ocs_hal_t *hal, const char *keyword, char *value, uint32_t value_len, const char *resp, uint32_t resp_len)
8105 {
8106  char *start = NULL;
8107  char *end = NULL;
8108 
8109  /* look for specified keyword in string */
8110  start = ocs_strstr(resp, keyword);
8111  if (start == NULL) {
8112  ocs_log_test(hal->os, "could not find keyword=%s in CLP response\n",
8113  keyword);
8114  return -1;
8115  }
8116 
8117  /* now look for '=' and go one past */
8118  start = ocs_strchr(start, '=');
8119  if (start == NULL) {
8120  ocs_log_test(hal->os, "could not find \'=\' in CLP response for keyword=%s\n",
8121  keyword);
8122  return -1;
8123  }
8124  start++;
8125 
8126  /* \r\n terminates value */
8127  end = ocs_strstr(start, "\r\n");
8128  if (end == NULL) {
8129  ocs_log_test(hal->os, "could not find \\r\\n for keyword=%s in CLP response\n",
8130  keyword);
8131  return -1;
8132  }
8133 
8134  /* make sure given result array is big enough */
8135  if ((end - start + 1) > value_len) {
8136  ocs_log_test(hal->os, "value len=%d not large enough for actual=%ld\n",
8137  value_len, (end-start));
8138  return -1;
8139  }
8140 
8141  ocs_strncpy(value, start, (end - start));
8142  value[end-start] = '\0';
8143  return (end-start+1);
8144 }
8145 
8146 /**
8147  * @brief Cause chip to enter an unrecoverable error state.
8148  *
8149  * @par Description
8150  * Cause chip to enter an unrecoverable error state. This is
8151  * used when detecting unexpected FW behavior so that the FW can be
8152  * halted from the driver as soon as the error is detected.
8153  *
8154  * @param hal Hardware context.
8155  * @param dump Generate dump as part of reset.
8156  *
8157  * @return Returns 0 on success, or a non-zero value on failure.
8158  *
8159  */
8161 ocs_hal_raise_ue(ocs_hal_t *hal, uint8_t dump)
8162 {
8164 
8165  if (sli_raise_ue(&hal->sli, dump) != 0) {
8166  rc = OCS_HAL_RTN_ERROR;
8167  } else {
8168  if (hal->state != OCS_HAL_STATE_UNINITIALIZED) {
8169  hal->state = OCS_HAL_STATE_QUEUES_ALLOCATED;
8170  }
8171  }
8172 
8173  return rc;
8174 }
8175 
8176 /**
8177  * @brief Called when the OBJECT_GET command completes.
8178  *
8179  * @par Description
8180  * Get the number of bytes actually written out of the response, free the mailbox
8181  * that was malloc'd by ocs_hal_dump_get(), then call the callback
8182  * and pass the status and bytes read.
8183  *
8184  * @param hal Hardware context.
8185  * @param status Status field from the mbox completion.
8186  * @param mqe Mailbox response structure.
8187  * @param arg Pointer to a callback function that signals the caller that the command is done.
8188  * The callback function prototype is <tt>void cb(int32_t status, uint32_t bytes_read)</tt>.
8189  *
8190  * @return Returns 0.
8191  */
8192 static int32_t
8193 ocs_hal_cb_dump_get(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
8194 {
8195  sli4_cmd_sli_config_t *mbox_rsp = (sli4_cmd_sli_config_t *)mqe;
8197  ocs_hal_dump_get_cb_arg_t *cb_arg = arg;
8198  uint32_t bytes_read = rd_obj_rsp->actual_read_length;
8199  uint8_t eof = rd_obj_rsp->eof;
8200 
8201  if (rd_obj_rsp->hdr.status)
8202  ocs_hal_log_sli4_rsp_hdr(hal, &rd_obj_rsp->hdr);
8203 
8204  if (!cb_arg || !cb_arg->cb)
8205  goto ocs_hal_cb_dump_get_done;
8206 
8207  if (0 == status) {
8208  if (mbox_rsp->hdr.status)
8209  status = mbox_rsp->hdr.status;
8210  else if (rd_obj_rsp->hdr.status)
8211  status = rd_obj_rsp->hdr.status;
8212  }
8213 
8214  cb_arg->cb(status, bytes_read, eof, cb_arg->arg);
8215 
8216 ocs_hal_cb_dump_get_done:
8217  if (cb_arg)
8218  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
8219 
8220  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
8221  return 0;
8222 }
8223 
8224 
8225 /**
8226  * @brief Read a dump image to the host.
8227  *
8228  * @par Description
8229  * Creates a SLI_CONFIG mailbox command, fills in the correct values to read a
8230  * dump image chunk, then sends the command with the ocs_hal_command(). On completion,
8231  * the callback function ocs_hal_cb_dump_get() gets called to free the mailbox
8232  * and signal the caller that the read has completed.
8233  *
8234  * @param hal Hardware context.
8235  * @param dma DMA structure to transfer the dump chunk into.
8236  * @param size Size of the dump chunk.
8237  * @param offset Offset, in bytes, from the beginning of the dump.
8238  * @param cb Pointer to a callback function that is called when the command completes.
8239  * The callback function prototype is
8240  * <tt>void cb(int32_t status, uint32_t bytes_read, uint8_t eof, void *arg)</tt>.
8241  * @param arg Pointer to be passed to the callback function.
8242  *
8243  * @return Returns 0 on success, or a non-zero value on failure.
8244  */
8246 ocs_hal_dump_get(ocs_hal_t *hal, ocs_dma_t *dma, uint32_t size, uint32_t offset, ocs_hal_dump_get_cb_t cb, void *arg)
8247 {
8249  uint8_t *mbxdata;
8250  ocs_hal_dump_get_cb_arg_t *cb_arg;
8251  uint32_t opts = (hal->state == OCS_HAL_STATE_ACTIVE ? OCS_CMD_NOWAIT : OCS_CMD_POLL);
8252 
8253  if (SLI4_IF_TYPE_LANCER_FC_ETH != sli_get_if_type(&hal->sli)) {
8254  ocs_log_test(hal->os, "Function only supported for I/F type 2\n");
8255  return OCS_HAL_RTN_ERROR;
8256  }
8257 
8258  if (1 != sli_dump_is_present(&hal->sli)) {
8259  ocs_log_test(hal->os, "No dump is present\n");
8260  return OCS_HAL_RTN_ERROR;
8261  }
8262 
8263  if (1 == sli_reset_required(&hal->sli)) {
8264  ocs_log_test(hal->os, "device reset required\n");
8265  return OCS_HAL_RTN_ERROR;
8266  }
8267 
8268  mbxdata = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
8269  if (mbxdata == NULL) {
8270  ocs_log_err(hal->os, "failed to malloc mbox\n");
8271  return OCS_HAL_RTN_NO_MEMORY;
8272  }
8273 
8274  cb_arg = ocs_malloc(hal->os, sizeof(ocs_hal_dump_get_cb_arg_t), OCS_M_NOWAIT);
8275  if (cb_arg == NULL) {
8276  ocs_log_err(hal->os, "failed to malloc cb_arg\n");
8277  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
8278  return OCS_HAL_RTN_NO_MEMORY;
8279  }
8280 
8281  cb_arg->cb = cb;
8282  cb_arg->arg = arg;
8283  cb_arg->mbox_cmd = mbxdata;
8284 
8285  /* Send the HAL command */
8286  sli_cmd_common_read_object(&hal->sli, mbxdata, SLI4_BMBX_SIZE, size, offset, "/dbg/dump.bin", dma);
8287  rc = ocs_hal_command(hal, mbxdata, opts, ocs_hal_cb_dump_get, cb_arg);
8288  if (rc) {
8289  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
8290  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
8291  } else if (opts == OCS_CMD_POLL) {
8292  /* If we're polling, call the callback here */
8293  rc = ocs_hal_cb_dump_get(hal, 0, mbxdata, cb_arg);
8294  }
8295 
8296  return rc;
8297 }
8298 
8299 /**
8300  * @brief Called when the OBJECT_DELETE command completes.
8301  *
8302  * @par Description
8303  * Free the mailbox that was malloc'd
8304  * by ocs_hal_dump_clear(), then call the callback and pass the status.
8305  *
8306  * @param hal Hardware context.
8307  * @param status Status field from the mbox completion.
8308  * @param mqe Mailbox response structure.
8309  * @param arg Pointer to a callback function that signals the caller that the command is done.
8310  * The callback function prototype is <tt>void cb(int32_t status, void *arg)</tt>.
8311  *
8312  * @return Returns 0.
8313  */
8314 static int32_t
8315 ocs_hal_cb_dump_clear(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
8316 {
8317  sli4_cmd_sli_config_t *mbox_rsp = (sli4_cmd_sli_config_t *)mqe;
8318  ocs_hal_dump_clear_cb_arg_t *cb_arg = arg;
8319 
8320  if (!cb_arg || !cb_arg->cb)
8321  goto ocs_hal_cb_dump_clear_done;
8322 
8323  if ((0 == status) && mbox_rsp->hdr.status)
8324  status = mbox_rsp->hdr.status;
8325 
8326  cb_arg->cb(status, cb_arg->arg);
8327 
8328 ocs_hal_cb_dump_clear_done:
8329  if (cb_arg)
8330  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
8331 
8332  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
8333  return 0;
8334 }
8335 
8336 /**
8337  * @brief Clear a dump image from the device.
8338  *
8339  * @par Description
8340  * Creates a SLI_CONFIG mailbox command, fills it with the correct values to clear
8341  * the dump, then sends the command with ocs_hal_command(). On completion,
8342  * the callback function ocs_hal_cb_dump_clear() gets called to free the mailbox
8343  * and to signal the caller that the write has completed.
8344  *
8345  * @param hal Hardware context.
8346  * @param cb Pointer to a callback function that is called when the command completes.
8347  * The callback function prototype is
8348  * <tt>void cb(int32_t status, uint32_t bytes_written, void *arg)</tt>.
8349  * @param arg Pointer to be passed to the callback function.
8350  *
8351  * @return Returns 0 on success, or a non-zero value on failure.
8352  */
8354 ocs_hal_dump_clear(ocs_hal_t *hal, ocs_hal_dump_clear_cb_t cb, void *arg)
8355 {
8357  uint8_t *mbxdata;
8359  uint32_t opts = (hal->state == OCS_HAL_STATE_ACTIVE ? OCS_CMD_NOWAIT : OCS_CMD_POLL);
8360 
8361  if (SLI4_IF_TYPE_LANCER_FC_ETH != sli_get_if_type(&hal->sli)) {
8362  ocs_log_test(hal->os, "Function only supported for I/F type 2\n");
8363  return OCS_HAL_RTN_ERROR;
8364  }
8365 
8366  mbxdata = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
8367  if (mbxdata == NULL) {
8368  ocs_log_err(hal->os, "failed to malloc mbox\n");
8369  return OCS_HAL_RTN_NO_MEMORY;
8370  }
8371 
8372  cb_arg = ocs_malloc(hal->os, sizeof(ocs_hal_dump_clear_cb_arg_t), OCS_M_NOWAIT);
8373  if (cb_arg == NULL) {
8374  ocs_log_err(hal->os, "failed to malloc cb_arg\n");
8375  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
8376  return OCS_HAL_RTN_NO_MEMORY;
8377  }
8378 
8379  cb_arg->cb = cb;
8380  cb_arg->arg = arg;
8381  cb_arg->mbox_cmd = mbxdata;
8382 
8383  /* Send the HAL command */
8384  sli_cmd_common_delete_object(&hal->sli, mbxdata, SLI4_BMBX_SIZE, "/dbg/dump.bin");
8385  rc = ocs_hal_command(hal, mbxdata, opts, ocs_hal_cb_dump_clear, cb_arg);
8386  if (rc) {
8387  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
8388  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
8389  } else if (opts == OCS_CMD_POLL) {
8390  /* If we're polling, call the callback here */
8391  rc = ocs_hal_cb_dump_clear(hal, 0, mbxdata, cb_arg);
8392  }
8393 
8394  return rc;
8395 }
8396 
8397 typedef struct ocs_hal_get_port_protocol_cb_arg_s {
8399  void *arg;
8400  uint32_t pci_func;
8401  ocs_dma_t payload;
8403 
8404 /**
8405  * @brief Called for the completion of get_port_profile for a
8406  * user request.
8407  *
8408  * @param hal Hardware context.
8409  * @param status The status from the MQE.
8410  * @param mqe Pointer to mailbox command buffer.
8411  * @param arg Pointer to a callback argument.
8412  *
8413  * @return Returns 0 on success, or a non-zero value on failure.
8414  */
8415 static int32_t
8416 ocs_hal_get_port_protocol_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
8417 {
8418  sli4_cmd_sli_config_t *mbox_rsp = (sli4_cmd_sli_config_t *)mqe;
8419  sli4_res_common_get_profile_config_t *sli4_rsp = NULL;
8420  ocs_hal_get_port_protocol_cb_arg_t *cb_arg = arg;
8421  ocs_dma_t *payload = NULL;
8425  int i, num_descriptors;
8426 
8427  if (!cb_arg || !cb_arg->cb)
8428  goto ocs_hal_get_port_protocol_cb_done;
8429 
8430  payload = &cb_arg->payload;
8431  sli4_rsp = (sli4_res_common_get_profile_config_t *)payload->virt;
8432  if (sli4_rsp->hdr.status)
8433  ocs_hal_log_sli4_rsp_hdr(hal, &sli4_rsp->hdr);
8434 
8435  num_descriptors = sli4_rsp->desc_count;
8436  desc_p = (sli4_resource_descriptor_v1_t *)sli4_rsp->desc;
8437  for (i = 0; i < num_descriptors; i++) {
8439  pcie_desc_p = (sli4_pcie_resource_descriptor_v1_t *)desc_p;
8440  if (pcie_desc_p->pf_number == cb_arg->pci_func) {
8441  switch(pcie_desc_p->pf_type) {
8442  case 0x02:
8443  port_protocol = OCS_HAL_PORT_PROTOCOL_ISCSI;
8444  break;
8445  case 0x04:
8446  port_protocol = OCS_HAL_PORT_PROTOCOL_FCOE;
8447  break;
8448  case 0x10:
8449  port_protocol = OCS_HAL_PORT_PROTOCOL_FC;
8450  break;
8451  }
8452  }
8453  }
8454 
8455  desc_p = (sli4_resource_descriptor_v1_t *)((uint8_t *)desc_p + desc_p->descriptor_length);
8456  }
8457 
8458  if (0 == status) {
8459  if (mbox_rsp->hdr.status)
8460  status = mbox_rsp->hdr.status;
8461  else if (sli4_rsp->hdr.status)
8462  status = sli4_rsp->hdr.status;
8463  }
8464 
8465  cb_arg->cb(status, port_protocol, cb_arg->arg);
8466 
8467 ocs_hal_get_port_protocol_cb_done:
8468  if (cb_arg) {
8469  ocs_dma_free(hal->os, &cb_arg->payload);
8470  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
8471  }
8472 
8473  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
8474  return 0;
8475 }
8476 
8477 /**
8478  * @ingroup io
8479  * @brief Get the current port protocol.
8480  * @par Description
8481  * Issues a SLI4 COMMON_GET_PROFILE_CONFIG mailbox. When the
8482  * command completes the provided mgmt callback function is
8483  * called.
8484  *
8485  * @param hal Hardware context.
8486  * @param pci_func PCI function to query for current protocol.
8487  * @param cb Callback function to be called when the command completes.
8488  * @param ul_arg An argument that is passed to the callback function.
8489  *
8490  * @return
8491  * - OCS_HAL_RTN_SUCCESS on success.
8492  * - OCS_HAL_RTN_NO_MEMORY if a malloc fails.
8493  * - OCS_HAL_RTN_NO_RESOURCES if unable to get a command
8494  * context.
8495  * - OCS_HAL_RTN_ERROR on any other error.
8496  */
8498 ocs_hal_get_port_protocol(ocs_hal_t *hal, uint32_t pci_func,
8499  ocs_get_port_protocol_cb_t cb, void* ul_arg)
8500 {
8501  uint8_t *mbxdata;
8504 
8505  /* Only supported on Skyhawk */
8506  if (sli_get_if_type(&hal->sli) != SLI4_IF_TYPE_BE3_SKH_PF) {
8507  return OCS_HAL_RTN_ERROR;
8508  }
8509 
8510  /* mbxdata holds the header of the command */
8511  mbxdata = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
8512  if (mbxdata == NULL) {
8513  ocs_log_err(hal->os, "failed to malloc mbox\n");
8514  return OCS_HAL_RTN_NO_MEMORY;
8515  }
8516 
8517 
8518  /* cb_arg holds the data that will be passed to the callback on completion */
8519  cb_arg = ocs_malloc(hal->os, sizeof(ocs_hal_get_port_protocol_cb_arg_t), OCS_M_NOWAIT);
8520  if (cb_arg == NULL) {
8521  ocs_log_err(hal->os, "failed to malloc cb_arg\n");
8522  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
8523  return OCS_HAL_RTN_NO_MEMORY;
8524  }
8525 
8526  cb_arg->cb = cb;
8527  cb_arg->arg = ul_arg;
8528  cb_arg->pci_func = pci_func;
8529 
8530  /* dma_mem holds the non-embedded portion */
8531  if (ocs_dma_alloc(hal->os, &cb_arg->payload, 4096, 4)) {
8532  ocs_log_err(hal->os, "Failed to allocate DMA buffer\n");
8533  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
8534  ocs_free(hal->os, cb_arg, sizeof(ocs_hal_get_port_protocol_cb_arg_t));
8535  return OCS_HAL_RTN_NO_MEMORY;
8536  }
8537 
8538  /* Send the HAL command */
8539  sli_cmd_common_get_profile_config(&hal->sli, mbxdata, SLI4_BMBX_SIZE, &cb_arg->payload);
8540  rc = ocs_hal_command(hal, mbxdata, OCS_CMD_NOWAIT, ocs_hal_get_port_protocol_cb, cb_arg);
8541  if (rc) {
8542  ocs_dma_free(hal->os, &cb_arg->payload);
8543  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
8544  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
8545  }
8546 
8547  return rc;
8548 
8549 }
8550 
8551 typedef struct ocs_hal_set_port_protocol_cb_arg_s {
8553  void *arg;
8554  ocs_dma_t payload;
8555  uint32_t new_protocol;
8556  uint32_t pci_func;
8558 
8559 /**
8560  * @brief Called for the completion of set_port_profile for a
8561  * user request.
8562  *
8563  * @par Description
8564  * This is the second of two callbacks for the set_port_protocol
8565  * function. The set operation is a read-modify-write. This
8566  * callback is called when the write (SET_PROFILE_CONFIG)
8567  * completes.
8568  *
8569  * @param hal Hardware context.
8570  * @param status The status from the MQE.
8571  * @param mqe Pointer to mailbox command buffer.
8572  * @param arg Pointer to a callback argument.
8573  *
8574  * @return 0 on success, non-zero otherwise
8575  */
8576 static int32_t
8577 ocs_hal_set_port_protocol_cb2(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
8578 {
8579  sli4_cmd_sli_config_t *mbox_rsp = (sli4_cmd_sli_config_t *)mqe;
8580  sli4_res_common_set_profile_config_t *sli4_rsp = NULL;
8581  ocs_hal_set_port_protocol_cb_arg_t *cb_arg = arg;
8582  ocs_dma_t *payload = NULL;
8583 
8584  if (!cb_arg || !cb_arg->cb)
8585  goto ocs_hal_set_port_protocol_cb2_done;
8586 
8587  payload = &cb_arg->payload;
8588  sli4_rsp = (sli4_res_common_set_profile_config_t *)payload->virt;
8589  if (sli4_rsp->hdr.status)
8590  ocs_hal_log_sli4_rsp_hdr(hal, &sli4_rsp->hdr);
8591 
8592  if (0 == status) {
8593  if (mbox_rsp->hdr.status)
8594  status = mbox_rsp->hdr.status;
8595  else if (sli4_rsp->hdr.status)
8596  status = sli4_rsp->hdr.status;
8597  }
8598 
8599  cb_arg->cb(status, cb_arg->arg);
8600 
8601 ocs_hal_set_port_protocol_cb2_done:
8602  if (cb_arg) {
8603  ocs_dma_free(hal->os, &cb_arg->payload);
8604  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
8605  }
8606 
8607  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
8608  return 0;
8609 }
8610 
8611 /**
8612  * @brief Called for the completion of set_port_profile for a
8613  * user request.
8614  *
8615  * @par Description
8616  * This is the first of two callbacks for the set_port_protocol
8617  * function. The set operation is a read-modify-write. This
8618  * callback is called when the read completes
8619  * (GET_PROFILE_CONFG). It will updated the resource
8620  * descriptors, then queue the write (SET_PROFILE_CONFIG).
8621  *
8622  * On entry there are three memory areas that were allocated by
8623  * ocs_hal_set_port_protocol. If a failure is detected in this
8624  * function those need to be freed. If this function succeeds
8625  * it allocates three more areas.
8626  *
8627  * @param hal Hardware context.
8628  * @param status The status from the MQE
8629  * @param mqe Pointer to mailbox command buffer.
8630  * @param arg Pointer to a callback argument.
8631  *
8632  * @return Returns 0 on success, or a non-zero value otherwise.
8633  */
8634 static int32_t
8635 ocs_hal_set_port_protocol_cb1(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
8636 {
8637  ocs_hal_set_port_protocol_cb_arg_t *cb_arg = arg;
8639  ocs_dma_t *payload = &cb_arg->payload;
8643  sli4_isap_resouce_descriptor_v1_t *isap_desc_p;
8645  uint8_t *dst, *mbxdata;
8646  int i, num_descriptors = response->desc_count;
8647  int pci_descriptor_count = 0;
8648  int num_fcoe_ports = 0;
8649  int num_iscsi_ports = 0;
8651 
8652  /* Count PCI descriptors */
8653  for (i = 0; i < num_descriptors; i++) {
8654  if (SLI4_RESOURCE_DESCRIPTOR_TYPE_PCIE == desc_p->descriptor_type)
8655  ++pci_descriptor_count;
8656 
8657  desc_p = (sli4_resource_descriptor_v1_t *)((uint8_t *)desc_p + desc_p->descriptor_length);
8658  }
8659 
8660  /* mbxdata holds the header of the command */
8661  mbxdata = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
8662  if (!mbxdata) {
8663  ocs_log_err(hal->os, "Failed to malloc mbox\n");
8664  return OCS_HAL_RTN_NO_MEMORY;
8665  }
8666 
8667  /* cb_arg holds the data that will be passed to the callback on completion */
8668  new_cb_arg = ocs_malloc(hal->os, sizeof(*new_cb_arg), OCS_M_NOWAIT);
8669  if (!new_cb_arg) {
8670  ocs_log_err(hal->os, "Failed to malloc cb_arg\n");
8671  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
8672  return OCS_HAL_RTN_NO_MEMORY;
8673  }
8674 
8675  new_cb_arg->cb = cb_arg->cb;
8676  new_cb_arg->arg = cb_arg->arg;
8677 
8678  /**
8679  * Allocate memory for the descriptors we're going to send.
8680  * i.e. one for each PCI descriptor plus one ISAP descriptor.
8681  */
8682  if (ocs_dma_alloc(hal->os, &new_cb_arg->payload, sizeof(sli4_req_common_set_profile_config_t) +
8683  (pci_descriptor_count * sizeof(sli4_pcie_resource_descriptor_v1_t)) +
8684  sizeof(sli4_isap_resouce_descriptor_v1_t), 4)) {
8685  ocs_log_err(hal->os, "Failed to allocate DMA buffer\n");
8686  ocs_free(hal->os, new_cb_arg, sizeof(*new_cb_arg));
8687  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
8688  return OCS_HAL_RTN_NO_MEMORY;
8689  }
8690 
8692  &new_cb_arg->payload, 0, pci_descriptor_count+1, 1);
8693 
8694  /* Point dst to the first descriptor entry in the SET_PROFILE_CONFIG command */
8695  dst = (uint8_t *)&(((sli4_req_common_set_profile_config_t *)new_cb_arg->payload.virt)->desc);
8696 
8697  /**
8698  * Loop over all descriptors. If the descriptor is a PCIe descriptor, copy it
8699  * to the SET_PROFILE_CONFIG command to be written back. If it's the descriptor
8700  * that we're trying to change, set its pf_type as well.
8701  */
8702  desc_p = (sli4_resource_descriptor_v1_t *)response->desc;
8703  for (i = 0; i < num_descriptors; i++) {
8704  if (SLI4_RESOURCE_DESCRIPTOR_TYPE_PCIE == desc_p->descriptor_type) {
8705  pcie_desc_p = (sli4_pcie_resource_descriptor_v1_t *)desc_p;
8706  if (pcie_desc_p->pf_number == cb_arg->pci_func) {
8707  /**
8708  * This is the PCIe descriptor for this OCS instance.
8709  * Update it with the new pf_type.
8710  */
8711  switch(new_protocol) {
8713  pcie_desc_p->pf_type = SLI4_PROTOCOL_FC;
8714  break;
8716  pcie_desc_p->pf_type = SLI4_PROTOCOL_FCOE;
8717  break;
8719  pcie_desc_p->pf_type = SLI4_PROTOCOL_ISCSI;
8720  break;
8721  default:
8722  pcie_desc_p->pf_type = SLI4_PROTOCOL_DEFAULT;
8723  break;
8724  }
8725  }
8726 
8727  if (SLI4_PROTOCOL_FCOE == pcie_desc_p->pf_type)
8728  ++num_fcoe_ports;
8729 
8730  if (SLI4_PROTOCOL_ISCSI == pcie_desc_p->pf_type)
8731  ++num_iscsi_ports;
8732 
8733  ocs_memcpy(dst, pcie_desc_p, sizeof(*pcie_desc_p));
8734  dst += sizeof(*pcie_desc_p);
8735  }
8736 
8737  desc_p = (sli4_resource_descriptor_v1_t *)((uint8_t *)desc_p + desc_p->descriptor_length);
8738  }
8739 
8740  /* Create an ISAP resource descriptor */
8741  isap_desc_p = (sli4_isap_resouce_descriptor_v1_t *)dst;
8744  if (num_iscsi_ports > 0) {
8745  isap_desc_p->iscsi_tgt = 1;
8746  isap_desc_p->iscsi_ini = 1;
8747  isap_desc_p->iscsi_dif = 1;
8748  }
8749  if (num_fcoe_ports > 0) {
8750  isap_desc_p->fcoe_tgt = 1;
8751  isap_desc_p->fcoe_ini = 1;
8752  isap_desc_p->fcoe_dif = 1;
8753  }
8754 
8755  /* At this point we're done with the memory allocated by ocs_port_set_protocol */
8756  ocs_dma_free(hal->os, &cb_arg->payload);
8757  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
8758  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
8759 
8760  /* Send a SET_PROFILE_CONFIG mailbox command with the new descriptors */
8761  rc = ocs_hal_command(hal, mbxdata, OCS_CMD_NOWAIT, ocs_hal_set_port_protocol_cb2, new_cb_arg);
8762  if (rc) {
8763  /* Call the upper level callback to report a failure */
8764  if (new_cb_arg->cb)
8765  new_cb_arg->cb(rc, new_cb_arg->arg);
8766 
8767  /* Free the memory allocated by this function */
8768  ocs_dma_free(hal->os, &new_cb_arg->payload);
8769  ocs_free(hal->os, new_cb_arg, sizeof(*new_cb_arg));
8770  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
8771  }
8772 
8773  return rc;
8774 }
8775 
8776 /**
8777  * @ingroup io
8778  * @brief Set the port protocol.
8779  * @par Description
8780  * Setting the port protocol is a read-modify-write operation.
8781  * This function submits a GET_PROFILE_CONFIG command to read
8782  * the current settings. The callback function will modify the
8783  * settings and issue the write.
8784  *
8785  * On successful completion this function will have allocated
8786  * two regular memory areas and one dma area which will need to
8787  * get freed later in the callbacks.
8788  *
8789  * @param hal Hardware context.
8790  * @param new_protocol New protocol to use.
8791  * @param pci_func PCI function to configure.
8792  * @param cb Callback function to be called when the command completes.
8793  * @param ul_arg An argument that is passed to the callback function.
8794  *
8795  * @return
8796  * - OCS_HAL_RTN_SUCCESS on success.
8797  * - OCS_HAL_RTN_NO_MEMORY if a malloc fails.
8798  * - OCS_HAL_RTN_NO_RESOURCES if unable to get a command
8799  * context.
8800  * - OCS_HAL_RTN_ERROR on any other error.
8801  */
8804  uint32_t pci_func, ocs_set_port_protocol_cb_t cb, void *ul_arg)
8805 {
8806  uint8_t *mbxdata;
8809 
8810  /* Only supported on Skyhawk */
8811  if (sli_get_if_type(&hal->sli) != SLI4_IF_TYPE_BE3_SKH_PF) {
8812  return OCS_HAL_RTN_ERROR;
8813  }
8814 
8815  /* mbxdata holds the header of the command */
8816  mbxdata = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
8817  if (mbxdata == NULL) {
8818  ocs_log_err(hal->os, "failed to malloc mbox\n");
8819  return OCS_HAL_RTN_NO_MEMORY;
8820  }
8821 
8822 
8823  /* cb_arg holds the data that will be passed to the callback on completion */
8824  cb_arg = ocs_malloc(hal->os, sizeof(ocs_hal_set_port_protocol_cb_arg_t), OCS_M_NOWAIT);
8825  if (cb_arg == NULL) {
8826  ocs_log_err(hal->os, "failed to malloc cb_arg\n");
8827  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
8828  return OCS_HAL_RTN_NO_MEMORY;
8829  }
8830 
8831  cb_arg->cb = cb;
8832  cb_arg->arg = ul_arg;
8833  cb_arg->new_protocol = new_protocol;
8834  cb_arg->pci_func = pci_func;
8835 
8836  /* dma_mem holds the non-embedded portion */
8837  if (ocs_dma_alloc(hal->os, &cb_arg->payload, 4096, 4)) {
8838  ocs_log_err(hal->os, "Failed to allocate DMA buffer\n");
8839  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
8840  ocs_free(hal->os, cb_arg, sizeof(ocs_hal_get_port_protocol_cb_arg_t));
8841  return OCS_HAL_RTN_NO_MEMORY;
8842  }
8843 
8844  /* Send the HAL command */
8845  sli_cmd_common_get_profile_config(&hal->sli, mbxdata, SLI4_BMBX_SIZE, &cb_arg->payload);
8846  rc = ocs_hal_command(hal, mbxdata, OCS_CMD_NOWAIT, ocs_hal_set_port_protocol_cb1, cb_arg);
8847  if (rc) {
8848  ocs_dma_free(hal->os, &cb_arg->payload);
8849  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
8850  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
8851  }
8852 
8853  return rc;
8854 }
8855 
8856 typedef struct ocs_hal_get_profile_list_cb_arg_s {
8858  void *arg;
8859  ocs_dma_t payload;
8861 
8862 /**
8863  * @brief Called for the completion of get_profile_list for a
8864  * user request.
8865  * @par Description
8866  * This function is called when the COMMMON_GET_PROFILE_LIST
8867  * mailbox completes. The response will be in
8868  * ctx->non_embedded_mem.virt. This function parses the
8869  * response and creates a ocs_hal_profile_list, then calls the
8870  * mgmt_cb callback function and passes that list to it.
8871  *
8872  * @param hal Hardware context.
8873  * @param status The status from the MQE
8874  * @param mqe Pointer to mailbox command buffer.
8875  * @param arg Pointer to a callback argument.
8876  *
8877  * @return Returns 0 on success, or a non-zero value on failure.
8878  */
8879 static int32_t
8880 ocs_hal_get_profile_list_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
8881 {
8882  sli4_cmd_sli_config_t *mbox_rsp = (sli4_cmd_sli_config_t *)mqe;
8883  sli4_res_common_get_profile_list_t *sli4_rsp = NULL;
8884  ocs_hal_get_profile_list_cb_arg_t *cb_arg = arg;
8885  ocs_dma_t *payload = NULL;
8886  ocs_hal_profile_list_t *list;
8887  int i, num_descriptors;
8888 
8889  if (!cb_arg || !cb_arg->cb)
8890  goto ocs_hal_get_profile_list_cb_done;
8891 
8892  payload = &cb_arg->payload;
8893  sli4_rsp = (sli4_res_common_get_profile_list_t *)payload->virt;
8894  if (sli4_rsp->hdr.status)
8895  ocs_hal_log_sli4_rsp_hdr(hal, &sli4_rsp->hdr);
8896 
8897  list = ocs_malloc(hal->os, sizeof(*list), OCS_M_ZERO);
8898  ocs_hal_assert(list);
8899 
8900  list->num_descriptors = sli4_rsp->profile_descriptor_count;
8901  num_descriptors = list->num_descriptors;
8902  if (num_descriptors > OCS_HAL_MAX_PROFILES)
8903  num_descriptors = OCS_HAL_MAX_PROFILES;
8904 
8905  for (i = 0; i < num_descriptors; i++) {
8906  list->descriptors[i].profile_id = sli4_rsp->profile_descriptor[i].profile_id;
8908  ocs_strcpy(list->descriptors[i].profile_description,
8909  (char *)sli4_rsp->profile_descriptor[i].profile_description);
8910  }
8911 
8912  if (0 == status) {
8913  if (mbox_rsp->hdr.status)
8914  status = mbox_rsp->hdr.status;
8915  else if (sli4_rsp->hdr.status)
8916  status = sli4_rsp->hdr.status;
8917  }
8918 
8919  cb_arg->cb(status, list, cb_arg->arg);
8920  if (status)
8921  ocs_free(hal->os, list, sizeof(*list));
8922 
8923 ocs_hal_get_profile_list_cb_done:
8924  if (cb_arg) {
8925  ocs_dma_free(hal->os, &cb_arg->payload);
8926  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
8927  }
8928 
8929  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
8930  return 0;
8931 }
8932 
8933 /**
8934  * @ingroup io
8935  * @brief Get a list of available profiles.
8936  * @par Description
8937  * Issues a SLI-4 COMMON_GET_PROFILE_LIST mailbox. When the
8938  * command completes the provided mgmt callback function is
8939  * called.
8940  *
8941  * @param hal Hardware context.
8942  * @param cb Callback function to be called when the
8943  * command completes.
8944  * @param ul_arg An argument that is passed to the callback
8945  * function.
8946  *
8947  * @return
8948  * - OCS_HAL_RTN_SUCCESS on success.
8949  * - OCS_HAL_RTN_NO_MEMORY if a malloc fails.
8950  * - OCS_HAL_RTN_NO_RESOURCES if unable to get a command
8951  * context.
8952  * - OCS_HAL_RTN_ERROR on any other error.
8953  */
8955 ocs_hal_get_profile_list(ocs_hal_t *hal, ocs_get_profile_list_cb_t cb, void* ul_arg)
8956 {
8957  uint8_t *mbxdata;
8960 
8961  /* Only supported on Skyhawk */
8962  if (sli_get_if_type(&hal->sli) != SLI4_IF_TYPE_BE3_SKH_PF) {
8963  return OCS_HAL_RTN_ERROR;
8964  }
8965 
8966  /* mbxdata holds the header of the command */
8967  mbxdata = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
8968  if (mbxdata == NULL) {
8969  ocs_log_err(hal->os, "failed to malloc mbox\n");
8970  return OCS_HAL_RTN_NO_MEMORY;
8971  }
8972 
8973 
8974  /* cb_arg holds the data that will be passed to the callback on completion */
8975  cb_arg = ocs_malloc(hal->os, sizeof(ocs_hal_get_profile_list_cb_arg_t), OCS_M_NOWAIT);
8976  if (cb_arg == NULL) {
8977  ocs_log_err(hal->os, "failed to malloc cb_arg\n");
8978  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
8979  return OCS_HAL_RTN_NO_MEMORY;
8980  }
8981 
8982  cb_arg->cb = cb;
8983  cb_arg->arg = ul_arg;
8984 
8985  /* dma_mem holds the non-embedded portion */
8986  if (ocs_dma_alloc(hal->os, &cb_arg->payload, sizeof(sli4_res_common_get_profile_list_t), 4)) {
8987  ocs_log_err(hal->os, "Failed to allocate DMA buffer\n");
8988  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
8989  ocs_free(hal->os, cb_arg, sizeof(ocs_hal_get_profile_list_cb_arg_t));
8990  return OCS_HAL_RTN_NO_MEMORY;
8991  }
8992 
8993  /* Send the HAL command */
8994  sli_cmd_common_get_profile_list(&hal->sli, mbxdata, SLI4_BMBX_SIZE, 0, &cb_arg->payload);
8995  rc = ocs_hal_command(hal, mbxdata, OCS_CMD_NOWAIT, ocs_hal_get_profile_list_cb, cb_arg);
8996  if (rc) {
8997  ocs_dma_free(hal->os, &cb_arg->payload);
8998  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
8999  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
9000  }
9001 
9002  return rc;
9003 }
9004 
9005 typedef struct ocs_hal_get_active_profile_cb_arg_s {
9007  void *arg;
9009 
9010 /**
9011  * @brief Called for the completion of get_active_profile for a
9012  * user request.
9013  *
9014  * @param hal Hardware context.
9015  * @param status The status from the MQE
9016  * @param mqe Pointer to mailbox command buffer.
9017  * @param arg Pointer to a callback argument.
9018  *
9019  * @return Returns 0 on success, or a non-zero value on failure.
9020  */
9021 static int32_t
9022 ocs_hal_get_active_profile_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
9023 {
9024  sli4_cmd_sli_config_t *mbox_rsp = (sli4_cmd_sli_config_t *)mqe;
9025  sli4_res_common_get_active_profile_t *sli4_rsp = NULL;
9027  uint32_t active_profile;
9028 
9029  sli4_rsp = (sli4_res_common_get_active_profile_t *)mbox_rsp->payload.embed;
9030  if (sli4_rsp->hdr.status)
9031  ocs_hal_log_sli4_rsp_hdr(hal, &sli4_rsp->hdr);
9032 
9033  if (!cb_arg || !cb_arg->cb)
9034  goto ocs_hal_get_active_profile_cb_done;
9035 
9036  active_profile = sli4_rsp->active_profile_id;
9037 
9038  if (0 == status) {
9039  if (mbox_rsp->hdr.status)
9040  status = mbox_rsp->hdr.status;
9041  else if (sli4_rsp->hdr.status)
9042  status = sli4_rsp->hdr.status;
9043  }
9044 
9045  cb_arg->cb(status, active_profile, cb_arg->arg);
9046 
9047 ocs_hal_get_active_profile_cb_done:
9048  if (cb_arg)
9049  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
9050 
9051  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
9052  return 0;
9053 }
9054 
9055 /**
9056  * @ingroup io
9057  * @brief Get the currently active profile.
9058  * @par Description
9059  * Issues a SLI-4 COMMON_GET_ACTIVE_PROFILE mailbox. When the
9060  * command completes the provided mgmt callback function is
9061  * called.
9062  *
9063  * @param hal Hardware context.
9064  * @param cb Callback function to be called when the
9065  * command completes.
9066  * @param ul_arg An argument that is passed to the callback
9067  * function.
9068  *
9069  * @return
9070  * - OCS_HAL_RTN_SUCCESS on success.
9071  * - OCS_HAL_RTN_NO_MEMORY if a malloc fails.
9072  * - OCS_HAL_RTN_NO_RESOURCES if unable to get a command
9073  * context.
9074  * - OCS_HAL_RTN_ERROR on any other error.
9075  */
9076 int32_t
9078 {
9079  uint8_t *mbxdata;
9082 
9083  /* Only supported on Skyhawk */
9084  if (sli_get_if_type(&hal->sli) != SLI4_IF_TYPE_BE3_SKH_PF) {
9085  return OCS_HAL_RTN_ERROR;
9086  }
9087 
9088  /* mbxdata holds the header of the command */
9089  mbxdata = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
9090  if (mbxdata == NULL) {
9091  ocs_log_err(hal->os, "failed to malloc mbox\n");
9092  return OCS_HAL_RTN_NO_MEMORY;
9093  }
9094 
9095  /* cb_arg holds the data that will be passed to the callback on completion */
9096  cb_arg = ocs_malloc(hal->os, sizeof(ocs_hal_get_active_profile_cb_arg_t), OCS_M_NOWAIT);
9097  if (cb_arg == NULL) {
9098  ocs_log_err(hal->os, "failed to malloc cb_arg\n");
9099  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
9100  return OCS_HAL_RTN_NO_MEMORY;
9101  }
9102 
9103  cb_arg->cb = cb;
9104  cb_arg->arg = ul_arg;
9105 
9106  /* Send the HAL command */
9108  rc = ocs_hal_command(hal, mbxdata, OCS_CMD_NOWAIT, ocs_hal_get_active_profile_cb, cb_arg);
9109  if (rc) {
9110  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
9111  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
9112  }
9113 
9114  return rc;
9115 }
9116 
9117 typedef struct ocs_hal_get_nvparms_cb_arg_s {
9119  void *arg;
9121 
9122 /**
9123  * @brief Called for the completion of get_nvparms for a
9124  * user request.
9125  *
9126  * @param hal Hardware context.
9127  * @param status The status from the MQE.
9128  * @param mqe Pointer to mailbox command buffer.
9129  * @param arg Pointer to a callback argument.
9130  *
9131  * @return 0 on success, non-zero otherwise
9132  */
9133 static int32_t
9134 ocs_hal_get_nvparms_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
9135 {
9137  ocs_hal_get_nvparms_cb_arg_t *cb_arg = arg;
9138 
9139  if (!cb_arg || !cb_arg->cb)
9140  goto ocs_hal_get_nvparms_cb_done;
9141 
9142  if ((0 == status) && mbox_rsp->hdr.status)
9143  status = mbox_rsp->hdr.status;
9144 
9145  cb_arg->cb(status, mbox_rsp->wwpn, mbox_rsp->wwnn, mbox_rsp->hard_alpa,
9146  mbox_rsp->preferred_d_id, cb_arg->arg);
9147 
9148 ocs_hal_get_nvparms_cb_done:
9149  if (cb_arg)
9150  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
9151 
9152  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
9153  return 0;
9154 }
9155 
9156 /**
9157  * @ingroup io
9158  * @brief Read non-volatile parms.
9159  * @par Description
9160  * Issues a SLI-4 READ_NVPARMS mailbox. When the
9161  * command completes the provided mgmt callback function is
9162  * called.
9163  *
9164  * @param hal Hardware context.
9165  * @param cb Callback function to be called when the
9166  * command completes.
9167  * @param ul_arg An argument that is passed to the callback
9168  * function.
9169  *
9170  * @return
9171  * - OCS_HAL_RTN_SUCCESS on success.
9172  * - OCS_HAL_RTN_NO_MEMORY if a malloc fails.
9173  * - OCS_HAL_RTN_NO_RESOURCES if unable to get a command
9174  * context.
9175  * - OCS_HAL_RTN_ERROR on any other error.
9176  */
9177 int32_t
9178 ocs_hal_get_nvparms(ocs_hal_t *hal, ocs_get_nvparms_cb_t cb, void* ul_arg)
9179 {
9180  uint8_t *mbxdata;
9183 
9184  /* mbxdata holds the header of the command */
9185  mbxdata = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
9186  if (mbxdata == NULL) {
9187  ocs_log_err(hal->os, "failed to malloc mbox\n");
9188  return OCS_HAL_RTN_NO_MEMORY;
9189  }
9190 
9191  /* cb_arg holds the data that will be passed to the callback on completion */
9192  cb_arg = ocs_malloc(hal->os, sizeof(ocs_hal_get_nvparms_cb_arg_t), OCS_M_NOWAIT);
9193  if (cb_arg == NULL) {
9194  ocs_log_err(hal->os, "failed to malloc cb_arg\n");
9195  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
9196  return OCS_HAL_RTN_NO_MEMORY;
9197  }
9198 
9199  cb_arg->cb = cb;
9200  cb_arg->arg = ul_arg;
9201 
9202  /* Send the HAL command */
9203  sli_cmd_read_nvparms(&hal->sli, mbxdata, SLI4_BMBX_SIZE);
9204  rc = ocs_hal_command(hal, mbxdata, OCS_CMD_NOWAIT, ocs_hal_get_nvparms_cb, cb_arg);
9205  if (rc) {
9206  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
9207  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
9208  }
9209 
9210  return rc;
9211 }
9212 
9213 typedef struct ocs_hal_set_nvparms_cb_arg_s {
9215  void *arg;
9217 
9218 /**
9219  * @brief Called for the completion of set_nvparms for a
9220  * user request.
9221  *
9222  * @param hal Hardware context.
9223  * @param status The status from the MQE.
9224  * @param mqe Pointer to mailbox command buffer.
9225  * @param arg Pointer to a callback argument.
9226  *
9227  * @return Returns 0 on success, or a non-zero value on failure.
9228  */
9229 static int32_t
9230 ocs_hal_set_nvparms_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
9231 {
9233  ocs_hal_set_nvparms_cb_arg_t *cb_arg = arg;
9234 
9235  if (!cb_arg || !cb_arg->cb)
9236  goto ocs_hal_set_nvparms_cb_done;
9237 
9238  if ((0 == status) && mbox_rsp->hdr.status)
9239  status = mbox_rsp->hdr.status;
9240 
9241  cb_arg->cb(status, cb_arg->arg);
9242 
9243 ocs_hal_set_nvparms_cb_done:
9244  if (cb_arg)
9245  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
9246 
9247  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
9248  return 0;
9249 }
9250 
9251 /**
9252  * @ingroup io
9253  * @brief Write non-volatile parms.
9254  * @par Description
9255  * Issues a SLI-4 WRITE_NVPARMS mailbox. When the
9256  * command completes the provided mgmt callback function is
9257  * called.
9258  *
9259  * @param hal Hardware context.
9260  * @param cb Callback function to be called when the
9261  * command completes.
9262  * @param wwpn Port's WWPN in big-endian order, or NULL to use default.
9263  * @param wwnn Port's WWNN in big-endian order, or NULL to use default.
9264  * @param hard_alpa A hard AL_PA address setting used during loop
9265  * initialization. If no hard AL_PA is required, set to 0.
9266  * @param preferred_d_id A preferred D_ID address setting
9267  * that may be overridden with the CONFIG_LINK mailbox command.
9268  * If there is no preference, set to 0.
9269  * @param ul_arg An argument that is passed to the callback
9270  * function.
9271  *
9272  * @return
9273  * - OCS_HAL_RTN_SUCCESS on success.
9274  * - OCS_HAL_RTN_NO_MEMORY if a malloc fails.
9275  * - OCS_HAL_RTN_NO_RESOURCES if unable to get a command
9276  * context.
9277  * - OCS_HAL_RTN_ERROR on any other error.
9278  */
9279 int32_t
9280 ocs_hal_set_nvparms(ocs_hal_t *hal, ocs_set_nvparms_cb_t cb, uint8_t *wwpn,
9281  uint8_t *wwnn, uint8_t hard_alpa, uint32_t preferred_d_id, void* ul_arg)
9282 {
9283  uint8_t *mbxdata;
9286 
9287  /* mbxdata holds the header of the command */
9288  mbxdata = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
9289  if (mbxdata == NULL) {
9290  ocs_log_err(hal->os, "failed to malloc mbox\n");
9291  return OCS_HAL_RTN_NO_MEMORY;
9292  }
9293 
9294  /* cb_arg holds the data that will be passed to the callback on completion */
9295  cb_arg = ocs_malloc(hal->os, sizeof(ocs_hal_set_nvparms_cb_arg_t), OCS_M_NOWAIT);
9296  if (cb_arg == NULL) {
9297  ocs_log_err(hal->os, "failed to malloc cb_arg\n");
9298  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
9299  return OCS_HAL_RTN_NO_MEMORY;
9300  }
9301 
9302  cb_arg->cb = cb;
9303  cb_arg->arg = ul_arg;
9304 
9305  /* Send the HAL command */
9306  sli_cmd_write_nvparms(&hal->sli, mbxdata, SLI4_BMBX_SIZE, wwpn, wwnn, hard_alpa, preferred_d_id);
9307  rc = ocs_hal_command(hal, mbxdata, OCS_CMD_NOWAIT, ocs_hal_set_nvparms_cb, cb_arg);
9308  if (rc) {
9309  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
9310  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
9311  }
9312 
9313  return rc;
9314 }
9315 
9316 /**
9317  * @brief Called to obtain the count for the specified type.
9318  *
9319  * @param hal Hardware context.
9320  * @param io_count_type IO count type (inuse, free, wait_free).
9321  *
9322  * @return Returns the number of IOs on the specified list type.
9323  */
9324 uint32_t
9325 ocs_hal_io_get_count(ocs_hal_t *hal, ocs_hal_io_count_type_e io_count_type)
9326 {
9327  ocs_hal_io_t *io = NULL;
9328  uint32_t count = 0;
9329 
9330  ocs_lock(&hal->io_lock);
9331 
9332  switch (io_count_type) {
9333  case OCS_HAL_IO_INUSE_COUNT :
9334  ocs_list_foreach(&hal->io_inuse, io) {
9335  count++;
9336  }
9337  break;
9338  case OCS_HAL_IO_FREE_COUNT :
9339  ocs_list_foreach(&hal->io_free, io) {
9340  count++;
9341  }
9342  break;
9344  ocs_list_foreach(&hal->io_wait_free, io) {
9345  count++;
9346  }
9347  break;
9349  ocs_list_foreach(&hal->io_port_owned, io) {
9350  count++;
9351  }
9352  break;
9354  count = hal->config.n_io;
9355  break;
9356  }
9357 
9358  ocs_unlock(&hal->io_lock);
9359 
9360  return count;
9361 }
9362 
9363 /**
9364  * @brief Called to obtain active RPI count
9365  *
9366  * @param hal Hardware context.
9367  *
9368  * @return Returns the number of RPIs on the specified list type.
9369  */
9370 uint32_t
9372 {
9373  uint32_t active_rpi_count = 0;
9374 
9375  if (hal->rpi_ref) {
9376  uint32_t max_rpi, i;
9377 
9378  max_rpi = sli_get_max_rsrc(&hal->sli, SLI_RSRC_FCOE_RPI);
9379  for (i = 0; i < max_rpi; i ++) {
9380  if (ocs_atomic_read(&hal->rpi_ref[i].rpi_attached)) {
9381  active_rpi_count += ocs_atomic_read(&hal->rpi_ref[i].rpi_count);
9382  }
9383  }
9384  }
9385 
9386  return active_rpi_count;
9387 }
9388 /**
9389  * @brief Called to obtain the count of produced RQs.
9390  *
9391  * @param hal Hardware context.
9392  *
9393  * @return Returns the number of RQs produced.
9394  */
9395 uint32_t
9397 {
9398  uint32_t count = 0;
9399  uint32_t i;
9400  uint32_t j;
9401 
9402  for (i = 0; i < hal->hal_rq_count; i++) {
9403  hal_rq_t *rq = hal->hal_rq[i];
9404  if (rq->rq_tracker != NULL) {
9405  for (j = 0; j < rq->entry_count; j++) {
9406  if (rq->rq_tracker[j] != NULL) {
9407  count++;
9408  }
9409  }
9410  }
9411  }
9412 
9413  return count;
9414 }
9415 
9416 typedef struct ocs_hal_set_active_profile_cb_arg_s {
9418  void *arg;
9420 
9421 /**
9422  * @brief Called for the completion of set_active_profile for a
9423  * user request.
9424  *
9425  * @param hal Hardware context.
9426  * @param status The status from the MQE
9427  * @param mqe Pointer to mailbox command buffer.
9428  * @param arg Pointer to a callback argument.
9429  *
9430  * @return Returns 0 on success, or a non-zero value on failure.
9431  */
9432 static int32_t
9433 ocs_hal_set_active_profile_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
9434 {
9435  sli4_cmd_sli_config_t *mbox_rsp = (sli4_cmd_sli_config_t *)mqe;
9436  sli4_res_common_set_active_profile_t *sli4_rsp = NULL;
9438 
9439  sli4_rsp = (sli4_res_common_set_active_profile_t *)mbox_rsp->payload.embed;
9440  if (sli4_rsp->hdr.status)
9441  ocs_hal_log_sli4_rsp_hdr(hal, &sli4_rsp->hdr);
9442 
9443  if (!cb_arg || !cb_arg->cb)
9444  goto ocs_hal_set_active_profile_cb_done;
9445 
9446  if (0 == status) {
9447  if (mbox_rsp->hdr.status)
9448  status = mbox_rsp->hdr.status;
9449  else if (sli4_rsp->hdr.status)
9450  status = sli4_rsp->hdr.status;
9451  }
9452 
9453  cb_arg->cb(status, cb_arg->arg);
9454 
9455 ocs_hal_set_active_profile_cb_done:
9456  if (cb_arg)
9457  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
9458 
9459  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
9460  return 0;
9461 }
9462 
9463 /**
9464  * @ingroup io
9465  * @brief Set the currently active profile.
9466  * @par Description
9467  * Issues a SLI4 COMMON_GET_ACTIVE_PROFILE mailbox. When the
9468  * command completes the provided mgmt callback function is
9469  * called.
9470  *
9471  * @param hal Hardware context.
9472  * @param profile_id Profile ID to activate.
9473  * @param cb Callback function to be called when the command completes.
9474  * @param ul_arg An argument that is passed to the callback function.
9475  *
9476  * @return
9477  * - OCS_HAL_RTN_SUCCESS on success.
9478  * - OCS_HAL_RTN_NO_MEMORY if a malloc fails.
9479  * - OCS_HAL_RTN_NO_RESOURCES if unable to get a command
9480  * context.
9481  * - OCS_HAL_RTN_ERROR on any other error.
9482  */
9483 int32_t
9484 ocs_hal_set_active_profile(ocs_hal_t *hal, ocs_set_active_profile_cb_t cb, uint32_t profile_id, void* ul_arg)
9485 {
9486  uint8_t *mbxdata;
9489 
9490  /* Only supported on Skyhawk */
9491  if (sli_get_if_type(&hal->sli) != SLI4_IF_TYPE_BE3_SKH_PF) {
9492  return OCS_HAL_RTN_ERROR;
9493  }
9494 
9495  /* mbxdata holds the header of the command */
9496  mbxdata = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
9497  if (mbxdata == NULL) {
9498  ocs_log_err(hal->os, "failed to malloc mbox\n");
9499  return OCS_HAL_RTN_NO_MEMORY;
9500  }
9501 
9502 
9503  /* cb_arg holds the data that will be passed to the callback on completion */
9504  cb_arg = ocs_malloc(hal->os, sizeof(ocs_hal_set_active_profile_cb_arg_t), OCS_M_NOWAIT);
9505  if (cb_arg == NULL) {
9506  ocs_log_err(hal->os, "failed to malloc cb_arg\n");
9507  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
9508  return OCS_HAL_RTN_NO_MEMORY;
9509  }
9510 
9511  cb_arg->cb = cb;
9512  cb_arg->arg = ul_arg;
9513 
9514  /* Send the HAL command */
9515  sli_cmd_common_set_active_profile(&hal->sli, mbxdata, SLI4_BMBX_SIZE, 0, profile_id);
9516  rc = ocs_hal_command(hal, mbxdata, OCS_CMD_NOWAIT, ocs_hal_set_active_profile_cb, cb_arg);
9517  if (rc) {
9518  ocs_free(hal->os, cb_arg, sizeof(*cb_arg));
9519  ocs_free(hal->os, mbxdata, SLI4_BMBX_SIZE);
9520  }
9521 
9522  return rc;
9523 }
9524 
9525 /*
9526  * Private functions
9527  */
9528 
9529 /**
9530  * @brief Update the queue hash with the ID and index.
9531  *
9532  * @param hash Pointer to hash table.
9533  * @param id ID that was created.
9534  * @param index The index into the hash object.
9535  */
9536 static void
9537 ocs_hal_queue_hash_add(ocs_queue_hash_t *hash, uint16_t id, uint16_t index)
9538 {
9539  uint32_t hash_index = id & (OCS_HAL_Q_HASH_SIZE - 1);
9540 
9541  /*
9542  * Since the hash is always bigger than the number of queues, then we
9543  * never have to worry about an infinite loop.
9544  */
9545  while(hash[hash_index].in_use) {
9546  hash_index = (hash_index + 1) & (OCS_HAL_Q_HASH_SIZE - 1);
9547  }
9548 
9549  /* not used, claim the entry */
9550  hash[hash_index].id = id;
9551  hash[hash_index].in_use = 1;
9552  hash[hash_index].index = index;
9553 }
9554 
9555 /**
9556  * @brief Find index given queue ID.
9557  *
9558  * @param hash Pointer to hash table.
9559  * @param id ID to find.
9560  *
9561  * @return Returns the index into the HAL cq array or -1 if not found.
9562  */
9563 int32_t
9565 {
9566  int32_t rc = -1;
9567  int32_t index = id & (OCS_HAL_Q_HASH_SIZE - 1);
9568 
9569  /*
9570  * Since the hash is always bigger than the maximum number of Qs, then we
9571  * never have to worry about an infinite loop. We will always find an
9572  * unused entry.
9573  */
9574  do {
9575  if (hash[index].in_use &&
9576  hash[index].id == id) {
9577  rc = hash[index].index;
9578  } else {
9579  index = (index + 1) & (OCS_HAL_Q_HASH_SIZE - 1);
9580  }
9581  } while(rc == -1 && hash[index].in_use);
9582 
9583  return rc;
9584 }
9585 
9586 static int32_t
9587 ocs_hal_domain_add(ocs_hal_t *hal, ocs_domain_t *domain)
9588 {
9589  int32_t rc = OCS_HAL_RTN_ERROR;
9590  uint16_t fcfi = UINT16_MAX;
9591 
9592  if ((hal == NULL) || (domain == NULL)) {
9593  ocs_log_err(NULL, "bad parameter hal=%p domain=%p\n",
9594  hal, domain);
9595  return OCS_HAL_RTN_ERROR;
9596  }
9597 
9598  fcfi = domain->fcf_indicator;
9599 
9600  if (fcfi < SLI4_MAX_FCFI) {
9601  uint16_t fcf_index = UINT16_MAX;
9602 
9603  ocs_log_debug(hal->os, "adding domain %p @ %#x\n",
9604  domain, fcfi);
9605  hal->domains[fcfi] = domain;
9606 
9607  /* HAL_WORKAROUND_OVERRIDE_FCFI_IN_SRB */
9608  if (hal->workaround.override_fcfi) {
9609  if (hal->first_domain_idx < 0) {
9610  hal->first_domain_idx = fcfi;
9611  }
9612  }
9613 
9614  fcf_index = domain->fcf;
9615 
9616  if (fcf_index < SLI4_MAX_FCF_INDEX) {
9617  ocs_log_debug(hal->os, "adding map of FCF index %d to FCFI %d\n",
9618  fcf_index, fcfi);
9619  hal->fcf_index_fcfi[fcf_index] = fcfi;
9620  rc = OCS_HAL_RTN_SUCCESS;
9621  } else {
9622  ocs_log_test(hal->os, "FCF index %d out of range (max %d)\n",
9623  fcf_index, SLI4_MAX_FCF_INDEX);
9624  hal->domains[fcfi] = NULL;
9625  }
9626  } else {
9627  ocs_log_test(hal->os, "FCFI %#x out of range (max %#x)\n",
9628  fcfi, SLI4_MAX_FCFI);
9629  }
9630 
9631  return rc;
9632 }
9633 
9634 static int32_t
9635 ocs_hal_domain_del(ocs_hal_t *hal, ocs_domain_t *domain)
9636 {
9637  int32_t rc = OCS_HAL_RTN_ERROR;
9638  uint16_t fcfi = UINT16_MAX;
9639 
9640  if ((hal == NULL) || (domain == NULL)) {
9641  ocs_log_err(NULL, "bad parameter hal=%p domain=%p\n",
9642  hal, domain);
9643  return OCS_HAL_RTN_ERROR;
9644  }
9645 
9646  fcfi = domain->fcf_indicator;
9647 
9648  if (fcfi < SLI4_MAX_FCFI) {
9649  uint16_t fcf_index = UINT16_MAX;
9650 
9651  ocs_log_debug(hal->os, "deleting domain %p @ %#x\n",
9652  domain, fcfi);
9653 
9654  if (domain != hal->domains[fcfi]) {
9655  ocs_log_test(hal->os, "provided domain %p does not match stored domain %p\n",
9656  domain, hal->domains[fcfi]);
9657  return OCS_HAL_RTN_ERROR;
9658  }
9659 
9660  hal->domains[fcfi] = NULL;
9661 
9662  /* HAL_WORKAROUND_OVERRIDE_FCFI_IN_SRB */
9663  if (hal->workaround.override_fcfi) {
9664  if (hal->first_domain_idx == fcfi) {
9665  hal->first_domain_idx = -1;
9666  }
9667  }
9668 
9669  fcf_index = domain->fcf;
9670 
9671  if (fcf_index < SLI4_MAX_FCF_INDEX) {
9672  if (hal->fcf_index_fcfi[fcf_index] == fcfi) {
9673  hal->fcf_index_fcfi[fcf_index] = 0;
9674  rc = OCS_HAL_RTN_SUCCESS;
9675  } else {
9676  ocs_log_test(hal->os, "indexed FCFI %#x doesn't match provided %#x @ %d\n",
9677  hal->fcf_index_fcfi[fcf_index], fcfi, fcf_index);
9678  }
9679  } else {
9680  ocs_log_test(hal->os, "FCF index %d out of range (max %d)\n",
9681  fcf_index, SLI4_MAX_FCF_INDEX);
9682  }
9683  } else {
9684  ocs_log_test(hal->os, "FCFI %#x out of range (max %#x)\n",
9685  fcfi, SLI4_MAX_FCFI);
9686  }
9687 
9688  return rc;
9689 }
9690 
9691 ocs_domain_t *
9692 ocs_hal_domain_get(ocs_hal_t *hal, uint16_t fcfi)
9693 {
9694 
9695  if (hal == NULL) {
9696  ocs_log_err(NULL, "bad parameter hal=%p\n", hal);
9697  return NULL;
9698  }
9699 
9700  if (fcfi < SLI4_MAX_FCFI) {
9701  return hal->domains[fcfi];
9702  } else {
9703  ocs_log_test(hal->os, "FCFI %#x out of range (max %#x)\n",
9704  fcfi, SLI4_MAX_FCFI);
9705  return NULL;
9706  }
9707 }
9708 
9709 static ocs_domain_t *
9710 ocs_hal_domain_get_indexed(ocs_hal_t *hal, uint16_t fcf_index)
9711 {
9712 
9713  if (hal == NULL) {
9714  ocs_log_err(NULL, "bad parameter hal=%p\n", hal);
9715  return NULL;
9716  }
9717 
9718  if (fcf_index < SLI4_MAX_FCF_INDEX) {
9719  return ocs_hal_domain_get(hal, hal->fcf_index_fcfi[fcf_index]);
9720  } else {
9721  ocs_log_test(hal->os, "FCF index %d out of range (max %d)\n",
9722  fcf_index, SLI4_MAX_FCF_INDEX);
9723  return NULL;
9724  }
9725 }
9726 
9727 /**
9728  * @brief Quaratine an IO by taking a reference count and adding it to the
9729  * quarantine list. When the IO is popped from the list then the
9730  * count is released and the IO MAY be freed depending on whether
9731  * it is still referenced by the IO.
9732  *
9733  * @n @b Note: BZ 160124 - If this is a target write or an initiator read using
9734  * DIF, then we must add the XRI to a quarantine list until we receive
9735  * 4 more completions of this same type.
9736  *
9737  * @param hal Hardware context.
9738  * @param wq Pointer to the WQ associated with the IO object to quarantine.
9739  * @param io Pointer to the io object to quarantine.
9740  */
9741 static void
9742 ocs_hal_io_quarantine(ocs_hal_t *hal, hal_wq_t *wq, ocs_hal_io_t *io)
9743 {
9744  ocs_quarantine_info_t *q_info = &wq->quarantine_info;
9745  uint32_t index;
9746  ocs_hal_io_t *free_io = NULL;
9747 
9748  /* return if the QX bit was clear */
9749  if (!io->quarantine) {
9750  return;
9751  }
9752 
9753  /* increment the IO refcount to prevent it from being freed before the quarantine is over */
9754  if (ocs_ref_get_unless_zero(&io->ref) == 0) {
9755  /* command no longer active */
9756  ocs_log_debug(hal ? hal->os : NULL,
9757  "io not active xri=%#x tag=%#x\n",
9758  io->indicator, io->reqtag);
9759  return;
9760  }
9761 
9762  sli_queue_lock(wq->queue);
9763  index = q_info->quarantine_index;
9764  free_io = q_info->quarantine_ios[index];
9765  q_info->quarantine_ios[index] = io;
9766  q_info->quarantine_index = (index + 1) % OCS_HAL_QUARANTINE_QUEUE_DEPTH;
9767  sli_queue_unlock(wq->queue);
9768 
9769  if (free_io != NULL) {
9770  ocs_ref_put(&free_io->ref); /* ocs_ref_get(): same function */
9771  }
9772 }
9773 
9774 /**
9775  * @brief Process entries on the given completion queue.
9776  *
9777  * @param hal Hardware context.
9778  * @param cq Pointer to the HAL completion queue object.
9779  *
9780  * @return None.
9781  */
9782 void
9783 ocs_hal_cq_process(ocs_hal_t *hal, hal_cq_t *cq, uint32_t cq_process_limit)
9784 {
9785  uint8_t cqe[sizeof(sli4_mcqe_t)];
9786  uint16_t rid = UINT16_MAX;
9787  sli4_qentry_e ctype; /* completion type */
9788  int32_t status;
9789  uint32_t n_processed = 0;
9790  uint64_t elapsed_time_ms;
9791  uint64_t tstart;
9792  uint64_t telapsed;
9793  tstart = ocs_get_os_ticks();
9794 
9795  while (!sli_queue_read(&hal->sli, cq->queue, cqe)) {
9796  status = sli_cq_parse(&hal->sli, cq->queue, cqe, &ctype, &rid);
9797  /*
9798  * The sign of status is significant. If status is:
9799  * == 0 : call completed correctly and the CQE indicated success
9800  * > 0 : call completed correctly and the CQE indicated an error
9801  * < 0 : call failed and no information is available about the CQE
9802  */
9803  if (status < 0) {
9804  if (status == -2) {
9805  /* Notification that an entry was consumed, but not completed */
9806  continue;
9807  }
9808 
9809  break;
9810  }
9811 
9812  switch (ctype) {
9813  case SLI_QENTRY_ASYNC:
9814  CPUTRACE("async");
9815  sli_cqe_async(&hal->sli, cqe);
9816  break;
9817  case SLI_QENTRY_MQ:
9818  /*
9819  * Process MQ entry. Note there is no way to determine
9820  * the MQ_ID from the completion entry.
9821  */
9822  CPUTRACE("mq");
9823  ocs_hal_mq_process(hal, status, hal->mq[0]);
9824  break;
9826  ocs_hal_rqpair_tow_cmd_process(hal, cq, cqe);
9827  break;
9829  ocs_hal_rqpair_tow_data_process(hal, cq, cqe);
9830  break;
9831  case SLI_QENTRY_WQ:
9832  CPUTRACE("wq");
9833  ocs_hal_wq_process(hal, cq, cqe, status, rid);
9834  break;
9835  case SLI_QENTRY_WQ_RELEASE: {
9836  uint32_t wq_id = rid;
9837  uint32_t index = ocs_hal_queue_hash_find(hal->wq_hash, wq_id);
9838  hal_wq_t *wq = hal->hal_wq[index];
9839 
9840  /* Submit any HAL IOs that are on the WQ pending list */
9841  hal_wq_submit_pending(wq, wq->wqec_set_count);
9842 
9843  break;
9844  }
9845 
9846  case SLI_QENTRY_RQ:
9847  CPUTRACE("rq");
9848  ocs_hal_rqpair_process_rq(hal, cq, cqe);
9849  break;
9850  case SLI_QENTRY_XABT: {
9851  CPUTRACE("xabt");
9852  ocs_hal_xabt_process(hal, cq, cqe, rid);
9853  break;
9854 
9855  }
9856  default:
9857  ocs_log_test(hal->os, "unhandled ctype=%#x rid=%#x\n", ctype, rid);
9858  break;
9859  }
9860 
9861  n_processed++;
9862  if (n_processed == cq_process_limit) {
9863  break;
9864  }
9865 
9866  if (cq->queue->n_posted >= (cq->queue->posted_limit)) {
9867  sli_queue_arm(&hal->sli, cq->queue, FALSE);
9868  }
9869  }
9870 
9871  sli_queue_arm(&hal->sli, cq->queue, TRUE);
9872 
9873  cq->queue->last_processed_time = ocs_ticks_to_ms(ocs_get_os_ticks());
9874 
9875  if (n_processed > cq->queue->max_num_processed) {
9876  cq->queue->max_num_processed = n_processed;
9877  }
9878 
9879  telapsed = ocs_get_os_ticks() - tstart;
9880  elapsed_time_ms = ocs_ticks_to_ms(telapsed);
9881  if (elapsed_time_ms > cq->queue->max_process_time_ms) {
9882  cq->queue->max_process_time_ms = elapsed_time_ms;
9883  }
9884 }
9885 
9886 /**
9887  * @brief Process WQ completion queue entries.
9888  *
9889  * @param hal Hardware context.
9890  * @param cq Pointer to the HAL completion queue object.
9891  * @param cqe Pointer to WQ completion queue.
9892  * @param status Completion status.
9893  * @param rid Resource ID (IO tag).
9894  *
9895  * @return none
9896  */
9897 void
9898 ocs_hal_wq_process(ocs_hal_t *hal, hal_cq_t *cq, uint8_t *cqe, int32_t status, uint16_t rid)
9899 {
9900  hal_wq_callback_t *wqcb;
9901 
9902  ocs_queue_history_cqe(&hal->q_hist, SLI_QENTRY_WQ, (void *)cqe, ((sli4_fc_wcqe_t *)cqe)->status, cq->queue->id,
9903  ((cq->queue->index - 1) & (cq->queue->length - 1)));
9904 
9905  wqcb = ocs_hal_reqtag_get_instance(hal, rid);
9906  if (wqcb == NULL) {
9907  ocs_log_err(hal->os, "invalid request tag: x%x\n", rid);
9908  return;
9909  }
9910 
9911  if (wqcb->callback == NULL) {
9912  ocs_log_err(hal->os, "wqcb callback is NULL\n");
9913  return;
9914  }
9915 
9916  (*wqcb->callback)(wqcb->arg, cqe, status);
9917 }
9918 
9919 /**
9920  * @brief Process WQ completions for IO requests
9921  *
9922  * @param arg Generic callback argument
9923  * @param cqe Pointer to completion queue entry
9924  * @param status Completion status
9925  *
9926  * @par Description
9927  * @n @b Note: Regarding io->reqtag, the reqtag is assigned once when HAL IOs are initialized
9928  * in ocs_hal_setup_io(), and don't need to be returned to the hal->wq_reqtag_pool.
9929  *
9930  * @return None.
9931  */
9932 static void
9933 ocs_hal_wq_process_io(void *arg, uint8_t *cqe, int32_t status)
9934 {
9935  ocs_hal_io_t *io = arg;
9936  ocs_hal_t *hal = io->hal;
9937  sli4_fc_wcqe_t *wcqe = (void *)cqe;
9938  uint32_t len = 0;
9939  uint32_t ext = 0;
9940  uint8_t tow_ooo_cmd = FALSE;
9941  uint8_t tow_ooo_data = FALSE;
9942  uint8_t lock_taken = 0;
9943 #if defined(OCS_DISC_SPIN_DELAY)
9944  uint32_t delay = 0;
9945  char prop_buf[32];
9946 #endif
9947 
9948  /*
9949  * For the primary IO, this will also be used for the
9950  * response. So it is important to only set/clear this
9951  * flag on the first data phase of the IO because
9952  * subsequent phases will be done on the secondary XRI.
9953  */
9954  if (io->quarantine && io->quarantine_first_phase) {
9955  io->quarantine = (wcqe->qx == 1);
9956  ocs_hal_io_quarantine(hal, io->wq, io);
9957  }
9958  io->quarantine_first_phase = FALSE;
9959 
9960  /* BZ 161832 - free secondary HAL IO */
9961  if (io->sec_hio != NULL &&
9962  io->sec_hio->quarantine) {
9963  /*
9964  * If the quarantine flag is set on the
9965  * IO, then set it on the secondary IO
9966  * based on the quarantine XRI (QX) bit
9967  * sent by the FW.
9968  */
9969  io->sec_hio->quarantine = (wcqe->qx == 1);
9970  /* use the primary io->wq because it is not set on the secondary IO. */
9971  ocs_hal_io_quarantine(hal, io->wq, io->sec_hio);
9972  }
9973 
9974  ocs_hal_remove_io_timed_wqe(hal, io);
9975 
9976  /* clear xbusy flag if WCQE[XB] is clear */
9977  if (io->xbusy && wcqe->xb == 0) {
9978  io->xbusy = FALSE;
9979  }
9980 
9981  /* get extended CQE status */
9982  switch (io->type) {
9983  case OCS_HAL_BLS_ACC:
9984  case OCS_HAL_BLS_ACC_SID:
9985  case OCS_HAL_BLS_RJT:
9986  break;
9987  case OCS_HAL_ELS_REQ:
9988  sli_fc_els_did(&hal->sli, cqe, &ext);
9989  len = sli_fc_response_length(&hal->sli, cqe);
9990  break;
9991  case OCS_HAL_ELS_RSP:
9992  case OCS_HAL_ELS_RSP_SID:
9993  case OCS_HAL_FC_CT_RSP:
9994  break;
9995  case OCS_HAL_FC_CT:
9996  len = sli_fc_response_length(&hal->sli, cqe);
9997  break;
9999  len = sli_fc_io_length(&hal->sli, cqe);
10000 #if defined(OCS_DISC_SPIN_DELAY)
10001  if (ocs_get_property("disk_spin_delay", prop_buf, sizeof(prop_buf)) == 0) {
10002  delay = ocs_strtoul(prop_buf, 0, 0);
10003  ocs_delay_usec(delay);
10004  }
10005 #endif
10006  break;
10008  len = sli_fc_io_length(&hal->sli, cqe);
10009  /*
10010  * if_type == 2 seems to return 0 "total length placed" on
10011  * FCP_TSEND64_WQE completions. If this appears to happen,
10012  * use the CTIO data transfer length instead.
10013  */
10014  if (hal->workaround.retain_tsend_io_length && !len && !status) {
10015  len = io->length;
10016  }
10017 
10018  break;
10019  case OCS_HAL_IO_TARGET_RSP:
10020  if(io->is_port_owned) {
10021  ocs_lock(&io->tow_lock);
10022  lock_taken = 1;
10023  if(io->tow_buf->call_tow_cmd) {
10024  tow_ooo_cmd = TRUE;
10025  }
10026 
10027  if(io->tow_buf->call_tow_data) {
10028  tow_ooo_data = TRUE;
10029  }
10030  }
10031  break;
10033  len = sli_fc_io_length(&hal->sli, cqe);
10034  break;
10036  len = sli_fc_io_length(&hal->sli, cqe);
10037  break;
10039  break;
10041  /* release the count for re-posting the buffer */
10042  //ocs_hal_io_free(hal, io);
10043  break;
10044  default:
10045  ocs_log_err(hal->os, "Unhandled io type %#x for io=%p xri=%#x tag=%#x\n",
10046  io->type, io, io->indicator, io->reqtag);
10047  ocs_hal_assert(0);
10048  return;
10049  }
10050 
10051  if (status) {
10052  ext = sli_fc_ext_status(&hal->sli, cqe);
10053  io->status_saved = 1;
10054  io->saved_status = status;
10055  io->saved_ext = ext;
10056  io->saved_len = len;
10057 
10058  /* Emulate IAAB=0 for initiator WQEs only; i.e. automatically
10059  * abort exchange if an error occurred and exchange is still busy.
10060  */
10061  if (hal->config.i_only_aab &&
10062  (ocs_hal_iotype_is_originator(io->type)) &&
10063  (ocs_hal_wcqe_abort_needed(status, ext, wcqe->xb))) {
10064  ocs_hal_rtn_e rc;
10065 
10066  ocs_log_info(hal->os, "aborting xri=%#x tag=%#x type=%d\n",
10067  io->indicator, io->reqtag, io->type);
10068  /*
10069  * Because the initiator will not issue another IO phase, then it is OK to to issue the
10070  * callback on the abort completion, but for consistency with the target, wait for the
10071  * XRI_ABORTED CQE to issue the IO callback.
10072  */
10073  rc = ocs_hal_io_abort(hal, io, TRUE, NULL, NULL);
10074 
10075  if (rc == OCS_HAL_RTN_SUCCESS) {
10076  goto exit_ocs_hal_wq_process_io;
10077  } else if (rc == OCS_HAL_RTN_IO_ABORT_IN_PROGRESS) {
10078  /*
10079  * Already being aborted by someone else (ABTS
10080  * perhaps). Just fall through and return original
10081  * error.
10082  */
10083  ocs_log_info(hal->os, "abort in progress xri=%#x tag=%#x type=%d\n",
10084  io->indicator, io->reqtag, io->type);
10085 
10086  } else {
10087  /* Failed to abort for some other reason, log error */
10088  ocs_log_err(hal->os,
10089  "Failed to abort xri=%#x tag=%#x type=%d rc=%d\n",
10090  io->indicator, io->reqtag, io->type, rc);
10091  }
10092  }
10093 
10094  /*
10095  * If we're not an originator IO, and XB is set, then issue abort for the IO from within the HAL
10096  */
10097  if ( (! ocs_hal_iotype_is_originator(io->type)) && wcqe->xb) {
10098  ocs_hal_rtn_e rc;
10099 
10100  ocs_log_info(hal->os, "aborting xri=%#x tag=%#x type=%d\n",
10101  io->indicator, io->reqtag, io->type);
10102 
10103  /*
10104  * Because targets may send a response when the IO completes using the same XRI, we must
10105  * wait for the XRI_ABORTED CQE to issue the IO callback
10106  */
10107  if (wcqe->rha || ocs_hal_wcqe_abort_needed(status, ext, wcqe->xb)) {
10108  rc = ocs_hal_io_abort(hal, io, FALSE, NULL, NULL);
10109  } else {
10110  /* This IO was rejected locally because of a link event. Do nothing, XRI will be
10111  * reclaimed via' UNREG_RPI.
10112  */
10114  }
10115  if ((rc == OCS_HAL_RTN_SUCCESS) ||
10117  goto exit_ocs_hal_wq_process_io;
10118  } else {
10119  /* Failed to abort for some other reason, log error */
10120  ocs_log_test(hal->os, "Failed to abort xri=%#x tag=%#x rc=%d\n",
10121  io->indicator, io->reqtag, rc);
10122  }
10123  }
10124  }
10125  /* BZ 161832 - free secondary HAL IO */
10126  if (io->sec_hio != NULL) {
10127  ocs_hal_io_free(hal, io->sec_hio);
10128  io->sec_hio = NULL;
10129  }
10130 
10131  if (io->done != NULL) {
10132  ocs_hal_done_t done = io->done;
10133  void *arg = io->arg;
10134 
10135  io->done = NULL;
10136 
10137  if (io->status_saved) {
10138  /* use latched status if exists */
10139  status = io->saved_status;
10140  len = io->saved_len;
10141  ext = io->saved_ext;
10142  io->status_saved = 0;
10144  ocs_log_info(hal->os,
10145  "IO marked as timedout, xri=%#x tag=%#x type=%d\n",
10146  io->indicator, io->reqtag, io->type);
10147  }
10148  }
10149 
10150  /* Restore default SGL */
10151  ocs_hal_io_restore_sgl(hal, io);
10152  done(io, io->rnode, len, status, ext, arg);
10153  }
10154 
10155  if (tow_ooo_cmd) {
10156  /* bounce enabled, single RQ, we snoop the ox_id to choose the cpuidx */
10157  if (hal->config.bounce) {
10158  fc_header_t *hdr = io->tow_buf->cmd_seq->header->dma.virt;
10159  uint32_t s_id = fc_be24toh(hdr->s_id);
10160  uint32_t d_id = fc_be24toh(hdr->d_id);
10161  uint32_t ox_id = ocs_be16toh(hdr->ox_id);
10162  if (hal->callback.bounce != NULL) {
10163  (*hal->callback.bounce)(ocs_hal_unsol_process_bounce, io->tow_buf->cmd_seq, s_id, d_id, ox_id);
10164  }
10165  }else {
10166  hal->callback.unsolicited(hal->args.unsolicited, io->tow_buf->cmd_seq);
10167  }
10168 
10169  if (tow_ooo_data) {
10170  /* bounce enabled, single RQ, we snoop the ox_id to choose the cpuidx */
10171  if (hal->config.bounce) {
10172  fc_header_t *hdr = io->tow_buf->seq.header->dma.virt;
10173  uint32_t s_id = fc_be24toh(hdr->s_id);
10174  uint32_t d_id = fc_be24toh(hdr->d_id);
10175  uint32_t ox_id = ocs_be16toh(hdr->ox_id);
10176  if (hal->callback.bounce != NULL) {
10177  (*hal->callback.bounce)(ocs_hal_unsol_process_bounce, &io->tow_buf->seq, s_id, d_id, ox_id);
10178  }
10179  }else {
10180  hal->callback.unsolicited(hal->args.unsolicited, &io->tow_buf->seq);
10181  }
10182  }
10183  }
10184 
10185 exit_ocs_hal_wq_process_io:
10186  if(lock_taken) {
10187  ocs_unlock(&io->tow_lock);
10188  }
10189 }
10190 
10191 /**
10192  * @brief Process WQ completions for abort requests.
10193  *
10194  * @param arg Generic callback argument.
10195  * @param cqe Pointer to completion queue entry.
10196  * @param status Completion status.
10197  *
10198  * @return None.
10199  */
10200 static void
10201 ocs_hal_wq_process_abort(void *arg, uint8_t *cqe, int32_t status)
10202 {
10203  ocs_hal_io_t *io = arg;
10204  ocs_hal_t *hal = io->hal;
10205  uint32_t ext = 0;
10206  uint32_t len = 0;
10207  hal_wq_callback_t *wqcb;
10208 
10209  if (io->state == OCS_HAL_IO_STATE_WAIT_FREE) {
10210  ocs_hal_assert(0);
10211  return;
10212  }
10213  /*
10214  * For IOs that were aborted internally, we may need to issue the callback here depending
10215  * on whether a XRI_ABORTED CQE is expected ot not. If the status is Local Reject/No XRI, then
10216  * issue the callback now.
10217  */
10218  ext = sli_fc_ext_status(&hal->sli, cqe);
10219  if (status == SLI4_FC_WCQE_STATUS_LOCAL_REJECT &&
10220  ext == SLI4_FC_LOCAL_REJECT_NO_XRI &&
10221  io->done != NULL) {
10222  ocs_hal_done_t done = io->done;
10223  void *arg = io->arg;
10224 
10225  io->done = NULL;
10226 
10227  /*
10228  * Use latched status as this is always saved for an internal abort
10229  *
10230  * Note: We wont have both a done and abort_done function, so don't worry about
10231  * clobbering the len, status and ext fields.
10232  */
10233  status = io->saved_status;
10234  len = io->saved_len;
10235  ext = io->saved_ext;
10236  io->status_saved = 0;
10237 
10239  ocs_log_info(hal->os,
10240  "IO marked as timedout, xri=%#x tag=%#x type=%d\n",
10241  io->indicator, io->reqtag, io->type);
10242  }
10243 
10244  done(io, io->rnode, len, status, ext, arg);
10245  }
10246 
10247  if (io->abort_done != NULL) {
10248  ocs_hal_done_t done = io->abort_done;
10249  void *arg = io->abort_arg;
10250 
10251  io->abort_done = NULL;
10252 
10253  done(io, io->rnode, len, status, ext, arg);
10254  }
10255  ocs_lock(&hal->io_abort_lock);
10256  /* clear abort bit to indicate abort is complete */
10257  io->abort_in_progress = 0;
10258  ocs_unlock(&hal->io_abort_lock);
10259 
10260  /* Free the WQ callback */
10261  ocs_hal_assert(io->abort_reqtag != UINT32_MAX);
10262  wqcb = ocs_hal_reqtag_get_instance(hal, io->abort_reqtag);
10263  ocs_hal_reqtag_free(hal, wqcb);
10264 
10265  /*
10266  * Call ocs_hal_io_free() because this releases the WQ reservation as
10267  * well as doing the refcount put. Don't duplicate the code here.
10268  */
10269  (void)ocs_hal_io_free(hal, io);
10270 }
10271 
10272 /**
10273  * @brief Process XABT completions
10274  *
10275  * @param hal Hardware context.
10276  * @param cq Pointer to the HAL completion queue object.
10277  * @param cqe Pointer to WQ completion queue.
10278  * @param rid Resource ID (IO tag).
10279  *
10280  *
10281  * @return None.
10282  */
10283 void
10284 ocs_hal_xabt_process(ocs_hal_t *hal, hal_cq_t *cq, uint8_t *cqe, uint16_t rid)
10285 {
10286  /* search IOs wait free list */
10287  ocs_hal_io_t *io = NULL;
10288 
10289  io = ocs_hal_io_lookup(hal, rid);
10290 
10291  ocs_queue_history_cqe(&hal->q_hist, SLI_QENTRY_XABT, (void *)cqe, 0, cq->queue->id,
10292  ((cq->queue->index - 1) & (cq->queue->length - 1)));
10293  if (io == NULL) {
10294  /* IO lookup failure should never happen */
10295  ocs_log_err(hal->os, "Error: xabt io lookup failed rid=%#x\n", rid);
10296  return;
10297  }
10298 
10299  if (!io->xbusy) {
10300  ocs_log_debug(hal->os, "xabt io not busy rid=%#x\n", rid);
10301  } else {
10302  /* mark IO as no longer busy */
10303  io->xbusy = FALSE;
10304  }
10305 
10306  if (io->is_port_owned) {
10307  ocs_lock(&hal->io_lock);
10308  /* Take reference so that below callback will not free io before reque */
10309  ocs_ref_get(&io->ref);
10310  ocs_unlock(&hal->io_lock);
10311  }
10312 
10313  /* For IOs that were aborted internally, we need to issue any pending callback here. */
10314  if (io->status_saved && io->done != NULL) {
10315  ocs_hal_done_t done = io->done;
10316  void *arg = io->arg;
10317 
10318  /* Use latched status as this is always saved for an internal abort */
10319  int32_t status = io->saved_status;
10320  uint32_t len = io->saved_len;
10321  uint32_t ext = io->saved_ext;
10322 
10323  io->done = NULL;
10324  io->status_saved = 0;
10325 
10327  ocs_log_info(hal->os,
10328  "IO marked as timedout, xri=%#x tag=%#x type=%d\n",
10329  io->indicator, io->reqtag, io->type);
10330  }
10331 
10332  done(io, io->rnode, len, status, ext, arg);
10333  }
10334 
10335  /* Check to see if this is a port owned XRI */
10336  if (io->is_port_owned) {
10337  ocs_lock(&hal->io_lock);
10338  ocs_hal_reque_xri(hal, io);
10339  ocs_unlock(&hal->io_lock);
10340  /* Not hanlding reque xri completion, free io */
10341  ocs_hal_io_free(hal, io);
10342  return;
10343  }
10344 
10345  ocs_lock(&hal->io_lock);
10346  if (io->state == OCS_HAL_IO_STATE_WAIT_FREE) {
10347  /* if on wait_free list, caller has already freed IO;
10348  * remove from wait_free list and add to free list.
10349  */
10350  io->state = OCS_HAL_IO_STATE_FREE;
10351  ocs_list_remove(&hal->io_wait_free, io);
10353  }
10354  ocs_unlock(&hal->io_lock);
10355 }
10356 
10357 /**
10358  * @brief Adjust the number of WQs and CQs within the HAL.
10359  *
10360  * @par Description
10361  * Calculates the number of WQs and associated CQs needed in the HAL based on
10362  * the number of IOs. Calculates the starting CQ index for each WQ, RQ and
10363  * MQ.
10364  *
10365  * @param hal Hardware context allocated by the caller.
10366  */
10367 static void
10368 ocs_hal_adjust_wqs(ocs_hal_t *hal)
10369 {
10370  uint32_t max_wq_num = sli_get_max_queue(&hal->sli, SLI_QTYPE_WQ);
10371  uint32_t max_wq_entries = hal->num_qentries[SLI_QTYPE_WQ];
10372  uint32_t max_cq_entries = hal->num_qentries[SLI_QTYPE_CQ];
10373 
10374  /*
10375  * possibly adjust the the size of the WQs so that the CQ is twice as
10376  * big as the WQ to allow for 2 completions per IO. This allows us to
10377  * handle multi-phase as well as aborts.
10378  */
10379  if (max_cq_entries < max_wq_entries * 2) {
10380  max_wq_entries = hal->num_qentries[SLI_QTYPE_WQ] = max_cq_entries / 2;
10381  }
10382 
10383  /*
10384  * Calculate the number of WQs to use base on the number of IOs.
10385  *
10386  * Note: We need to reserve room for aborts which must be sent down
10387  * the same WQ as the IO. So we allocate enough WQ space to
10388  * handle 2 times the number of IOs. Half of the space will be
10389  * used for normal IOs and the other half is reserved for aborts.
10390  */
10391  hal->config.n_wq = ((hal->config.n_io * 2) + (max_wq_entries - 1)) / max_wq_entries;
10392 
10393  /*
10394  * For performance reasons, it is best to use use a minimum of 4 WQs
10395  * for BE3 and Skyhawk.
10396  */
10397  if (hal->config.n_wq < 4 &&
10398  SLI4_IF_TYPE_BE3_SKH_PF == sli_get_if_type(&hal->sli)) {
10399  hal->config.n_wq = 4;
10400  }
10401 
10402  /*
10403  * For dual-chute support, we need to have at least one WQ per chute.
10404  */
10405  if (hal->config.n_wq < 2 &&
10406  ocs_hal_get_num_chutes(hal) > 1) {
10407  hal->config.n_wq = 2;
10408  }
10409 
10410  /* make sure we haven't exceeded the max supported in the HAL */
10411  if (hal->config.n_wq > OCS_HAL_MAX_NUM_WQ) {
10412  hal->config.n_wq = OCS_HAL_MAX_NUM_WQ;
10413  }
10414 
10415  /* make sure we haven't exceeded the chip maximum */
10416  if (hal->config.n_wq > max_wq_num) {
10417  hal->config.n_wq = max_wq_num;
10418  }
10419 
10420  /*
10421  * Using Queue Topology string, we divide by number of chutes
10422  */
10423  hal->config.n_wq /= ocs_hal_get_num_chutes(hal);
10424 }
10425 
10426 static int32_t
10427 ocs_hal_command_process(ocs_hal_t *hal, int32_t status, uint8_t *mqe, size_t size)
10428 {
10429  ocs_command_ctx_t *ctx = NULL;
10431 
10432  ocs_lock(&hal->cmd_lock);
10433  if (NULL == (ctx = ocs_list_remove_head(&hal->cmd_head))) {
10434  ocs_log_err(hal->os, "Can't find the MQE command context!!!\n");
10435  ocs_unlock(&hal->cmd_lock);
10436  return -1;
10437  }
10438 
10439  hal->cmd_head_count--;
10440 
10441  /* Post any pending requests */
10443  ocs_unlock(&hal->cmd_lock);
10444 
10445  if (status || hdr->status) {
10446  /**
10447  * There is no point in logging the entire MQE because the FW can potentially
10448  * clear the mailbox area when the cmd completes. So, just log the mbox hdr.
10449  */
10450  ocs_log_err(hal->os, "MQE failed; mqe_hdr: %08X, mqe_cmd: %#x, mqe_status: %#x, cqe_status: %#x\n",
10451  (uint32_t *)hdr, hdr->command, hdr->status, status);
10452  }
10453 
10454  if (ctx->cb) {
10455  if (ctx->buf)
10456  ocs_memcpy(ctx->buf, mqe, size);
10457 
10458  ctx->cb(hal, status, ctx->buf, ctx->arg);
10459  }
10460 
10461  ocs_memset(ctx, 0, sizeof(*ctx));
10462  ocs_free(hal->os, ctx, sizeof(*ctx));
10463  return 0;
10464 }
10465 
10466 /**
10467  * @brief Process entries on the given mailbox queue.
10468  *
10469  * @param hal Hardware context.
10470  * @param status CQE status.
10471  * @param mq Pointer to the mailbox queue object.
10472  *
10473  * @return Returns 0 on success, or a non-zero value on failure.
10474  */
10475 static int32_t
10476 ocs_hal_mq_process(ocs_hal_t *hal, int32_t status, sli4_queue_t *mq)
10477 {
10478  uint8_t mqe[SLI4_BMBX_SIZE];
10479 
10480  if (!sli_queue_read(&hal->sli, mq, mqe)) {
10481  ocs_hal_command_process(hal, status, mqe, mq->size);
10482  }
10483 
10484  return 0;
10485 }
10486 
10487 /**
10488  * @brief Read a FCF table entry.
10489  *
10490  * @param hal Hardware context.
10491  * @param index Table index to read. Use SLI4_FCOE_FCF_TABLE_FIRST for the first
10492  * read and the next_index field from the FCOE_READ_FCF_TABLE command
10493  * for subsequent reads.
10494  *
10495  * @return Returns 0 on success, or a non-zero value on failure.
10496  */
10497 static ocs_hal_rtn_e
10498 ocs_hal_read_fcf(ocs_hal_t *hal, uint32_t index)
10499 {
10500  ocs_dma_t *dma = NULL;
10501  uint8_t *buf = NULL;
10502  int32_t rc = OCS_HAL_RTN_ERROR;
10503 
10504  buf = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
10505  if (!buf) {
10506  ocs_log_err(hal->os, "no buffer for command\n");
10507  return OCS_HAL_RTN_NO_MEMORY;
10508  }
10509 
10510  dma = ocs_malloc(hal->os, sizeof(*dma), OCS_M_ZERO | OCS_M_NOWAIT);
10511  if (dma == NULL) {
10512  ocs_log_err(hal->os, "ocs_malloc(ocs_dma_t) failed\n");
10513  ocs_free(hal->os, buf, SLI4_BMBX_SIZE);
10514  return OCS_HAL_RTN_NO_MEMORY;
10515  }
10516 
10517  if (ocs_dma_alloc(hal->os, dma, OCS_HAL_READ_FCF_SIZE, OCS_HAL_READ_FCF_SIZE)) {
10518  ocs_log_err(hal->os, "ocs_dma_alloc() failed\n");
10519  ocs_free(hal->os, buf, SLI4_BMBX_SIZE);
10520  ocs_free(hal->os, dma, sizeof(ocs_dma_t));
10521  return OCS_HAL_RTN_ERROR;
10522  }
10523 
10524  if (sli_cmd_fcoe_read_fcf_table(&hal->sli, buf, SLI4_BMBX_SIZE, dma, index)) {
10525  rc = ocs_hal_command(hal, buf, OCS_CMD_NOWAIT, ocs_hal_cb_read_fcf, dma);
10526  }
10527 
10528  if (rc) {
10529  ocs_log_test(hal->os, "FCOE_READ_FCF_TABLE failed\n");
10530  ocs_dma_free(hal->os, dma);
10531  ocs_free(hal->os, dma, sizeof(*dma));
10532  ocs_free(hal->os, buf, SLI4_BMBX_SIZE);
10533  }
10534 
10535  return rc;
10536 }
10537 
10538 /**
10539  * @brief Callback function for the FCOE_READ_FCF_TABLE command.
10540  *
10541  * @par Description
10542  * Note that the caller has allocated:
10543  * - DMA memory to hold the table contents
10544  * - DMA memory structure
10545  * - Command/results buffer
10546  * .
10547  * Each of these must be freed here.
10548  *
10549  * @param hal Hardware context.
10550  * @param status Hardware status.
10551  * @param mqe Pointer to the mailbox command/results buffer.
10552  * @param arg Pointer to the DMA memory structure.
10553  *
10554  * @return Returns 0 on success, or a non-zero value on failure.
10555  */
10556 static int32_t
10557 ocs_hal_cb_read_fcf(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
10558 {
10559  sli4_cmd_sli_config_t *mbox_rsp = (sli4_cmd_sli_config_t *)mqe;
10560  sli4_res_fcoe_read_fcf_table_t *read_fcf_rsp = NULL;
10561  ocs_dma_t *payload = arg;
10562 
10563  read_fcf_rsp = (sli4_res_fcoe_read_fcf_table_t *)payload->virt;
10564  if (!read_fcf_rsp)
10565  goto ocs_hal_cb_read_fcf_done;
10566 
10567  if (read_fcf_rsp->hdr.status)
10568  ocs_hal_log_sli4_rsp_hdr(hal, &read_fcf_rsp->hdr);
10569 
10570  if (0 == status) {
10571  if (mbox_rsp->hdr.status)
10572  status = mbox_rsp->hdr.status;
10573  else if (read_fcf_rsp->hdr.status)
10574  status = read_fcf_rsp->hdr.status;
10575  }
10576 
10577  if (status)
10578  goto ocs_hal_cb_read_fcf_done;
10579 
10580  /* If either FC / FCOE and FCF entry is valid, process it */
10581  if (read_fcf_rsp->fcf_entry.fc || (read_fcf_rsp->fcf_entry.val && !read_fcf_rsp->fcf_entry.sol)) {
10582  if (hal->callback.domain) {
10583  ocs_domain_record_t drec = { 0 };
10584 
10585  if (read_fcf_rsp->fcf_entry.fc) {
10586  /*
10587  * This is a pseudo FCF entry. Create a domain
10588  * record based on the read topology information.
10589  */
10590  drec.speed = hal->link.speed;
10591  drec.fc_id = hal->link.fc_id;
10592  drec.is_fc = TRUE;
10593  if (SLI_LINK_TOPO_LOOP == hal->link.topology) {
10594  drec.is_loop = TRUE;
10595  ocs_memcpy(drec.map.loop, hal->link.loop_map, sizeof(drec.map.loop));
10596  } else if (SLI_LINK_TOPO_NPORT == hal->link.topology) {
10597  drec.is_nport = TRUE;
10598  }
10599  } else {
10600  drec.index = read_fcf_rsp->fcf_entry.fcf_index;
10601  drec.priority = read_fcf_rsp->fcf_entry.fip_priority;
10602 
10603  /* Copy address, wwn and vlan_bitmap */
10604  ocs_memcpy(drec.address, read_fcf_rsp->fcf_entry.fcf_mac_address, sizeof(drec.address));
10605  ocs_memcpy(drec.wwn, read_fcf_rsp->fcf_entry.fabric_name_id, sizeof(drec.wwn));
10606  ocs_memcpy(drec.map.vlan, read_fcf_rsp->fcf_entry.vlan_bitmap, sizeof(drec.map.vlan));
10607 
10608  drec.is_ethernet = TRUE;
10609  drec.is_nport = TRUE;
10610  }
10611 
10612  hal->callback.domain(hal->args.domain, OCS_HAL_DOMAIN_FOUND, &drec);
10613  }
10614  } else {
10615  ocs_log_test(hal->os, "Ignoring the invalid FCF entry\n");
10616  }
10617 
10618  if (SLI4_FCOE_FCF_TABLE_LAST != read_fcf_rsp->next_index)
10619  ocs_hal_read_fcf(hal, read_fcf_rsp->next_index);
10620 
10621 ocs_hal_cb_read_fcf_done:
10622  ocs_dma_free(hal->os, payload);
10623  ocs_free(hal->os, payload, sizeof(*payload));
10624  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
10625  return 0;
10626 }
10627 
10628 /**
10629  * @brief callback function to read link module type
10630  *
10631  * @param ctx Hardware context pointer
10632  * @param MQE completion status
10633  * @param MQE data buffer
10634  * @param optional argument
10635  * @return Returns 0 on success, or a non-zero value on failure.
10636  */
10637 void
10638 __ocs_hal_read_lmt_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
10639 {
10641 
10642  if ((0 == status) && mbox_rsp->hdr.status)
10643  status = mbox_rsp->hdr.status;
10644 
10645  if (0 == status)
10646  hal->sli.config.link_module_type = mbox_rsp->lmt;
10647 
10648  if (hal->callback.xport)
10649  hal->callback.xport(hal->args.xport, OCS_HAL_XPORT_FC_SPEED_UPDATE);
10650 
10651  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
10652 }
10653 
10654 /**
10655  * @brief function to read link module type
10656  *
10657  * @par Description
10658  * This function allocates memory which must be freed in its callback.
10659  *
10660  * @param ctx Hardware context pointer
10661  * @return Returns 0 on success, or a non-zero value on failure.
10662  */
10663 static int32_t
10664 ocs_hal_read_lmt(ocs_hal_t *hal)
10665 {
10666  uint8_t *buf = NULL;
10667  int32_t rc = -1;
10668 
10669  buf = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
10670  if (!buf) {
10671  ocs_log_err(hal->os, "no buffer for command\n");
10672  return rc;
10673  }
10674 
10675  /* Issue read_config to update link module type */
10676  sli_cmd_read_config(&hal->sli, buf, SLI4_BMBX_SIZE);
10677  rc = ocs_hal_command(hal, buf, OCS_CMD_NOWAIT, __ocs_hal_read_lmt_cb, NULL);
10678  if (rc)
10679  ocs_free(hal->os, buf, SLI4_BMBX_SIZE);
10680 
10681  return rc;
10682 }
10683 
10684 /**
10685  * @brief Callback function for the SLI link events.
10686  *
10687  * @par Description
10688  * This function allocates memory which must be freed in its callback.
10689  *
10690  * @param ctx Hardware context pointer (that is, ocs_hal_t *).
10691  * @param e Event structure pointer (that is, sli4_link_event_t *).
10692  *
10693  * @return Returns 0 on success, or a non-zero value on failure.
10694  */
10695 static int32_t
10696 ocs_hal_cb_link(void *ctx, void *e)
10697 {
10698  ocs_hal_t *hal = ctx;
10699  sli4_link_event_t *event = e;
10700  ocs_domain_t *d = NULL;
10701  uint32_t i = 0;
10702  int32_t rc = OCS_HAL_RTN_ERROR;
10703 
10704  switch (event->status) {
10705  case SLI_LINK_STATUS_UP:
10706 
10708  hal->link = *event;
10709 
10710  if (SLI_LINK_TOPO_NPORT == event->topology) {
10711  uint8_t *buf = NULL;
10712  ocs_log_info(hal->os, "Link Up, NPORT, speed is %d\n", event->speed);
10714 
10715  buf = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
10716  if (!buf) {
10717  ocs_log_err(hal->os, "no buffer for command\n");
10718  break;
10719  }
10720 
10721  //Issue read_topology to log FEC settings and state
10722  if (sli_cmd_read_topology(&hal->sli, buf, SLI4_BMBX_SIZE, NULL)) {
10723  rc = ocs_hal_command(hal, buf, OCS_CMD_NOWAIT, __ocs_read_fec_cb, NULL);
10724  }
10725 
10726  if (rc) {
10727  ocs_log_test(hal->os, "READ_TOPOLOGY failed\n");
10728  ocs_free(hal->os, buf, SLI4_BMBX_SIZE);
10729  }
10730  } else if (SLI_LINK_TOPO_LOOP == event->topology) {
10731  uint8_t *buf = NULL;
10732  ocs_log_info(hal->os, "Link Up, LOOP, speed is %d\n", event->speed);
10733  if ((0 == hal->loop_map.size) &&
10734  ocs_dma_alloc(hal->os, &hal->loop_map,
10736  ocs_log_err(hal->os, "XXX ocs_dma_alloc_fail\n");
10737  }
10738 
10739  buf = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
10740  if (!buf) {
10741  ocs_log_err(hal->os, "no buffer for command\n");
10742  break;
10743  }
10744 
10745  if (sli_cmd_read_topology(&hal->sli, buf, SLI4_BMBX_SIZE, &hal->loop_map)) {
10746  rc = ocs_hal_command(hal, buf, OCS_CMD_NOWAIT, __ocs_read_topology_cb, NULL);
10747  }
10748 
10749  if (rc) {
10750  ocs_log_test(hal->os, "READ_TOPOLOGY failed\n");
10751  ocs_free(hal->os, buf, SLI4_BMBX_SIZE);
10752  }
10753  } else if (SLI_LINK_TOPO_LOOPBACK_INTERNAL == event->topology) {
10754  ocs_log_info(hal->os, "Link Up, link in internal loopback mode, speed is %d\n", event->speed);
10756  } else {
10757  ocs_log_info(hal->os, "Link Up, unsupported topology (%#x), speed is %d\n",
10758  event->topology, event->speed);
10759  }
10760  break;
10761  case SLI_LINK_STATUS_DOWN:
10762  ocs_log_info(hal->os, "Link down\n");
10763 
10765  hal->link.status = event->status;
10766 
10767  for (i = 0; i < SLI4_MAX_FCFI; i++) {
10768  d = hal->domains[i];
10769  if (d != NULL && hal->callback.domain != NULL) {
10770  hal->callback.domain(hal->args.domain, OCS_HAL_DOMAIN_LOST, d);
10771  }
10772  }
10773  break;
10775  ocs_hal_read_lmt(hal);
10776  break;
10778  hal->link.logical_link_speed = event->logical_link_speed;
10779  hal->link.aggregate_link_speed = event->aggregate_link_speed;
10780  break;
10781  default:
10782  ocs_log_test(hal->os, "unhandled link status %#x\n", event->status);
10783  break;
10784  }
10785 
10786  return 0;
10787 }
10788 
10789 static int32_t
10790 ocs_hal_cb_fip(void *ctx, void *e)
10791 {
10792  ocs_hal_t *hal = ctx;
10793  ocs_domain_t *domain = NULL;
10794  sli4_fip_event_t *event = e;
10795 
10796  // Find the associated domain object
10797  if (event->type == SLI4_FCOE_FIP_FCF_CLEAR_VLINK) {
10798  ocs_domain_t *d = NULL;
10799  uint32_t i = 0;
10800 
10801  // Clear VLINK is different from the other FIP events as it passes back
10802  // a VPI instead of a FCF index. Check all attached SLI ports for a
10803  // matching VPI
10804  for (i = 0; i < SLI4_MAX_FCFI; i++) {
10805  d = hal->domains[i];
10806  if (d != NULL) {
10807  ocs_sport_t *sport = NULL;
10808 
10809  ocs_list_foreach(&d->sport_list, sport) {
10810  if (sport->indicator == event->index) {
10811  domain = d;
10812  break;
10813  }
10814  }
10815 
10816  // Did we find a matching domain?
10817  if (domain != NULL) {
10818  break;
10819  }
10820  }
10821  }
10822  } else {
10823  domain = ocs_hal_domain_get_indexed(hal, event->index);
10824  }
10825 
10826  switch (event->type) {
10828  ocs_hal_read_fcf(hal, event->index);
10829  break;
10831  if (domain != NULL &&
10832  hal->callback.domain != NULL) {
10833  hal->callback.domain(hal->args.domain, OCS_HAL_DOMAIN_LOST, domain);
10834  }
10835  break;
10837  if (domain != NULL &&
10838  hal->callback.domain != NULL) {
10839  /*
10840  * We will want to issue rediscover FCF when this domain is free'd in order
10841  * to invalidate the FCF table
10842  */
10843  domain->req_rediscover_fcf = TRUE;
10844  hal->callback.domain(hal->args.domain, OCS_HAL_DOMAIN_LOST, domain);
10845  }
10846  break;
10848  if (domain != NULL &&
10849  hal->callback.domain != NULL) {
10850  hal->callback.domain(hal->args.domain, OCS_HAL_DOMAIN_LOST, domain);
10851  }
10852 
10853  ocs_hal_read_fcf(hal, event->index);
10854  break;
10855  default:
10856  ocs_log_test(hal->os, "unsupported event %#x\n", event->type);
10857  }
10858 
10859  return 0;
10860 }
10861 
10862 static int32_t
10863 ocs_hal_cb_node_attach(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
10864 {
10865  ocs_remote_node_t *rnode = arg;
10868 
10869  if (status || hdr->status) {
10870  rnode->attached = FALSE;
10872  } else {
10873  rnode->attached = TRUE;
10874  ocs_atomic_set(&hal->rpi_ref[rnode->index].rpi_attached, 1);
10875  evt = OCS_HAL_NODE_ATTACH_OK;
10876  }
10877 
10878  if (hal->callback.rnode)
10879  hal->callback.rnode(hal->args.rnode, evt, rnode);
10880 
10881  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
10882  return 0;
10883 }
10884 
10885 static int32_t
10886 ocs_hal_cb_node_free(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
10887 {
10888  ocs_remote_node_t *rnode = arg;
10891  int32_t rc = 0;
10892 
10893  if (status || hdr->status) {
10894  /*
10895  * In certain cases, a non-zero MQE status is OK (all must be true):
10896  * - node is attached
10897  * - if High Login Mode is enabled, node is part of a node group
10898  * - status is 0x1400
10899  */
10900  if (!rnode->attached || ((sli_get_hlm(&hal->sli) == TRUE) && !rnode->node_group) ||
10902  rc = -1;
10903  }
10904  }
10905 
10906  if (rc == 0) {
10907  rnode->node_group = FALSE;
10908  rnode->attached = FALSE;
10909  evt = OCS_HAL_NODE_FREE_OK;
10910  }
10911 
10912  /* In HLM, Free the RPI after the last remote node unregistered.
10913  * rnode->indicator is valid for the last UNREG_RPI of remote node */
10914  if (rnode->indicator != UINT32_MAX) {
10915  if (sli_resource_free(&hal->sli, SLI_RSRC_FCOE_RPI, rnode->indicator)) {
10916  ocs_log_err(hal->os, "FCOE_RPI (%d) free failed, addr=%#x\n", rnode->indicator, rnode->fc_id);
10917  }
10918 
10919  rnode->indicator = UINT32_MAX;
10920  }
10921 
10922  rnode->free_group = FALSE;
10923  if (hal->callback.rnode)
10924  hal->callback.rnode(hal->args.rnode, evt, rnode);
10925 
10926  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
10927  return rc;
10928 }
10929 
10930 static int32_t
10931 ocs_hal_cb_unreg_rpi_all(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
10932 {
10935  ocs_sport_t *sport = arg;
10936  ocs_remote_node_t *rnode;
10937  ocs_node_t *node;
10938  ocs_node_t *node_next;
10939  int32_t rc = 0;
10940 
10941  if (status || hdr->status) {
10942  rc = -1;
10943  } else {
10944  evt = OCS_HAL_NODE_FREE_OK;
10945  }
10946 
10947  ocs_list_foreach_safe(&sport->node_list, node, node_next) {
10948  rnode = &node->rnode;
10949  if (!rnode->attached)
10950  continue;
10951 
10952  rnode->node_group = FALSE;
10953  rnode->attached = FALSE;
10954  if (ocs_atomic_read(&hal->rpi_ref[rnode->index].rpi_count) == 0)
10955  ocs_atomic_set(&hal->rpi_ref[rnode->index].rpi_attached, 0);
10956 
10957  if (hal->callback.rnode)
10958  hal->callback.rnode(hal->args.rnode, evt, rnode);
10959  }
10960 
10961  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
10962  return rc;
10963 }
10964 
10965 /**
10966  * @brief Initialize the pool of HAL IO objects.
10967  *
10968  * @param hal Hardware context.
10969  *
10970  * @return Returns 0 on success, or a non-zero value on failure.
10971  */
10972 static ocs_hal_rtn_e
10973 ocs_hal_setup_io(ocs_hal_t *hal)
10974 {
10975  uint32_t i = 0;
10976  ocs_hal_io_t *io = NULL;
10977  uintptr_t xfer_virt = 0;
10978  uintptr_t xfer_phys = 0;
10979  uint32_t index;
10980  uint8_t new_alloc = TRUE;
10981 
10982  if (NULL == hal->io) {
10983  hal->io = ocs_malloc(hal->os, hal->config.n_io * sizeof(ocs_hal_io_t *), OCS_M_ZERO | OCS_M_NOWAIT);
10984 
10985  if (NULL == hal->io) {
10986  ocs_log_err(hal->os, "IO pointer memory allocation failed, %d Ios at size %zu\n",
10987  hal->config.n_io,
10988  sizeof(ocs_hal_io_t *));
10989  return OCS_HAL_RTN_NO_MEMORY;
10990  }
10991  for (i = 0; i < hal->config.n_io; i++) {
10992  hal->io[i] = ocs_malloc(hal->os, sizeof(ocs_hal_io_t),
10993  OCS_M_ZERO | OCS_M_NOWAIT);
10994  if (hal->io[i] == NULL) {
10995  ocs_log_err(hal->os, "IO(%d) memory allocation failed\n", i);
10996  goto error;
10997  }
10998  }
10999 
11000  /* Create WQE buffs for IO */
11001  hal->wqe_buffs = ocs_malloc(hal->os, hal->config.n_io * hal->sli.config.wqe_size,
11002  OCS_M_ZERO | OCS_M_NOWAIT);
11003  if (NULL == hal->wqe_buffs) {
11004  ocs_free(hal->os, hal->io, hal->config.n_io * sizeof(ocs_hal_io_t));
11005  ocs_log_err(hal->os, "IO WQE buff allocation failed, %d Ios at size %zu\n",
11006  hal->config.n_io, hal->sli.config.wqe_size);
11007  return OCS_HAL_RTN_NO_MEMORY;
11008  }
11009 
11010  } else {
11011  /* re-use existing IOs, including SGLs */
11012  new_alloc = FALSE;
11013  }
11014 
11015  if (new_alloc) {
11016  if (ocs_dma_alloc(hal->os, &hal->xfer_rdy,
11017  sizeof(fcp_xfer_rdy_iu_t) * hal->config.n_io,
11018  4/*XXX what does this need to be? */)) {
11019  ocs_log_err(hal->os, "XFER_RDY buffer allocation failed\n");
11020  return OCS_HAL_RTN_NO_MEMORY;
11021  }
11022  }
11023  xfer_virt = (uintptr_t)hal->xfer_rdy.virt;
11024  xfer_phys = hal->xfer_rdy.phys;
11025 
11026  for (i = 0; i < hal->config.n_io; i++) {
11027  hal_wq_callback_t *wqcb;
11028 
11029  io = hal->io[i];
11030 
11031  /* initialize IO fields */
11032  io->hal = hal;
11033 
11034  /* Assign a WQE buff */
11035  io->wqe.wqebuf = &hal->wqe_buffs[i * hal->sli.config.wqe_size];
11036 
11037  /* Allocate the request tag for this IO */
11039  if (wqcb == NULL) {
11040  ocs_log_err(hal->os, "can't allocate request tag\n");
11041  return OCS_HAL_RTN_NO_RESOURCES;
11042  }
11043  io->reqtag = wqcb->instance_index;
11044 
11045  /* Now for the fields that are initialized on each free */
11047 
11048  /* The XB flag isn't cleared on IO free, so initialize it to zero here */
11049  io->xbusy = 0;
11050 
11051  if (sli_resource_alloc(&hal->sli, SLI_RSRC_FCOE_XRI, &io->indicator, &index)) {
11052  ocs_log_err(hal->os, "sli_resource_alloc failed @ %d\n", i);
11053  return OCS_HAL_RTN_NO_MEMORY;
11054  }
11055 
11056  if (new_alloc && ocs_dma_alloc(hal->os, &io->def_sgl, hal->config.n_sgl * sizeof(sli4_sge_t), 64)) {
11057  ocs_log_err(hal->os, "ocs_dma_alloc failed @ %d\n", i);
11058  ocs_memset(&io->def_sgl, 0, sizeof(ocs_dma_t));
11059  return OCS_HAL_RTN_NO_MEMORY;
11060  }
11061  io->def_sgl_count = hal->config.n_sgl;
11062  io->sgl = &io->def_sgl;
11063  io->sgl_count = io->def_sgl_count;
11064 
11065  if (hal->xfer_rdy.size) {
11066  io->xfer_rdy.virt = (void *)xfer_virt;
11067  io->xfer_rdy.phys = xfer_phys;
11068  io->xfer_rdy.size = sizeof(fcp_xfer_rdy_iu_t);
11069 
11070  xfer_virt += sizeof(fcp_xfer_rdy_iu_t);
11071  xfer_phys += sizeof(fcp_xfer_rdy_iu_t);
11072  }
11073  }
11074 
11075  return OCS_HAL_RTN_SUCCESS;
11076 error:
11077  for (i = 0; i < hal->config.n_io && hal->io[i]; i++) {
11078  ocs_free(hal->os, hal->io[i], sizeof(ocs_hal_io_t));
11079  hal->io[i] = NULL;
11080  }
11081 
11082  return OCS_HAL_RTN_NO_MEMORY;
11083 }
11084 
11085 static ocs_hal_rtn_e
11086 ocs_hal_init_io(ocs_hal_t *hal)
11087 {
11088  uint32_t i = 0, io_index = 0;
11089  uint32_t prereg = 0, sge_index = 0;
11090  ocs_hal_io_t *io = NULL;
11091  uint8_t cmd[SLI4_BMBX_SIZE];
11093  uint32_t nremaining;
11094  uint32_t n = 0;
11095  uint32_t sgls_per_request = 256;
11096  ocs_dma_t **sgls = NULL;
11097  ocs_dma_t reqbuf = { 0 };
11098  uint16_t reqbuf_length = sizeof(sli4_req_fcoe_post_sgl_pages_t) +
11099  sizeof(sli4_fcoe_post_sgl_page_desc_t)*sgls_per_request;
11100 
11101  prereg = sli_get_sgl_preregister(&hal->sli);
11102  if (prereg) {
11103  sgls = ocs_malloc(hal->os, sizeof(*sgls) * sgls_per_request, OCS_M_NOWAIT);
11104  if (sgls == NULL) {
11105  ocs_log_err(hal->os, "ocs_malloc sgls failed\n");
11106  return OCS_HAL_RTN_NO_MEMORY;
11107  }
11108 
11109  /* Create a buffer that can hold sgls for 256 SGLs at a time */
11110  rc = ocs_dma_alloc(hal->os, &reqbuf, reqbuf_length, OCS_MIN_DMA_ALIGNMENT);
11111  if (rc) {
11112  ocs_log_err(hal->os, "ocs_dma_alloc reqbuf failed\n");
11113  ocs_free(hal->os, sgls, sizeof(*sgls) * sgls_per_request);
11114  return OCS_HAL_RTN_NO_MEMORY;
11115  }
11116  }
11117 
11118  for (nremaining = hal->config.n_io; nremaining; nremaining -= n) {
11119  if (prereg) {
11120  /* Copy address of SGL's into local sgls[] array, break out if the xri
11121  * is not contiguous.
11122  */
11123  for (n = 0; n < MIN(sgls_per_request, nremaining); n++) {
11124  sge_index = io_index + n;
11125 
11126  /* Check that we have contiguous xri values */
11127  if (n > 0) {
11128  if (hal->io[sge_index]->indicator != (hal->io[sge_index-1]->indicator+1)) {
11129  break;
11130  }
11131  }
11132  sgls[n] = hal->io[sge_index]->sgl;
11133  }
11134 
11135  sli_cmd_fcoe_post_sgl_pages(&hal->sli, cmd, sizeof(cmd),
11136  hal->io[io_index]->indicator, n, sgls, NULL, &reqbuf);
11137  rc = ocs_hal_command(hal, cmd, OCS_CMD_POLL, NULL, NULL);
11138  if (rc) {
11139  rc = OCS_HAL_RTN_ERROR;
11140  break;
11141  }
11142  } else {
11143  n = nremaining;
11144  }
11145 
11146  /* Add to tail if successful */
11147  for (i = 0; i < n; i++, io_index++) {
11148  io = hal->io[io_index];
11149  io->is_port_owned = 0;
11150  io->state = OCS_HAL_IO_STATE_FREE;
11151  ocs_list_add_tail(&hal->io_free, io);
11152  }
11153  }
11154 
11155  if (prereg) {
11156  ocs_dma_free(hal->os, &reqbuf);
11157  ocs_free(hal->os, sgls, sizeof(*sgls) * sgls_per_request);
11158  }
11159 
11160  return rc;
11161 }
11162 
11163 int32_t
11164 ocs_hal_flush(ocs_hal_t *hal)
11165 {
11166  uint32_t i = 0;
11167 
11168  /* Process any remaining completions */
11169  for (i = 0; i < hal->eq_count; i++) {
11170  ocs_hal_process(hal, i, ~0);
11171  }
11172 
11173  return 0;
11174 }
11175 
11176 static int32_t
11177 ocs_hal_command_cancel(ocs_hal_t *hal)
11178 {
11179 
11180  ocs_lock(&hal->cmd_lock);
11181 
11182  /*
11183  * Manually clean up remaining commands. Note: since this calls
11184  * ocs_hal_command_process(), we'll also process the cmd_pending
11185  * list, so no need to manually clean that out.
11186  */
11187  while (!ocs_list_empty(&hal->cmd_head)) {
11188  uint8_t mqe[SLI4_BMBX_SIZE] = { 0 };
11189  ocs_command_ctx_t *ctx = ocs_list_get_head(&hal->cmd_head);
11190 
11191  ocs_log_test(hal->os, "hung command %08x\n",
11192  NULL == ctx ? UINT32_MAX :
11193  (NULL == ctx->buf ? UINT32_MAX : *((uint32_t *)ctx->buf)));
11194  ocs_unlock(&hal->cmd_lock);
11195  ocs_hal_command_process(hal, -1/*Bad status*/, mqe, SLI4_BMBX_SIZE);
11196  ocs_lock(&hal->cmd_lock);
11197  }
11198 
11199  ocs_unlock(&hal->cmd_lock);
11200 
11201  return 0;
11202 }
11203 
11204 /**
11205  * @brief Find IO given indicator (xri).
11206  *
11207  * @param hal Hal context.
11208  * @param indicator Indicator (xri) to look for.
11209  *
11210  * @return Returns io if found, NULL otherwise.
11211  */
11212 ocs_hal_io_t *
11213 ocs_hal_io_lookup(ocs_hal_t *hal, uint32_t xri)
11214 {
11215  uint32_t ioindex;
11216  ioindex = xri - hal->sli.config.extent[SLI_RSRC_FCOE_XRI].base[0];
11217  return hal->io[ioindex];
11218 }
11219 
11220 /**
11221  * @brief Issue any pending callbacks for an IO and remove off the timer and pending lists.
11222  *
11223  * @param hal Hal context.
11224  * @param io Pointer to the IO to cleanup.
11225  */
11226 static void
11227 ocs_hal_io_cancel_cleanup(ocs_hal_t *hal, ocs_hal_io_t *io)
11228 {
11229  ocs_hal_done_t done = io->done;
11230  ocs_hal_done_t abort_done = io->abort_done;
11231 
11232  /* first check active_wqe list and remove if there */
11233  if (ocs_list_on_list(&io->wqe_link) && !ocs_list_empty(&hal->io_timed_wqe)) {
11234  ocs_list_remove(&hal->io_timed_wqe, io);
11235  }
11236 
11237  /* Remove from WQ pending list */
11238  if ((io->wq != NULL) && ocs_list_on_list(&io->wq->pending_list) &&
11239  !ocs_list_empty(&io->wq->pending_list)) {
11240  ocs_list_remove(&io->wq->pending_list, io);
11241  }
11242 
11243  if (io->done) {
11244  void *arg = io->arg;
11245 
11246  io->done = NULL;
11247  ocs_unlock(&hal->io_lock);
11248  done(io, io->rnode, 0, SLI4_FC_WCQE_STATUS_SHUTDOWN, 0, arg);
11249  ocs_lock(&hal->io_lock);
11250  }
11251 
11252  if (io->abort_done != NULL) {
11253  void *abort_arg = io->abort_arg;
11254 
11255  io->abort_done = NULL;
11256  ocs_unlock(&hal->io_lock);
11257  abort_done(io, io->rnode, 0, SLI4_FC_WCQE_STATUS_SHUTDOWN, 0, abort_arg);
11258  ocs_lock(&hal->io_lock);
11259  }
11260 }
11261 
11262 int32_t ocs_hal_io_cancel(ocs_hal_t *hal)
11263 {
11264  ocs_hal_io_t *io = NULL;
11265  ocs_hal_io_t *tmp_io = NULL;
11266  uint32_t iters = 100; // One second limit
11267 
11268  /*
11269  * Manually clean up outstanding IO.
11270  * Only walk through list once: the backend will cleanup any IOs when done/abort_done is called.
11271  */
11272  ocs_lock(&hal->io_lock);
11273  ocs_list_foreach_safe(&hal->io_inuse, io, tmp_io) {
11274  ocs_hal_done_t done = io->done;
11275  ocs_hal_done_t abort_done = io->abort_done;
11276 
11277  ocs_hal_io_cancel_cleanup(hal, io);
11278 
11279  /*
11280  * Since this is called in a reset/shutdown
11281  * case, If there is no callback, then just
11282  * free the IO.
11283  *
11284  * Note: A port owned XRI cannot be on
11285  * the in use list. We cannot call
11286  * ocs_hal_io_free() because we already
11287  * hold the io_lock.
11288  */
11289  if (done == NULL &&
11290  abort_done == NULL) {
11291  /*
11292  * Since this is called in a reset/shutdown
11293  * case, If there is no callback, then just
11294  * free the IO.
11295  */
11296  ocs_hal_io_free_common(hal, io);
11297  ocs_list_remove(&hal->io_inuse, io);
11299  }
11300  }
11301 
11302  /*
11303  * For port owned XRIs, they are not on the in use list, so
11304  * walk though XRIs and issue any callbacks.
11305  */
11306  ocs_list_foreach_safe(&hal->io_port_owned, io, tmp_io) {
11307  /* check list and remove if there */
11308  if (ocs_list_on_list(&io->dnrx_link)) {
11309  ocs_list_remove(&hal->io_port_dnrx, io);
11310  ocs_ref_put(&io->ref); /* ocs_ref_get(): same function */
11311  }
11312  ocs_hal_io_cancel_cleanup(hal, io);
11313  ocs_list_remove(&hal->io_port_owned, io);
11314  ocs_hal_io_free_common(hal, io);
11315  }
11316  ocs_unlock(&hal->io_lock);
11317 
11318  /* Give time for the callbacks to complete */
11319  do {
11320  ocs_delay_usec(10000);
11321  iters--;
11322  } while (!ocs_list_empty(&hal->io_inuse) && iters);
11323 
11324  /* Leave a breadcrumb that cleanup is not yet complete. */
11325  if (!ocs_list_empty(&hal->io_inuse)) {
11326  ocs_log_test(hal->os, "io_inuse list is not empty\n");
11327  }
11328 
11329  return 0;
11330 }
11331 
11332 static int32_t
11333 ocs_hal_io_ini_sge(ocs_hal_t *hal, ocs_hal_io_t *io, ocs_dma_t *cmnd, uint32_t cmnd_size,
11334  ocs_dma_t *rsp)
11335 {
11336  sli4_sge_t *data = NULL;
11337 
11338  if (!hal || !io) {
11339  ocs_log_err(NULL, "bad parm hal=%p io=%p\n", hal, io);
11340  return OCS_HAL_RTN_ERROR;
11341  }
11342 
11343  data = io->def_sgl.virt;
11344 
11345  // setup command pointer
11346  data->buffer_address_high = ocs_addr32_hi(cmnd->phys);
11347  data->buffer_address_low = ocs_addr32_lo(cmnd->phys);
11348  data->buffer_length = cmnd_size;
11349  data++;
11350 
11351  // setup response pointer
11352  data->buffer_address_high = ocs_addr32_hi(rsp->phys);
11353  data->buffer_address_low = ocs_addr32_lo(rsp->phys);
11354  data->buffer_length = rsp->size;
11355 
11356  return 0;
11357 }
11358 
11359 // log the fec status for debug purpose
11360 static int32_t
11361 __ocs_read_fec_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
11362 {
11364 
11365  if ((0 == status) && (0 == read_topo->hdr.status))
11366  ocs_log_info(hal->os, "fec_enable = %d, fec_state = %d, current_link_speed = %d\n",
11367  read_topo->fecen, read_topo->fec, read_topo->link_current.link_speed);
11368 
11369  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
11370  return 0;
11371 }
11372 
11373 static int32_t
11374 __ocs_read_topology_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
11375 {
11377 
11378  if (status || read_topo->hdr.status) {
11379  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
11380  return -1;
11381  }
11382 
11383  switch (read_topo->attention_type) {
11385  hal->link.status = SLI_LINK_STATUS_UP;
11386  break;
11388  hal->link.status = SLI_LINK_STATUS_DOWN;
11389  break;
11391  hal->link.status = SLI_LINK_STATUS_NO_ALPA;
11392  break;
11393  default:
11394  hal->link.status = SLI_LINK_STATUS_MAX;
11395  break;
11396  }
11397 
11398  switch (read_topo->topology) {
11400  hal->link.topology = SLI_LINK_TOPO_NPORT;
11401  break;
11403  hal->link.topology = SLI_LINK_TOPO_LOOP;
11404  if (SLI_LINK_STATUS_UP == hal->link.status) {
11405  hal->link.loop_map = hal->loop_map.virt;
11406  }
11407  hal->link.fc_id = read_topo->acquired_al_pa;
11408  break;
11409  default:
11410  hal->link.topology = SLI_LINK_TOPO_MAX;
11411  break;
11412  }
11413 
11414  hal->link.medium = SLI_LINK_MEDIUM_FC;
11415 
11416  switch (read_topo->link_current.link_speed) {
11418  hal->link.speed = 1 * 1000;
11419  break;
11421  hal->link.speed = 2 * 1000;
11422  break;
11424  hal->link.speed = 4 * 1000;
11425  break;
11427  hal->link.speed = 8 * 1000;
11428  break;
11430  hal->link.speed = 16 * 1000;
11431  hal->link.loop_map = NULL;
11432  break;
11434  hal->link.speed = 32 * 1000;
11435  hal->link.loop_map = NULL;
11436  break;
11437  }
11438 
11439  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
11441 
11442  return 0;
11443 }
11444 
11445 static int32_t
11446 __ocs_hal_port_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
11447 {
11448  ocs_sli_port_t *sport = ctx->app;
11449  ocs_hal_t *hal = sport->hal;
11450 
11451  smtrace("port");
11452 
11453  switch (evt) {
11454  case OCS_EVT_EXIT:
11455  /* ignore */
11456  break;
11457 
11460  if (data != NULL) {
11461  ocs_free(hal->os, data, SLI4_BMBX_SIZE);
11462  }
11463  /* fall through */
11464  default:
11465  ocs_log_test(hal->os, "%s %-20s not handled\n", funcname, ocs_sm_event_name(evt));
11466  break;
11467  }
11468 
11469  return 0;
11470 }
11471 
11472 static void *
11473 __ocs_hal_port_free_report_fail(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
11474 {
11475  ocs_sli_port_t *sport = ctx->app;
11476  ocs_hal_t *hal = sport->hal;
11477 
11478  smtrace("port");
11479 
11480  switch (evt) {
11481  case OCS_EVT_ENTER:
11482  if (data != NULL) {
11483  ocs_free(hal->os, data, SLI4_BMBX_SIZE);
11484  }
11485  if (hal->callback.port != NULL) {
11486  hal->callback.port(hal->args.port,
11487  OCS_HAL_PORT_FREE_FAIL, sport);
11488  }
11489  break;
11490  default:
11491  break;
11492  }
11493 
11494  return NULL;
11495 }
11496 
11497 static void *
11498 __ocs_hal_port_freed(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
11499 {
11500  ocs_sli_port_t *sport = ctx->app;
11501  ocs_hal_t *hal = sport->hal;
11502 
11503  smtrace("port");
11504 
11505  switch (evt) {
11506  case OCS_EVT_ENTER:
11507  /* free SLI resource */
11508  if (sli_resource_free(&hal->sli, SLI_RSRC_FCOE_VPI, sport->indicator)) {
11509  ocs_log_err(hal->os, "FCOE_VPI (%d) free failed, addr=%#x\n", sport->indicator, sport->fc_id);
11510  }
11511 
11512  /* free mailbox buffer */
11513  if (data != NULL) {
11514  ocs_free(hal->os, data, SLI4_BMBX_SIZE);
11515  }
11516 
11517  if (hal->callback.port != NULL) {
11518  hal->callback.port(hal->args.port,
11519  OCS_HAL_PORT_FREE_OK, sport);
11520  }
11521  break;
11522  default:
11523  break;
11524  }
11525 
11526  return NULL;
11527 }
11528 
11529 static void *
11530 __ocs_hal_port_attach_report_fail(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
11531 {
11532  ocs_sli_port_t *sport = ctx->app;
11533  ocs_hal_t *hal = sport->hal;
11534 
11535  smtrace("port");
11536 
11537  switch (evt) {
11538  case OCS_EVT_ENTER:
11539  /* free SLI resource */
11540  if (sli_resource_free(&hal->sli, SLI_RSRC_FCOE_VPI, sport->indicator)) {
11541  ocs_log_err(hal->os, "FCOE_VPI (%d) free failed, addr=%#x\n", sport->indicator, sport->fc_id);
11542  }
11543 
11544  /* free mailbox buffer */
11545  if (data != NULL) {
11546  ocs_free(hal->os, data, SLI4_BMBX_SIZE);
11547  }
11548 
11549  if (hal->callback.port != NULL) {
11550  hal->callback.port(hal->args.port,
11551  OCS_HAL_PORT_ATTACH_FAIL, sport);
11552  }
11553 
11554  if (sport->sm_free_req_pending) {
11556  }
11557  break;
11558  default:
11559  __ocs_hal_port_common(__func__, ctx, evt, data);
11560  break;
11561  }
11562 
11563  return NULL;
11564 }
11565 
11566 static void *
11567 __ocs_hal_port_free_unreg_vpi(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
11568 {
11569  ocs_sli_port_t *sport = ctx->app;
11570  ocs_hal_t *hal = sport->hal;
11571  uint8_t *cmd = NULL;
11572 
11573  smtrace("port");
11574 
11575  switch (evt) {
11576  case OCS_EVT_ENTER:
11577  /* allocate memory and send unreg_vpi */
11578  cmd = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
11579  if (!cmd) {
11580  ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
11581  break;
11582  }
11583 
11584  if (0 == sli_cmd_unreg_vpi(&hal->sli, cmd, SLI4_BMBX_SIZE, sport->indicator,
11586  ocs_log_err(hal->os, "UNREG_VPI format failure\n");
11587  ocs_free(hal->os, cmd, SLI4_BMBX_SIZE);
11588  ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
11589  break;
11590  }
11591 
11592  if (ocs_hal_command(hal, cmd, OCS_CMD_NOWAIT, __ocs_hal_port_cb, sport)) {
11593  ocs_free(hal->os, cmd, SLI4_BMBX_SIZE);
11594  ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
11595  }
11596 
11597  break;
11598  case OCS_EVT_RESPONSE:
11600  break;
11601  case OCS_EVT_ERROR:
11603  break;
11604  default:
11605  __ocs_hal_port_common(__func__, ctx, evt, data);
11606  break;
11607  }
11608 
11609  return NULL;
11610 }
11611 
11612 static void *
11613 __ocs_hal_port_free_nop(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
11614 {
11615  ocs_sli_port_t *sport = ctx->app;
11616  ocs_hal_t *hal = sport->hal;
11617 
11618  smtrace("port");
11619 
11620  switch (evt) {
11621  case OCS_EVT_ENTER:
11622  /* Forward to execute in mailbox completion processing context */
11623  if (ocs_hal_async_call(hal, __ocs_hal_port_realloc_cb, sport)) {
11624  ocs_log_err(hal->os, "ocs_hal_async_call failed\n");
11625  }
11626  break;
11627  case OCS_EVT_RESPONSE:
11629  break;
11630  case OCS_EVT_ERROR:
11632  break;
11633  default:
11634  break;
11635  }
11636 
11637  return NULL;
11638 }
11639 
11640 static void *
11641 __ocs_hal_port_attached(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
11642 {
11643  ocs_sli_port_t *sport = ctx->app;
11644  ocs_hal_t *hal = sport->hal;
11645 
11646  smtrace("port");
11647 
11648  switch (evt) {
11649  case OCS_EVT_ENTER:
11650  if (data != NULL) {
11651  ocs_free(hal->os, data, SLI4_BMBX_SIZE);
11652  }
11653  if (hal->callback.port != NULL) {
11654  hal->callback.port(hal->args.port,
11655  OCS_HAL_PORT_ATTACH_OK, sport);
11656  }
11657  if (sport->sm_free_req_pending) {
11659  }
11660  break;
11662  /* virtual/physical port request free */
11664  break;
11665  default:
11666  __ocs_hal_port_common(__func__, ctx, evt, data);
11667  break;
11668  }
11669 
11670  return NULL;
11671 }
11672 
11673 static void *
11674 __ocs_hal_port_attach_reg_vpi(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
11675 {
11676  ocs_sli_port_t *sport = ctx->app;
11677  ocs_hal_t *hal = sport->hal;
11678 
11679  smtrace("port");
11680 
11681  switch (evt) {
11682  case OCS_EVT_ENTER:
11683  if (0 == sli_cmd_reg_vpi(&hal->sli, data, SLI4_BMBX_SIZE, sport, FALSE)) {
11684  ocs_log_err(hal->os, "REG_VPI format failure\n");
11685  ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
11686  break;
11687  }
11688 
11689  if (ocs_hal_command(hal, data, OCS_CMD_NOWAIT, __ocs_hal_port_cb, sport))
11690  ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
11691 
11692  break;
11693  case OCS_EVT_RESPONSE:
11695  break;
11696  case OCS_EVT_ERROR:
11698  break;
11700  /* Wait for attach response and then free */
11701  sport->sm_free_req_pending = 1;
11702  break;
11703  default:
11704  __ocs_hal_port_common(__func__, ctx, evt, data);
11705  break;
11706  }
11707 
11708  return NULL;
11709 }
11710 
11711 static void *
11712 __ocs_hal_port_done(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
11713 {
11714  ocs_sli_port_t *sport = ctx->app;
11715  ocs_hal_t *hal = sport->hal;
11716 
11717  smtrace("port");
11718 
11719  switch (evt) {
11720  case OCS_EVT_ENTER:
11721  /* free SLI resource */
11722  if (sli_resource_free(&hal->sli, SLI_RSRC_FCOE_VPI, sport->indicator)) {
11723  ocs_log_err(hal->os, "FCOE_VPI (%d) free failed, addr=%#x\n", sport->indicator, sport->fc_id);
11724  }
11725 
11726  /* free mailbox buffer */
11727  if (data != NULL) {
11728  ocs_free(hal->os, data, SLI4_BMBX_SIZE);
11729  }
11730  break;
11731  default:
11732  __ocs_hal_port_common(__func__, ctx, evt, data);
11733  break;
11734  }
11735 
11736  return NULL;
11737 }
11738 
11739 static void *
11740 __ocs_hal_port_allocated(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
11741 {
11742  ocs_sli_port_t *sport = ctx->app;
11743  ocs_hal_t *hal = sport->hal;
11744 
11745  smtrace("port");
11746 
11747  switch (evt) {
11748  case OCS_EVT_ENTER:
11749  if (data != NULL) {
11750  ocs_free(hal->os, data, SLI4_BMBX_SIZE);
11751  }
11752  if (hal->callback.port != NULL) {
11753  hal->callback.port(hal->args.port,
11754  OCS_HAL_PORT_ALLOC_OK, sport);
11755  }
11756  /* If there is a pending free request, then handle it now */
11757  if (sport->sm_free_req_pending) {
11759  }
11760  break;
11762  /* virtual port requests attach */
11764  break;
11766  /* physical port attached (as part of attaching domain) */
11768  break;
11770  /* virtual port request free */
11771  if (SLI4_IF_TYPE_LANCER_FC_ETH == sli_get_if_type(&hal->sli)) {
11773  } else {
11774  /*
11775  * Note: BE3/Skyhawk will respond with a status of 0x20
11776  * unless the reg_vpi has been issued, so we can
11777  * skip the unreg_vpi for these adapters.
11778  *
11779  * Send a nop to make sure that free doesn't occur in
11780  * same context
11781  */
11783  }
11784  break;
11785  default:
11786  __ocs_hal_port_common(__func__, ctx, evt, data);
11787  break;
11788  }
11789 
11790  return NULL;
11791 }
11792 
11793 static void *
11794 __ocs_hal_port_alloc_report_fail(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
11795 {
11796  ocs_sli_port_t *sport = ctx->app;
11797  ocs_hal_t *hal = sport->hal;
11798 
11799  smtrace("port");
11800 
11801  switch (evt) {
11802  case OCS_EVT_ENTER:
11803  /* free SLI resource */
11804  if (sli_resource_free(&hal->sli, SLI_RSRC_FCOE_VPI, sport->indicator)) {
11805  ocs_log_err(hal->os, "FCOE_VPI (%d) free failed, addr=%#x\n", sport->indicator, sport->fc_id);
11806  }
11807 
11808  /* free mailbox buffer */
11809  if (data != NULL) {
11810  ocs_free(hal->os, data, SLI4_BMBX_SIZE);
11811  }
11812 
11813  if (hal->callback.port != NULL) {
11814  hal->callback.port(hal->args.port,
11815  OCS_HAL_PORT_ALLOC_FAIL, sport);
11816  }
11817 
11818  /* If there is a pending free request, then handle it now */
11819  if (sport->sm_free_req_pending) {
11821  }
11822  break;
11823  default:
11824  __ocs_hal_port_common(__func__, ctx, evt, data);
11825  break;
11826  }
11827 
11828  return NULL;
11829 }
11830 
11831 static void *
11832 __ocs_hal_port_alloc_read_sparm64(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
11833 {
11834  ocs_sli_port_t *sport = ctx->app;
11835  ocs_hal_t *hal = sport->hal;
11836  uint8_t *payload = NULL;
11837 
11838  smtrace("port");
11839 
11840  switch (evt) {
11841  case OCS_EVT_ENTER:
11842  // allocate memory for the service parameters
11843  if (ocs_dma_alloc(hal->os, &sport->dma, 112, 4)) {
11844  ocs_log_err(hal->os, "Failed to allocate DMA memory\n");
11846  break;
11847  }
11848 
11849  if (0 == sli_cmd_read_sparm64(&hal->sli, data, SLI4_BMBX_SIZE,
11850  &sport->dma, sport->indicator)) {
11851  ocs_log_err(hal->os, "READ_SPARM64 allocation failure\n");
11852  ocs_dma_free(hal->os, &sport->dma);
11854  break;
11855  }
11856 
11857  if (ocs_hal_command(hal, data, OCS_CMD_NOWAIT, __ocs_hal_port_cb, sport)) {
11858  ocs_dma_free(hal->os, &sport->dma);
11860  }
11861 
11862  break;
11863  case OCS_EVT_RESPONSE:
11864  payload = sport->dma.virt;
11865 
11866  ocs_display_sparams(sport->display_name, "sport sparm64", 0, NULL, payload);
11867 
11868  ocs_memcpy(&sport->sli_wwpn, payload + SLI4_READ_SPARM64_WWPN_OFFSET,
11869  sizeof(sport->sli_wwpn));
11870  ocs_memcpy(&sport->sli_wwnn, payload + SLI4_READ_SPARM64_WWNN_OFFSET,
11871  sizeof(sport->sli_wwnn));
11872 
11873  ocs_dma_free(hal->os, &sport->dma);
11875  break;
11876  case OCS_EVT_ERROR:
11877  ocs_dma_free(hal->os, &sport->dma);
11879  break;
11881  /* Wait for attach response and then free */
11882  sport->sm_free_req_pending = 1;
11883  break;
11884  case OCS_EVT_EXIT:
11885  break;
11886  default:
11887  __ocs_hal_port_common(__func__, ctx, evt, data);
11888  break;
11889  }
11890 
11891  return NULL;
11892 }
11893 
11894 static void *
11895 __ocs_hal_port_alloc_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
11896 {
11897  ocs_sli_port_t *sport = ctx->app;
11898 
11899  smtrace("port");
11900 
11901  switch (evt) {
11902  case OCS_EVT_ENTER:
11903  /* no-op */
11904  break;
11907  break;
11910  break;
11912  /* Wait for attach response and then free */
11913  sport->sm_free_req_pending = 1;
11914  break;
11915  default:
11916  __ocs_hal_port_common(__func__, ctx, evt, data);
11917  break;
11918  }
11919 
11920  return NULL;
11921 }
11922 
11923 static void *
11924 __ocs_hal_port_alloc_init_vpi(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
11925 {
11926  ocs_sli_port_t *sport = ctx->app;
11927  ocs_hal_t *hal = sport->hal;
11928 
11929  smtrace("port");
11930 
11931  switch (evt) {
11932  case OCS_EVT_ENTER:
11933  /* If there is a pending free request, then handle it now */
11934  if (sport->sm_free_req_pending) {
11936  return NULL;
11937  }
11938 
11939  //TODO XXX transitioning to done only works if this is called
11940  // directly from ocs_hal_port_alloc BUT not if called from
11941  // read_sparm64. In the later case, we actually want to go
11942  // through report_ok/fail
11943  if (0 == sli_cmd_init_vpi(&hal->sli, data, SLI4_BMBX_SIZE,
11944  sport->indicator, sport->domain->indicator)) {
11945  ocs_log_err(hal->os, "INIT_VPI allocation failure\n");
11947  break;
11948  }
11949 
11950  if (ocs_hal_command(hal, data, OCS_CMD_NOWAIT, __ocs_hal_port_cb, sport))
11952 
11953  break;
11954  case OCS_EVT_RESPONSE:
11956  break;
11957  case OCS_EVT_ERROR:
11959  break;
11961  /* Wait for attach response and then free */
11962  sport->sm_free_req_pending = 1;
11963  break;
11964  case OCS_EVT_EXIT:
11965  break;
11966  default:
11967  __ocs_hal_port_common(__func__, ctx, evt, data);
11968  break;
11969  }
11970 
11971  return NULL;
11972 }
11973 
11974 static int32_t
11975 __ocs_hal_port_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
11976 {
11977  ocs_sli_port_t *sport = arg;
11979  ocs_sm_event_t evt;
11980 
11981  if (status || hdr->status) {
11982  evt = OCS_EVT_ERROR;
11983  } else {
11984  evt = OCS_EVT_RESPONSE;
11985  }
11986 
11987  ocs_sm_post_event(&sport->ctx, evt, mqe);
11988  return 0;
11989 }
11990 
11991 static int32_t
11992 __ocs_hal_port_realloc_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
11993 {
11994  ocs_sli_port_t *sport = arg;
11996  ocs_sm_event_t evt;
11997  uint8_t *mqecpy;
11998 
11999  if (status || hdr->status) {
12000  evt = OCS_EVT_ERROR;
12001  } else {
12002  evt = OCS_EVT_RESPONSE;
12003  }
12004 
12005  /*
12006  * In this case we have to malloc a mailbox command buffer, as it is reused
12007  * in the state machine post event call, and eventually freed
12008  */
12009  mqecpy = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
12010  if (mqecpy == NULL) {
12011  ocs_log_err(hal->os, "malloc mqecpy failed\n");
12012  return -1;
12013  }
12014  ocs_memcpy(mqecpy, mqe, SLI4_BMBX_SIZE);
12015 
12016  ocs_sm_post_event(&sport->ctx, evt, mqecpy);
12017 
12018  return 0;
12019 }
12020 
12021 /***************************************************************************
12022  * Domain state machine
12023  */
12024 
12025 static int32_t
12026 __ocs_hal_domain_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
12027 {
12028  ocs_domain_t *domain = ctx->app;
12029  ocs_hal_t *hal = domain->hal;
12030 
12031  smtrace("domain");
12032 
12033  switch (evt) {
12034  case OCS_EVT_EXIT:
12035  /* ignore */
12036  break;
12037 
12038  default:
12039  ocs_log_test(hal->os, "%s %-20s not handled\n", funcname, ocs_sm_event_name(evt));
12040  break;
12041  }
12042 
12043  return 0;
12044 }
12045 
12046 static void *
12047 __ocs_hal_domain_alloc_report_fail(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
12048 {
12049  ocs_domain_t *domain = ctx->app;
12050  ocs_hal_t *hal = domain->hal;
12051 
12052  smtrace("domain");
12053 
12054  switch (evt) {
12055  case OCS_EVT_ENTER:
12056  /* free service parameters buffer */
12057  if (domain->dma.virt) {
12058  ocs_dma_free(hal->os, &domain->dma);
12059  }
12060 
12061  /* free command buffer */
12062  if (data != NULL) {
12063  ocs_free(hal->os, data, SLI4_BMBX_SIZE);
12064  }
12065 
12066  /* free SLI resources */
12067  if (sli_resource_free(&hal->sli, SLI_RSRC_FCOE_VFI, domain->indicator)) {
12068  ocs_log_err(hal->os, "FCOE_VFI (%d) free failed\n", domain->indicator);
12069  }
12070 
12071  // TODO: how to free FCFI (or do we at all)?
12072 
12073  if (hal->callback.domain != NULL) {
12074  hal->callback.domain(hal->args.domain, OCS_HAL_DOMAIN_ALLOC_FAIL, domain);
12075  }
12076  break;
12077  default:
12078  __ocs_hal_domain_common(__func__, ctx, evt, data);
12079  break;
12080  }
12081 
12082  return NULL;
12083 }
12084 
12085 static void *
12086 __ocs_hal_domain_attached(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
12087 {
12088  ocs_domain_t *domain = ctx->app;
12089  ocs_hal_t *hal = domain->hal;
12090 
12091  smtrace("domain");
12092 
12093  switch (evt) {
12094  case OCS_EVT_ENTER:
12095  /* free mailbox buffer and send alloc ok to physical sport */
12096  ocs_free(hal->os, data, SLI4_BMBX_SIZE);
12097  ocs_sm_post_event(&domain->sport->ctx, OCS_EVT_HAL_PORT_ATTACH_OK, NULL);
12098 
12099  /* now inform registered callbacks */
12100  if (hal->callback.domain != NULL) {
12101  hal->callback.domain(hal->args.domain,
12103  domain);
12104  }
12105  break;
12108  break;
12109  default:
12110  __ocs_hal_domain_common(__func__, ctx, evt, data);
12111  break;
12112  }
12113 
12114  return NULL;
12115 }
12116 
12117 static void *
12118 __ocs_hal_domain_attach_report_fail(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
12119 {
12120  ocs_domain_t *domain = ctx->app;
12121  ocs_hal_t *hal = domain->hal;
12122 
12123  smtrace("domain");
12124 
12125  switch (evt) {
12126  case OCS_EVT_ENTER:
12127  /* free service parameters buffer */
12128  if (domain->dma.virt) {
12129  ocs_dma_free(hal->os, &domain->dma);
12130  }
12131 
12132  /* free command buffer */
12133  if (data != NULL) {
12134  ocs_free(hal->os, data, SLI4_BMBX_SIZE);
12135  }
12136 
12137  /* free SLI resources */
12138  if (sli_resource_free(&hal->sli, SLI_RSRC_FCOE_VFI, domain->indicator)) {
12139  ocs_log_err(hal->os, "FCOE_VFI (%d) free failed\n", domain->indicator);
12140  }
12141 
12142  // TODO: how to free FCFI (or do we at all)?
12143 
12144  if (hal->callback.domain != NULL) {
12145  hal->callback.domain(hal->args.domain, OCS_HAL_DOMAIN_ATTACH_FAIL, domain);
12146  }
12147  break;
12148  case OCS_EVT_EXIT:
12149  break;
12150  default:
12151  __ocs_hal_domain_common(__func__, ctx, evt, data);
12152  break;
12153  }
12154 
12155  return NULL;
12156 }
12157 
12158 static void *
12159 __ocs_hal_domain_attach_reg_vfi(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
12160 {
12161  ocs_domain_t *domain = ctx->app;
12162  ocs_hal_t *hal = domain->hal;
12163 
12164  smtrace("domain");
12165 
12166  switch (evt) {
12167  case OCS_EVT_ENTER:
12168 
12169  ocs_display_sparams("", "reg vpi", 0, NULL, domain->dma.virt);
12170 
12171  if (0 == sli_cmd_reg_vfi(&hal->sli, data, SLI4_BMBX_SIZE, domain)) {
12172  ocs_log_err(hal->os, "REG_VFI format failure\n");
12173  ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
12174  break;
12175  }
12176 
12177  if (ocs_hal_command(hal, data, OCS_CMD_NOWAIT, __ocs_hal_domain_cb, domain))
12178  ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
12179 
12180  break;
12181  case OCS_EVT_RESPONSE:
12183  break;
12184  case OCS_EVT_ERROR:
12186  break;
12187  default:
12188  __ocs_hal_domain_common(__func__, ctx, evt, data);
12189  break;
12190  }
12191 
12192  return NULL;
12193 }
12194 
12195 static void *
12196 __ocs_hal_domain_allocated(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
12197 {
12198  ocs_domain_t *domain = ctx->app;
12199  ocs_hal_t *hal = domain->hal;
12200 
12201  smtrace("domain");
12202 
12203  switch (evt) {
12204  case OCS_EVT_ENTER:
12205  /* free mailbox buffer and send alloc ok to physical sport */
12206  ocs_free(hal->os, data, SLI4_BMBX_SIZE);
12207  ocs_sm_post_event(&domain->sport->ctx, OCS_EVT_HAL_PORT_ALLOC_OK, NULL);
12208 
12209  ocs_hal_domain_add(hal, domain);
12210 
12211  /* now inform registered callbacks */
12212  if (hal->callback.domain != NULL) {
12213  hal->callback.domain(hal->args.domain,
12215  domain);
12216  }
12217  break;
12220  break;
12222  /* unreg_fcfi/vfi */
12223  if (SLI4_IF_TYPE_BE3_SKH_PF == sli_get_if_type(&hal->sli)) {
12225  } else {
12227  }
12228  break;
12229  default:
12230  __ocs_hal_domain_common(__func__, ctx, evt, data);
12231  break;
12232  }
12233 
12234  return NULL;
12235 }
12236 
12237 static void *
12238 __ocs_hal_domain_alloc_read_sparm64(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
12239 {
12240  ocs_domain_t *domain = ctx->app;
12241  ocs_hal_t *hal = domain->hal;
12242 
12243  smtrace("domain");
12244 
12245  switch (evt) {
12246  case OCS_EVT_ENTER:
12247  if (0 == sli_cmd_read_sparm64(&hal->sli, data, SLI4_BMBX_SIZE,
12248  &domain->dma, SLI4_READ_SPARM64_VPI_DEFAULT)) {
12249  ocs_log_err(hal->os, "READ_SPARM64 format failure\n");
12250  ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
12251  break;
12252  }
12253 
12254  if (ocs_hal_command(hal, data, OCS_CMD_NOWAIT, __ocs_hal_domain_cb, domain))
12255  ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
12256 
12257  break;
12258  case OCS_EVT_EXIT:
12259  break;
12260  case OCS_EVT_RESPONSE:
12261  ocs_display_sparams(domain->display_name, "domain sparm64", 0, NULL, domain->dma.virt);
12262 
12264  break;
12265  case OCS_EVT_ERROR:
12267  break;
12268  default:
12269  __ocs_hal_domain_common(__func__, ctx, evt, data);
12270  break;
12271  }
12272 
12273  return NULL;
12274 }
12275 
12276 static void *
12277 __ocs_hal_domain_alloc_init_vfi(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
12278 {
12279  ocs_domain_t *domain = ctx->app;
12280  ocs_sli_port_t *sport = domain->sport;
12281  ocs_hal_t *hal = domain->hal;
12282 
12283  smtrace("domain");
12284 
12285  switch (evt) {
12286  case OCS_EVT_ENTER:
12287  if (0 == sli_cmd_init_vfi(&hal->sli, data, SLI4_BMBX_SIZE, domain->indicator,
12288  domain->fcf_indicator, sport->indicator)) {
12289  ocs_log_err(hal->os, "INIT_VFI format failure\n");
12290  ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
12291  break;
12292  }
12293 
12294  if (ocs_hal_command(hal, data, OCS_CMD_NOWAIT, __ocs_hal_domain_cb, domain))
12295  ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
12296 
12297  break;
12298  case OCS_EVT_EXIT:
12299  break;
12300  case OCS_EVT_RESPONSE:
12302  break;
12303  case OCS_EVT_ERROR:
12305  break;
12306  default:
12307  __ocs_hal_domain_common(__func__, ctx, evt, data);
12308  break;
12309  }
12310 
12311  return NULL;
12312 }
12313 
12314 static void *
12315 __ocs_hal_domain_alloc_reg_fcfi(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
12316 {
12317  ocs_domain_t *domain = ctx->app;
12318  ocs_hal_t *hal = domain->hal;
12319 
12320  smtrace("domain");
12321 
12322  switch (evt) {
12323  case OCS_EVT_ENTER: {
12325  uint32_t i;
12326 
12327  /* Set the filter match/mask values from hal's filter_def values */
12328  for (i = 0; i < SLI4_CMD_REG_FCFI_NUM_RQ_CFG; i++) {
12329  rq_cfg[i].rq_id = 0xffff;
12330  rq_cfg[i].r_ctl_mask = (uint8_t) hal->config.filter_def[i];
12331  rq_cfg[i].r_ctl_match = (uint8_t) (hal->config.filter_def[i] >> 8);
12332  rq_cfg[i].type_mask = (uint8_t) (hal->config.filter_def[i] >> 16);
12333  rq_cfg[i].type_match = (uint8_t) (hal->config.filter_def[i] >> 24);
12334  }
12335 
12336  /* Set the rq_id for each, in order of RQ definition */
12337  for (i = 0; i < hal->hal_rq_count; i++) {
12338  if (i >= ARRAY_SIZE(rq_cfg)) {
12339  ocs_log_warn(hal->os, "more RQs than REG_FCFI filter entries\n");
12340  break;
12341  }
12342  rq_cfg[i].rq_id = hal->hal_rq[i]->hdr->id;
12343  }
12344 
12345  if (!data) {
12346  ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
12347  break;
12348  }
12349 
12350  if (hal->hal_mrq_used) {
12352  domain->vlan_id, domain->fcf)) {
12353  ocs_log_err(hal->os, "REG_FCFI_MRQ format failure\n");
12354  ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
12355  break;
12356  }
12357 
12358  } else {
12359  if (0 == sli_cmd_reg_fcfi(&hal->sli, data, SLI4_BMBX_SIZE, domain->fcf,
12360  rq_cfg, domain->vlan_id)) {
12361  ocs_log_err(hal->os, "REG_FCFI format failure\n");
12362  ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
12363  break;
12364  }
12365  }
12366 
12367  if (ocs_hal_command(hal, data, OCS_CMD_NOWAIT, __ocs_hal_domain_cb, domain))
12368  ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
12369 
12370  break;
12371  }
12372  case OCS_EVT_EXIT:
12373  break;
12374  case OCS_EVT_RESPONSE:
12375  if (!data) {
12376  ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
12377  break;
12378  }
12379 
12380  domain->fcf_indicator = ((sli4_cmd_reg_fcfi_t *)data)->fcfi;
12381 
12382  /*
12383  * IF_TYPE 0 devices do not support explicit VFI and VPI initialization
12384  * and instead rely on implicit initialization during VFI registration.
12385  * Short circuit normal processing here for those devices.
12386  */
12387  if (SLI4_IF_TYPE_BE3_SKH_PF == sli_get_if_type(&hal->sli)) {
12389  } else {
12391  }
12392  break;
12393  case OCS_EVT_ERROR:
12395  break;
12396  default:
12397  __ocs_hal_domain_common(__func__, ctx, evt, data);
12398  break;
12399  }
12400 
12401  return NULL;
12402 }
12403 
12404 static void *
12405 __ocs_hal_domain_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
12406 {
12407  ocs_domain_t *domain = ctx->app;
12408  ocs_hal_t *hal = domain->hal;
12409 
12410  smtrace("domain");
12411 
12412  switch (evt) {
12413  case OCS_EVT_ENTER:
12414  if (sli_get_medium(&hal->sli) == SLI_LINK_MEDIUM_FC) {
12415  /*
12416  * For FC, the HAL alread registered a FCFI
12417  * Copy FCF information into the domain and jump to INIT_VFI
12418  */
12419  domain->fcf_indicator = hal->fcf_indicator;
12421  } else {
12423  }
12424  break;
12425  default:
12426  __ocs_hal_domain_common(__func__, ctx, evt, data);
12427  break;
12428  }
12429 
12430  return NULL;
12431 }
12432 
12433 static void *
12434 __ocs_hal_domain_free_report_fail(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
12435 {
12436  ocs_domain_t *domain = ctx->app;
12437 
12438  smtrace("domain");
12439 
12440  switch (evt) {
12441  case OCS_EVT_ENTER:
12442  if (domain != NULL) {
12443  ocs_hal_t *hal = domain->hal;
12444 
12445  ocs_hal_domain_del(hal, domain);
12446  ocs_dma_free(hal->os, &domain->dma);
12447 
12448  if (hal->callback.domain != NULL) {
12449  hal->callback.domain(hal->args.domain,
12451  domain);
12452  }
12453  }
12454 
12455  // free command buffer
12456  if (data != NULL) {
12457  ocs_free(domain != NULL ? domain->hal->os : NULL, data, SLI4_BMBX_SIZE);
12458  }
12459  break;
12460  case OCS_EVT_EXIT:
12461  break;
12462  default:
12463  __ocs_hal_domain_common(__func__, ctx, evt, data);
12464  break;
12465  }
12466 
12467  return NULL;
12468 }
12469 
12470 static void *
12471 __ocs_hal_domain_freed(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
12472 {
12473  ocs_domain_t *domain = ctx->app;
12474 
12475  smtrace("domain");
12476 
12477  switch (evt) {
12478  case OCS_EVT_ENTER:
12479  /* Free DMA and mailbox buffer */
12480  if (domain != NULL) {
12481  ocs_hal_t *hal = domain->hal;
12482 
12483  /* free VFI resource */
12484  if (sli_resource_free(&hal->sli, SLI_RSRC_FCOE_VFI, domain->indicator)) {
12485  ocs_log_err(hal->os, "FCOE_VFI (%d) free failed\n", domain->indicator);
12486  }
12487 
12488  ocs_hal_domain_del(hal, domain);
12489  ocs_dma_free(hal->os, &domain->dma);
12490 
12491  /* inform registered callbacks */
12492  if (hal->callback.domain != NULL) {
12493  hal->callback.domain(hal->args.domain, OCS_HAL_DOMAIN_FREE_OK, domain);
12494  }
12495  }
12496  if (data != NULL) {
12497  ocs_free(domain != NULL ? domain->hal->os : NULL, data, SLI4_BMBX_SIZE);
12498  }
12499  break;
12500  case OCS_EVT_EXIT:
12501  break;
12502  default:
12503  __ocs_hal_domain_common(__func__, ctx, evt, data);
12504  break;
12505  }
12506 
12507  return NULL;
12508 }
12509 
12510 
12511 static void *
12512 __ocs_hal_domain_free_redisc_fcf(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
12513 {
12514  ocs_domain_t *domain = ctx->app;
12515  ocs_hal_t *hal = domain->hal;
12516 
12517  smtrace("domain");
12518 
12519  switch (evt) {
12520  case OCS_EVT_ENTER:
12521  /* if we're in the middle of a teardown, skip sending rediscover */
12522  if (hal->state == OCS_HAL_STATE_TEARDOWN_IN_PROGRESS) {
12524  break;
12525  }
12526  if (0 == sli_cmd_fcoe_rediscover_fcf(&hal->sli, data, SLI4_BMBX_SIZE, domain->fcf)) {
12527  ocs_log_err(hal->os, "REDISCOVER_FCF format failure\n");
12528  ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
12529  break;
12530  }
12531 
12532  if (ocs_hal_command(hal, data, OCS_CMD_NOWAIT, __ocs_hal_domain_cb, domain))
12533  ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
12534 
12535  break;
12536  case OCS_EVT_RESPONSE:
12537  case OCS_EVT_ERROR:
12538  /* REDISCOVER_FCF can fail if none exist */
12540  break;
12541  case OCS_EVT_EXIT:
12542  break;
12543  default:
12544  __ocs_hal_domain_common(__func__, ctx, evt, data);
12545  break;
12546  }
12547 
12548  return NULL;
12549 }
12550 
12551 static void *
12552 __ocs_hal_domain_free_unreg_fcfi(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
12553 {
12554  ocs_domain_t *domain = ctx->app;
12555  ocs_hal_t *hal = domain->hal;
12556 
12557  smtrace("domain");
12558 
12559  switch (evt) {
12560  case OCS_EVT_ENTER:
12561  if (data == NULL) {
12562  data = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
12563  if (!data) {
12564  ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
12565  break;
12566  }
12567  }
12568 
12569  if (0 == sli_cmd_unreg_fcfi(&hal->sli, data, SLI4_BMBX_SIZE, domain->fcf_indicator)) {
12570  ocs_log_err(hal->os, "UNREG_FCFI format failure\n");
12571  ocs_free(hal->os, data, SLI4_BMBX_SIZE);
12572  ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
12573  break;
12574  }
12575 
12576  if (ocs_hal_command(hal, data, OCS_CMD_NOWAIT, __ocs_hal_domain_cb, domain)) {
12577  ocs_free(hal->os, data, SLI4_BMBX_SIZE);
12578  ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
12579  }
12580 
12581  break;
12582  case OCS_EVT_RESPONSE:
12583  if (domain->req_rediscover_fcf) {
12584  domain->req_rediscover_fcf = FALSE;
12586  } else {
12588  }
12589  break;
12590  case OCS_EVT_ERROR:
12592  break;
12593  case OCS_EVT_EXIT:
12594  break;
12595  default:
12596  __ocs_hal_domain_common(__func__, ctx, evt, data);
12597  break;
12598  }
12599 
12600  return NULL;
12601 }
12602 
12603 static void *
12604 __ocs_hal_domain_free_unreg_vfi(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
12605 {
12606  ocs_domain_t *domain = ctx->app;
12607  ocs_hal_t *hal = domain->hal;
12608  uint8_t is_fc = FALSE;
12609 
12610  smtrace("domain");
12611 
12612  is_fc = (sli_get_medium(&hal->sli) == SLI_LINK_MEDIUM_FC);
12613 
12614  switch (evt) {
12615  case OCS_EVT_ENTER:
12616  if (data == NULL) {
12617  data = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
12618  if (!data) {
12619  ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
12620  break;
12621  }
12622  }
12623 
12624  if (0 == sli_cmd_unreg_vfi(&hal->sli, data, SLI4_BMBX_SIZE, domain,
12626  ocs_log_err(hal->os, "UNREG_VFI format failure\n");
12627  ocs_free(hal->os, data, SLI4_BMBX_SIZE);
12628  ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
12629  break;
12630  }
12631 
12632  if (ocs_hal_command(hal, data, OCS_CMD_NOWAIT, __ocs_hal_domain_cb, domain)) {
12633  ocs_free(hal->os, data, SLI4_BMBX_SIZE);
12634  ocs_sm_post_event(ctx, OCS_EVT_ERROR, NULL);
12635  }
12636 
12637  break;
12638  case OCS_EVT_ERROR:
12639  if (is_fc) {
12641  } else {
12643  }
12644  break;
12645  case OCS_EVT_RESPONSE:
12646  if (is_fc) {
12648  } else {
12650  }
12651  break;
12652  default:
12653  __ocs_hal_domain_common(__func__, ctx, evt, data);
12654  break;
12655  }
12656 
12657  return NULL;
12658 }
12659 
12660 // callback for domain alloc/attach/free
12661 static int32_t
12662 __ocs_hal_domain_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
12663 {
12664  ocs_domain_t *domain = arg;
12666  ocs_sm_event_t evt;
12667 
12668  if (status || hdr->status) {
12669  evt = OCS_EVT_ERROR;
12670  } else {
12671  evt = OCS_EVT_RESPONSE;
12672  }
12673 
12674  ocs_sm_post_event(&domain->sm, evt, mqe);
12675  return 0;
12676 }
12677 
12678 static int32_t
12679 target_wqe_timer_nop_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
12680 {
12681  ocs_hal_io_t *io = NULL;
12682  ocs_hal_io_t *io_next = NULL;
12683  uint64_t ticks_current = ocs_get_os_ticks();
12684  uint32_t sec_elapsed;
12685  int32_t rc;
12686 
12687  /* loop through active WQE list and check for timeouts */
12688  ocs_lock(&hal->io_lock);
12689  ocs_list_foreach_safe(&hal->io_timed_wqe, io, io_next) {
12690  sec_elapsed = ((ticks_current - io->submit_ticks) / ocs_get_os_tick_freq());
12691 
12692  /*
12693  * If elapsed time > timeout, abort it. No need to check type since
12694  * it wouldn't be on this list unless it was a target WQE
12695  */
12696  if (sec_elapsed > io->tgt_wqe_timeout) {
12697  ocs_log_info(hal->os, "IO timeout xri=%#x tag=%#x type=%d\n",
12698  io->indicator, io->reqtag, io->type);
12699 
12700  /* remove from active_wqe list so won't try to abort again */
12701  ocs_list_remove(&hal->io_timed_wqe, io);
12702 
12703  /* save status of "timed out" for when abort completes */
12704  io->status_saved = 1;
12705  io->saved_status = SLI4_FC_WCQE_STATUS_TARGET_WQE_TIMEOUT;
12706  io->saved_ext = 0;
12707  io->saved_len = 0;
12708 
12709  /* now abort outstanding IO */
12710  rc = ocs_hal_io_abort(hal, io, FALSE, NULL, NULL);
12711  if (rc) {
12712  ocs_log_err(hal->os,
12713  "Abort submit failed on timedout xri=%#x " \
12714  "tag=%#x type=%d rc=%d\n",
12715  io->indicator, io->reqtag, io->type, rc);
12716  }
12717  }
12718  /*
12719  * need to go through entire list since each IO could have a
12720  * different timeout value
12721  */
12722  }
12723  ocs_unlock(&hal->io_lock);
12724 
12725  /* if we're not in the middle of shutting down, schedule next timer */
12726  if (!hal->active_wqe_timer_shutdown) {
12727  ocs_setup_timer(hal->os, &hal->wqe_timer, target_wqe_timer_cb,
12728  hal, OCS_HAL_WQ_TIMER_PERIOD_MS, false);
12729  }
12730  hal->in_active_wqe_timer = FALSE;
12731  return 0;
12732 }
12733 
12734 static void
12736 {
12737  ocs_hal_t *hal = (ocs_hal_t *)arg;
12738 
12739  /* delete existing timer; will kick off new timer after checking wqe timeouts */
12740  hal->in_active_wqe_timer = TRUE;
12741  ocs_del_timer(&hal->wqe_timer);
12742 
12743  /* Forward timer callback to execute in the mailbox completion processing context */
12745  ocs_log_test(hal->os, "ocs_hal_async_call failed\n");
12746  }
12747 }
12748 
12749 static void
12751 {
12752  uint32_t iters = 100;
12753 
12754  if (hal->config.emulate_tgt_wqe_timeout) {
12755  /* request active wqe timer shutdown, then wait for it to complete */
12756  hal->active_wqe_timer_shutdown = TRUE;
12757 
12758  /* delete WQE timer and wait for timer handler to complete (if necessary) */
12759  ocs_del_timer(&hal->wqe_timer);
12760 
12761  /* now wait for timer handler to complete (if necessary) */
12762  while (hal->in_active_wqe_timer && iters) {
12763  /*
12764  * if we happen to have just sent NOP mailbox command, make sure
12765  * completions are being processed
12766  */
12767  ocs_hal_flush(hal);
12768  iters--;
12769  }
12770 
12771  if (iters == 0) {
12772  ocs_log_test(hal->os, "Failed to shutdown active wqe timer\n");
12773  }
12774  }
12775 }
12776 
12777 /**
12778  * @brief Determine if HAL IO is owned by the port.
12779  *
12780  * @par Description
12781  * Determines if the given HAL IO has been posted to the chip.
12782  *
12783  * @param hal Hardware context allocated by the caller.
12784  * @param io HAL IO.
12785  *
12786  * @return Returns TRUE if given HAL IO is port-owned.
12787  */
12788 uint8_t
12789 ocs_hal_is_io_port_owned(ocs_hal_t *hal, ocs_hal_io_t *io)
12790 {
12791  /* Check to see if this is a port owned XRI */
12792  return io->is_port_owned;
12793 }
12794 
12795 /**
12796  * @brief Return TRUE if exchange is port-owned.
12797  *
12798  * @par Description
12799  * Test to see if the xri is a port-owned xri.
12800  *
12801  * @param hal Hardware context.
12802  * @param xri Exchange indicator.
12803  *
12804  * @return Returns TRUE if XRI is a port owned XRI.
12805  */
12806 
12807 uint8_t
12808 ocs_hal_is_xri_port_owned(ocs_hal_t *hal, uint32_t xri)
12809 {
12810  ocs_hal_io_t *io = ocs_hal_io_lookup(hal, xri);
12811  return (io == NULL ? FALSE : io->is_port_owned);
12812 }
12813 
12814 /**
12815  * @brief Returns an XRI from the port owned list to the host.
12816  *
12817  * @par Description
12818  * Used when the POST_XRI command fails as well as when the RELEASE_XRI completes.
12819  *
12820  * @param hal Hardware context.
12821  * @param xri_base The starting XRI number.
12822  * @param xri_count The number of XRIs to free from the base.
12823  */
12824 static void
12825 ocs_hal_reclaim_xri(ocs_hal_t *hal, uint16_t xri_base, uint16_t xri_count)
12826 {
12827  ocs_hal_io_t *io;
12828  uint32_t i;
12829 
12830  for (i = 0; i < xri_count; i++) {
12831  io = ocs_hal_io_lookup(hal, xri_base + i);
12832 
12833  /*
12834  * If this is an TOW XRI, then we need to release any
12835  * buffer attached to the XRI before moving the XRI back to the free pool.
12836  */
12837  if (hal->tow_enabled) {
12839  }
12840 
12841  ocs_lock(&hal->io_lock);
12842  ocs_list_remove(&hal->io_port_owned, io);
12843  io->is_port_owned = 0;
12844  ocs_list_add_tail(&hal->io_free, io);
12845  ocs_unlock(&hal->io_lock);
12846  }
12847 }
12848 
12849 /**
12850  * @brief Called when the POST_XRI command completes.
12851  *
12852  * @par Description
12853  * Free the mailbox command buffer and reclaim the XRIs on failure.
12854  *
12855  * @param hal Hardware context.
12856  * @param status Status field from the mbox completion.
12857  * @param mqe Mailbox response structure.
12858  * @param arg Pointer to a callback function that signals the caller that the command is done.
12859  *
12860  * @return Returns 0.
12861  */
12862 static int32_t
12863 ocs_hal_cb_post_xri(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
12864 {
12865  sli4_cmd_post_xri_t *post_xri = (sli4_cmd_post_xri_t *)mqe;
12866 
12867  /* Reclaim the XRIs as host owned if the command fails */
12868  if (status || post_xri->hdr.status) {
12869  ocs_log_debug(hal->os, "Status 0x%x for XRI base 0x%x, cnt =x%x\n",
12870  status, post_xri->xri_base, post_xri->xri_count);
12871  ocs_hal_reclaim_xri(hal, post_xri->xri_base, post_xri->xri_count);
12872  }
12873 
12874  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
12875  return 0;
12876 }
12877 
12878 /**
12879  * @brief Issues a mailbox command to move XRIs from the host-controlled pool to the port.
12880  *
12881  * @param hal Hardware context.
12882  * @param xri_start The starting XRI to post.
12883  * @param num_to_post The number of XRIs to post.
12884  *
12885  * @return Returns OCS_HAL_RTN_NO_MEMORY, OCS_HAL_RTN_ERROR, or OCS_HAL_RTN_SUCCESS.
12886  */
12887 
12888 static ocs_hal_rtn_e
12889 ocs_hal_post_xri(ocs_hal_t *hal, uint32_t xri_start, uint32_t num_to_post)
12890 {
12891  uint8_t *post_xri;
12893 
12894  /* Since we need to allocate for mailbox queue, just always allocate */
12895  post_xri = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
12896  if (post_xri == NULL) {
12897  ocs_log_err(hal->os, "no buffer for command\n");
12898  return OCS_HAL_RTN_NO_MEMORY;
12899  }
12900 
12901  /* Register the XRIs */
12902  sli_cmd_post_xri(&hal->sli, post_xri, SLI4_BMBX_SIZE, xri_start, num_to_post);
12903  rc = ocs_hal_command(hal, post_xri, OCS_CMD_NOWAIT, ocs_hal_cb_post_xri, NULL);
12904  if (rc)
12905  ocs_free(hal->os, post_xri, SLI4_BMBX_SIZE);
12906 
12907  return rc;
12908 }
12909 
12910 /**
12911  * @brief Move XRIs from the host-controlled pool to the port.
12912  *
12913  * @par Description
12914  * Removes IOs from the free list and moves them to the port.
12915  *
12916  * @param hal Hardware context.
12917  * @param num_xri The number of XRIs being requested to move to the chip.
12918  *
12919  * @return Returns the number of XRIs that were moved.
12920  */
12921 uint32_t ocs_hal_xri_move_to_port_owned(ocs_hal_t *hal, uint32_t num_xri)
12922 {
12923  ocs_hal_io_t *io;
12924  uint32_t i;
12925  uint32_t num_posted = 0;
12926 
12927  /*
12928  * Note: We cannot use ocs_hal_io_alloc() because that would place the
12929  * IO on the io_inuse list. We need to move from the io_free to
12930  * the io_port_owned list.
12931  */
12932  ocs_lock(&hal->io_lock);
12933 
12934  for (i = 0; i < num_xri; i++) {
12935  if (NULL != (io = ocs_list_remove_head(&hal->io_free))) {
12936  ocs_hal_rtn_e rc;
12937 
12938  /*
12939  * For TOW, we need to attach a buffer to the XRI before
12940  * submitting it to the chip.
12941  * If a buffer is unavailable, then we cannot post it, so return it
12942  * to the free pool.
12943  */
12944  if (hal->tow_enabled) {
12945  /* Note: uses the IO lock to get the tow buffer */
12946  ocs_unlock(&hal->io_lock);
12947  rc = ocs_hal_rqpair_tow_move_to_port(hal, io);
12948  ocs_lock(&hal->io_lock);
12949  if (rc != OCS_HAL_RTN_SUCCESS) {
12950  ocs_list_add_head(&hal->io_free, io);
12951  break;
12952  }
12953  }
12954 
12955  ocs_lock_init(hal->os, &io->tow_lock, "tow_lock[%d]", io->indicator);
12956  io->is_port_owned = 1;
12957  ocs_list_add_tail(&hal->io_port_owned, io);
12958 
12959  /* Post XRI */
12960  if (ocs_hal_post_xri(hal, io->indicator, 1) != OCS_HAL_RTN_SUCCESS ) {
12961  ocs_log_info(hal->os, "Post xri failed! reclaim xri %d\n",
12962  io->indicator);
12963  ocs_hal_reclaim_xri(hal, io->indicator, i);
12964  break;
12965  }
12966  num_posted++;
12967  } else {
12968  /* no more free XRIs */
12969  break;
12970  }
12971  }
12972  ocs_unlock(&hal->io_lock);
12973 
12974  return num_posted;
12975 }
12976 
12977 /**
12978  * @brief Called when the RELEASE_XRI command completes.
12979  *
12980  * @par Description
12981  * Move the IOs back to the free pool on success.
12982  *
12983  * @param hal Hardware context.
12984  * @param status Status field from the mbox completion.
12985  * @param mqe Mailbox response structure.
12986  * @param arg Pointer to a callback function that signals the caller that the command is done.
12987  *
12988  * @return Returns 0.
12989  */
12990 static int32_t
12991 ocs_hal_cb_release_xri(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
12992 {
12993  sli4_cmd_release_xri_t *release_xri = (sli4_cmd_release_xri_t *)mqe;
12994  uint8_t i;
12995 
12996  /* Reclaim the XRIs as host owned if the command succeeds */
12997  if ((0 == status) && (0 == release_xri->hdr.status)) {
12998  for (i = 0; i < release_xri->released_xri_count; i++) {
12999  uint16_t xri = ((i & 1) == 0 ? release_xri->xri_tbl[i/2].xri_tag0 :
13000  release_xri->xri_tbl[i/2].xri_tag1);
13001 
13002  ocs_hal_reclaim_xri(hal, xri, 1);
13003  }
13004  }
13005 
13006  ocs_free(hal->os, mqe, SLI4_BMBX_SIZE);
13007  return 0;
13008 }
13009 
13010 /**
13011  * @brief Move XRIs from the port-controlled pool to the host.
13012  *
13013  * Requests XRIs from the FW to return to the host-owned pool.
13014  *
13015  * @param hal Hardware context.
13016  * @param num_xri The number of XRIs being requested to moved from the chip.
13017  *
13018  * @return Returns 0 for success, or a negative error code value for failure.
13019  */
13020 
13022 ocs_hal_xri_move_to_host_owned(ocs_hal_t *hal, uint8_t num_xri)
13023 {
13024  uint8_t *release_xri;
13026 
13027  /* non-local buffer required for mailbox queue */
13028  release_xri = ocs_malloc(hal->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
13029  if (release_xri == NULL) {
13030  ocs_log_err(hal->os, "no buffer for command\n");
13031  return OCS_HAL_RTN_NO_MEMORY;
13032  }
13033 
13034  /* Release the XRIs */
13035  sli_cmd_release_xri(&hal->sli, release_xri, SLI4_BMBX_SIZE, num_xri);
13036  rc = ocs_hal_command(hal, release_xri, OCS_CMD_NOWAIT, ocs_hal_cb_release_xri, NULL);
13037  if (rc)
13038  ocs_free(hal->os, release_xri, SLI4_BMBX_SIZE);
13039 
13040  return rc;
13041 }
13042 
13043 /**
13044  * @brief Free an ocs_hal_rx_buffer_t array.
13045  *
13046  * @par Description
13047  * The ocs_hal_rx_buffer_t array is freed, along with allocated DMA memory.
13048  *
13049  * @param hal Pointer to HAL object.
13050  * @param rq_buf Pointer to ocs_hal_rx_buffer_t array.
13051  * @param count Count of buffers in array.
13052  *
13053  * @return None.
13054  */
13055 static void
13056 ocs_hal_rx_buffer_free(ocs_hal_t *hal, ocs_hal_rq_buffer_t **rq_buf, uint32_t count)
13057 {
13058  ocs_t *ocs = hal->os;
13059  uint32_t i;
13060 
13061  if (rq_buf) {
13062  for (i = 0; i < count && rq_buf[i]; i++) {
13063  ocs_dma_free(ocs, &rq_buf[i]->dma);
13064  ocs_free(hal->os, rq_buf[i], sizeof(ocs_hal_rq_buffer_t));
13065  rq_buf[i] = NULL;
13066  }
13067 
13068  ocs_free(hal->os, rq_buf, count * sizeof(ocs_hal_rq_buffer_t *));
13069  }
13070 }
13071 
13072 /**
13073  * @brief Allocate an ocs_hal_rx_buffer_t array.
13074  *
13075  * @par Description
13076  * An ocs_hal_rx_buffer_t array is allocated, along with the required DMA memory.
13077  *
13078  * @param hal Pointer to HAL object.
13079  * @param rqindex RQ index for this buffer.
13080  * @param count Count of buffers in array.
13081  * @param size Size of buffer.
13082  *
13083  * @return Returns the pointer to the allocated ocs_hal_rq_buffer_t array.
13084  */
13085 static ocs_hal_rq_buffer_t **
13086 ocs_hal_rx_buffer_alloc(ocs_hal_t *hal, uint32_t rqindex, uint32_t count, uint32_t size)
13087 {
13088  ocs_t *ocs = hal->os;
13089  ocs_hal_rq_buffer_t **rq_buf = NULL;
13090  uint32_t i;
13091 
13092  if (count != 0) {
13093  rq_buf = ocs_malloc(hal->os, count * sizeof(ocs_hal_rq_buffer_t *), OCS_M_ZERO);
13094  if (!rq_buf) {
13095  ocs_log_err(hal->os, "Failed to alloc pointer for unsolicited DMA trackers\n");
13096  goto free_rx_buffer;
13097  }
13098 
13099  for (i = 0; i < count; i++) {
13100  rq_buf[i] = ocs_malloc(hal->os, sizeof(ocs_hal_rq_buffer_t), OCS_M_ZERO);
13101  if (!rq_buf[i]) {
13102  ocs_log_err(hal->os, "Failed to alloc unsolicited DMA tracker[%d]\n", i);
13103  goto free_rx_buffer;
13104  }
13105 
13106  rq_buf[i]->rqindex = rqindex;
13107  if (ocs_dma_alloc(ocs, &rq_buf[i]->dma, size, OCS_MIN_DMA_ALIGNMENT)) {
13108  ocs_log_err(hal->os, "DMA allocation failed\n");
13109  goto free_rx_buffer;
13110  }
13111  }
13112  }
13113 
13114  return rq_buf;
13115 
13116 free_rx_buffer:
13117  ocs_hal_rx_buffer_free(hal, rq_buf, count);
13118  return NULL;
13119 }
13120 
13121 /**
13122  * @brief Allocate the RQ data buffers.
13123  *
13124  * @param hal Pointer to HAL object.
13125  *
13126  * @return Returns 0 on success, or a non-zero value on failure.
13127  */
13129 ocs_hal_rx_allocate(ocs_hal_t *hal)
13130 {
13131  ocs_t *ocs = hal->os;
13132  uint32_t i;
13133  int32_t rc = OCS_HAL_RTN_SUCCESS;
13134  uint32_t rqindex = 0;
13135  hal_rq_t *rq;
13136  uint32_t hdr_size = OCS_HAL_RQ_SIZE_HDR;
13137  uint32_t payload_size = hal->config.rq_default_buffer_size;
13138 
13139  rqindex = 0;
13140 
13141  for (i = 0; i < hal->hal_rq_count; i++) {
13142  rq = hal->hal_rq[i];
13143 
13144  /* skip over nvme qs */
13145  if (rq->nvmeq) {
13146  rqindex += 2;
13147  continue;
13148  }
13149 
13150  /* Allocate header buffers */
13151  rq->hdr_buf = ocs_hal_rx_buffer_alloc(hal, rqindex, rq->entry_count, hdr_size);
13152  if (rq->hdr_buf == NULL) {
13153  ocs_log_err(ocs, "ocs_hal_rx_buffer_alloc hdr_buf failed\n");
13154  rc = OCS_HAL_RTN_ERROR;
13155  break;
13156  }
13157 
13158  ocs_log_debug(hal->os, "rq[%2d] rq_id %02d header %4d by %4d bytes\n", i, rq->hdr->id,
13159  rq->entry_count, hdr_size);
13160 
13161  rqindex++;
13162 
13163  /* Allocate payload buffers */
13164  rq->payload_buf = ocs_hal_rx_buffer_alloc(hal, rqindex, rq->entry_count, payload_size);
13165  if (rq->payload_buf == NULL) {
13166  ocs_log_err(ocs, "ocs_hal_rx_buffer_alloc fb_buf failed\n");
13167  rc = OCS_HAL_RTN_ERROR;
13168  break;
13169  }
13170  ocs_log_debug(hal->os, "rq[%2d] rq_id %02d default %4d by %4d bytes\n", i, rq->data->id,
13171  rq->entry_count, payload_size);
13172  rqindex++;
13173  }
13174 
13175  return rc ? OCS_HAL_RTN_ERROR : OCS_HAL_RTN_SUCCESS;
13176 }
13177 
13178 /**
13179  * @brief Post the RQ data buffers to the chip.
13180  *
13181  * @param hal Pointer to HAL object.
13182  *
13183  * @return Returns 0 on success, or a non-zero value on failure.
13184  */
13186 ocs_hal_rx_post(ocs_hal_t *hal)
13187 {
13188  uint32_t i;
13189  uint32_t idx;
13190  uint32_t rq_idx;
13191  int32_t rc = 0;
13192 
13193  /*
13194  * In RQ pair mode, we MUST post the header and payload buffer at the
13195  * same time.
13196  */
13197  for (rq_idx = 0, idx = 0; rq_idx < hal->hal_rq_count; rq_idx++) {
13198  hal_rq_t *rq = hal->hal_rq[rq_idx];
13199 
13200  if (rq->nvmeq)
13201  continue;
13202 
13203 //tomc: added -1
13204  for (i = 0; i < rq->entry_count-1; i++) {
13205  ocs_hal_sequence_t *seq = ocs_array_get(hal->seq_pool, idx++);
13206  ocs_hal_assert(seq != NULL);
13207 
13208  seq->header = rq->hdr_buf[i];
13209  seq->payload = rq->payload_buf[i];
13210 
13211  rc = ocs_hal_sequence_free(hal, seq);
13212  if (rc) {
13213  break;
13214  }
13215  }
13216  if (rc) {
13217  break;
13218  }
13219  }
13220 
13221  return rc;
13222 }
13223 
13224 /**
13225  * @brief Free the RQ data buffers.
13226  *
13227  * @param hal Pointer to HAL object.
13228  *
13229  */
13230 void
13231 ocs_hal_rx_free(ocs_hal_t *hal)
13232 {
13233  hal_rq_t *rq;
13234  uint32_t i;
13235 
13236  /* Free hal_rq buffers */
13237  for (i = 0; i < hal->hal_rq_count; i++) {
13238  rq = hal->hal_rq[i];
13239 
13240  if (rq != NULL) {
13241  if (rq->nvmeq)
13242  continue;
13243  ocs_hal_rx_buffer_free(hal, rq->hdr_buf, rq->entry_count);
13244  rq->hdr_buf = NULL;
13245  ocs_hal_rx_buffer_free(hal, rq->payload_buf, rq->entry_count);
13246  rq->payload_buf = NULL;
13247  }
13248  }
13249 }
13250 
13251 /**
13252  * @brief HAL async call context structure.
13253  */
13254 typedef struct {
13256  void *arg;
13257  uint8_t cmd[SLI4_BMBX_SIZE];
13259 
13260 /**
13261  * @brief HAL async callback handler
13262  *
13263  * @par Description
13264  * This function is called when the NOP mailbox command completes. The callback stored
13265  * in the requesting context is invoked.
13266  *
13267  * @param hal Pointer to HAL object.
13268  * @param status Completion status.
13269  * @param mqe Pointer to mailbox completion queue entry.
13270  * @param arg Caller-provided argument.
13271  *
13272  * @return None.
13273  */
13274 static void
13275 ocs_hal_async_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
13276 {
13277  sli4_cmd_sli_config_t *mbox_rsp = (sli4_cmd_sli_config_t *)mqe;
13278  sli4_res_common_nop_t *sli4_rsp = NULL;
13279  ocs_hal_async_call_ctx_t *ctx = arg;
13280 
13281  sli4_rsp = (sli4_res_common_nop_t *)mbox_rsp->payload.embed;
13282  if (sli4_rsp->hdr.status)
13283  ocs_hal_log_sli4_rsp_hdr(hal, &sli4_rsp->hdr);
13284 
13285  if (!ctx || !ctx->callback)
13286  goto ocs_hal_async_cb_done;
13287 
13288  if (0 == status) {
13289  if (mbox_rsp->hdr.status)
13290  status = mbox_rsp->hdr.status;
13291  else if (sli4_rsp->hdr.status)
13292  status = sli4_rsp->hdr.status;
13293  }
13294 
13295  (*ctx->callback)(hal, status, mqe, ctx->arg);
13296 
13297 ocs_hal_async_cb_done:
13298  if (ctx)
13299  ocs_free(hal->os, ctx, sizeof(*ctx));
13300 }
13301 
13302 /**
13303  * @brief Make an async callback using NOP mailbox command
13304  *
13305  * @par Description
13306  * Post a NOP mailbox command; the callback with argument is invoked upon completion
13307  * while in the event processing context.
13308  *
13309  * @param hal Pointer to HAL object.
13310  * @param callback Pointer to callback function.
13311  * @param arg Caller-provided callback.
13312  *
13313  * @return Returns 0 on success, or a negative error code value on failure.
13314  */
13315 int32_t
13316 ocs_hal_async_call(ocs_hal_t *hal, ocs_hal_async_cb_t callback, void *arg)
13317 {
13318  int32_t rc = 0;
13320 
13321  /*
13322  * Allocate a callback context (which includes the mailbox command buffer), we need
13323  * this to be persistent as the mailbox command submission may be queued and executed later
13324  * execution.
13325  */
13326  ctx = ocs_malloc(hal->os, sizeof(*ctx), OCS_M_ZERO | OCS_M_NOWAIT);
13327  if (ctx == NULL) {
13328  ocs_log_err(hal->os, "failed to malloc async call context\n");
13329  return OCS_HAL_RTN_NO_MEMORY;
13330  }
13331 
13332  ctx->callback = callback;
13333  ctx->arg = arg;
13334 
13335  /* Build and send a NOP mailbox command */
13336  sli_cmd_common_nop(&hal->sli, ctx->cmd, sizeof(ctx->cmd), 0);
13337  rc = ocs_hal_command(hal, ctx->cmd, OCS_CMD_NOWAIT, ocs_hal_async_cb, ctx);
13338  if (rc)
13339  ocs_free(hal->os, ctx, sizeof(*ctx));
13340 
13341  return rc;
13342 }
13343 
13344 /**
13345  * @brief Initialize the reqtag pool.
13346  *
13347  * @par Description
13348  * The WQ request tag pool is initialized.
13349  *
13350  * @param hal Pointer to HAL object.
13351  *
13352  * @return Returns 0 on success, or a negative error code value on failure.
13353  */
13355 ocs_hal_reqtag_init(ocs_hal_t *hal)
13356 {
13357  if (hal->wq_reqtag_pool == NULL) {
13358  hal->wq_reqtag_pool = ocs_pool_alloc(hal->os, sizeof(hal_wq_callback_t), 65536, TRUE);
13359  if (hal->wq_reqtag_pool == NULL) {
13360  ocs_log_err(hal->os, "ocs_pool_alloc hal_wq_callback_t failed\n");
13361  return OCS_HAL_RTN_NO_MEMORY;
13362  }
13363  }
13364  ocs_hal_reqtag_reset(hal);
13365  return OCS_HAL_RTN_SUCCESS;
13366 }
13367 
13368 /**
13369  * @brief Allocate a WQ request tag.
13370  *
13371  * Allocate and populate a WQ request tag from the WQ request tag pool.
13372  *
13373  * @param hal Pointer to HAL object.
13374  * @param callback Callback function.
13375  * @param arg Pointer to callback argument.
13376  *
13377  * @return Returns pointer to allocated WQ request tag, or NULL if object cannot be allocated.
13378  */
13380 ocs_hal_reqtag_alloc(ocs_hal_t *hal, void (*callback)(void *arg, uint8_t *cqe, int32_t status), void *arg)
13381 {
13382  hal_wq_callback_t *wqcb;
13383 
13384  ocs_hal_assert(callback != NULL);
13385 
13386  wqcb = ocs_pool_get(hal->wq_reqtag_pool);
13387  if (wqcb != NULL) {
13388  ocs_hal_assert(wqcb->callback == NULL);
13389  wqcb->callback = callback;
13390  wqcb->arg = arg;
13391  }
13392  return wqcb;
13393 }
13394 
13395 /**
13396  * @brief Free a WQ request tag.
13397  *
13398  * Free the passed in WQ request tag.
13399  *
13400  * @param hal Pointer to HAL object.
13401  * @param wqcb Pointer to WQ request tag object to free.
13402  *
13403  * @return None.
13404  */
13405 void
13407 {
13408  ocs_hal_assert(wqcb->callback != NULL);
13409  wqcb->callback = NULL;
13410  wqcb->arg = NULL;
13411  ocs_pool_put(hal->wq_reqtag_pool, wqcb);
13412 }
13413 
13414 /**
13415  * @brief Return WQ request tag by index.
13416  *
13417  * @par Description
13418  * Return pointer to WQ request tag object given an index.
13419  *
13420  * @param hal Pointer to HAL object.
13421  * @param instance_index Index of WQ request tag to return.
13422  *
13423  * @return Pointer to WQ request tag, or NULL.
13424  */
13426 ocs_hal_reqtag_get_instance(ocs_hal_t *hal, uint32_t instance_index)
13427 {
13428  hal_wq_callback_t *wqcb;
13429 
13430  wqcb = ocs_pool_get_instance(hal->wq_reqtag_pool, instance_index);
13431  if (wqcb == NULL) {
13432  ocs_log_err(hal->os, "wqcb for instance %d is null\n", instance_index);
13433  }
13434  return wqcb;
13435 }
13436 
13437 /**
13438  * @brief Reset the WQ request tag pool.
13439  *
13440  * @par Description
13441  * Reset the WQ request tag pool, returning all to the free list.
13442  *
13443  * @param hal pointer to HAL object.
13444  *
13445  * @return None.
13446  */
13447 void
13448 ocs_hal_reqtag_reset(ocs_hal_t *hal)
13449 {
13450  hal_wq_callback_t *wqcb;
13451  uint32_t i;
13452 
13453  /* Remove all from freelist */
13454  while(ocs_pool_get(hal->wq_reqtag_pool) != NULL) {
13455  ;
13456  }
13457 
13458  /* Put them all back */
13459  for (i = 0; ((wqcb = ocs_pool_get_instance(hal->wq_reqtag_pool, i)) != NULL); i++) {
13460  wqcb->instance_index = i;
13461  wqcb->callback = NULL;
13462  wqcb->arg = NULL;
13463 
13464  // Set aside a specific reqtag for REQUEUE_XRI WQE completion with error status.
13465  if (i != OCS_HAL_REQUE_XRI_REGTAG) {
13466  ocs_pool_put(hal->wq_reqtag_pool, wqcb);
13467  }
13468  }
13469 }
13470 
13471 /**
13472  * @brief Handle HAL assertion
13473  *
13474  * HAL assert, display diagnostic message, and abort.
13475  *
13476  * @param cond string describing failing assertion condition
13477  * @param filename file name
13478  * @param linenum line number
13479  *
13480  * @return none
13481  */
13482 void
13483 _ocs_hal_assert(const char *cond, const char *filename, int linenum)
13484 {
13485  ocs_printf("%s(%d): HAL assertion (%s) failed\n", filename, linenum, cond);
13486  ocs_abort();
13487  /* no return */
13488 }
13489 
13490 /**
13491  * @brief Handle HAL verify
13492  *
13493  * HAL verify, display diagnostic message, dump stack and return.
13494  *
13495  * @param cond string describing failing verify condition
13496  * @param filename file name
13497  * @param linenum line number
13498  *
13499  * @return none
13500  */
13501 void
13502 _ocs_hal_verify(const char *cond, const char *filename, int linenum)
13503 {
13504  ocs_printf("%s(%d): HAL verify (%s) failed\n", filename, linenum, cond);
13505  ocs_print_stack();
13506 }
13507 
13508 static void
13509 ocs_hal_wq_handle_bad_reque_xri(void *arg, uint8_t *cqe, int32_t status)
13510 {
13511  uint32_t *ptr = (uint32_t *)cqe;
13512 
13513  ocs_log_err(NULL, "requeue_xri failed, status = %d, CQE = [ %#x, %#x, %#x, %#x ]\n",
13514  status, *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3));
13515 }
13516 
13517 /**
13518  * @brief Reque XRI
13519  *
13520  * @par Description
13521  * Reque XRI
13522  *
13523  * @param hal Pointer to HAL object.
13524  * @param io Pointer to HAL IO
13525  *
13526  * @return Return 0 if successful else returns -1
13527  */
13528 int32_t ocs_hal_reque_xri(ocs_hal_t *hal, ocs_hal_io_t *io)
13529 {
13530  int32_t rc = 0;
13531  hal_wq_callback_t *wqcb;
13532 
13533  rc = ocs_hal_rqpair_tow_xri_buffer_attach(hal, io, 1);
13534  if (rc) {
13535  ocs_list_add_tail(&hal->io_port_dnrx, io);
13536  rc = -1;
13537  goto exit_ocs_hal_reque_xri;
13538  }
13539 
13541  if (!wqcb) {
13542  rc = -1;
13543  goto exit_ocs_hal_reque_xri;
13544  }
13546  wqcb->arg = wqcb;
13547 
13548  io->tow_dnrx = 0;
13549  io->type = OCS_HAL_IO_DNRX_REQUEUE;
13550  if (sli_requeue_xri_wqe(&hal->sli, io->wqe.wqebuf, hal->sli.config.wqe_size,
13551  io->indicator, OCS_HAL_REQUE_XRI_REGTAG, SLI4_CQ_DEFAULT)) {
13552  /* Clear buffer from XRI */
13553  ocs_pool_put(hal->tow_buffer_pool, io->tow_buf);
13554  io->tow_buf = NULL;
13555 
13556  ocs_log_err(hal->os, "requeue_xri WQE error\n");
13557  ocs_list_add_tail(&hal->io_port_dnrx, io);
13558 
13559  rc = -1;
13560  goto exit_ocs_hal_reque_xri;
13561  }
13562 
13563  if (io->wq == NULL) {
13564  io->wq = ocs_hal_queue_next_wq(hal, io);
13565  ocs_hal_assert(io->wq != NULL);
13566  }
13567 
13568  /*
13569  * Add IO to active io wqe list before submitting, in case the
13570  * wcqe processing preempts this thread.
13571  */
13572  OCS_STAT(hal->tcmd_wq_submit[io->wq->instance]++);
13573  OCS_STAT(io->wq->use_count++);
13574 
13575  rc = hal_wq_write(io->wq, &io->wqe);
13576  if (rc < 0) {
13577  ocs_log_err(hal->os, "sli_queue_write reque xri failed: %d\n", rc);
13578  rc = -1;
13579  }
13580 
13581 exit_ocs_hal_reque_xri:
13582  return 0;
13583 }
13584 
13585 /**
13586  * @brief Validate HAL IO state to make sure HAL can accept and post wqe to SLI
13587  */
13589 {
13591  return -EPERM;
13592 
13593  return 0;
13594 }
13595 
13596 /* vim: set noexpandtab textwidth=120: */
13597 
13598 /**
13599  * @page fc_hal_api_overview HAL APIs
13600  * - @ref devInitShutdown
13601  * - @ref domain
13602  * - @ref port
13603  * - @ref node
13604  * - @ref io
13605  * - @ref interrupt
13606  *
13607  * <div class="overview">
13608  * The Hardware Abstraction Layer (HAL) insulates the higher-level code from the SLI-4
13609  * message details, but the higher level code must still manage domains, ports,
13610  * IT nexuses, and IOs. The HAL API is designed to help the higher level manage
13611  * these objects.<br><br>
13612  *
13613  * The HAL uses function callbacks to notify the higher-level code of events
13614  * that are received from the chip. There are currently three types of
13615  * functions that may be registered:
13616  *
13617  * <ul><li>domain – This function is called whenever a domain event is generated
13618  * within the HAL. Examples include a new FCF is discovered, a connection
13619  * to a domain is disrupted, and allocation callbacks.</li>
13620  * <li>unsolicited – This function is called whenever new data is received in
13621  * the SLI-4 receive queue.</li>
13622  * <li>rnode – This function is called for remote node events, such as attach status
13623  * and allocation callbacks.</li></ul>
13624  *
13625  * Upper layer functions may be registered by using the ocs_hal_callback() function.
13626  *
13627  * <img src="elx_fc_hal.jpg" alt="FC/FCoE HAL" title="FC/FCoE HAL" align="right"/>
13628  * <h2>FC/FCoE HAL API</h2>
13629  * The FC/FCoE HAL component builds upon the SLI-4 component to establish a flexible
13630  * interface for creating the necessary common objects and sending I/Os. It may be used
13631  * ā€œas isā€ in customer implementations or it can serve as an example of typical interactions
13632  * between a driver and the SLI-4 hardware. The broad categories of functionality include:
13633  *
13634  * <ul><li>Setting-up and tearing-down of the HAL.</li>
13635  * <li>Allocating and using the common objects (SLI Port, domain, remote node).</li>
13636  * <li>Sending and receiving I/Os.</li></ul>
13637  *
13638  * <h3>HAL Setup</h3>
13639  * To set up the HAL:
13640  *
13641  * <ol>
13642  * <li>Set up the HAL object using ocs_hal_setup().<br>
13643  * This step performs a basic configuration of the SLI-4 component and the HAL to
13644  * enable querying the hardware for its capabilities. At this stage, the HAL is not
13645  * capable of general operations (such as, receiving events or sending I/Os).</li><br><br>
13646  * <li>Configure the HAL according to the driver requirements.<br>
13647  * The HAL provides functions to discover hardware capabilities (ocs_hal_get()), as
13648  * well as configures the amount of resources required (ocs_hal_set()). The driver
13649  * must also register callback functions (ocs_hal_callback()) to receive notification of
13650  * various asynchronous events.<br><br>
13651  * @b Note: Once configured, the driver must initialize the HAL (ocs_hal_init()). This
13652  * step creates the underlying queues, commits resources to the hardware, and
13653  * prepares the hardware for operation. While the hardware is operational, the
13654  * port is not online, and cannot send or receive data.</li><br><br>
13655  * <br><br>
13656  * <li>Finally, the driver can bring the port online (ocs_hal_port_control()).<br>
13657  * When the link comes up, the HAL determines if a domain is present and notifies the
13658  * driver using the domain callback function. This is the starting point of the driver's
13659  * interaction with the common objects.<br><br>
13660  * @b Note: For FCoE, there may be more than one domain available and, therefore,
13661  * more than one callback.</li>
13662  * </ol>
13663  *
13664  * <h3>Allocating and Using Common Objects</h3>
13665  * Common objects provide a mechanism through which the various OneCore Storage
13666  * driver components share and track information. These data structures are primarily
13667  * used to track SLI component information but can be extended by other components, if
13668  * needed. The main objects are:
13669  *
13670  * <ul><li>DMA – the ocs_dma_t object describes a memory region suitable for direct
13671  * memory access (DMA) transactions.</li>
13672  * <li>SCSI domain – the ocs_domain_t object represents the SCSI domain, including
13673  * any infrastructure devices such as FC switches and FC forwarders. The domain
13674  * object contains both an FCFI and a VFI.</li>
13675  * <li>SLI Port (sport) – the ocs_sli_port_t object represents the connection between
13676  * the driver and the SCSI domain. The SLI Port object contains a VPI.</li>
13677  * <li>Remote node – the ocs_remote_node_t represents a connection between the SLI
13678  * Port and another device in the SCSI domain. The node object contains an RPI.</li></ul>
13679  *
13680  * Before the driver can send I/Os, it must allocate the SCSI domain, SLI Port, and remote
13681  * node common objects and establish the connections between them. The goal is to
13682  * connect the driver to the SCSI domain to exchange I/Os with other devices. These
13683  * common object connections are shown in the following figure, FC Driver Common Objects:
13684  * <img src="elx_fc_common_objects.jpg"
13685  * alt="FC Driver Common Objects" title="FC Driver Common Objects" align="center"/>
13686  *
13687  * The first step is to create a connection to the domain by allocating an SLI Port object.
13688  * The SLI Port object represents a particular FC ID and must be initialized with one. With
13689  * the SLI Port object, the driver can discover the available SCSI domain(s). On identifying
13690  * a domain, the driver allocates a domain object and attaches to it using the previous SLI
13691  * port object.<br><br>
13692  *
13693  * @b Note: In some cases, the driver may need to negotiate service parameters (that is,
13694  * FLOGI) with the domain before attaching.<br><br>
13695  *
13696  * Once attached to the domain, the driver can discover and attach to other devices
13697  * (remote nodes). The exact discovery method depends on the driver, but it typically
13698  * includes using a position map, querying the fabric name server, or an out-of-band
13699  * method. In most cases, it is necessary to log in with devices before performing I/Os.
13700  * Prior to sending login-related ELS commands (ocs_hal_srrs_send()), the driver must
13701  * allocate a remote node object (ocs_hal_node_alloc()). If the login negotiation is
13702  * successful, the driver must attach the nodes (ocs_hal_node_attach()) to the SLI Port
13703  * before exchanging FCP I/O.<br><br>
13704  *
13705  * @b Note: The HAL manages both the well known fabric address and the name server as
13706  * nodes in the domain. Therefore, the driver must allocate node objects prior to
13707  * communicating with either of these entities.
13708  *
13709  * <h3>Sending and Receiving I/Os</h3>
13710  * The HAL provides separate interfaces for sending BLS/ ELS/ FC-CT and FCP, but the
13711  * commands are conceptually similar. Since the commands complete asynchronously,
13712  * the caller must provide a HAL I/O object that maintains the I/O state, as well as
13713  * provide a callback function. The driver may use the same callback function for all I/O
13714  * operations, but each operation must use a unique HAL I/O object. In the SLI-4
13715  * architecture, there is a direct association between the HAL I/O object and the SGL used
13716  * to describe the data. Therefore, a driver typically performs the following operations:
13717  *
13718  * <ul><li>Allocates a HAL I/O object (ocs_hal_io_alloc()).</li>
13719  * <li>Formats the SGL, specifying both the HAL I/O object and the SGL.
13720  * (ocs_hal_io_init_sges() and ocs_hal_io_add_sge()).</li>
13721  * <li>Sends the HAL I/O (ocs_hal_io_send()).</li></ul>
13722  *
13723  * <h3>HAL Tear Down</h3>
13724  * To tear-down the HAL:
13725  *
13726  * <ol><li>Take the port offline (ocs_hal_port_control()) to prevent receiving further
13727  * data andevents.</li>
13728  * <li>Destroy the HAL object (ocs_hal_teardown()).</li>
13729  * <li>Free any memory used by the HAL, such as buffers for unsolicited data.</li></ol>
13730  * <br>
13731  * </div><!-- overview -->
13732  *
13733  */
13734 
#define OCS_HAL_TOW_APP_TAG_VALID_DEFAULT
Definition: ocs_hal.c:63
sli4_mbox_command_header_t hdr
Definition: sli4.h:980
ocs_hal_rtn_e ocs_hal_dump_get(ocs_hal_t *hal, ocs_dma_t *dma, uint32_t size, uint32_t offset, ocs_hal_dump_get_cb_t cb, void *arg)
Read a dump image to the host.
Definition: ocs_hal.c:8246
READ_STATUS - read tx/rx status of a particular port.
Definition: sli4.h:1278
int32_t ocs_node_suppress_resp(ocs_remote_node_t *rnode)
Return node suppress_rsp state.
Definition: ocs_node.c:2584
Mailbox Completion Queue Entry.
Definition: sli4.h:3324
uint32_t s_id
Definition: ocs_hal.h:504
ocs_hal_rtn_e ocs_hal_domain_attach(ocs_hal_t *hal, ocs_domain_t *domain, uint32_t fc_id)
Attach a SLI port to a domain.
Definition: ocs_hal.c:3280
int32_t sli_cmd_read_link_stats(sli4_t *sli4, void *buf, size_t size, uint8_t req_ext_counters, uint8_t clear_overflow_flags, uint8_t clear_all_counters)
Write a READ_LINK_STAT command to the provided buffer.
Definition: sli4.c:679
uint32_t atrt
Definition: sli4.h:533
#define OCS_HAL_READ_FCF_SIZE
Definition: ocs_hal.c:56
int32_t sli_cmd_down_link(sli4_t *sli4, void *buf, size_t size)
Write a DOWN_LINK command to the provided buffer.
Definition: sli4.c:577
uint32_t sge_type
Definition: sli4.h:501
ocs_hal_rtn_e ocs_hal_rqpair_init(ocs_hal_t *hal)
Configure the rq_pair function from ocs_hal_init(). Must be after the IOs are setup and the state is ...
void ocs_hal_xabt_process(ocs_hal_t *hal, hal_cq_t *cq, uint8_t *cqe, uint16_t rid)
Process XABT completions.
Definition: ocs_hal.c:10284
uint32_t buffer_length
Definition: sli4.h:504
int32_t ocs_hal_flush(ocs_hal_t *hal)
Definition: ocs_hal.c:11164
uint32_t repl_app_tag
Definition: ocs_hal.h:407
#define FC_LINK_SPEED_2G
Definition: sli4.h:705
#define SLI4_FCOE_FIP_FCF_MODIFIED
Definition: sli4_fc.h:1550
static void __ocs_hal_read_lmt_cb(ocs_hal_t *, int32_t, uint8_t *, void *)
callback function to read link module type
Definition: ocs_hal.c:10638
int32_t sli_cmd_fcoe_post_hdr_templates(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *dma, uint16_t rpi, ocs_dma_t *payload_dma)
Write an FCOE_POST_HDR_TEMPLATES command.
Definition: sli4_fc.c:585
uint32_t ocs_instance(void *os)
Return instance index of an opaque ocs structure.
int32_t sli_cmd_read_status(sli4_t *sli4, void *buf, size_t size, uint8_t clear_counters)
Write a READ_STATUS command to the provided buffer.
Definition: sli4.c:707
int32_t sli_cmd_common_nop(sli4_t *sli4, void *buf, size_t size, uint64_t context)
Write a COMMON_NOP command.
Definition: sli4.c:2628
#define SLI4_SGE_DIF_OP_IN_CHKSUM_OUT_CHKSUM
Definition: sli4.h:584
union sli4_cmd_sli_config_t::@36 payload
static int32_t ocs_hal_cb_temp(ocs_hal_t *, int32_t, uint8_t *, void *)
Called when the DUMP command completes.
Definition: ocs_hal.c:5863
#define SLI4_SET_FEATURES_SET_CONFIG_AXR_T10PI
Definition: sli4.h:2746
uint32_t ref_tag_cmp
Definition: sli4.h:531
uint8_t payload[12]
Definition: ocs_hal.h:501
int32_t sli_cmd_write_nvparms(sli4_t *sli4, void *buf, size_t size, uint8_t *wwpn, uint8_t *wwnn, uint8_t hard_alpa, uint32_t preferred_d_id)
Write a WRITE_NVPARMS command to the provided buffer.
Definition: sli4.c:1007
#define FC_LINK_SPEED_AUTO_16_8_4
Definition: sli4.h:720
ocs_hal_port_control_cb_t cb
Definition: ocs_hal.c:6268
static uint32_t sli_get_hlm_capable(sli4_t *sli4)
Definition: sli4.h:3921
static int32_t ocs_hal_cb_release_xri(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
Called when the RELEASE_XRI command completes.
Definition: ocs_hal.c:12991
int32_t ocs_hal_io_free(ocs_hal_t *hal, ocs_hal_io_t *io)
Free a previously-allocated HAL IO object.
Definition: ocs_hal.c:4001
uint32_t uint32_t iscsi_tgt
Definition: sli4.h:2969
void _ocs_hal_assert(const char *cond, const char *filename, int linenum)
Handle HAL assertion.
Definition: ocs_hal.c:13483
static ocs_hal_rtn_e ocs_hal_init_io(ocs_hal_t *)
Definition: ocs_hal.c:11086
ocs_hal_rtn_e ocs_hal_srrs_send(ocs_hal_t *hal, ocs_hal_io_type_e type, ocs_hal_io_t *io, ocs_dma_t *send, uint32_t len, ocs_dma_t *receive, ocs_remote_node_t *rnode, ocs_hal_io_param_t *iparam, ocs_hal_srrs_cb_t cb, void *arg)
Send a Single Request/Response Sequence (SRRS).
Definition: ocs_hal.c:4295
uint32_t empty_xri_pool_count
Definition: sli4.h:1297
static int32_t ocs_list_on_list(ocs_list_link_t *link)
Test if object is on a list.
Definition: ocs_list.h:460
static ocs_hal_rtn_e ocs_hal_init_tow_t10pi(ocs_hal_t *hal)
Definition: ocs_hal.c:240
int32_t sli_cmd_common_read_transceiver_data(sli4_t *sli4, void *buf, size_t size, uint32_t page_num, ocs_dma_t *dma)
Write a COMMON_READ_TRANSCEIVER_DATA command.
Definition: sli4.c:629
ocs_hal_rtn_e ocs_hal_get_itcm_parity_stats(ocs_hal_t *hal, bool clear_stats, ocs_hal_parity_stat_cb_t cb, void *arg)
Definition: ocs_hal.c:6823
ocs_atomic_t refcnt
Definition: ocs_hal.h:1274
#define SLI4_READ_TOPOLOGY_SPEED_32G
Definition: sli4.h:1036
ocs_hal_rtn_e ocs_hal_get_sfp(ocs_hal_t *hal, uint16_t page, ocs_hal_sfp_cb_t cb, void *arg)
Function to retrieve the SFP information.
Definition: ocs_hal.c:5759
uint8_t cs_ctl
Definition: ocs_hal.h:541
#define FC_LINK_SPEED_8G
Definition: sli4.h:711
ocs_dma_t * rsp
Definition: ocs_hal.h:550
static void ocs_hal_get_active_link_config_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
Get the link configuration callback.
Definition: ocs_hal.c:6574
void ocs_hal_rqpair_tow_move_to_host(ocs_hal_t *hal, ocs_hal_io_t *io)
Prepares an XRI to move back to the host.
uint8_t ocs_hal_io_inuse(ocs_hal_t *hal, ocs_hal_io_t *io)
Check if given HAL IO is in-use.
Definition: ocs_hal.c:4029
uint32_t uint32_t iscsi_ini
Definition: sli4.h:2969
ocs_hal_rtn_e ocs_hal_node_alloc(ocs_hal_t *hal, ocs_remote_node_t *rnode, uint32_t fc_addr, ocs_sli_port_t *sport)
Allocate a remote node object.
Definition: ocs_hal.c:3389
#define SLI4_SET_FEATURES_SLI_PORT_PAUSE_STATE
Definition: sli4.h:2744
uint8_t ocs_hal_is_io_port_owned(ocs_hal_t *hal, ocs_hal_io_t *io)
Determine if HAL IO is owned by the port.
Definition: ocs_hal.c:12789
uint32_t ocs_hal_get_rqes_produced_count(ocs_hal_t *hal)
Called to obtain the count of produced RQs.
Definition: ocs_hal.c:9396
HAL object describing fc host stats.
Definition: ocs_hal.h:843
int32_t sli_fw_error_status(sli4_t *sli4)
Read the SLIPORT_SEMAPHORE and SLIPORT_STATUS registers to check if the port status indicates that a ...
Definition: sli4.c:6283
int32_t hal_wq_write(hal_wq_t *wq, ocs_hal_wqe_t *wqe)
Write a HAL IO to a work queue.
Definition: ocs_hal.c:4092
static uint32_t sli_get_is_ulp_enabled(sli4_t *sli4, uint16_t ulp)
Definition: sli4.h:3915
static int32_t ocs_hal_cb_sfp(ocs_hal_t *, int32_t, uint8_t *, void *)
Called when the READ_TRANSCEIVER_DATA command completes.
Definition: ocs_hal.c:5710
void ocs_hal_reqtag_free(ocs_hal_t *hal, hal_wq_callback_t *wqcb)
Free a WQ request tag.
Definition: ocs_hal.c:13406
sli4_mbox_command_header_t hdr
Definition: sli4.h:883
uint32_t data_offset
Definition: sli4.h:501
static void ocs_hal_init_free_io(ocs_hal_io_t *io)
Initialize IO fields on each free call.
Definition: ocs_hal.c:3775
HAL wqe object.
Definition: ocs_hal.h:572
#define SLI4_MIN_LOOP_MAP_BYTES
Definition: sli4.h:1019
ocs_hal_rtn_e ocs_hal_get_port_protocol(ocs_hal_t *hal, uint32_t pci_func, ocs_get_port_protocol_cb_t cb, void *ul_arg)
Get the current port protocol.
Definition: ocs_hal.c:8498
uint32_t ref_tag_repl
Definition: ocs_hal.h:404
static uint32_t sli_get_max_sgl(sli4_t *sli4)
Definition: sli4.h:3746
ocs_dma_t * dma_resp
Definition: ocs_hal.c:7909
struct ocs_hal_io_param_t::@18 fc_ct
int32_t sli_cmd_common_set_dump_location(sli4_t *sli4, void *buf, size_t size, uint8_t query, uint8_t is_buffer_list, ocs_dma_t *buffer, uint8_t fdb)
Write a COMMON_SET_DUMP_LOCATION command.
Definition: sli4.c:3031
void * ocs_pool_get(ocs_pool_t *pool)
Allocate a memory pool item.
Definition: ocs_pool.c:197
static int32_t ocs_hal_cb_read_fcf(ocs_hal_t *, int32_t, uint8_t *, void *)
Callback function for the FCOE_READ_FCF_TABLE command.
Definition: ocs_hal.c:10557
void ocs_domain_force_free(ocs_domain_t *domain)
Free memory resources of a domain object.
Definition: ocs_domain.c:341
void ocs_hal_reqtag_reset(ocs_hal_t *hal)
Reset the WQ request tag pool.
Definition: ocs_hal.c:13448
uint32_t repl_ref_tag
Definition: ocs_hal.h:407
uint16_t size
Definition: sli4.h:3453
sli4_mbox_command_header_t hdr
Definition: sli4.h:864
static ocs_hal_skyhawk_linkcfg_map_t skyhawk_linkcfg_map[]
Mapping from the HAL linkcfg enum to the Skyhawk link config IDs.
Definition: ocs_hal.c:6177
#define OCS_HAL_RQ_SIZE_PAYLOAD
static void * __ocs_hal_port_free_nop(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
Definition: ocs_hal.c:11613
int32_t sli_cq_parse(sli4_t *sli4, sli4_queue_t *cq, uint8_t *cqe, sli4_qentry_e *etype, uint16_t *q_id)
Parse a CQ entry to retrieve the event type and the associated queue.
Definition: sli4.c:6046
#define SLI4_RESOURCE_DESCRIPTOR_TYPE_PCIE
Resource descriptor.
Definition: sli4.h:2921
static ocs_hal_rtn_e ocs_hal_config_set_fdt_xfer_hint(ocs_hal_t *hal, uint32_t fdt_xfer_hint)
Set FTD transfer hint feature.
Definition: ocs_hal.c:7410
uint8_t filtermask
Definition: sli4.h:4103
int32_t sli_dump_is_ready(sli4_t *sli4)
Read the SLIPORT_STATUS register to to check if a dump is present.
Definition: sli4.c:6142
uint8_t val
Definition: sli4_fc.h:328
ocs_hal_rtn_e ocs_hal_init(ocs_hal_t *hal)
Allocate memory structures to prepare for the device operation.
Definition: ocs_hal.c:813
ocs_hal_property_e
Definition: ocs_hal.h:179
static ocs_hal_rtn_e ocs_hal_teardown_fw_diagnostic_logging(ocs_hal_t *hal)
If required disable firmware diagnostic logging (RAS) and then free resources.
Definition: ocs_hal.c:7047
#define SLI4_FC_WCQE_STATUS_SHUTDOWN
Definition: sli4_fc.h:1663
#define SLI4_FCOE_FIP_FCF_DISCOVERED
Definition: sli4_fc.h:1546
#define SLI4_PAUSE_ERRX_PAIR_CNT
Definition: sli4.h:3498
static void ocs_hal_cb_itcm_parity_stats(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
Definition: ocs_hal.c:6793
int32_t sli_xmit_sequence64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *payload, uint32_t payload_len, uint8_t timeout, uint16_t ox_id, uint16_t xri, uint16_t tag, ocs_remote_node_t *rnode, uint8_t r_ctl, uint8_t type, uint8_t df_ctl)
Write a XMIT_SEQUENCE64 work queue entry.
Definition: sli4_fc.c:1799
ocs_hal_rtn_e ocs_hal_port_migration(ocs_hal_t *hal)
Definition: ocs_hal.c:1657
ocs_hal_rq_buffer_t * header
Definition: ocs_hal.h:790
const char * clp_str
Definition: ocs_hal.c:6146
void(* ocs_set_active_profile_cb_t)(int32_t status, void *arg)
Definition: ocs_hal.h:1415
Link configuration callback argument.
Definition: ocs_hal.c:6267
static int32_t ocs_hal_cb_dump_get(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
Called when the OBJECT_GET command completes.
Definition: ocs_hal.c:8193
static int32_t _hal_wq_write(hal_wq_t *wq, ocs_hal_wqe_t *wqe)
Write a HAL IO to a work queue.
Definition: ocs_hal.c:4048
#define FC_LINK_SPEED_32G
Definition: sli4.h:722
#define ocs_queue_history_wq(...)
Definition: ocs_debug.h:160
uint32_t uint32_t additional_status
Definition: sli4.h:1685
#define SLI4_MGMT_STATUS_FEATURE_NOT_SUPPORTED
Definition: sli4.h:1590
struct sli_bls_payload_t::@52::@53 acc
static int32_t ocs_hal_read_lmt(ocs_hal_t *hal)
function to read link module type
Definition: ocs_hal.c:10664
int32_t ocs_hal_io_get_xid(ocs_hal_t *hal, ocs_hal_io_t *io)
Return the OX_ID/RX_ID of the IO.
Definition: ocs_hal.c:5488
static int32_t ocs_hal_cmd_submit_pending(ocs_hal_t *hal)
Submit queued (pending) mbx commands.
Definition: ocs_hal.c:2686
static void * sli_get_wwn_port(sli4_t *sli4)
Definition: sli4.h:3810
static uint32_t sli_is_dif_separate_capable(sli4_t *sli4)
Definition: sli4.h:3897
uint8_t ocs_hal_is_xri_port_owned(ocs_hal_t *hal, uint32_t xri)
Return TRUE if exchange is port-owned.
Definition: ocs_hal.c:12808
int32_t sli_cmd_init_link(sli4_t *sli4, void *buf, size_t size, uint32_t speed, uint8_t reset_alpa)
Write an INIT_LINK command to the provided buffer.
Definition: sli4.c:772
static int32_t ocs_list_empty(ocs_list_t *list)
Test if a list is empty.
Definition: ocs_list.h:125
static int32_t ocs_fw_dump_buffer_alloc(ocs_t *ocs, uint8_t dump_level)
Definition: ocs_hal.c:7604
static ocs_hal_linkcfg_e ocs_hal_linkcfg_from_clp(const char *clp_str)
Helper function for getting the HAL linkcfg enum from the CLP string value.
Definition: ocs_hal.c:6191
uint32_t total_exchanges_originator
Definition: sli4.h:1290
#define ocs_queue_history_init(...)
Definition: ocs_debug.h:163
uint32_t receive_frame_count
Definition: sli4.h:1287
Event Queue Entry.
Definition: sli4.h:3305
void hal_queue_teardown(ocs_hal_t *hal)
Teardown HAL queue objects.
static ocs_hal_rtn_e ocs_hal_set_linkcfg(ocs_hal_t *, ocs_hal_linkcfg_e, uint32_t, ocs_hal_port_control_cb_t, void *)
Set link configuration.
Definition: ocs_hal.c:6290
T10 DIF information passed to the transport.
Definition: ocs_hal.h:400
static void shutdown_target_wqe_timer(ocs_hal_t *hal)
Definition: ocs_hal.c:12750
sli4_qentry_e
Definition: sli4.h:3436
static void ocs_hal_check_sec_hio_list(ocs_hal_t *hal)
Check to see if there are any BZ 161832 workaround waiting IOs.
Definition: ocs_hal.c:4179
int32_t sli_cmd_common_set_features(sli4_t *sli4, void *buf, size_t size, uint32_t feature, uint32_t param_len, void *parameter)
Write a COMMON_SET_FEATURES command.
Definition: sli4.c:3202
static int32_t ocs_hal_cb_dump_clear(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
Called when the OBJECT_DELETE command completes.
Definition: ocs_hal.c:8315
int32_t ocs_hal_rqpair_process_rq(ocs_hal_t *hal, hal_cq_t *cq, uint8_t *cqe)
Process receive queue completions for RQ Pair mode.
#define SLI4_READ_TOPOLOGY_LINK_UP
Definition: sli4.h:1021
static ocs_hal_rtn_e ocs_hal_config_sli_port_health_check(ocs_hal_t *hal, uint8_t query, uint8_t enable)
enable sli port health check
Definition: ocs_hal.c:7219
#define SLI4_READ_CFG_TOPO_FC_DA
Definition: sli4.h:857
static ocs_hal_rtn_e ocs_hal_queue_hash_alloc(ocs_hal_t *hal)
Definition: ocs_hal.c:562
int32_t ocs_hal_get_num_eq(ocs_hal_t *hal)
Definition: ocs_hal.c:1823
#define SLI4_READ_CFG_TOPO_FCOE
Definition: sli4.h:855
ocs_hal_rtn_e ocs_hal_teardown(ocs_hal_t *hal)
Tear down the Hardware Abstraction Layer module.
Definition: ocs_hal.c:1446
static void ocs_hal_adjust_wqs(ocs_hal_t *hal)
Adjust the number of WQs and CQs within the HAL.
Definition: ocs_hal.c:10368
uint8_t cmd[SLI4_BMBX_SIZE]
Definition: ocs_hal.c:13257
static void ocs_hal_linkcfg_dmtf_clp_cb(ocs_hal_t *hal, int32_t status, uint32_t result_len, void *arg)
Get the link configuration callback.
Definition: ocs_hal.c:7444
uint8_t mrq_set_count
Definition: sli4.h:4105
static void * __ocs_hal_port_attach_report_fail(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
Definition: ocs_hal.c:11530
int32_t sli_setup(sli4_t *sli4, ocs_os_handle_t os, sli4_port_type_e port_type)
Set up the SLI context.
Definition: sli4.c:4452
void(* ocs_hal_parity_stat_cb_t)(int32_t status, uint8_t num_ulp, ocs_parity_err_count_t *counter, void *arg)
Definition: ocs_hal.h:1433
uint32_t at
Definition: sli4.h:533
#define SLI4_FCOE_FIP_FCF_CLEAR_VLINK
Definition: sli4_fc.h:1549
static int32_t __ocs_hal_port_realloc_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
Definition: ocs_hal.c:11992
#define SLI4_CMD_REG_FCFI_NUM_RQ_CFG
REG_FCFI - activate a FC Forwarder.
Definition: sli4.h:1041
static int32_t sli_set_dpp(sli4_t *sli4, uint32_t value)
Definition: sli4.h:3952
int32_t sli_cmd_config_optimized_write_hp(sli4_t *sli4, void *buf, size_t size, uint32_t max_burst_len, uint32_t xri_cnt, uint32_t block_size, uint32_t tow_feature)
Write an CONFIG_OPTIMIZED_WRITE_HP command to the provided buffer.
Definition: sli4.c:1849
ocs_hal_dump_get_cb_t cb
Definition: ocs_hal.c:5532
#define SLI4_WKI_TAG_SAT_TEM
DUMP Type 4.
Definition: sli4.h:630
void ocs_pool_put(ocs_pool_t *pool, void *item)
free memory pool item
Definition: ocs_pool.c:230
uint32_t id
Definition: ocs_hal.h:870
uint32_t dif_op_rx
Definition: sli4.h:546
void sli4_cmd_lowlevel_get_itcm_parity_stats(sli4_t *sli4, void *buf, size_t size, bool clear_stats)
Definition: sli4.c:2412
#define SLI4_FC_WCQE_STATUS_LOCAL_REJECT
Definition: sli4_fc.h:1641
static void ocs_hal_set_active_link_config_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
Callback for ocs_hal_set_linkcfg_skyhawk.
Definition: ocs_hal.c:6388
uint32_t dif_blk_size
Definition: sli4.h:546
uint32_t app_tag_cmp
Definition: ocs_hal.h:405
ocs_hal_rtn_e ocs_hal_send_frame(ocs_hal_t *hal, fc_header_le_t *hdr, uint8_t sof, uint8_t eof, ocs_dma_t *payload, ocs_hal_send_frame_context_t *ctx, void(*callback)(void *arg, uint8_t *cqe, int32_t status), void *arg)
Send a raw frame.
Definition: ocs_hal.c:4817
ocs_hal_rtn_e ocs_hal_unreg_rpi_all(ocs_hal_t *hal, ocs_sport_t *sport)
Free all remote node objects.
Definition: ocs_hal.c:3658
static ocs_hal_rtn_e ocs_hal_set_eth_license(ocs_hal_t *hal, uint32_t license)
Set the Ethernet license.
Definition: ocs_hal.c:7864
uint16_t instance_index
Definition: ocs_hal.h:889
static ocs_hal_rtn_e ocs_hal_set_dump_location(ocs_hal_t *hal, uint32_t num_buffers, ocs_dma_t *dump_buffers, uint8_t fdb)
Set the Lancer dump location.
Definition: ocs_hal.c:7497
ocs_hal_async_cb_t callback
Definition: ocs_hal.c:13255
int32_t sli_queue_write(sli4_t *sli4, sli4_queue_t *q, uint8_t *entry)
Write an entry to the queue object.
Definition: sli4.c:5645
void ocs_hal_free_dump_to_host_buffers(ocs_hal_t *hal)
Definition: ocs_hal.c:7561
static void ocs_hal_wq_handle_bad_reque_xri(void *arg, uint8_t *cqe, int32_t status)
Definition: ocs_hal.c:13509
static void * __ocs_hal_port_alloc_init(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
Definition: ocs_hal.c:11895
static void * ocs_list_get_head(ocs_list_t *list)
Return the first item in the list.
Definition: ocs_list.h:292
#define ocs_queue_history_cqe(...)
Definition: ocs_debug.h:161
ocs_hal_rtn_e ocs_hal_init_queues(ocs_hal_t *hal, ocs_hal_qtop_t *qtop)
Initialize queues.
static int32_t ocs_hal_get_profile_list_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
Called for the completion of get_profile_list for a user request.
Definition: ocs_hal.c:8880
ocs_hal_global_t hal_global
Definition: ocs_hal.c:78
void sli4_cmd_lowlevel_set_watchdog(sli4_t *sli4, void *buf, size_t size, uint16_t timeout)
Write a LOWLEVEL_SET_WATCHDOG command.
Definition: sli4.c:2304
struct ocs_hal_io_param_t::@20 fcp_tgt
#define OCS_HAL_MAX_NUM_RQ
Definition: ocs_hal.h:120
ocs_hal_rtn_e ocs_hal_io_abort(ocs_hal_t *hal, ocs_hal_io_t *io_to_abort, uint32_t send_abts, void *cb, void *arg)
Abort a previously-started IO.
Definition: ocs_hal.c:5343
#define OCS_HAL_RQ_SIZE_HDR
Defines the size of the RQ buffers used for each RQ.
ocs_hal_rtn_e ocs_hal_port_attach(ocs_hal_t *hal, ocs_sli_port_t *sport, uint32_t fc_id)
Attach a physical/virtual SLI port to a domain.
Definition: ocs_hal.c:2966
#define SLI4_READ_TOPOLOGY_SPEED_16G
Definition: sli4.h:1035
static void * __ocs_hal_domain_free_unreg_fcfi(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
Definition: ocs_hal.c:12552
ocs_hal_rtn_e ocs_hal_get_profile_list(ocs_hal_t *hal, ocs_get_profile_list_cb_t cb, void *ul_arg)
Get a list of available profiles.
Definition: ocs_hal.c:8955
void(* ocs_get_profile_list_cb_t)(int32_t status, ocs_hal_profile_list_t *, void *arg)
Definition: ocs_hal.h:1411
T10 DIF Seed Scatter-Gather Entry (SGE)
Definition: sli4.h:529
static ocs_hal_rtn_e ocs_hal_exec_dmtf_clp_cmd(ocs_hal_t *hal, ocs_dma_t *dma_cmd, ocs_dma_t *dma_resp, uint32_t opts, ocs_hal_dmtf_clp_cb_t cb, void *arg)
Execute the DMTF CLP command.
Definition: ocs_hal.c:7929
#define OCS_FW_VER_STR(x)
ocs_hal_rtn_e ocs_hal_node_group_attach(ocs_hal_t *hal, ocs_remote_node_group_t *ngroup, ocs_remote_node_t *rnode)
Definition: ocs_hal.c:3714
static ocs_domain_t * ocs_hal_domain_get_indexed(ocs_hal_t *hal, uint16_t fcf_index)
Definition: ocs_hal.c:9710
static void ocs_hal_cb_cfg_watchdog(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
Definition: ocs_hal.c:6736
#define SLI4_PROTOCOL_FCOE
Definition: sli4.h:2931
static uint32_t sli_get_tow_capable(sli4_t *sli4)
Definition: sli4.h:3864
static int32_t __ocs_hal_domain_cb(ocs_hal_t *, int32_t, uint8_t *, void *)
Definition: ocs_hal.c:12662
FCOE_POST_SGL_PAGES.
Definition: sli4_fc.h:155
static void sli_queue_lock(sli4_queue_t *q)
Definition: sli4.h:3487
int32_t sli_queue_free(sli4_t *sli4, sli4_queue_t *q, uint32_t destroy_queues, uint32_t free_memory)
Free a queue.
Definition: sli4.c:5335
#define SLI4_SGE_DIF_OP_IN_CRC_OUT_NODIF
Definition: sli4.h:580
uint32_t qx
Definition: sli4_fc.h:1602
uint32_t uint32_t id
Definition: ocs_hal.h:573
uint32_t app_tag_repl
Definition: sli4.h:533
int32_t sli_xmit_bcast64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *payload, uint32_t payload_len, uint8_t timeout, uint16_t xri, uint16_t tag, uint16_t cq_id, ocs_remote_node_t *rnode, uint8_t r_ctl, uint8_t type, uint8_t df_ctl)
Definition: sli4_fc.c:1903
#define SLI4_READ_SPARM64_VPI_DEFAULT
Definition: sli4.h:956
#define SLI4_READ_TOPOLOGY_SPEED_2G
Definition: sli4.h:1031
int32_t sli_fw_ready(sli4_t *sli4)
Determine if the chip FW is in a ready state.
Definition: sli4.c:6332
uint32_t ox_id
Definition: ocs_fcp.h:168
uint32_t attention_type
Definition: sli4.h:983
ocs_hal_rtn_e ocs_hal_io_add_seed_sge(ocs_hal_t *hal, ocs_hal_io_t *io, ocs_hal_dif_info_t *dif_info)
Add a T10 PI seed scatter gather list entry.
Definition: ocs_hal.c:5029
uint8_t mrq_set_num
Definition: sli4.h:4107
ocs_hal_rtn_e
Definition: ocs_hal.h:159
static uint32_t sli_is_dif_inline_capable(sli4_t *sli4)
Definition: sli4.h:3891
uint32_t fw_diag_log_size
Definition: ocs_hal.h:1268
uint16_t flags
Definition: ocs_hal.h:540
hal_wq_callback_t * wqcb
Definition: ocs_hal.h:1450
static ocs_hal_rtn_e ocs_hal_config_tow_t10pi(ocs_hal_t *hal)
Set configuration parameters for TOW T10 PI feature.
Definition: ocs_hal.c:7131
#define OCS_MIN_FW_VER_LANCER
int32_t sli_resource_alloc(sli4_t *sli4, sli4_resource_e rtype, uint32_t *rid, uint32_t *index)
Allocate SLI Port resources.
Definition: sli4.c:5851
uint16_t ox_id
Definition: ocs_hal.h:499
int32_t sli_cmd_post_xri(sli4_t *sli4, void *buf, size_t size, uint16_t xri_base, uint16_t xri_count)
Write a POST_XRI command to the provided buffer.
Definition: sli4.c:909
int32_t sli_cmd_unreg_rpi(sli4_t *sli4, void *buf, size_t size, uint16_t indicator, sli4_resource_e which, uint32_t fc_id)
Write an UNREG_RPI command to the provided buffer.
Definition: sli4.c:1601
int32_t sli_queue_is_empty(sli4_t *sli4, sli4_queue_t *q)
Check if the given queue is empty.
Definition: sli4.c:5463
uint32_t hard_alpa
Definition: sli4.h:872
sli4_mbox_command_header_t hdr
Definition: sli4.h:791
int32_t sli_cmd_fc_set_trunk_mode(sli4_t *sli4, void *buf, size_t size, uint32_t trunk_mode)
Write a SLI4_OPC_FC_SET_TRUNK_MODE command.
Definition: sli4.c:3165
#define SLI4_IO_DNRX
Definition: sli4_fc.h:1002
int32_t ocs_fw_dump_state_check(ocs_t *ocs, uint32_t state)
Check the fw dump state.
Definition: ocs_gendump.c:277
ocs_hal_linkcfg_e linkcfg
Definition: ocs_hal.c:6145
uintptr_t ocs_ras_get_lwpd_dma_addr(ocs_os_handle_t *ocs_os)
Definition: ocs_ras.c:172
uint32_t buffer_address_high
Definition: sli4.h:565
ocs_hal_reset_e
Definition: ocs_hal.h:173
uint8_t protocol
Definition: sli4.h:4102
#define OCS_HAL_MAX_NUM_EQ
Definition: ocs_hal.h:121
uint32_t sli_fc_io_length(sli4_t *sli4, uint8_t *cqe)
Return the FCP IO length.
Definition: sli4_fc.c:2693
int32_t ocs_hal_reque_xri(ocs_hal_t *hal, ocs_hal_io_t *io)
Reque XRI.
Definition: ocs_hal.c:13528
static void * __ocs_hal_domain_free_redisc_fcf(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
Definition: ocs_hal.c:12512
#define SLI4_FC_LOCAL_REJECT_ABORT_REQUESTED
Definition: sli4_fc.h:1697
void(* ocs_get_active_profile_cb_t)(int32_t status, uint32_t active_profile, void *arg)
Definition: ocs_hal.h:1413
HAL async call context structure.
Definition: ocs_hal.c:13254
ocs_hal_rtn_e ocs_hal_set_loopback_mode(ocs_hal_t *hal, uint32_t type)
Set the Lancer dump location.
Definition: ocs_hal.c:7772
uint32_t dropped_frames_due_to_no_rq_buffer_count
Definition: sli4.h:1294
uint32_t uint32_t profile_description[128]
Definition: sli4.h:3051
ocs_hal_rtn_e ocs_hal_get_host_stats(ocs_hal_t *hal, uint8_t cc, ocs_hal_host_stat_cb_t cb, void *arg)
Function to retrieve the link and host statistics.
Definition: ocs_hal.c:6044
static int32_t ocs_hal_command_process(ocs_hal_t *, int32_t, uint8_t *, size_t)
Definition: ocs_hal.c:10427
uint32_t subsystem
Definition: sli4.h:1685
ocs_hal_rtn_e ocs_hal_xri_move_to_host_owned(ocs_hal_t *hal, uint8_t num_xri)
Move XRIs from the port-controlled pool to the host.
Definition: ocs_hal.c:13022
static void ocs_hal_reclaim_xri(ocs_hal_t *hal, uint16_t xri_base, uint16_t xri_count)
Returns an XRI from the port owned list to the host.
Definition: ocs_hal.c:12825
#define SLI4_SGE_TYPE_DISEED
Definition: sli4.h:595
#define SLI4_SGE_TYPE_DIF
Definition: sli4.h:591
struct ocs_hal_io_param_t::@13 bls
#define OCS_HAL_WQ_TIMER_PERIOD_MS
Definition: ocs_hal.c:58
#define SLI4_IF_TYPE_BE3_SKH_VF
Definition: sli4.h:114
int32_t sli_cmd_reg_fcfi(sli4_t *sli4, void *buf, size_t size, uint16_t index, sli4_cmd_rq_cfg_t rq_cfg[SLI4_CMD_REG_FCFI_NUM_RQ_CFG], uint16_t vlan_id)
Write a REG_FCFI command to the provided buffer.
Definition: sli4.c:1148
uint32_t sge_type
Definition: sli4.h:533
uint32_t receive_kbyte_count
Definition: sli4.h:1285
ocs_hal_rtn_e ocs_hal_io_add_sge(ocs_hal_t *hal, ocs_hal_io_t *io, uintptr_t addr, uint32_t length)
Add a scatter gather list entry to an IO.
Definition: ocs_hal.c:5214
#define SLI4_SET_FEATURES_AUTO_RSP_PARAM_RESET
Definition: sli4.h:2751
ocs_hal_rtn_e ocs_hal_domain_force_free(ocs_hal_t *hal, ocs_domain_t *domain)
Free a fabric domain object.
Definition: ocs_hal.c:3362
#define SLI4_CMD_REG_FCFI_SET_MRQ_MODE
Definition: sli4.h:1066
#define FW_FUNC_DUMP_STATE_VALID
Definition: ocs_gendump.h:61
static sli4_link_medium_e sli_get_medium(sli4_t *sli4)
Definition: sli4.h:3759
uint32_t profile_index
Definition: sli4.h:3051
static void ocs_hal_remove_io_timed_wqe(ocs_hal_t *hal, ocs_hal_io_t *io)
Definition: ocs_hal.c:313
static ocs_hal_rtn_e ocs_hal_init_tow_feature(ocs_hal_t *hal)
Initialize TOW feature for AXR/FB.
Definition: ocs_hal.c:262
ocs_hal_state_e
Definition: ocs_hal.h:772
#define OCS_HAL_MAX_NUM_WQ
Definition: ocs_hal.h:122
int32_t sli_cmd_config_optimized_write(sli4_t *sli4, void *buf, size_t size, uint32_t max_burst_len, uint32_t xri_cnt, uint32_t tow_feature)
Write an CONFIG_OPTIMIZED_WRITE command to the provided buffer.
Definition: sli4.c:1810
Define the WQ callback object.
Definition: ocs_hal.h:888
uint32_t dif_separate
Definition: ocs_hal.h:407
ocs_hal_rtn_e ocs_hal_callback(ocs_hal_t *hal, ocs_hal_callback_e which, void *func, void *arg)
Register a callback for the given event.
Definition: ocs_hal.c:2824
int32_t sli_xmit_els_rsp64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *rsp, uint32_t rsp_len, uint16_t xri, uint16_t tag, uint16_t cq_id, uint16_t ox_id, ocs_remote_node_t *rnode, uint32_t flags, uint32_t s_id)
Write a XMIT_ELS_RSP64_WQE work queue entry.
Definition: sli4_fc.c:2066
int32_t ocs_hal_queue_hash_find(ocs_queue_hash_t *hash, uint16_t id)
Find index given queue ID.
Definition: ocs_hal.c:9564
int32_t sli_queue_read(sli4_t *sli4, sli4_queue_t *q, uint8_t *entry)
Read an entry from the queue object.
Definition: sli4.c:5720
void ocs_display_sparams(const char *prelabel, const char *reqlabel, int dest, void *textbuf, void *sparams)
Display service parameters.
Definition: ocs_debug.c:495
uint32_t in_use
Definition: ocs_hal.h:870
static void * sli_get_wwn_node(sli4_t *sli4)
Definition: sli4.h:3816
void(* ocs_hal_temp_cb_t)(int32_t status, uint32_t curr_temp, uint32_t crit_temp_thrshld, uint32_t warn_temp_thrshld, uint32_t norm_temp_thrshld, uint32_t fan_off_thrshld, uint32_t fan_on_thrshld, void *arg)
Definition: ocs_hal.h:1360
static void ocs_hal_io_free_move_correct_list(ocs_hal_t *hal, ocs_hal_io_t *io)
When an IO is freed, depending on the exchange busy flag, and other workarounds, move it to the corre...
Definition: ocs_hal.c:3898
#define SLI4_READ_TOPOLOGY_SPEED_4G
Definition: sli4.h:1032
#define OCS_HAL_MAX_NUM_MQ
Definition: ocs_hal.h:112
static uint32_t sli_get_max_sge(sli4_t *sli4)
Definition: sli4.h:3740
hal_wq_callback_t * ocs_hal_reqtag_get_instance(ocs_hal_t *hal, uint32_t instance_index)
Return WQ request tag by index.
Definition: ocs_hal.c:13426
#define SLI4_READ_CFG_TOPO_FC
Definition: sli4.h:856
T10 DIF Scatter-Gather Entry (SGE)
Definition: sli4.h:513
int32_t sli_teardown(sli4_t *sli4)
Tear down a SLI context.
Definition: sli4.c:4743
uint32_t app_id
Definition: ocs_hal.h:545
#define SLI4_CQ_DEFAULT
Definition: sli4_fc.h:80
uint32_t fw_diag_log_level
Definition: ocs_hal.h:1269
uint8_t address[6]
Definition: ocs_common.h:88
#define SLI4_READ_TOPOLOGY_LINK_DOWN
Definition: sli4.h:1022
static ocs_hal_rtn_e ocs_hal_config_sliport_pause(ocs_hal_t *hal, uint8_t enable)
Definition: ocs_hal.c:7376
#define SLI4_SGE_DIF_OP_IN_CRC_OUT_CRC
Definition: sli4.h:583
#define SLI4_SGE_DIF_OP_IN_NODIF_OUT_CRC
Definition: sli4.h:579
uint32_t sli4_diseed_sge_t scsi_diseed_sge
Definition: sli4.h:2813
int32_t sli_cmd_reg_fcfi_mrq(sli4_t *sli4, void *buf, size_t size, uint8_t mode, uint16_t fcf_index, uint16_t vlan_id, sli4_cmd_rq_cfg_t rq_cfg[SLI4_CMD_REG_FCFI_NUM_RQ_CFG])
Write REG_FCFI_MRQ to provided command buffer.
Definition: sli4.c:1193
HAL command context.
Definition: ocs_hal.h:475
int32_t sli_cmd_common_write_object(sli4_t *sli4, void *buf, size_t size, uint16_t noc, uint16_t eof, uint32_t desired_write_length, uint32_t offset, char *object_name, ocs_dma_t *dma)
Write a COMMON_WRITE_OBJECT command.
Definition: sli4.c:2831
uint32_t repl_app_tag
Definition: sli4.h:533
uint16_t rq_id
Definition: sli4.h:4096
struct ocs_hal_io_param_t::@14 bls_sid
sli4_profile_descriptor_t profile_descriptor[MAX_PRODUCT_DESCRIPTORS]
Definition: sli4.h:3084
uint32_t check_app_tag
Definition: sli4.h:546
ocs_pool_t * ocs_pool_alloc(ocs_os_handle_t os, uint32_t size, uint32_t count, uint32_t use_lock)
Allocate a memory pool.
Definition: ocs_pool.c:88
uint8_t r_ctl_match
Definition: sli4.h:4098
ocs_hal_dmtf_clp_cb_t cb
Definition: ocs_hal.c:7908
union ocs_domain_record_t::@5 map
void(* ocs_hal_fw_cb_t)(int32_t status, int32_t ext_status, uint32_t bytes_written, uint32_t change_status, void *arg)
Definition: ocs_hal.h:1351
#define OCS_HAL_REQUE_XRI_REGTAG
Definition: ocs_hal.c:71
uint8_t fabric_name_id[8]
Definition: sli4_fc.h:326
#define OCS_HAL_TOW_BLK_SIZE_DEFAULT
Definition: ocs_hal.c:61
static void ocs_hal_wq_process_abort(void *arg, uint8_t *cqe, int32_t status)
Process WQ completions for abort requests.
Definition: ocs_hal.c:10201
uint32_t fip_priority
Definition: sli4_fc.h:322
ocs_hal_port_protocol_e
Port protocols.
Definition: ocs_hal.h:279
static ocs_hal_rtn_e ocs_hal_sli_reset(ocs_hal_t *hal, ocs_hal_reset_e reset, ocs_hal_state_e prev_state)
Definition: ocs_hal.c:1618
ocs_hal_profile_descriptor_t descriptors[OCS_HAL_MAX_PROFILES]
Definition: ocs_hal.h:301
void ocs_pool_free(ocs_pool_t *pool)
Free a previously allocated memory pool.
Definition: ocs_pool.c:173
uint8_t wwnn[8]
Definition: sli4.h:871
READ_NVPARMS - read SLI port configuration parameters.
Definition: sli4.h:863
uint32_t ref_tag_repl
Definition: sli4.h:532
sli4_mbox_command_header_t hdr
Definition: sli4.h:632
static int32_t sli_set_sgl_preregister(sli4_t *sli4, uint32_t value)
Definition: sli4.h:3983
static void * ocs_list_remove(ocs_list_t *list, void *item)
Remove an item from the list.
Definition: ocs_list.h:385
static ocs_hal_io_t * _ocs_hal_io_alloc(ocs_hal_t *hal)
Lockless allocate a HAL IO object.
Definition: ocs_hal.c:3806
ocs_hal_io_t * ocs_hal_io_lookup(ocs_hal_t *hal, uint32_t xri)
Find IO given indicator (xri).
Definition: ocs_hal.c:11213
static uint32_t sli_get_sgl_preregister_required(sli4_t *sli4)
Definition: sli4.h:3971
static uint32_t sli_get_max_queue(sli4_t *sli4, sli4_qtype_e qtype)
Definition: sli4.h:3724
uint8_t ocs_hal_rqpair_tow_xri_buffer_attach(ocs_hal_t *hal, ocs_hal_io_t *io, int reuse_buf)
int ocs_hal_can_accept_wqes(struct ocs_hal_io_s *hio)
Validate HAL IO state to make sure HAL can accept and post wqe to SLI.
Definition: ocs_hal.c:13588
static ocs_hal_rtn_e ocs_hal_sequence_free(ocs_hal_t *hal, ocs_hal_sequence_t *seq)
Definition: ocs_hal.h:1512
static void * __ocs_hal_domain_allocated(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
Definition: ocs_hal.c:12196
int32_t sli_link_is_configurable(sli4_t *sli)
Determine if the link can be configured.
Definition: sli4.c:6364
static int32_t ocs_hal_command_cancel(ocs_hal_t *)
Definition: ocs_hal.c:11177
uint8_t df_ctl
Definition: ocs_hal.h:512
#define SLI4_FC_WCQE_STATUS_TARGET_WQE_TIMEOUT
Definition: sli4_fc.h:1662
uint32_t uint32_t trunk_config
Definition: sli4.h:1010
static void ocs_hal_watchdog_timer_cb(void *arg)
Definition: ocs_hal.c:6728
int32_t sli_resource_free(sli4_t *sli4, sli4_resource_e rtype, uint32_t rid)
Free the SLI Port resources.
Definition: sli4.c:5913
static uint8_t ocs_hal_iotype_is_originator(uint16_t io_type)
Definition: ocs_hal.c:328
ocs_hal_dump_clear_cb_t cb
Definition: ocs_hal.c:5538
ocs_hal_dif_oper_e dif_oper
Definition: ocs_hal.h:542
static void * sli_get_fw_name(sli4_t *sli4, uint32_t which)
Definition: sli4.h:3840
ocs_hal_callback_e
Definition: ocs_hal.h:694
static int32_t ocs_hal_cb_fip(void *, void *)
Definition: ocs_hal.c:10790
#define SLI4_RESOURCE_DESCRIPTOR_TYPE_ISAP
Definition: sli4.h:2927
int32_t sli_cqe_async(sli4_t *sli4, void *buf)
Check the asynchronous event completion entry.
Definition: sli4.c:3586
uint32_t sge_type
Definition: sli4.h:567
static int32_t ocs_hal_get_fw_timed_out(ocs_hal_t *hal)
Definition: ocs_hal.c:1829
int32_t sli_cmd_config_auto_xfer_rdy(sli4_t *sli4, void *buf, size_t size, uint32_t max_burst_len)
Write an CONFIG_AUTO_XFER_RDY command to the provided buffer. Command to enable AXR in G5...
Definition: sli4.c:1748
uint32_t xri_tag0
Definition: sli4.h:798
#define CPUTRACE(...)
Definition: ocs_hal.h:1537
static uint32_t sli_get_hlm(sli4_t *sli4)
Definition: sli4.h:3940
uint32_t xri_count
Definition: sli4.h:773
const char * ocs_sm_event_name(ocs_sm_event_t evt)
Definition: ocs_sm.c:92
ocs_hal_io_t * ocs_hal_io_alloc(ocs_hal_t *hal)
Allocate a HAL IO object.
Definition: ocs_hal.c:3839
static ocs_hal_rtn_e ocs_hal_read_fcf(ocs_hal_t *hal, uint32_t index)
Read a FCF table entry.
Definition: ocs_hal.c:10498
int32_t sli_cmd_read_sparm64(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *dma, uint16_t vpi)
Write a READ_SPARM64 command to the provided buffer.
Definition: sli4.c:1067
#define SLI4_BMBX_SIZE
Definition: sli4.h:150
ocs_hal_rtn_e ocs_hal_set_dump_to_host_buffers(ocs_hal_t *hal)
Allocates dump dma buffers, if not already allocated. Set the Lancer dump location.
Definition: ocs_hal.c:7721
ocs_hal_io_type_e
Definition: ocs_hal.h:426
#define OCS_HAL_DMTF_CLP_RSP_MAX
Definition: ocs_hal.c:75
int32_t sli_cmd_common_set_reconfig_link_id(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *dma, uint32_t fd, uint32_t active_link_config_id)
Write a COMMON_SET_RECONFIG_LINK_ID command.
Definition: sli4.c:3505
uint32_t sli_fc_get_rpi_requirements(sli4_t *sli4, uint32_t n_rpi)
Get the RPI resource requirements.
Definition: sli4_fc.c:3131
static uint8_t ocs_hal_wcqe_abort_needed(uint16_t status, uint8_t ext, uint8_t xb)
Definition: ocs_hal.c:342
static void * __ocs_hal_port_freed(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
Definition: ocs_hal.c:11498
ocs_hal_rtn_e ocs_hal_domain_alloc(ocs_hal_t *hal, ocs_domain_t *domain, uint32_t fcf, uint32_t vlan)
Allocate a fabric domain object.
Definition: ocs_hal.c:3217
int32_t sli_port_migration(sli4_t *sli4)
Definition: sli4.c:4701
uint32_t uint32_t saved_status
Definition: ocs_hal.h:614
uint32_t uint32_t uint32_t response_length
Definition: sli4.h:1685
#define SLI4_FC_LOCAL_REJECT_NO_XRI
Definition: sli4_fc.h:1683
uint32_t uint32_t lmt
Definition: sli4.h:827
static uint32_t sli_get_max_qentries(sli4_t *sli4, sli4_qtype_e qtype)
Definition: sli4.h:3733
bool protocol_valid
Definition: sli4.h:4101
ocs_hal_rtn_e ocs_hal_node_detach(ocs_hal_t *hal, ocs_remote_node_t *rnode)
Free a remote node object.
Definition: ocs_hal.c:3562
#define ocs_list_init(head, type, link)
Definition: ocs_list.h:113
uint32_t num_descriptors
Definition: ocs_hal.h:300
uint32_t d_id
Definition: ocs_fcp.h:158
uint32_t sge_type
Definition: sli4.h:517
#define SLI4_FCOE_FCF_TABLE_FIRST
Definition: sli4_fc.h:311
ocs_hal_rtn_e ocs_hal_reset(ocs_hal_t *hal, ocs_hal_reset_e reset)
Definition: ocs_hal.c:1670
static int32_t ocs_hal_set_active_profile_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
Called for the completion of set_active_profile for a user request.
Definition: ocs_hal.c:9433
ocs_hal_rtn_e ocs_hal_io_register_sgl(ocs_hal_t *hal, ocs_hal_io_t *io, ocs_dma_t *sgl, uint32_t sgl_count)
Definition: ocs_hal.c:4867
FC header in big-endian order.
Definition: ocs_fcp.h:157
int32_t sli_queue_eq_arm(sli4_t *sli4, sli4_queue_t *q, uint8_t arm)
Arm an EQ.
Definition: sli4.c:5492
static void * __ocs_hal_port_attach_reg_vpi(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
Definition: ocs_hal.c:11674
int32_t sli_raise_ue(sli4_t *sli4, uint8_t dump)
Cause chip to enter an unrecoverable error state.
Definition: sli4.c:6092
FC/FCoE WQ completion queue entry.
Definition: sli4_fc.h:1595
uint16_t rqindex
Definition: ocs_hal.h:327
static int ocs_list_valid(ocs_list_t *list)
Test if a list is valid (ready for use)
Definition: ocs_list.h:155
hal_wq_callback_t * ocs_hal_reqtag_alloc(ocs_hal_t *hal, void(*callback)(void *arg, uint8_t *cqe, int32_t status), void *arg)
Allocate a WQ request tag.
Definition: ocs_hal.c:13380
ocs_hal_rtn_e ocs_hal_dump_clear(ocs_hal_t *hal, ocs_hal_dump_clear_cb_t cb, void *arg)
Clear a dump image from the device.
Definition: ocs_hal.c:8354
void(* ocs_set_nvparms_cb_t)(int32_t status, void *arg)
Definition: ocs_hal.h:1421
static int32_t ocs_hal_io_ini_sge(ocs_hal_t *, ocs_hal_io_t *, ocs_dma_t *, uint32_t, ocs_dma_t *)
Definition: ocs_hal.c:11333
uint32_t ocs_hal_rpi_active_count(ocs_hal_t *hal)
Called to obtain active RPI count.
Definition: ocs_hal.c:9371
static ocs_hal_rtn_e ocs_hal_read_max_dump_size(ocs_hal_t *hal)
Read the max dump size for this port.
Definition: ocs_hal.c:420
static ocs_hal_rtn_e ocs_hal_bmbx_command(ocs_hal_t *hal, uint8_t *cmd)
Definition: ocs_hal.c:2644
#define SLI4_READ_TOPOLOGY_SPEED_1G
Definition: sli4.h:1030
void(* ocs_hal_host_stat_cb_t)(int32_t status, uint32_t num_counters, ocs_hal_host_stat_counts_t *counters, void *arg)
Definition: ocs_hal.h:1385
uint32_t abort_reqtag
Definition: ocs_hal.h:578
static ocs_hal_rtn_e ocs_hal_init_tow(ocs_hal_t *hal, uint32_t tow_feature)
Definition: ocs_hal.c:212
int32_t sli_requeue_xri_wqe(sli4_t *sli4, void *buf, size_t size, uint16_t xri, uint16_t tag, uint16_t cq_id)
Write a REQUEUE_XRI_WQE work queue entry.
Definition: sli4_fc.c:1885
static int32_t ocs_hal_cb_host_stat(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
Called when the READ_STATUS command completes.
Definition: ocs_hal.c:6096
#define SLI4_READ_TOPOLOGY_FC_AL
Definition: sli4.h:1027
static ocs_hal_rtn_e ocs_hal_post_xri(ocs_hal_t *hal, uint32_t xri_start, uint32_t num_to_post)
Issues a mailbox command to move XRIs from the host-controlled pool to the port.
Definition: ocs_hal.c:12889
uint32_t xri_base
Definition: sli4.h:773
hal_wq_t * ocs_hal_queue_next_wq(ocs_hal_t *hal, ocs_hal_io_t *io)
Allocate a WQ to an IO object.
#define smtrace(...)
Definition: ocs_sm.h:205
void(* ocs_hal_dump_clear_cb_t)(int32_t status, void *arg)
Definition: ocs_hal.h:1430
#define SLI4_PROTOCOL_FC
Definition: sli4.h:2933
static int32_t ocs_hal_config_mrq(ocs_hal_t *hal, uint8_t, uint16_t, uint16_t)
Configure Multi-RQ.
Definition: ocs_hal.c:1321
static void ocs_hal_io_cancel_cleanup(ocs_hal_t *hal, ocs_hal_io_t *io)
Issue any pending callbacks for an IO and remove off the timer and pending lists. ...
Definition: ocs_hal.c:11227
void _ocs_hal_verify(const char *cond, const char *filename, int linenum)
Handle HAL verify.
Definition: ocs_hal.c:13502
uint32_t first_burst
Definition: ocs_hal.h:556
void *(* ocs_sm_function_t)(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
Definition: ocs_sm.h:188
int32_t sli_fc_els_did(sli4_t *sli4, uint8_t *cqe, uint32_t *d_id)
Retrieve the D_ID from the completion.
Definition: sli4_fc.c:2711
#define ocs_list_foreach_safe(list, item, nxt)
Iterate a linked list safely.
Definition: ocs_list.h:446
static uint32_t sli_get_hw_revision(sli4_t *sli4, uint32_t which)
Definition: sli4.h:3852
COMMON_SET_PROFILE_CONFIG.
Definition: sli4.h:3029
int32_t sli_fcp_treceive64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl, uint32_t first_data_sge, uint32_t relative_off, uint32_t xfer_len, uint16_t xri, uint16_t tag, uint16_t cq_id, uint16_t xid, uint32_t rpi, ocs_remote_node_t *rnode, uint32_t flags, uint8_t dif, uint8_t bs, uint8_t csctl, uint32_t app_id, uint8_t timer)
Write an FCP_TRECEIVE64_WQE work queue entry.
Definition: sli4_fc.c:1204
int32_t sli_cmd_reg_vpi(sli4_t *sli4, void *buf, size_t size, ocs_sli_port_t *sport, uint8_t update)
Write a REG_VPI command to the provided buffer.
Definition: sli4.c:1423
int32_t(* cb)(struct ocs_hal_s *, int32_t, uint8_t *, void *)
Definition: ocs_hal.h:478
uint32_t sli4_fcf_entry_t fcf_entry
Definition: sli4_fc.h:348
uint32_t * ocs_ras_get_dma_addr_list(ocs_os_handle_t *ocs_os, int32_t *buf_count)
Definition: ocs_ras.c:185
int32_t sli_eq_parse(sli4_t *sli4, uint8_t *buf, uint16_t *cq_id)
Parse an EQ entry to retrieve the CQ_ID for this event.
Definition: sli4.c:6000
uint16_t rx_id
Definition: ocs_hal.h:500
sli4_mbox_command_header_t hdr
Definition: sli4.h:771
ocs_hal_linkcfg_e
Link configurations.
Definition: ocs_hal.h:367
static uint32_t sli_get_sli_rev(sli4_t *sli4)
Definition: sli4.h:3792
FC header in little-endian order.
Definition: ocs_fcp.h:177
uint32_t empty_rq_timeout_count
Definition: sli4.h:1295
int32_t ocs_hal_set_nvparms(ocs_hal_t *hal, ocs_set_nvparms_cb_t cb, uint8_t *wwpn, uint8_t *wwnn, uint8_t hard_alpa, uint32_t preferred_d_id, void *ul_arg)
Write non-volatile parms.
Definition: ocs_hal.c:9280
static ocs_hal_rtn_e ocs_hal_set_linkcfg_lancer(ocs_hal_t *, ocs_hal_linkcfg_e, uint32_t, ocs_hal_port_control_cb_t, void *)
Set link configuration for Lancer.
Definition: ocs_hal.c:6321
void ocs_hal_wq_process(ocs_hal_t *hal, hal_cq_t *cq, uint8_t *cqe, int32_t status, uint16_t rid)
Process WQ completion queue entries.
Definition: ocs_hal.c:9898
ocs_hal_temp_cb_t cb
Definition: ocs_hal.c:5512
ocs_hal_rtn_e ocs_hal_io_add_dif_sge(ocs_hal_t *hal, ocs_hal_io_t *io, uintptr_t addr)
Add a T10 DIF scatter gather list entry to an IO.
Definition: ocs_hal.c:5283
#define SLI4_SGE_DIF_OP_IN_CHKSUM_OUT_CRC
Definition: sli4.h:586
static int32_t ocs_hal_cb_node_free(ocs_hal_t *, int32_t, uint8_t *, void *)
Definition: ocs_hal.c:10886
static void * __ocs_hal_domain_alloc_read_sparm64(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
Definition: ocs_hal.c:12238
static int32_t __ocs_read_topology_cb(ocs_hal_t *, int32_t, uint8_t *, void *)
Definition: ocs_hal.c:11374
ocs_hal_rtn_e ocs_hal_get(ocs_hal_t *hal, ocs_hal_property_e prop, uint32_t *value)
Definition: ocs_hal.c:1840
POST_XRI - post XRI resources to the SLI Port.
Definition: sli4.h:770
uint32_t dropped_frames_due_to_no_xri_count
Definition: sli4.h:1296
int32_t sli_send_frame_wqe(sli4_t *sli4, void *buf, size_t size, uint8_t sof, uint8_t eof, uint32_t *hdr, ocs_dma_t *payload, uint32_t req_len, uint8_t timeout, uint16_t xri, uint16_t req_tag)
Write a SEND_FRAME work queue entry.
Definition: sli4_fc.c:1724
uint8_t wwn[8]
Definition: ocs_common.h:89
void ocs_hal_qtop_free(ocs_hal_qtop_t *qtop)
free queue topology object
ocs_hal_rtn_e ocs_hal_port_free(ocs_hal_t *hal, ocs_sli_port_t *sport)
Free port resources.
Definition: ocs_hal.c:3172
ocs_array_t * ocs_array_alloc(ocs_os_handle_t os, uint32_t size, uint32_t count)
Allocate an array object.
Definition: ocs_array.c:87
uint8_t * wqebuf
Definition: ocs_hal.h:580
static void ocs_hal_io_restore_sgl(ocs_hal_t *, ocs_hal_io_t *)
Definition: ocs_hal.c:4881
static ocs_hal_rtn_e ocs_hal_config_fec(ocs_hal_t *hal, uint8_t enable)
configure fec (enable/disable) on physical port
Definition: ocs_hal.c:7254
uint32_t disable_app_ffff
Definition: ocs_hal.h:407
static int32_t sli_set_topology(sli4_t *sli4, uint32_t value)
Definition: sli4.h:4008
uint32_t xri_tag1
Definition: sli4.h:798
sli4_mbox_command_header_t hdr
Definition: sli4.h:1254
static uint32_t sli_get_sgl_preregister(sli4_t *sli4)
Definition: sli4.h:3977
#define SLI4_READ_CFG_TOPO_FC_AL
Definition: sli4.h:858
#define SLI4_FCOE_FIP_FCF_DEAD
Definition: sli4_fc.h:1548
#define ocs_queue_history_free(...)
Definition: ocs_debug.h:164
int32_t sli_cmd_fcoe_read_fcf_table(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *dma, uint16_t index)
Write an FCOE_READ_FCF_TABLE command.
Definition: sli4_fc.c:549
static ocs_hal_rtn_e ocs_hal_sli_queue_alloc(ocs_hal_t *hal)
Definition: ocs_hal.c:491
void ocs_array_free(ocs_array_t *array)
Free an array object.
Definition: ocs_array.c:139
ocs_hal_rtn_e ocs_hal_node_attach(ocs_hal_t *hal, ocs_remote_node_t *rnode, ocs_dma_t *sparms)
Update a remote node object with the remote port&#39;s service parameters.
Definition: ocs_hal.c:3433
uint32_t last
Definition: sli4.h:567
static int32_t ocs_hal_mq_process(ocs_hal_t *, int32_t, sli4_queue_t *)
Process entries on the given mailbox queue.
Definition: ocs_hal.c:10476
ocs_hal_rtn_e ocs_hal_set_ptr(ocs_hal_t *hal, ocs_hal_property_e prop, void *value)
Definition: ocs_hal.c:2437
int32_t sli_cmd_read_nvparms(sli4_t *sli4, void *buf, size_t size)
Write a READ_NVPARMS command to the provided buffer.
Definition: sli4.c:982
int32_t sli_dump_is_present(sli4_t *sli4)
Read the SLIPORT_STATUS register to check if a dump is present.
Definition: sli4.c:6216
int32_t(* ocs_hal_done_t)(struct ocs_hal_io_s *, ocs_remote_node_t *, uint32_t len, int32_t status, uint32_t ext, void *ul_arg)
HAL callback type.
Definition: ocs_hal.h:494
static int32_t ocs_hal_cb_node_attach(ocs_hal_t *, int32_t, uint8_t *, void *)
Definition: ocs_hal.c:10863
int ocs_hal_stop_fw_diagnostic_logging(ocs_hal_t *hal)
Stop firmware diagnostic logging (RAS).
Definition: ocs_hal.c:7016
static void * __ocs_hal_port_done(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
Definition: ocs_hal.c:11712
#define OCS_HAL_Q_HASH_SIZE
Definition: ocs_hal.h:138
uint32_t rha
Definition: sli4_fc.h:1602
uint32_t dif_op_tx
Definition: sli4.h:546
Defines a wrapper for the RQ payload buffers so that we can place it back on the proper queue...
Definition: ocs_hal.h:326
static int32_t __ocs_read_fec_cb(ocs_hal_t *, int32_t, uint8_t *, void *)
Definition: ocs_hal.c:11361
static void ocs_hal_generic_mbx_command_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
Definition: ocs_hal.c:6856
ocs_hal_rtn_e ocs_hal_raise_ue(ocs_hal_t *hal, uint8_t dump)
Cause chip to enter an unrecoverable error state.
Definition: ocs_hal.c:8161
static int32_t __ocs_hal_port_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
Definition: ocs_hal.c:11446
static void sli_skh_chain_sge_build(sli4_t *sli4, sli4_sge_t *sge, uint32_t xri_index, uint32_t frag_num, uint32_t offset)
Definition: sli4.h:3774
struct ocs_hal_io_param_t::@19 fc_ct_rsp
ocs_hal_rtn_e ocs_hal_port_alloc(ocs_hal_t *hal, ocs_sli_port_t *sport, ocs_domain_t *domain, uint8_t *wwpn)
Allocate a port object.
Definition: ocs_hal.c:2882
static void ocs_hal_parse_pause_errx_pairs(ocs_hal_t *hal)
Definition: ocs_hal.c:7318
uint32_t buffer_address_low
Definition: sli4.h:516
static void * __ocs_hal_domain_init(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
Definition: ocs_hal.c:12405
int32_t sli_fcp_iread64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl, uint32_t first_data_sge, uint32_t xfer_len, uint16_t xri, uint16_t tag, uint16_t cq_id, uint32_t rpi, ocs_remote_node_t *rnode, uint8_t dif, uint8_t bs, uint8_t timeout)
Write an FCP_IREAD64_WQE work queue entry.
Definition: sli4_fc.c:996
A Profile List.
Definition: ocs_hal.h:299
sli4_abort_type_e
Definition: sli4_fc.h:547
ocs_hal_rtn_e ocs_hal_port_control(ocs_hal_t *hal, ocs_hal_port_e ctrl, uintptr_t value, ocs_hal_port_control_cb_t cb, void *arg)
Control a port (initialize, shutdown, or set link configuration).
Definition: ocs_hal.c:3060
uint32_t receive_f_bsy_count
Definition: sli4.h:1293
ocs_get_nvparms_cb_t cb
Definition: ocs_hal.c:9118
#define OCS_HAL_DMTF_CLP_CMD_MAX
Definition: ocs_hal.c:74
static ocs_hal_rtn_e ocs_hal_config_fw_ag_rsp(ocs_hal_t *hal, uint8_t enable)
Enable/disable firmware path to send auto-good response.
Definition: ocs_hal.c:7293
int32_t ocs_hal_event_check(ocs_hal_t *hal, uint32_t vector)
Check for the events associated with the interrupt vector.
Definition: ocs_hal.c:2480
void ocs_sm_transition(ocs_sm_ctx_t *ctx, ocs_sm_function_t state, void *data)
Transition to a new state.
Definition: ocs_sm.c:72
ocs_hal_t * hal
Definition: ocs_hal.h:785
void * ocs_pool_get_instance(ocs_pool_t *pool, uint32_t idx)
Return item given an index.
Definition: ocs_pool.c:315
int32_t ocs_hal_get_nvparms(ocs_hal_t *hal, ocs_get_nvparms_cb_t cb, void *ul_arg)
Read non-volatile parms.
Definition: ocs_hal.c:9178
static void * __ocs_hal_domain_freed(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
Definition: ocs_hal.c:12471
static ocs_hal_rtn_e ocs_hal_exec_mbx_command_generic_results(ocs_hal_t *hal, uint8_t *req_rsp_buf, bool handle_sli4_rsp, int timeout_usecs)
Issue a blocking hal command that has generic response handling in callback handler.
Definition: ocs_hal.c:6896
#define SLI4_SGE_DIF_OP_IN_CHKSUM_OUT_NODIF
Definition: sli4.h:582
int32_t sli_abort_wqe(sli4_t *sli4, void *buf, size_t size, sli4_abort_type_e type, uint32_t send_abts, uint32_t ids, uint32_t mask, uint16_t tag, uint16_t cq_id)
Write an ABORT_WQE work queue entry.
Definition: sli4_fc.c:682
static uint32_t sli_get_sli_family(sli4_t *sli4)
Definition: sli4.h:3798
static int32_t ocs_hal_set_port_protocol_cb1(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
Called for the completion of set_port_profile for a user request.
Definition: ocs_hal.c:8635
static int32_t target_wqe_timer_nop_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
Definition: ocs_hal.c:12679
uint8_t mrq_policy
Definition: sli4.h:4106
ocs_get_port_protocol_cb_t cb
Definition: ocs_hal.c:8398
static void * __ocs_hal_domain_alloc_init_vfi(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
Definition: ocs_hal.c:12277
int32_t sli_cmd_fcoe_set_loopback_mode(sli4_t *sli4, void *buf, size_t size, int type)
Write a SLI4_OPC_FCOE_SET_LINK_DIAG_LOOPBACK command.
Definition: sli4.c:3126
#define SLI4_SET_FEATURES_SLI_PORT_HEALTH_CHECK
Definition: sli4.h:2750
ocs_sem_t wait_sem
Definition: ocs_hal.h:1273
int32_t sli_cmd_common_get_profile_list(sli4_t *sli4, void *buf, size_t size, uint32_t start_profile_index, ocs_dma_t *dma)
Write a COMMON_COMMON_GET_PROFILE_LIST command.
Definition: sli4.c:3333
#define OCS_STAT(x)
Definition: ocs_stats.h:46
int32_t sli_cmd_common_read_object(sli4_t *sli4, void *buf, size_t size, uint32_t desired_read_length, uint32_t offset, char *object_name, ocs_dma_t *dma)
Write a COMMON_READ_OBJECT command.
Definition: sli4.c:2926
void(* ocs_get_port_protocol_cb_t)(int32_t status, ocs_hal_port_protocol_e port_protocol, void *arg)
Definition: ocs_hal.h:1404
static uint32_t sli_get_vpd_len(sli4_t *sli4)
Definition: sli4.h:3828
uint8_t timeout
Definition: ocs_hal.h:513
uint32_t check_crc
Definition: sli4.h:546
static uint32_t sli_get_max_rsrc(sli4_t *sli4, sli4_resource_e rsrc)
Definition: sli4.h:3714
static ocs_hal_rtn_e ocs_hal_get_linkcfg_skyhawk(ocs_hal_t *, uint32_t, ocs_hal_port_control_cb_t, void *)
Get link configuration for a Skyhawk.
Definition: ocs_hal.c:6620
ocs_hal_fw_cb_t cb
Definition: ocs_hal.c:5501
static void * __ocs_hal_domain_attach_report_fail(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
Definition: ocs_hal.c:12118
static int32_t __ocs_hal_port_cb(ocs_hal_t *, int32_t, uint8_t *, void *)
Definition: ocs_hal.c:11975
static int32_t ocs_hal_get_port_protocol_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
Called for the completion of get_port_profile for a user request.
Definition: ocs_hal.c:8416
static void * __ocs_hal_port_alloc_read_sparm64(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
Definition: ocs_hal.c:11832
static void ocs_hal_queue_hash_add(ocs_queue_hash_t *, uint16_t, uint16_t)
Update the queue hash with the ID and index.
Definition: ocs_hal.c:9537
uint16_t ox_id
Definition: sli4_fc.h:1370
ocs_hal_rtn_e ocs_hal_set_port_protocol(ocs_hal_t *hal, ocs_hal_port_protocol_e new_protocol, uint32_t pci_func, ocs_set_port_protocol_cb_t cb, void *ul_arg)
Set the port protocol.
Definition: ocs_hal.c:8803
void ocs_hal_workaround_setup(struct ocs_hal_s *hal)
Setup HAL runtime workarounds.
uint32_t segment_length
Definition: sli4.h:570
#define SLI4_SET_FEATURES_DIF_MEMORY_MODE
Definition: sli4.h:2743
static void * __ocs_hal_port_free_report_fail(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
Definition: ocs_hal.c:11473
uint8_t * buf
Definition: ocs_hal.h:480
static void ocs_hal_io_free_internal(void *arg)
Free a previously-allocated HAL IO object. Called when IO refcount goes to zero (host-owned IOs only)...
Definition: ocs_hal.c:3970
static char * sli_get_bios_version_string(sli4_t *sli4)
Definition: sli4.h:4040
static ocs_hal_linkcfg_e ocs_hal_linkcfg_from_config_id(const uint32_t config_id)
Helper function for getting the HAL linkcfg enum from a Skyhawk config ID.
Definition: ocs_hal.c:6253
ocs_domain_t * ocs_hal_domain_get(ocs_hal_t *hal, uint16_t fcfi)
Definition: ocs_hal.c:9692
uint32_t sli_fc_ext_status(sli4_t *sli4, uint8_t *cqe)
Definition: sli4_fc.c:2726
static void * __ocs_hal_domain_free_report_fail(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
Definition: ocs_hal.c:12434
WRITE_NVPARMS - write SLI port configuration parameters.
Definition: sli4.h:882
Definition: sli4_fc.h:162
ocs_hal_rtn_e ocs_hal_rqpair_tow_move_to_port(ocs_hal_t *hal, ocs_hal_io_t *io)
Prepares an XRI to move to the chip.
ocs_get_active_profile_cb_t cb
Definition: ocs_hal.c:9006
#define FC_LINK_SPEED_16G
Definition: sli4.h:719
uint32_t auto_incr_ref_tag
Definition: sli4.h:546
static int32_t ocs_hal_get_nvparms_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
Called for the completion of get_nvparms for a user request.
Definition: ocs_hal.c:9134
int32_t sli_cmd_fcoe_post_sgl_pages(sli4_t *sli4, void *buf, size_t size, uint16_t xri, uint32_t xri_count, ocs_dma_t *page0[], ocs_dma_t *page1[], ocs_dma_t *dma)
Write an FCOE_POST_SGL_PAGES command.
Definition: sli4_fc.c:276
int32_t sli_queue_arm(sli4_t *sli4, sli4_queue_t *q, uint8_t arm)
Arm a queue.
Definition: sli4.c:5519
HAL link configuration enum to Skyhawk link config ID mapping.
Definition: ocs_hal.c:6169
void(* ocs_get_nvparms_cb_t)(int32_t status, uint8_t *wwpn, uint8_t *wwnn, uint8_t hard_alpa, uint32_t preferred_d_id, void *arg)
Definition: ocs_hal.h:1418
void ocs_ras_init(uint32_t fw_log_level, uint32_t log_buf_size)
Definition: ocs_ras.c:395
int32_t sli_reset(sli4_t *sli4)
Definition: sli4.c:4611
int32_t sli_cmd_dmtf_exec_clp_cmd(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *cmd, ocs_dma_t *resp)
Write a DMTF_EXEC_CLP_CMD command.
Definition: sli4.c:2985
static void * __ocs_hal_domain_attach_reg_vfi(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
Definition: ocs_hal.c:12159
#define FW_DUMP_TYPE_DUMPTOHOST
Definition: ocs_gendump.h:64
uint8_t wwpn[8]
Definition: sli4.h:870
uint32_t ocs_varray_get_count(ocs_varray_t *va)
Return entry count for a void pointer array.
Definition: ocs_array.c:408
static ocs_hal_rtn_e ocs_hal_set_dif_mode(ocs_hal_t *hal)
Sets the DIF mode value.
Definition: ocs_hal.c:6705
void ocs_hal_cq_process(ocs_hal_t *hal, hal_cq_t *cq, uint32_t cq_process_limit)
Process entries on the given completion queue.
Definition: ocs_hal.c:9783
RELEASE_XRI - Release XRI resources from the SLI Port.
Definition: sli4.h:790
static ocs_hal_rtn_e ocs_hal_config_watchdog_timer(ocs_hal_t *hal)
Set configuration parameters for watchdog timer feature.
Definition: ocs_hal.c:6774
uint32_t cmnd_size
Definition: ocs_hal.h:553
#define SLI4_FCOE_FCF_TABLE_LAST
Definition: sli4_fc.h:357
void ocs_hal_rx_free(ocs_hal_t *hal)
Free the RQ data buffers.
Definition: ocs_hal.c:13231
static void * __ocs_hal_port_alloc_init_vpi(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
Definition: ocs_hal.c:11924
#define FW_FUNC_DESC_DUMP
Definition: ocs_gendump.h:56
static void sli_queue_unlock(sli4_queue_t *q)
Definition: sli4.h:3493
ocs_hal_rtn_e ocs_hal_node_free_resources(ocs_hal_t *hal, ocs_remote_node_t *rnode)
Free a remote node resource.
Definition: ocs_hal.c:3516
#define SLI4_MBOX_STATUS_RPI_NOT_REG
Definition: sli4.h:461
#define SLI4_PROTOCOL_ISCSI
Definition: sli4.h:2930
const char * queue_topology_string
Definition: ocs_hal.h:1267
FCOE_READ_FCF_TABLE response.
Definition: sli4_fc.h:344
#define SLI4_READ_SPARM64_WWNN_OFFSET
Definition: sli4.h:960
static void ocs_hal_queue_hash_free(ocs_hal_t *hal)
Definition: ocs_hal.c:543
uint16_t rx_id
Definition: sli4_fc.h:1371
static uint32_t sli_get_dpp_capable(sli4_t *sli4)
Definition: sli4.h:3946
sli4_res_hdr_t hdr
Definition: sli4.h:2159
int ocs_sm_post_event(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
Post an event to a context.
Definition: ocs_sm.c:58
uint32_t send_abts
Definition: ocs_hal.h:573
ocs_hal_rtn_e ocs_hal_get_temperature(ocs_hal_t *hal, ocs_hal_temp_cb_t cb, void *arg)
Function to retrieve the temperature information.
Definition: ocs_hal.c:5814
void * ocs_varray_iter_next(ocs_varray_t *va)
Return next entry from a void pointer array.
Definition: ocs_array.c:333
ocs_hal_rtn_e ocs_hal_set(ocs_hal_t *hal, ocs_hal_property_e prop, uint32_t value)
Definition: ocs_hal.c:2214
#define SLI4_SET_FEATURES_SET_FTD_XFER_HINT
Definition: sli4.h:2749
static void ocs_hal_io_quarantine(ocs_hal_t *hal, hal_wq_t *wq, ocs_hal_io_t *io)
Quaratine an IO by taking a reference count and adding it to the quarantine list. When the IO is popp...
Definition: ocs_hal.c:9742
ocs_hal_rtn_e ocs_hal_rx_allocate(ocs_hal_t *hal)
Allocate the RQ data buffers.
Definition: ocs_hal.c:13129
int ocs_ras_free_resc(ocs_os_handle_t *ocs_os)
Definition: ocs_ras.c:315
static void hal_wq_submit_pending(hal_wq_t *wq, uint32_t update_free_count)
Update free count and submit any pending HAL IOs.
Definition: ocs_hal.c:4141
ocs_hal_rtn_e ocs_hal_io_send(ocs_hal_t *hal, ocs_hal_io_type_e type, ocs_hal_io_t *io, uint32_t len, ocs_hal_io_param_t *iparam, ocs_remote_node_t *rnode, void *cb, void *arg)
Send a read, write, or response IO.
Definition: ocs_hal.c:4507
ocs_hal_io_t * quarantine_ios[OCS_HAL_QUARANTINE_QUEUE_DEPTH]
Definition: ocs_hal.h:882
int32_t sli_fcp_icmnd64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl, uint16_t xri, uint16_t tag, uint16_t cq_id, uint32_t rpi, ocs_remote_node_t *rnode, uint8_t timeout)
Write an FCP_ICMND64_WQE work queue entry.
Definition: sli4_fc.c:915
static void ocs_list_add_tail(ocs_list_t *list, void *item)
Add an item to the tail of the list.
Definition: ocs_list.h:263
#define OCS_HAL_MAX_NUM_CQ
Definition: ocs_hal.h:132
int32_t sli_cmd_common_get_profile_config(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *dma)
Write a COMMON_COMMON_GET_PROFILE_CONFIG command.
Definition: sli4.c:3243
static ocs_hal_rtn_e ocs_hal_init_tow_esoc(ocs_hal_t *hal, uint32_t tow_feature)
Definition: ocs_hal.c:177
ocs_hal_rtn_e ocs_hal_node_group_free(ocs_hal_t *hal, ocs_remote_node_group_t *ngroup)
Definition: ocs_hal.c:3743
Description of discovered Fabric Domain.
Definition: ocs_common.h:85
static void * __ocs_hal_domain_alloc_reg_fcfi(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
Definition: ocs_hal.c:12315
static ocs_hal_rtn_e ocs_hal_alloc_set_dump_buffers(ocs_hal_t *hal, uint8_t dump_level)
Definition: ocs_hal.c:7674
int32_t sli_els_request64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl, uint8_t req_type, uint32_t req_len, uint32_t max_rsp_len, uint8_t timeout, uint16_t xri, uint16_t tag, uint16_t cq_id, ocs_remote_node_t *rnode)
Write an ELS_REQUEST64_WQE work queue entry.
Definition: sli4_fc.c:744
uint32_t auto_incr_ref_tag
Definition: ocs_hal.h:407
void ocs_hal_unsol_process_bounce(void *arg)
Definition: ocs_hal.c:2518
sli4_port_state_t link_current
Definition: sli4.h:996
uint32_t ref_tag_cmp
Definition: ocs_hal.h:403
Callback argument structure for the DMTF CLP commands.
Definition: ocs_hal.c:7907
#define FW_CHIP_LEVEL_DUMP
Definition: ocs_gendump.h:55
static const char * ocs_hal_clp_from_linkcfg(ocs_hal_linkcfg_e linkcfg)
Helper function for getting the CLP string value from the HAL linkcfg enum.
Definition: ocs_hal.c:6212
ocs_hal_dif_oper_e dif_oper
Definition: ocs_hal.h:401
uint32_t ocs_hal_xri_move_to_port_owned(ocs_hal_t *hal, uint32_t num_xri)
Move XRIs from the host-controlled pool to the port.
Definition: ocs_hal.c:12921
void(* ocs_hal_port_control_cb_t)(int32_t status, uintptr_t value, void *arg)
Definition: ocs_hal.h:1314
int32_t ocs_hal_get_active_profile(ocs_hal_t *hal, ocs_get_active_profile_cb_t cb, void *ul_arg)
Get the currently active profile.
Definition: ocs_hal.c:9077
static ocs_hal_rtn_e ocs_hal_link_event_init(ocs_hal_t *hal)
Definition: ocs_hal.c:390
uint32_t uint32_t iscsi_dif
Definition: sli4.h:2969
#define ocs_list_remove_head(list)
Remove and return an item from the head of the list.
Definition: ocs_list.h:374
static uint16_t sli_get_link_module_type(sli4_t *sli4)
Definition: sli4.h:4028
int32_t sli_cmd_config_auto_xfer_rdy_hp(sli4_t *sli4, void *buf, size_t size, uint32_t max_burst_len, uint32_t block_size)
Write an CONFIG_AUTO_XFER_RDY_HP command to the provided buffer.
Definition: sli4.c:1778
ocs_hal_io_t * ocs_hal_io_activate_port_owned(ocs_hal_t *hal, ocs_hal_io_t *io)
Allocate/Activate a port owned HAL IO object.
Definition: ocs_hal.c:3867
int32_t ocs_hal_set_active_profile(ocs_hal_t *hal, ocs_set_active_profile_cb_t cb, uint32_t profile_id, void *ul_arg)
Set the currently active profile.
Definition: ocs_hal.c:9484
uint32_t quarantine_index
Definition: ocs_hal.h:881
int32_t sli_reset_required(sli4_t *sli4)
Read the SLIPORT_STATUS register to check if the reset required is set.
Definition: sli4.c:6253
ocs_hal_rtn_e ocs_hal_domain_free(ocs_hal_t *hal, ocs_domain_t *domain)
Free a fabric domain object.
Definition: ocs_hal.c:3324
ocs_hal_rtn_e ocs_hal_rx_post(ocs_hal_t *hal)
Post the RQ data buffers to the chip.
Definition: ocs_hal.c:13186
uint32_t sli_reg_read(sli4_t *sli, sli4_regname_e reg)
Read the given SLI register.
Definition: sli4.c:240
static void ocs_list_add_head(ocs_list_t *list, void *item)
Add an item to the head of the list.
Definition: ocs_list.h:235
uint32_t sli_fc_response_length(sli4_t *sli4, uint8_t *cqe)
Return the ELS/CT response length.
Definition: sli4_fc.c:2676
int32_t sli_cmd_common_delete_object(sli4_t *sli4, void *buf, size_t size, char *object_name)
Write a COMMON_DELETE_OBJECT command.
Definition: sli4.c:2887
static void ocs_hal_sli_queue_free(ocs_hal_t *hal)
Definition: ocs_hal.c:460
uint32_t offset
Definition: ocs_hal.h:538
ocs_set_nvparms_cb_t cb
Definition: ocs_hal.c:9214
uint32_t opcode
Definition: sli4.h:1685
uint32_t buffer_address_low
Definition: sli4.h:500
#define SLI4_SGE_TYPE_DATA
Definition: sli4.h:589
#define SLI4_SET_FEATURES_SET_CONFIG_TOW_T10PI
Definition: sli4.h:2747
static int32_t ocs_hal_cb_link_stat(ocs_hal_t *, int32_t, uint8_t *, void *)
Called when the READ_LINK_STAT command completes.
Definition: ocs_hal.c:5964
#define SLI4_IF_TYPE_LANCER_G7
Definition: sli4.h:117
#define SLI4_SGE_DIF_OP_IN_RAW_OUT_RAW
Definition: sli4.h:587
uint8_t type_match
Definition: sli4.h:4100
static uint32_t sli_get_is_sgl_chaining_capable(sli4_t *sli4)
Definition: sli4.h:3909
#define SLI4_READ_TOPOLOGY_SPEED_8G
Definition: sli4.h:1033
READ_TOPOLOGY - read the link event information.
Definition: sli4.h:979
#define FC_LINK_SPEED_10G
Definition: sli4.h:718
uint32_t index
Definition: ocs_hal.h:870
static void ocs_hal_dmtf_clp_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
Called when the DMTF CLP command completes.
Definition: ocs_hal.c:8029
#define OCS_HAL_TOW_APP_TAG_VALUE_DEFAULT
Definition: ocs_hal.c:64
ocs_hal_rtn_e ocs_hal_get_trunk_info(ocs_hal_t *hal, uint32_t *trunk_info)
Get trunking mode information.
Definition: ocs_hal.c:6987
static ocs_hal_rtn_e ocs_hal_set_dif_seed(ocs_hal_t *hal)
Sets the DIF seed value.
Definition: ocs_hal.c:6676
static int32_t ocs_hal_clp_resp_get_value(ocs_hal_t *hal, const char *keyword, char *value, uint32_t value_len, const char *resp, uint32_t resp_len)
Parse the CLP result and get the value corresponding to the given keyword.
Definition: ocs_hal.c:8104
struct ocs_hal_io_param_t::@15 bcast
uint32_t resp_data[59]
Definition: sli4.h:640
uint32_t check_app_tag
Definition: ocs_hal.h:407
#define SLI4_SGE_TYPE_LSP
Definition: sli4.h:592
uint32_t xb
Definition: sli4_fc.h:1602
static int32_t ocs_hal_cb_port_control(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
Called when the port control command completes.
Definition: ocs_hal.c:3011
#define SLI4_SGE_DIF_OP_IN_NODIF_OUT_CHKSUM
Definition: sli4.h:581
#define SLI4_SGE_MAX_RESERVED
Definition: sli4.h:577
int32_t ocs_hal_process(ocs_hal_t *hal, uint32_t vector, uint32_t max_isr_time_msec)
Definition: ocs_hal.c:2530
uint32_t abort_wqe_submit_needed
Definition: ocs_hal.h:573
uint32_t app_tag_cmp
Definition: sli4.h:546
ocs_hal_rtn_e ocs_hal_reqtag_init(ocs_hal_t *hal)
Initialize the reqtag pool.
Definition: ocs_hal.c:13355
uint32_t buffer_address_low
Definition: sli4.h:566
uint32_t acquired_al_pa
Definition: sli4.h:1006
ocs_hal_port_e
Definition: ocs_hal.h:655
void sli4_cmd_lowlevel_disable_ras(sli4_t *sli4, void *buf, size_t size)
Write a LOWLEVEL_SET_DIAG_LOG_OPTIONS command.
Definition: sli4.c:2389
static void * __ocs_hal_port_alloc_report_fail(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
Definition: ocs_hal.c:11794
uint8_t fc
Definition: sli4_fc.h:328
ocs_hal_qtop_t * ocs_hal_qtop_parse(ocs_hal_t *hal, const char *qtop_string)
Parse queue topology string.
int32_t sli_fw_reset(sli4_t *sli4)
Issue a Firmware Reset.
Definition: sli4.c:4658
static int32_t ocs_hal_set_nvparms_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
Called for the completion of set_nvparms for a user request.
Definition: ocs_hal.c:9230
int32_t sli_cmd_reg_vfi(sli4_t *sli4, void *buf, size_t size, ocs_domain_t *domain)
Write a REG_VFI command to the provided buffer.
Definition: sli4.c:1353
Defines a general FC sequence object, consisting of a header, payload buffers and a HAL IO in the cas...
Definition: ocs_hal.h:784
static char * sli_get_ipl_name(sli4_t *sli4)
Definition: sli4.h:3846
#define OCS_MIN_FW_VER_SKYHAWK
uint8_t cmd_buf[SLI4_BMBX_SIZE]
Definition: ocs_hal.h:1276
int32_t ocs_hal_eq_process(ocs_hal_t *hal, hal_eq_t *eq, uint32_t max_isr_time_msec)
Process events associated with an EQ.
Definition: ocs_hal.c:2588
#define SLI4_IO_AUTO_GOOD_RESPONSE
Definition: sli4_fc.h:1000
static void ocs_hal_rx_buffer_free(ocs_hal_t *hal, ocs_hal_rq_buffer_t **rq_buf, uint32_t count)
Free an ocs_hal_rx_buffer_t array.
Definition: ocs_hal.c:13056
static ocs_hal_rtn_e ocs_hal_config_axr_t10pi(ocs_hal_t *hal)
Set configuration parameters for AXR T10 PI feature.
Definition: ocs_hal.c:7165
sli_bls_type_e type
Definition: sli4_fc.h:1369
ocs_hal_rtn_e ocs_hal_node_group_alloc(ocs_hal_t *hal, ocs_remote_node_group_t *ngroup)
Definition: ocs_hal.c:3694
#define SLI4_CMD_REG_FCFI_SET_FCFI_MODE
Definition: sli4.h:1065
ocs_hal_sfp_cb_t cb
Definition: ocs_hal.c:5506
uint8_t fcp_data_ro[4]
Definition: ocs_fcp.h:917
uint32_t released_xri_count
Definition: sli4.h:793
uint32_t uint32_t topology
Definition: sli4.h:983
int32_t sli_cmd_common_get_reconfig_link_info(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *dma)
Write a COMMON_GET_RECONFIG_LINK_INFO command.
Definition: sli4.c:3458
HAL IO object.
Definition: ocs_hal.h:589
#define SLI4_FC_LOCAL_REJECT_INVALID_RPI
Definition: sli4_fc.h:1682
struct ocs_hal_io_param_t::@21 fcp_ini
uint32_t struct sli4_cmd_release_xri_t::@31 xri_tbl[62]
int32_t sli_cmd_unreg_vpi(sli4_t *sli4, void *buf, size_t size, uint16_t indicator, uint32_t which)
Write an UNREG_VPI command to the provided buffer.
Definition: sli4.c:1701
static void * __ocs_hal_port_allocated(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
Definition: ocs_hal.c:11740
uint32_t check_ref_tag
Definition: sli4.h:546
int32_t sli_cmd_common_set_active_profile(sli4_t *sli4, void *buf, size_t size, uint32_t fd, uint32_t active_profile_id)
Write a COMMON_COMMON_SET_ACTIVE_PROFILE command.
Definition: sli4.c:3416
static void ocs_hal_io_free_port_owned(void *arg)
Free a HAL IO object associated with a port-owned XRI.
Definition: ocs_hal.c:3941
uint32_t ocs_hal_io_get_count(ocs_hal_t *hal, ocs_hal_io_count_type_e io_count_type)
Called to obtain the count for the specified type.
Definition: ocs_hal.c:9325
#define ocs_hal_assert(cond)
Definition: ocs_hal.h:82
int32_t sli_cmd_common_get_active_profile(sli4_t *sli4, void *buf, size_t size)
Write a COMMON_COMMON_GET_ACTIVE_PROFILE command.
Definition: sli4.c:3376
#define SLI4_IF_TYPE_BE3_SKH_PF
Definition: sli4.h:113
uint32_t wqec
Definition: sli4_fc.h:476
ocs_hal_rtn_e ocs_hal_io_init_sges(ocs_hal_t *hal, ocs_hal_io_t *io, ocs_hal_io_type_e type)
Initialize the scatter gather list entries of an IO.
Definition: ocs_hal.c:4917
static int32_t sli_set_hlm(sli4_t *sli4, uint32_t value)
Definition: sli4.h:3927
int32_t sli_cmd_release_xri(sli4_t *sli4, void *buf, size_t size, uint8_t num_xri)
Write a RELEASE_XRI command to the provided buffer.
Definition: sli4.c:939
static ocs_hal_rtn_e ocs_hal_config_fw_diagnostic_logging(ocs_hal_t *hal, int32_t log_size, int32_t log_level)
Set configuration parameters for adapter firmware diagnostic logging (RAS) feature.
Definition: ocs_hal.c:7063
void(* ocs_hal_sfp_cb_t)(void *, int32_t, uint32_t, uint32_t *, void *)
Definition: ocs_hal.h:1356
union sli_bls_payload_t::@52 u
int32_t ocs_hal_rqpair_tow_data_process(ocs_hal_t *hal, hal_cq_t *cq, uint8_t *cqe)
Process CQ completions for Auto xfer rdy data phases.
static void * __ocs_hal_domain_alloc_report_fail(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
Definition: ocs_hal.c:12047
uint32_t uint32_t status
Definition: sli4.h:1685
int32_t sli_cmd_read_config(sli4_t *sli4, void *buf, size_t size)
Write a READ_CONFIG command to the provided buffer.
Definition: sli4.c:961
uint32_t last
Definition: sli4.h:501
uint8_t vlan_bitmap[512]
Definition: sli4_fc.h:334
uint32_t receive_p_bsy_count
Definition: sli4.h:1292
int32_t ocs_get_bus_dev_func(ocs_t *ocs, uint8_t *bus, uint8_t *dev, uint8_t *func)
static void ocs_hal_async_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
HAL async callback handler.
Definition: ocs_hal.c:13275
#define SLI4_IO_CONTINUATION
Definition: sli4_fc.h:999
int32_t ocs_hal_rqpair_tow_cmd_process(ocs_hal_t *hal, hal_cq_t *cq, uint8_t *cqe)
Process receive queue completions for RQ Pair mode - Auto xfer rdy.
int32_t sli_gen_request64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl, uint32_t req_len, uint32_t max_rsp_len, uint8_t timeout, uint16_t xri, uint16_t tag, uint16_t cq_id, ocs_remote_node_t *rnode, uint8_t r_ctl, uint8_t type, uint8_t df_ctl)
Write a GEN_REQUEST64 work queue entry.
Definition: sli4_fc.c:1633
uint32_t check_ref_tag
Definition: ocs_hal.h:407
uint32_t is_ethernet
Definition: ocs_common.h:96
static uint32_t sli_get_dif_capable(sli4_t *sli4)
Definition: sli4.h:3885
uint32_t buffer_address_high
Definition: sli4.h:499
#define OCS_HAL_TOW_REF_TAG_LBA_DEFAULT
Definition: ocs_hal.c:62
static void target_wqe_timer_cb(void *arg)
Definition: ocs_hal.c:12735
ocs_get_profile_list_cb_t cb
Definition: ocs_hal.c:8857
uint32_t buffer_address_high
Definition: sli4.h:515
int32_t ocs_hal_async_call(ocs_hal_t *hal, ocs_hal_async_cb_t callback, void *arg)
Make an async callback using NOP mailbox command.
Definition: ocs_hal.c:13316
ocs_hal_remote_node_event_e
Definition: ocs_hal.h:685
List Segment Pointer Scatter-Gather Entry (SGE)
Definition: sli4.h:563
#define OCS_HAL_FDT_XFER_HINT
static void ocs_hal_wq_process_io(void *arg, uint8_t *cqe, int32_t status)
Process WQ completions for IO requests.
Definition: ocs_hal.c:9933
ocs_hal_host_stat_cb_t cb
Definition: ocs_hal.c:5522
#define SLI4_MAX_FCFI
Maximum value for a FCFI.
Definition: sli4_fc.h:52
int32_t sli_xmit_bls_rsp64_wqe(sli4_t *sli4, void *buf, size_t size, sli_bls_payload_t *payload, uint16_t xri, uint16_t tag, uint16_t cq_id, ocs_remote_node_t *rnode, uint32_t s_id)
Write an XMIT_BLS_RSP64_WQE work queue entry.
Definition: sli4_fc.c:1973
int32_t sli_bmbx_command(sli4_t *sli4)
Submit a command to the bootstrap mailbox and check the status.
Definition: sli4.c:493
struct ocs_hal_io_param_t::@17 els_sid
ocs_hal_linkcfg_e linkcfg
Definition: ocs_hal.c:6170
static ocs_hal_rtn_e ocs_hal_firmware_write_lancer(ocs_hal_t *hal, ocs_dma_t *dma, uint32_t size, uint32_t offset, int last, ocs_hal_fw_cb_t cb, void *arg)
Write a portion of a firmware image to the Emulex XE201 ASIC (Lancer).
Definition: ocs_hal.c:5602
#define OCS_HAL_QUARANTINE_QUEUE_DEPTH
Define the fields required to implement the skyhawk DIF quarantine.
Definition: ocs_hal.h:878
ocs_set_active_profile_cb_t cb
Definition: ocs_hal.c:9417
uint32_t receive_sequence_count
Definition: sli4.h:1289
static void * __ocs_hal_domain_attached(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
Definition: ocs_hal.c:12086
static ocs_hal_rtn_e ocs_hal_setup_io(ocs_hal_t *)
Initialize the pool of HAL IO objects.
Definition: ocs_hal.c:10973
int32_t ocs_get_property(const char *prop_name, char *buffer, uint32_t buffer_len)
get driver wide property value
static void ocs_hal_init_linkcfg_cb(int32_t status, uintptr_t value, void *arg)
Callback function for getting linkcfg during HAL initialization.
Definition: ocs_hal.c:1422
int32_t sli_cmd_unreg_vfi(sli4_t *sli4, void *buf, size_t size, ocs_domain_t *domain, uint32_t which)
Write an UNREG_VFI command to the provided buffer.
Definition: sli4.c:1656
ocs_hal_rtn_e ocs_hal_setup(ocs_hal_t *hal, ocs_os_handle_t os, sli4_port_type_e port_type)
Set up the Hardware Abstraction Layer module.
Definition: ocs_hal.c:606
ocs_hal_io_count_type_e
Definition: ocs_hal.h:1112
int32_t sli_cmd_dump_type4(sli4_t *sli4, void *buf, size_t size, uint16_t wki)
Write a DUMP Type 4 command to the provided buffer.
Definition: sli4.c:602
static int32_t ocs_hal_get_active_profile_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
Called for the completion of get_active_profile for a user request.
Definition: ocs_hal.c:9022
int32_t sli_cmd_init_vpi(sli4_t *sli4, void *buf, size_t size, uint16_t vpi, uint16_t vfi)
Write an INIT_VPI command to the provided buffer.
Definition: sli4.c:883
#define ocs_assert(cond,...)
Definition: ocs_debug.h:176
int32_t sli_callback(sli4_t *sli4, sli4_callback_e which, void *func, void *arg)
Register a callback for the given event.
Definition: sli4.c:4786
int32_t sli_fcp_tsend64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl, uint32_t first_data_sge, uint32_t relative_off, uint32_t xfer_len, uint16_t xri, uint16_t tag, uint16_t cq_id, uint16_t xid, uint32_t rpi, ocs_remote_node_t *rnode, uint32_t flags, uint8_t dif, uint8_t bs, uint8_t csctl, uint32_t app_id)
Write an FCP_TSEND64_WQE work queue entry.
Definition: sli4_fc.c:1500
#define SLI4_READ_TOPOLOGY_LINK_NO_ALPA
Definition: sli4.h:1023
int32_t sli_fcp_iwrite64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl, uint32_t first_data_sge, uint32_t xfer_len, uint32_t first_burst, uint16_t xri, uint16_t tag, uint16_t cq_id, uint32_t rpi, ocs_remote_node_t *rnode, uint8_t dif, uint8_t bs, uint8_t timeout)
Write an FCP_IWRITE64_WQE work queue entry.
Definition: sli4_fc.c:1098
uint8_t embed[58 *sizeof(uint32_t)]
Definition: sli4.h:1265
uint32_t last
Definition: sli4.h:517
#define OCS_TARGET_READ_SKIPS
Scatter-Gather Entry (SGE)
Definition: sli4.h:497
ocs_hal_rtn_e ocs_hal_run_biu_diag(ocs_hal_t *hal, void *tx_buff, size_t tx_buff_len, void *rx_buff, size_t rx_buff_len)
Run Diagnostic PCI Loopback test.
Definition: ocs_hal.c:7801
uint8_t rsvd[4]
Definition: ocs_fcp.h:919
uint32_t sli4_parity_err_count_t counter[SLI4_MAX_ULP]
Definition: sli4.h:3211
void sli4_cmd_lowlevel_enable_ras(sli4_t *sli4, void *buf, size_t size, int log_level, uint32_t unit_size, int32_t buf_count, uint32_t *phys_addr, uintptr_t lwpd_phys_addr)
Write a LOWLEVEL_SET_DIAG_LOG_OPTIONS command.
Definition: sli4.c:2339
int32_t sli_cmd_common_set_profile_config(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *dma, uint8_t profile_id, uint32_t descriptor_count, uint8_t isap)
Write a COMMON_COMMON_SET_PROFILE_CONFIG command.
Definition: sli4.c:3287
static void * __ocs_hal_port_free_unreg_vpi(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
Definition: ocs_hal.c:11567
static int32_t ocs_hal_cb_fw_write(ocs_hal_t *, int32_t, uint8_t *, void *)
Called when the WRITE OBJECT command completes.
Definition: ocs_hal.c:5659
#define SLI4_SET_FEATURES_DIF_SEED
COMMON_SET_SET_FEATURES.
Definition: sli4.h:2737
uint8_t fcf_mac_address[6]
Definition: sli4_fc.h:323
static void * __ocs_hal_port_attached(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
Definition: ocs_hal.c:11641
int32_t sli_cmd_config_run_biu_diag(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *tx_buffer, size_t tx_buf_len, ocs_dma_t *rx_buffer, size_t rx_buf_len)
Write a RUN_BIU_DIAG command.
Definition: sli4.c:3084
struct ocs_hal_io_param_t::@16 els
static int32_t ocs_hal_cb_link(void *, void *)
Callback function for the SLI link events.
Definition: ocs_hal.c:10696
#define SLI4_FC_LOCAL_REJECT_RPI_SUSPENDED
Definition: sli4_fc.h:1687
static uint32_t sli_get_if_type(sli4_t *sli4)
Definition: sli4.h:3804
int32_t sli_cmd_init_vfi(sli4_t *sli4, void *buf, size_t size, uint16_t vfi, uint16_t fcfi, uint16_t vpi)
Write an INIT_VFI command to the provided buffer.
Definition: sli4.c:846
static uint32_t fc_be24toh(uint32_t x)
Definition: ocs_fcp.h:143
ocs_hal_rtn_e ocs_hal_command(ocs_hal_t *hal, uint8_t *cmd, uint32_t opts, void *cb, void *arg)
Issue a SLI command.
Definition: ocs_hal.c:2731
ocs_hal_rtn_e ocs_hal_clear_dump_location(ocs_hal_t *hal)
Clear the Lancer dump location.
Definition: ocs_hal.c:7980
#define FC_LINK_SPEED_4G
Definition: sli4.h:707
static ocs_hal_rtn_e ocs_hal_set_linkcfg_skyhawk(ocs_hal_t *, ocs_hal_linkcfg_e, uint32_t, ocs_hal_port_control_cb_t, void *)
Set link configuration for a Skyhawk.
Definition: ocs_hal.c:6421
uint8_t sol
Definition: sli4_fc.h:328
sli4_mbox_command_header_t hdr
Definition: sli4.h:814
void(* ocs_hal_link_stat_cb_t)(int32_t status, uint32_t num_counters, ocs_hal_link_stat_counts_t *counters, void *arg)
Definition: ocs_hal.h:1375
static void ocs_hal_add_io_timed_wqe(ocs_hal_t *hal, ocs_hal_io_t *io)
Definition: ocs_hal.c:298
#define SLI4_SGE_TYPE_SKIP
Definition: sli4.h:598
#define FW_DUMP_STATE_NONE
Definition: ocs_gendump.h:59
static uint32_t sli_get_is_dual_ulp_capable(sli4_t *sli4)
Definition: sli4.h:3903
uint32_t total_exchanges_responder
Definition: sli4.h:1291
void * ocs_hal_get_ptr(ocs_hal_t *hal, ocs_hal_property_e prop)
Definition: ocs_hal.c:2175
uint32_t link_speed
Definition: sli4.h:964
uint32_t new_ref_tag
Definition: sli4.h:546
int32_t(* ocs_hal_async_cb_t)(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
Definition: ocs_hal.h:1500
int32_t sli_cmd_unreg_fcfi(sli4_t *sli4, void *buf, size_t size, uint16_t indicator)
Write a UNREG_FCFI command to the provided buffer.
Definition: sli4.c:1570
#define SLI4_READ_TOPOLOGY_NPORT
Definition: sli4.h:1026
static ocs_hal_rtn_e ocs_hal_get_linkcfg(ocs_hal_t *, uint32_t, ocs_hal_port_control_cb_t, void *)
Get link configuration.
Definition: ocs_hal.c:6478
ocs_sm_event_t
Definition: ocs_sm.h:60
int32_t sli_cmd_config_link(sli4_t *sli4, void *buf, size_t size)
Write a CONFIG_LINK command to the provided buffer.
Definition: sli4.c:546
static ocs_hal_rq_buffer_t ** ocs_hal_rx_buffer_alloc(ocs_hal_t *hal, uint32_t rqindex, uint32_t count, uint32_t size)
Allocate an ocs_hal_rx_buffer_t array.
Definition: ocs_hal.c:13086
#define SLI4_PROTOCOL_DEFAULT
Definition: sli4.h:2934
uint8_t loop[128]
Definition: ocs_common.h:92
#define SLI4_MAX_FCF_INDEX
Maximum value for FCF index.
Definition: sli4_fc.h:61
#define SLI4_FC_LOCAL_REJECT_LINK_DOWN
Definition: sli4_fc.h:1700
#define SLI4_IO_SUPPRESS_RESPONSE
Definition: sli4_fc.h:1003
sli4_mbox_command_header_t hdr
Definition: sli4.h:1279
uint32_t s_id
Definition: ocs_fcp.h:161
#define ocs_list_foreach(list, item)
Iterate a linked list.
Definition: ocs_list.h:428
static uint32_t ocs_hal_config_id_from_linkcfg(ocs_hal_linkcfg_e linkcfg)
Helper function for getting a Skyhawk link config ID from the HAL linkcfg enum.
Definition: ocs_hal.c:6233
static int32_t __ocs_hal_domain_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *data)
Definition: ocs_hal.c:12026
int32_t ocs_hal_io_cancel(ocs_hal_t *hal)
Definition: ocs_hal.c:11262
void ocs_hal_rqpair_teardown(ocs_hal_t *hal)
Tear down the rq_pair function from ocs_hal_teardown().
Generic Command Response header.
Definition: sli4.h:1683
void(* callback)(void *arg, uint8_t *cqe, int32_t status)
Definition: ocs_hal.h:890
ocs_dma_t * cmnd
Definition: ocs_hal.h:549
ocs_hal_dif_blk_size_e blk_size
Definition: ocs_hal.h:402
uint32_t transmit_sequence_count
Definition: sli4.h:1288
static int32_t ocs_hal_domain_add(ocs_hal_t *, ocs_domain_t *)
Definition: ocs_hal.c:9587
void(* ocs_hal_dmtf_clp_cb_t)(ocs_hal_t *hal, int32_t status, uint32_t result_len, void *arg)
Definition: ocs_hal.c:105
void * ocs_array_get(ocs_array_t *array, uint32_t idx)
Return reference to an element of an array object.
Definition: ocs_array.c:166
int32_t(* ocs_hal_srrs_cb_t)(ocs_hal_io_t *io, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *arg)
Definition: ocs_hal.h:1334
static int32_t ocs_hal_set_port_protocol_cb2(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
Called for the completion of set_port_profile for a user request.
Definition: ocs_hal.c:8577
struct sli_bls_payload_t::@52::@54 rjt
static void ocs_hal_io_free_common(ocs_hal_t *hal, ocs_hal_io_t *io)
Free a HAL IO object. Perform cleanup common to port and host-owned IOs.
Definition: ocs_hal.c:3925
uint32_t app_tag_repl
Definition: ocs_hal.h:405
ocs_dma_t payload
Definition: ocs_hal.c:5508
#define OCS_HAL_SEND_FRAME_TIMEOUT
#define SLI4_READ_SPARM64_WWPN_OFFSET
Definition: sli4.h:959
uint32_t preferred_d_id
Definition: sli4.h:872
#define OCS_TARGET_WRITE_SKIPS
uint8_t vlan[512]
Definition: ocs_common.h:91
sli4_res_hdr_t hdr
Definition: sli4.h:2616
static void * __ocs_hal_domain_free_unreg_vfi(ocs_sm_ctx_t *, ocs_sm_event_t, void *)
Definition: ocs_hal.c:12604
uint32_t check_guard
Definition: ocs_hal.h:407
int32_t sli_cmd_read_topology(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *dma)
Write a READ_TOPOLOGY command to the provided buffer.
Definition: sli4.c:1108
int32_t ocs_ras_allocate_resc(ocs_os_handle_t *ocs_os)
Definition: ocs_ras.c:343
uint32_t disable_app_ref_ffff
Definition: ocs_hal.h:407
static int32_t ocs_hal_cb_unreg_rpi_all(ocs_hal_t *, int32_t, uint8_t *, void *)
Definition: ocs_hal.c:10931
int32_t _sli_queue_write(sli4_t *sli4, sli4_queue_t *q, uint8_t *entry)
Write an entry to the queue object.
Definition: sli4.c:5565
int32_t sli_fcp_cont_treceive64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl, uint32_t first_data_sge, uint32_t relative_off, uint32_t xfer_len, uint16_t xri, uint16_t sec_xri, uint16_t tag, uint16_t cq_id, uint16_t xid, uint32_t rpi, ocs_remote_node_t *rnode, uint32_t flags, uint8_t dif, uint8_t bs, uint8_t csctl, uint32_t app_id, uint8_t timer)
Write an FCP_CONT_TRECEIVE64_WQE work queue entry.
Definition: sli4_fc.c:1357
static void * sli_get_vpd(sli4_t *sli4)
Definition: sli4.h:3822
int32_t sli_fcp_trsp64_wqe(sli4_t *sli4, void *buf, size_t size, ocs_dma_t *sgl, uint32_t rsp_len, uint16_t xri, uint16_t tag, uint16_t cq_id, uint16_t xid, uint32_t rpi, ocs_remote_node_t *rnode, uint32_t flags, uint8_t csctl, uint8_t port_owned, uint32_t app_id)
Write an FCP_TRSP64_WQE work queue entry.
Definition: sli4_fc.c:1400
uint32_t transmit_kbyte_count
Definition: sli4.h:1284
static ocs_hal_rtn_e ocs_hal_io_overflow_sgl(ocs_hal_t *hal, ocs_hal_io_t *io)
Definition: ocs_hal.c:5131
static ocs_hal_linkcfg_map_t linkcfg_map[]
Mapping from the HAL linkcfg enum to the CLP command value string.
Definition: ocs_hal.c:6153
#define SLI4_SGE_DIF_OP_IN_CRC_OUT_CHKSUM
Definition: sli4.h:585
static uint32_t ocs_hal_get_num_chutes(ocs_hal_t *hal)
Determine the number of chutes on the device.
Definition: ocs_hal.c:377
static void ocs_hal_log_sli4_rsp_hdr(ocs_hal_t *hal, sli4_res_hdr_t *hdr)
Definition: ocs_hal.c:169
static uint32_t sli_get_portnum(sli4_t *sli4)
Definition: sli4.h:4034
uint32_t fcf_index
Definition: sli4_fc.h:332
int32_t sli_init(sli4_t *sli4)
Definition: sli4.c:4590
uint8_t wqe_timer
Definition: ocs_hal.h:546
int32_t sli_cmd_reg_rpi(sli4_t *sli4, void *buf, size_t size, uint32_t nport_id, uint16_t rpi, uint16_t vpi, ocs_dma_t *dma, uint8_t update, uint8_t enable_t10_pi, uint8_t hlm)
Write a REG_RPI command to the provided buffer.
Definition: sli4.c:1315
void(* ocs_set_port_protocol_cb_t)(int32_t status, void *arg)
Definition: ocs_hal.h:1406
ocs_set_port_protocol_cb_t cb
Definition: ocs_hal.c:8552
ocs_hal_rtn_e ocs_hal_set_trunk_mode(ocs_hal_t *hal, uint32_t trunk_mode)
Set trunking mode.
Definition: ocs_hal.c:6951
ocs_hal_rq_buffer_t * payload
Definition: ocs_hal.h:791
uint8_t fcp_burst_len[4]
Definition: ocs_fcp.h:918
sli4_port_type_e
Definition: sli4.h:3574
static uint32_t sli_get_auto_xfer_rdy_capable(sli4_t *sli4)
Definition: sli4.h:3858
uint32_t transmit_frame_count
Definition: sli4.h:1286
ocs_hal_rtn_e ocs_hal_firmware_write(ocs_hal_t *hal, ocs_dma_t *dma, uint32_t size, uint32_t offset, int last, ocs_hal_fw_cb_t cb, void *arg)
Write a portion of a firmware image to the device.
Definition: ocs_hal.c:5569
ocs_hal_rtn_e ocs_hal_get_link_stats(ocs_hal_t *hal, uint8_t req_ext_counters, uint8_t clear_overflow_flags, uint8_t clear_all_counters, ocs_hal_link_stat_cb_t cb, void *arg)
Function to retrieve the link statistics.
Definition: ocs_hal.c:5909
#define SLI4_SET_FEATURES_FEC
Definition: sli4.h:2741
void(* ocs_hal_dump_get_cb_t)(int32_t status, uint32_t bytes_read, uint8_t eof, void *arg)
Definition: ocs_hal.h:1392
static uint32_t sli_get_tow_xris_max(sli4_t *sli4)
Definition: sli4.h:3869
#define SLI4_IF_TYPE_LANCER_FC_ETH
Definition: sli4.h:115
uint8_t type_mask
Definition: sli4.h:4099
ocs_hal_parity_stat_cb_t cb
Definition: ocs_hal.c:5527
Generic WQE.
Definition: sli4_fc.h:442
static int32_t ocs_hal_cb_post_xri(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
Called when the POST_XRI command completes.
Definition: ocs_hal.c:12863
static ocs_hal_rtn_e ocs_hal_get_linkcfg_lancer(ocs_hal_t *, uint32_t, ocs_hal_port_control_cb_t, void *)
Get link configuration for a Lancer.
Definition: ocs_hal.c:6508
Stucture used for the hash lookup of queue IDs.
Definition: ocs_hal.h:869
static int32_t ocs_hal_domain_del(ocs_hal_t *, ocs_domain_t *)
Definition: ocs_hal.c:9635
ocs_hal_dif_blk_size_e blk_size
Definition: ocs_hal.h:543
HAL link configuration enum to the CLP string value mapping.
Definition: ocs_hal.c:6144
int32_t sli_cmd_fcoe_rediscover_fcf(sli4_t *sli4, void *buf, size_t size, uint16_t index)
Definition: sli4_fc.c:637
#define SLI4_CONFIG_FEC_LINK_TYPE_FC
Definition: sli4.h:2852
uint8_t r_ctl_mask
Definition: sli4.h:4097
#define OCS_HAL_MAX_PROFILES
Definition: ocs_hal.h:286