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