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