Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ocs_hal.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011-2015, Emulex
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors
16  * may be used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  */
32 
33 /**
34  * @file
35  * Define and implement the iSCSI Hardware Abstraction Layer (iHAL)
36  * All interaction with the hardware is done through the iHAL which abstracts
37  * away details of the underlying SLI implementation.
38  */
39 
40 /**
41  * @defgroup devInitShutdown Device Initialization and Shutdown
42  * @defgroup domain Domain Functions
43  * @defgroup port Port Functions
44  * @defgroup node Remote Node Functions
45  * @defgroup io IO Functions
46  * @defgroup interrupt Interrupt handling
47  * @defgroup os OS Required Functions
48  */
49 
50 /* Enable Work ARounds */
51 
52 #include "ocs.h"
53 #include "ocs_os.h"
54 #include "ocs_hal.h"
55 #include "sli4_iscsi.h"
56 #include "ocs_iscsi_spec.h"
57 
58 #define RC_MOVE_ASYNC 0x4173796e /* Asyn in hex */
59 #define OCS_HAL_WQ_ENTRIES 128 /* The number of WQEs per queue */
60 #define OCS_HAL_WQ_ENTRIES_USED (OCS_HAL_WQ_ENTRIES / 2) /* Prevent CQ overflow */
61 #define OCS_HAL_CQ_NUM_FOR_INI 2 /* Number of CQs reserved for INI */
62 #define OCS_HAL_MAX_ABORT_IOS 128 /* max number of IO that we can abort */
63 
64 static int32_t ocs_hal_cq_find(ocs_hal_t *, uint16_t);
65 static sli4_queue_t *ocs_hal_wq_find(ocs_hal_t *, uint16_t);
66 static int32_t ocs_hal_cq_process(ocs_hal_t *, sli4_queue_t *);
67 static int32_t ocs_hal_cb_link(void *, void *);
68 static int32_t ocs_hal_cb_iscsi_async(void *, void *);
69 static int32_t ocs_hal_command_process(ocs_hal_t *, int32_t, uint8_t *, size_t);
70 static int32_t ocs_hal_cmd_submit_pending(ocs_hal_t *hal);
71 static int32_t ocs_hal_mq_process(ocs_hal_t *, int32_t, sli4_queue_t *);
76 static int32_t ocs_hal_discovered_isns_cb(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx);
77 static int32_t ocs_hal_stateless_cb_if_info(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx);
79 static void ocs_hal_sgl_info_free(ocs_hal_t *hal, ocs_hal_sgl_info_t *sgl_info);
82 static void ocs_hal_rx_free(ocs_hal_t *hal);
83 
84 /**
85  * @ingroup devInitShutdown
86  * @brief Set up the Hardware Abstraction Layer module.
87  *
88  * @par Description
89  * Calls set up to configure the hardware.
90  *
91  * @param hal Hardware context allocated by caller.
92  * @param os Device abstraction.
93  * @param port_type Protocol type of port (e.g. FC, NIC, ...).
94  *
95  * @todo Why is port_type a parameter?
96  *
97  * @return Returns 0 on success, or a non-zero value otherwise.
98  */
100 ocs_hal_setup(ocs_hal_t *hal, ocs_os_handle_t os, sli4_port_type_e port_type)
101 {
102  uint32_t i;
103 
104  if (!hal) {
105  ocs_log_err(os, "bad parameter(s) hal=%p\n", hal);
106  return OCS_HAL_RTN_ERROR;
107  }
108 
109  /*
110  * ocs_hal_init() relies on NULL pointers indicating that a structure
111  * needs allocation. If a structure is non-NULL, ocs_hal_init() won't
112  * free/realloc that memory
113  */
114  ocs_memset(hal, 0, sizeof(ocs_hal_t));
115 
116  hal->os = os;
117 
118  ocs_lock_init(hal->os, &hal->cmd_lock, "HAL_cmd_lock[%d]", ocs_instance(hal->os));
122  hal->cmd_head_count = 0;
123 
124  for (i=0; i < OCS_HAL_MAX_NUM_RQ; i++) {
127  }
128 
129  ocs_lock_init(hal->os, &hal->cxn_lock, "HAL_connection_lock[%d]", ocs_instance(hal->os));
130  ocs_list_init(&hal->cxn_free, ocs_cxn_t, link);
131 
132  ocs_lock_init(hal->os, &hal->io_lock, "HAL_io_lock[%d]", ocs_instance(hal->os));
133  ocs_list_init(&hal->io_free, ocs_hal_io_t, link);
134 
139 
140  if (sli_setup(&hal->sli, hal->os, port_type)) {
141  ocs_log_err(hal->os, "SLI setup failed\n");
142  return OCS_HAL_RTN_ERROR;
143  }
144 
147 
148  sli_init(&hal->sli);
149 
150  /*
151  * TODO temp - move this out of HAL and into ocs once path support exists
152  * TODO Also specify depth of each queue as well
153  */
155  if (hal->config.n_eq > 2) {
156  /* BE3 only supports a single EQ */
157  hal->config.n_eq = 2;
158  }
159 
162  hal->config.n_mq = 1;
163  hal->config.n_rq = 2;
164  hal->config.n_io = hal->sli.config.max_ios;
166 
167  /*
168  * If we are dual-ulp enabled and both ulps are running iSCSI, then
169  * increase the number of RQs to one pair per ULP. Also use an EQ per
170  * chute.
171  */
172  if (sli_is_dual_ulp_capable(&hal->sli) &&
173  sli_is_ulp_enabled(&hal->sli, 0) &&
174  sli_is_ulp_enabled(&hal->sli, 1)) {
175  hal->config.n_rq += 2;
176  hal->config.n_eq++;
177  }
178 
180 
181  return OCS_HAL_RTN_SUCCESS;
182 }
183 
184 /**
185  * @ingroup devInitShutdown
186  * @brief Set up Hardware Abstraction Layer module
187  *
188  * @par Description
189  * Allocates memory structures needed by the device and prepares the device
190  * for operation.
191  * @n @n
192  * @b Note: This function may be called more than once (e.g. at initialization
193  * and then after a reset), but the size of internal resources may not be
194  * changed without tearing down the HAL (ocs_hal_teardown()).
195  *
196  * @param hal Hardware context allocated by caller.
197  *
198  * @return Returns 0 on success, or a non-zero value otherwise.
199  */
202 {
203  ocs_hal_rtn_e rc;
204  uint32_t i = 0;
205  uint32_t j;
206  uint16_t ulp_curr;
207  uint32_t eq_index_rq;
208  uint32_t eq_index_ulp[2];
209 
210  /*
211  * Check the FW version
212  */
213  if (!ocs_hal_fw_valid(hal)) {
214  ocs_log_err(hal->os, "ERROR: Current firmware version %s is older than the minimum supported version %s.\n",
216  /*
217  * Don't return an error here. We want ocs_hal_init() to succeed so that
218  * the management interface can be used to update the firmware. FW version
219  * will also be checked when the listen server is started and when connections
220  * are made.
221  */
222  }
223 
224  /*
225  * Make sure the command lists are empty. If this is start-of-day,
226  * they'll be empty since they were just initialized in ocs_hal_setup.
227  * If we've just gone through a reset, the command and command pending
228  * lists should have been cleaned up as part of the reset (ocs_hal_reset()).
229  */
230  ocs_lock(&hal->cmd_lock);
231  if (!ocs_list_empty(&hal->cmd_head)) {
232  ocs_log_err(hal->os, "command found on cmd list\n");
233  ocs_unlock(&hal->cmd_lock);
234  return OCS_HAL_RTN_ERROR;
235  }
236  if (!ocs_list_empty(&hal->cmd_pending)) {
237  ocs_log_err(hal->os, "command found on pending list\n");
238  ocs_unlock(&hal->cmd_lock);
239  return OCS_HAL_RTN_ERROR;
240  }
241  if (!ocs_list_empty(&hal->cmd_async)) {
242  ocs_log_err(hal->os, "command found on async list\n");
243  ocs_unlock(&hal->cmd_lock);
244  return OCS_HAL_RTN_ERROR;
245  }
246  ocs_unlock(&hal->cmd_lock);
247 
248  /*
249  * The IO queues must be initialized here for the reset case. The
250  * ocs_hal_init_io() function will re-add the IOs to the free list.
251  * The cmd_head/cmd_pending/cmd_async list should be OK since we free all
252  * entries in ocs_hal_ctx_cleanup() that is called in the
253  * ocs_hal_reset().
254  */
255  ocs_list_init(&hal->cxn_free, ocs_cxn_t, link);
256  ocs_list_init(&hal->io_free, ocs_hal_io_t, link);
257 
262 
263  sli_init(&hal->sli);
264 
265  /*
266  * TODO - This is boiler-plate code and should be consolidated into a function.
267  * Implement during path support effort
268  */
269  if (hal->config.n_eq > sli_get_max_queue(&hal->sli, SLI_QTYPE_EQ)) {
270  ocs_log_err(hal->os, "requested %d EQ but %d allowed\n",
271  hal->config.n_eq,
273  return OCS_HAL_RTN_ERROR;
274  }
275 
276  if (hal->config.n_cq > sli_get_max_queue(&hal->sli, SLI_QTYPE_CQ)) {
277  ocs_log_err(hal->os, "requested %d CQ but %d allowed\n",
278  hal->config.n_cq,
280  return OCS_HAL_RTN_ERROR;
281  }
282 
283  if (hal->config.n_wq > sli_get_max_queue(&hal->sli, SLI_QTYPE_WQ)) {
284  ocs_log_err(hal->os, "requested %d WQ but %d allowed\n",
285  hal->config.n_wq,
287  return OCS_HAL_RTN_ERROR;
288  }
289 
290  if (hal->config.n_mq > sli_get_max_queue(&hal->sli, SLI_QTYPE_MQ)) {
291  ocs_log_err(hal->os, "requested %d MQ but %d allowed\n",
292  hal->config.n_mq,
294  return OCS_HAL_RTN_ERROR;
295  }
296 
297  if (hal->config.n_rq > sli_get_max_queue(&hal->sli, SLI_QTYPE_RQ)) {
298  ocs_log_err(hal->os, "requested %d RQ but %d allowed\n",
299  hal->config.n_rq,
301  return OCS_HAL_RTN_ERROR;
302  }
303 
304  /* allocate the sli4_queue_t structures. */
305  hal->wq = ocs_malloc(hal->os, sizeof(sli4_queue_t) * hal->config.n_wq,
306  OCS_M_ZERO | OCS_M_NOWAIT);
307  if (NULL == hal->wq) {
308  ocs_log_err(hal->os, "Failed to allocate WQ structures\n");
309  return OCS_HAL_RTN_NO_MEMORY;
310  }
311 
312  hal->cq = ocs_malloc(hal->os, sizeof(sli4_queue_t) * hal->config.n_cq,
313  OCS_M_ZERO | OCS_M_NOWAIT);
314  if (NULL == hal->cq) {
315  ocs_log_err(hal->os, "Failed to allocate CQ structures\n");
316  return OCS_HAL_RTN_NO_MEMORY;
317  }
318 
319  /*
320  * Build the Event Queues
321  */
322  for (i = 0; i < hal->config.n_eq; i++) {
323  if (sli_queue_alloc(&hal->sli, SLI_QTYPE_EQ, &hal->eq[i],
325  NULL, 0)) {
326  ocs_log_err(hal->os, "EQ[%d] allocation failure\n", i);
327  return OCS_HAL_RTN_NO_MEMORY;
328  }
329 
330  hal->pending_cqs[i] = ocs_malloc(hal->os, sizeof(sli4_queue_t*) * hal->config.n_cq,
331  OCS_M_ZERO | OCS_M_NOWAIT);
332  if (NULL == hal->pending_cqs[i]) {
333  ocs_log_err(hal->os, "Failed to allocate CQ pending pointers\n");
334  return OCS_HAL_RTN_NO_MEMORY;
335  }
336  }
337 
338  sli_eq_modify_delay(&hal->sli, hal->eq, hal->config.n_eq, 0, 8);
339 
340  /*
341  * Figure out the starting and max ULP to spread the WQs across the
342  * ULPs.
343  */
344  if (sli_is_dual_ulp_capable(&hal->sli)) {
345  if (sli_is_ulp_enabled(&hal->sli, 0) &&
346  sli_is_ulp_enabled(&hal->sli, 1)) {
347  hal->ulp_start = 0;
348  hal->ulp_max = 1;
349  } else if (sli_is_ulp_enabled(&hal->sli, 0)) {
350  hal->ulp_start = 0;
351  hal->ulp_max = 0;
352  } else {
353  hal->ulp_start = 1;
354  hal->ulp_max = 1;
355  }
356  } else {
357  if (sli_is_ulp_enabled(&hal->sli, 0)) {
358  hal->ulp_start = 0;
359  hal->ulp_max = 0;
360  } else {
361  hal->ulp_start = 1;
362  hal->ulp_max = 1;
363  }
364  }
365  ocs_log_debug(hal->os, "ulp_start %d, ulp_max %d\n",
366  hal->ulp_start, hal->ulp_max);
367 
368  /*
369  * Calculate the EQ indexes
370  *
371  * Note: We are currently supporting up to 3 EQs per adapater.
372  * 0 - Mailbox and default RQ buffer CQ (RQ reassigned on offload)
373  * 1 - WQ Chute 0
374  * 2 - WQ Chute 1 (if supported)
375  */
376  eq_index_rq = 0;
377  eq_index_ulp[0] = (hal->config.n_eq > 1 ? 1 : 0);
378  eq_index_ulp[1] = hal->config.n_eq - 1;
379 
380  /*
381  * Calculate the CQ indexes
382  *
383  * Note: We reserve 1 CQ for the ULP MQ/RQ (default) and 2 for initiator
384  * connections. The remaining CQs are used for target WQs. The
385  * chip currently supports 448 connections / 60 remaining CQs =
386  * 8 WQ/CQ.
387  * Limit the WQ size to the minimum 128 entries (1 page) but
388  * further limit to 64 in the HAL. This leaves half the CQ
389  * available for RQ completions.
390  *
391  * 8 WQs * 64 WQEs/WQ = 512 CQEs
392  *
393  * If we limit the command window to 64 commands per connection,
394  * then we have a maximum of 512 RQEs as well. Which fits in the
395  * maximum 1K entries for a CQ.
396  *
397  * Immediate data will cause additional RQEs, but ignore that
398  * for now.
399  */
400  hal->cq_index_wq_tgt = 0;
401  hal->cq_index_mq = hal->config.n_cq - 1; /* last CQ */
403  hal->num_wq_per_cq = hal->config.n_wq / hal->cq_index_wq_ini;
404 
405  ocs_log_debug(hal->os, "%d Wqs, %d Tgt CQs, %d Ini CQs, %d total CQs\n",
406  hal->config.n_wq,
407  hal->cq_index_wq_ini,
409  hal->config.n_cq);
410 
411  if (hal->cq_index_mq + 1 != hal->config.n_cq) {
412  ocs_log_err(hal->os, "ERROR: Internal error allocating CQs.\n");
413  return OCS_HAL_RTN_ERROR;
414  }
415 
416  /*
417  * Build the Completion Queues - alternate the CQs between the EQs
418  */
419  ulp_curr = hal->ulp_start;
420  for (i = 0; i < hal->config.n_cq; i++) {
421  uint32_t eq_index;
422 
423  /* Find the right EQ based on the ULP */
424  if (i == hal->cq_index_mq) {
425  eq_index = eq_index_rq;
426  } else if (ulp_curr == hal->ulp_start) {
427  eq_index = eq_index_ulp[0];
428  } else {
429  eq_index = eq_index_ulp[1];
430  }
431 
432  if (sli_queue_alloc(&hal->sli, SLI_QTYPE_CQ, &hal->cq[i],
434  &hal->eq[eq_index], ulp_curr)) {
435  ocs_log_err(hal->os, "CQ[%d] allocation failure\n", i);
436  return OCS_HAL_RTN_NO_MEMORY;
437  }
438  hal->cq[i].u.flag.is_ini_cq = 0;
439  if (i >= hal->cq_index_wq_ini &&
440  i < hal->cq_index_mq) {
441  hal->cq[i].u.flag.is_ini_cq = 1;
442  }
443  ulp_curr++;
444  if (ulp_curr > hal->ulp_max) {
445  ulp_curr = hal->ulp_start;
446  }
447  }
448 
449  /*
450  * Build the Work Queues
451  *
452  * Note: The CQ assigned here is a placeholder. It is re-assigned when
453  * the connection is offloaded.
454  */
455  ulp_curr = hal->ulp_start;
456  for (i = 0; i < hal->config.n_wq; i++) {
457  if (sli_queue_alloc(&hal->sli, SLI_QTYPE_WQ, &hal->wq[i],
459  &hal->cq[hal->cq_index_wq_tgt],
460  ulp_curr)) {
461  ocs_log_err(hal->os, "WQ allocation failure\n");
462  return OCS_HAL_RTN_NO_MEMORY;
463  }
464 
465  ocs_list_init(&hal->wq[i].u.wq.wqe_free, sli4_wqe_context_t, link);
466  ocs_list_init(&hal->wq[i].u.wq.wqe_busy, sli4_wqe_context_t, link);
467  hal->wq[i].u.wq.wqe_free_cnt = OCS_HAL_WQ_ENTRIES_USED;
468  hal->wq[i].u.wq.wqe_context = ocs_malloc(hal->os, sizeof(sli4_wqe_context_t) *
470  OCS_M_ZERO | OCS_M_NOWAIT);
471  if (NULL == hal->wq[i].u.wq.wqe_context) {
472  ocs_log_err(hal->os, "Failed to allocate WQ %d context structures\n",
473  i);
474  return OCS_HAL_RTN_NO_MEMORY;
475  }
476 
477  for (j = 0; j < OCS_HAL_WQ_ENTRIES_USED; j++) {
478  hal->wq[i].u.wq.wqe_context[j].wrb_index = j;
479  hal->wq[i].u.wq.wqe_context[j].qe =
480  ((uint8_t*)hal->wq[i].dma.virt) + (j * hal->wq[i].size);
481  ocs_list_add_tail(&hal->wq[i].u.wq.wqe_free,
482  &hal->wq[i].u.wq.wqe_context[j]);
483  }
484  ulp_curr++;
485  if (ulp_curr > hal->ulp_max) {
486  ulp_curr = hal->ulp_start;
487  }
488  }
489 
490  /*
491  * Build the Receive Queues
492  *
493  * Note: The CQ assigned here is a placeholder. It is re-assigned when
494  * the connection is offloaded.
495  */
496  ulp_curr = hal->ulp_start;
497  for (i = 0; i < hal->config.n_rq; i += 2) {
498  if (sli_iscsi_defq_alloc(&hal->sli, &hal->rq[i], &hal->rq[i+1],
500  64, hal->config.rq_pl_size,
501  &hal->cq[hal->cq_index_mq],
502  ulp_curr)) {
503  ocs_log_err(hal->os, "RQ allocation failure\n");
504  return OCS_HAL_RTN_NO_MEMORY;
505  }
506  ulp_curr++;
507  if (ulp_curr > hal->ulp_max) {
508  ulp_curr = hal->ulp_start;
509  }
510  }
511 
512  for (i=0; i < hal->config.n_rq; i++) {
513  // Allocate space to track the DMA buffers placed on the RQ
514  if (!hal->rq_lookup[i]) {
515  hal->rq_lookup[i] = ocs_malloc(hal->os, sizeof(ocs_hal_rq_lookup_t) * hal->rq[i].length,
516  OCS_M_ZERO | OCS_M_NOWAIT);
517  if (!hal->rq_lookup[i]) {
518  ocs_log_err(hal->os, "RQ buf allocation failure\n");
519  return OCS_HAL_RTN_NO_MEMORY;
520  }
521  }
522 
523  if (!hal->rq_list[i]) {
524  hal->rq_list[i] = ocs_malloc(hal->os, sizeof(ocs_hal_rq_list_t) * hal->rq[i].length,
525  OCS_M_ZERO | OCS_M_NOWAIT);
526  if (!hal->rq_list[i]) {
527  ocs_log_err(hal->os, "RQ list allocation failure\n");
528  return OCS_HAL_RTN_NO_MEMORY;
529  }
530  }
533  for (j = 0; j < hal->rq[i].length; j++) {
535  &hal->rq_list[i][j]);
536  }
537  }
538 
539  /*
540  * Build the Mail Queue
541  */
542  if (sli_queue_alloc(&hal->sli, SLI_QTYPE_MQ, &hal->mq[0],
544  &hal->cq[hal->cq_index_mq], 0)) {
545  ocs_log_err(hal->os, "MQ allocation failure\n");
546  return OCS_HAL_RTN_NO_MEMORY;
547  }
548 
549  /* Set the DIF mode */
550  if (sli_is_dif_capable(&hal->sli)) {
551  rc = ocs_hal_set_dif_mode(hal);
552  if (rc != OCS_HAL_RTN_SUCCESS) {
553  ocs_log_err(hal->os, "Failed to set DIF mode value\n");
554  return rc;
555  }
556  }
557 
558  rc = ocs_hal_setup_cxns(hal);
559  if (rc) {
560  ocs_log_err(hal->os, "connections setup failure\n");
561  return rc;
562  }
563 
564  rc = ocs_hal_setup_io(hal);
565  if (rc) {
566  ocs_log_err(hal->os, "IO allocation failure\n");
567  return rc;
568  }
569 
570  rc = ocs_hal_init_io(hal);
571  if (rc) {
572  ocs_log_err(hal->os, "IO initialization failure\n");
573  return rc;
574  }
575 
576  if (hal->isns_mem.size == 0 &&
577  ocs_dma_alloc(hal->os, &hal->isns_mem, SLI_PAGE_SIZE, 4)) {
578  ocs_log_err(hal->os, "iSNS Send buffer allocation failed\n");
579  return OCS_HAL_RTN_NO_MEMORY;
580  }
581 
582  ocs_queue_history_init(hal->os, &hal->q_hist);
583 
584  /* Allocate and post RQ buffers */
585  rc = ocs_hal_rx_allocate(hal);
586  if (rc) {
587  ocs_log_err(hal->os, "rx_allocate failed\n");
588  return rc;
589  }
590 
591  if(ocs_hal_rx_post(hal)) {
592  ocs_log_warn(hal->os, "WARNING - error posting RQ buffers\n");
593  }
594 
595  /*
596  * Arming the EQ allows (e.g.) interrupts when CQ completions write EQ entries
597  */
598  for (i = 0; i < hal->config.n_eq; i++) {
599  sli_queue_arm(&hal->sli, &hal->eq[i], TRUE);
600  }
601  /*
602  * Arming the CQ allows (e.g.) MQ completions to write CQ entries
603  */
604  for (i = 0; i < hal->config.n_cq; i++) {
605  sli_queue_arm(&hal->sli, &hal->cq[i], TRUE);
606  }
607 
608  /* Set the global interrupt enable bit */
609  hal->is_hal_initialized = TRUE;
610  sli_interrupt_set(&hal->sli, TRUE);
611 
612  ocs_log_debug(hal->os, "complete\n");
613 
614  return OCS_HAL_RTN_SUCCESS;
615 }
616 
617 /**
618  * @brief Check that firmware version meets minimum requirements.
619  *
620  * @param hal Hardware context.
621  *
622  * @return Returns TRUE if firmware version is acceptable, or FALSE if not.
623  */
625  return (!hal->workaround.fw_version_too_low);
626 }
627 
628 /**
629  * @brief Find the CQ structure given the CQ_ID.
630  *
631  * @param hal Hardware context.
632  * @param cq_id CQ ID to find.
633  *
634  * @return Returns index of queue object, or -1 otherwise.
635  */
636 static int32_t
637 ocs_hal_cq_find(ocs_hal_t *hal, uint16_t cq_id)
638 {
639  uint32_t i = 0;
640  int32_t index = -1;
641 
642  /* The CQ IDs assigned are sequential, but do not start at 0 */
643  index = cq_id - hal->cq[0].id;
644  if (index < 0 ||
645  index > (int32_t)hal->config.n_cq ||
646  hal->cq[index].id != cq_id) {
647  index = -1;
648  ocs_log_test(hal->os, "Standard lookup failed\n");
649  for (i = 0; i < hal->config.n_cq; i++) {
650  if (cq_id == hal->cq[i].id) {
651  index = i;
652  break;
653  }
654  }
655  }
656 
657  return index;
658 }
659 
660 
661 /**
662  * @brief Find the WQ structure given the CQ_ID.
663  *
664  * @param hal Hardware context.
665  * @param wq_id WQ ID to find.
666  *
667  * @return Returns the Pointer to the queue object, or NULL otherwise.
668  */
669 static sli4_queue_t *
670 ocs_hal_wq_find(ocs_hal_t *hal, uint16_t wq_id)
671 {
672  int32_t index = -1;
673  sli4_queue_t *q = NULL;
674  uint32_t i = 0;
675 
676  /* The WQ IDs alternate, but assigned are sequential, but do not start at 0 */
677  index = (wq_id - hal->wq[0].id) * 2;
678  if (index < 0 ||
679  index > (int32_t)hal->config.n_wq ||
680  hal->wq[index].id != wq_id) {
681  index = ((wq_id - hal->wq[1].id) * 2) + 1;
682  if (index < 0 ||
683  index > (int32_t)hal->config.n_wq ||
684  hal->wq[index].id != wq_id) {
685  if (hal->sli.is_skyhawk) {
686  ocs_log_test(hal->os, "Standard lookup failed\n");
687  }
688  for (i = 0; i < hal->config.n_wq; i++) {
689  if (wq_id == hal->wq[i].id) {
690  q = &hal->wq[i];
691  break;
692  }
693  }
694  } else {
695  q = &hal->wq[index];
696  }
697  } else {
698  q = &hal->wq[index];
699  }
700 
701  return q;
702 }
703 
704 
705 /**
706  * @brief Find the connection structure given the WQ_ID.
707  *
708  * @param hal Hardware context.
709  * @param wq_id WQ ID to find.
710  *
711  * @return Returns the pointer to the queue object, or NULL otherwise.
712  */
713 static ocs_cxn_t *
714 ocs_hal_cxn_find(ocs_hal_t *hal, uint16_t wq_id)
715 {
716  ocs_cxn_t *cxn = NULL;
717  sli4_queue_t *q = ocs_hal_wq_find(hal, wq_id);
718 
719  if (q != NULL) {
720  cxn = q->host_arg;
721  }
722 
723  return cxn;
724 }
725 
726 
727 /**
728  * @brief Posts an RX buffer to a queue and update the verification structures.
729  *
730  * @param hal Hardware context.
731  * @param buffer Pointer to the RX buffer.
732  *
733  * @return Returns 0 on success, or a non-zero value otherwise.
734  */
735 static int32_t
737  ocs_hal_rq_buffer_t *buffer)
738 {
739  int32_t rc = OCS_HAL_RTN_SUCCESS;
740  uint16_t rqindex = buffer->rqindex;
741  sli4_queue_t *rq = &hal->rq[rqindex];
742  uint32_t phys[2];
743  int32_t qindex;
744 
745  /* Update the RQ verification lookup tables */
746  phys[0] = ocs_addr32_hi(buffer->dma.phys);
747  phys[1] = ocs_addr32_lo(buffer->dma.phys);
748 
749  ocs_lock(&rq->lock);
750  qindex = _sli_queue_write(&hal->sli, rq, (void *)phys);
751  if (qindex < 0) {
752  ocs_log_err(hal->os, "RQ_ID=%#x write failed\n", rq->id);
753  ocs_unlock(&rq->lock);
754  return OCS_HAL_RTN_ERROR;
755  }
756 
757  /* Update the lookup table */
758  if (hal->rq_lookup[rqindex][qindex].rq_buf == NULL) {
759  hal->rq_lookup[rqindex][qindex].rq_buf = buffer;
760  } else {
761  ocs_hal_rq_list_t *rq_list;
762 
763  rq_list = ocs_list_get_head(&hal->rq_list_free[rqindex]);
764  if (NULL != rq_list) {
765  ocs_list_remove_head(&hal->rq_list_free[rqindex]);
766  rq_list->rq_buf = buffer;
767  rq_list->index = qindex;
768  ocs_list_add_tail(&hal->rq_list_busy[rqindex], rq_list);
769  hal->rq_lookup[rqindex][qindex].list_cnt++;
770  } else {
771  ocs_log_err(hal->os, "out of rq_list_free buffers for rq[%d] index %d\n",
772  rqindex, qindex);
774  }
775  }
776  ocs_unlock(&rq->lock);
777  return rc;
778 }
779 
780 
781 /**
782  * @brief Process an unsolicited hdr/data.
783  *
784  * @param hal Hardware context.
785  * @param rqindex Index of the RQ that is being processed.
786  * @param bufindex Index into the RQ that is being processed.
787  * @param addr_high Upper 32 bits of buffer address.
788  * @param addr_low Lower 32 bits of buffer address.
789  * @param length Length of data placed.
790  *
791  * @return Returns the pointer to the dma buffer structure, or NULL otherwise.
792  */
793 static ocs_hal_rq_buffer_t *
795  uint16_t rqindex,
796  uint16_t bufindex,
797  uint32_t addr_high,
798  uint32_t addr_low,
799  uint32_t length)
800 {
801  sli4_queue_t *rq = &hal->rq[rqindex];
802  uintptr_t phys;
803  ocs_hal_rq_buffer_t *rc = NULL;
804  uint64_t zero = (0xdead0000 |
805  ((rq->id & 0xf) << 12) |
806  (bufindex & 0xfff));
807 
808  if (bufindex >= rq->length) {
809  return NULL;
810  }
811 
812  ocs_lock(&rq->lock);
813  if (hal->rq_lookup[rqindex][bufindex].rq_buf != NULL) {
814  phys = hal->rq_lookup[rqindex][bufindex].rq_buf->dma.phys + length;
815  if (addr_high == ocs_addr32_hi(phys) &&
816  addr_low == ocs_addr32_lo(phys)) {
817  rc = hal->rq_lookup[rqindex][bufindex].rq_buf;
818  hal->rq_lookup[rqindex][bufindex].rq_buf = NULL;
819  if (hal->rq_lookup[rqindex][bufindex].list_cnt == 0) {
820  _sli_queue_poke(&hal->sli, rq, bufindex, (uint8_t *)&zero);
821  }
822  }
823  }
824 
825  if (rc == NULL &&
826  hal->rq_lookup[rqindex][bufindex].list_cnt > 0) {
827  ocs_hal_rq_list_t *rq_list;
828 
829  ocs_list_foreach(&hal->rq_list_busy[rqindex], rq_list) {
830  if (rq_list->index == bufindex) {
831  phys = rq_list->rq_buf->dma.phys + length;
832  if (addr_high == ocs_addr32_hi(phys) &&
833  addr_low == ocs_addr32_lo(phys)) {
834  rc = rq_list->rq_buf;
835  ocs_list_remove(&hal->rq_list_busy[rqindex], rq_list);
836  ocs_list_add_tail(&hal->rq_list_free[rqindex], rq_list);
837  hal->rq_lookup[rqindex][bufindex].list_cnt--;
838  break;
839  }
840  }
841  }
842  }
843 #if defined(OCS_INCLUDE_DEBUG)
844  if (rc == NULL) {
845  ocs_hal_rq_list_t *rq_list;
846  uint64_t rq_addr;
847 
848  ocs_log_test(hal->os, "CQE address not found at index %d: 0x%x 0x%08x, dl = %d\n",
849  bufindex, addr_high, addr_low, length);
850 
851  /* log the addresses we have at that index */
852  if (hal->rq_lookup[rqindex][bufindex].rq_buf != NULL) {
853  ocs_log_test(hal->os, " RQ address 0x%x 0x%08x (Lookup tbl)\n",
854  ocs_addr32_hi(hal->rq_lookup[rqindex][bufindex].rq_buf->dma.phys),
855  ocs_addr32_lo(hal->rq_lookup[rqindex][bufindex].rq_buf->dma.phys));
856 
857  }
858 
859  /* Peek in the RQ and print that too */
860  if (_sli_queue_peek(&hal->sli, rq, bufindex, (uint8_t *)&rq_addr) == 0) {
861  ocs_log_test(hal->os, " RQ address 0x%x 0x%08x (Actual)\n",
862  (uint32_t)(rq_addr & 0xFFFFFFFF),
863  (uint32_t)(rq_addr >> 32));
864  }
865 
866  ocs_list_foreach(&hal->rq_list_busy[rqindex], rq_list) {
867  if (rq_list->index == bufindex) {
868  ocs_log_test(hal->os, " RQ address 0x%x 0x%08x (List)\n",
869  ocs_addr32_hi(rq_list->rq_buf->dma.phys),
870  ocs_addr32_lo(rq_list->rq_buf->dma.phys));
871  }
872  }
873  }
874 #endif
875  ocs_unlock(&rq->lock);
876  return rc;
877 }
878 
879 
880 /**
881  * @brief Process an unsolicited hdr/data.
882  *
883  * @param hal Hardware context.
884  * @param dpdu Pointer I_T_DPDU CQE fields.
885  *
886  * @return Returns 0 on success, or a non-zero value otherwise.
887  */
888 static int32_t
891 {
892  ocs_cxn_t *cxn;
893  ocs_hal_rq_buffer_t *rq_buf = NULL;
894  int32_t rc = 0;
895  uint8_t is_hdr = dpdu->code == ISCSI_CQE_CODE_UNSOL_HDR_NOTIFY;
896  uint8_t code = dpdu->code;
897 
898  if (hal->callback.unsolicited) {
899 
900  cxn = ocs_hal_cxn_find(hal, dpdu->cid);
901  if (cxn == NULL) {
902  ocs_log_test(hal->os, "DPDU CQE with index %d (CID 0x%x not found)\n",
903  dpdu->rq_index, dpdu->cid);
904  return -1;
905  }
906 
907  /*
908  * Note: Data digests completions do not contain a pointer to
909  * a buffer. So flag the error and this will be followed by the
910  * normal unsolicited data CQE.
911  */
913  cxn->data_digest_error = TRUE;
914  return 0;
915  }
916 
917  rq_buf = ocs_hal_rq_get(hal,
918  (is_hdr ? cxn->rqindex : cxn->rqindex + 1),
919  dpdu->rq_index,
920  dpdu->addr_high,
921  dpdu->addr_low,
922  dpdu->data_length);
923 
924  if (rq_buf == NULL) {
925  ocs_log_test(hal->os, "DPDU CQE with index %d (no DMA posted at this index) for cid 0x%x\n",
926  dpdu->rq_index, dpdu->cid);
927  return -1;
928  }
929 
930  /*
931  * The final bit is set when the last piece of the PDU is received.
932  *
933  * Note: This function assumes at most 1 data callback per PDU.
934  * This should be fine for IO as we negotiate immediate data
935  * to the buffer size, but login may be a problem.
936  */
937  if (dpdu->final) {
938  /* Flag the data digest errors */
939  if (cxn->data_digest_error) {
941  }
942 
943  if (is_hdr) {
945  cxn,
946  rq_buf,
947  dpdu->data_length,
948  NULL,
949  0,
950  code);
951  } else {
953  cxn,
954  cxn->hdr_buf,
955  cxn->hdr_length,
956  rq_buf,
957  dpdu->data_length,
958  code);
959  }
960  cxn->hdr_buf = NULL;
961  cxn->hdr_length = 0;
962  cxn->data_digest_error = FALSE;
963  } else {
964  if (cxn != NULL) {
965  if (is_hdr) {
966  cxn->hdr_buf = rq_buf;
967  cxn->hdr_length = dpdu->data_length;
968  } else {
969  ocs_log_test(hal->os, "Data PDU without final set for CID %d\n",
970  dpdu->cid);
971  rc = -1;
972  }
973  } else {
974  ocs_log_test(hal->os, "Data PDU with NULL Cxn for CID %d\n",
975  dpdu->cid);
976  rc = -1;
977  }
978  }
979  }
980  return rc;
981 }
982 
983 
984 
985 /**
986  * @brief Process an TCK acknowledgement(DMSG).
987  *
988  * @param hal Hardware context.
989  * @param dmsg Pointer I_T_DMSG CQE fields.
990  *
991  * @return Returns 0 on success, or a non-zero value otherwise.
992  */
993 static int32_t
996 {
997  int32_t rc = 0;
998  sli4_queue_t * wq;
999 
1000  wq = ocs_hal_wq_find(hal, dmsg->cid);
1001  if (NULL != wq) {
1002  rc = sli_queue_iscsi_tcp_ack(&hal->sli, wq, dmsg->wqe_index);
1003  } else {
1004  ocs_log_test(hal->os, "WQ for cid %d was not found, completion for WQE index 0x%x discarded\n", dmsg->cid, dmsg->wqe_index);
1005  rc = -1;
1006  }
1007  return rc;
1008 }
1009 
1010 
1011 /**
1012  * @brief Process an solicited target IO completion.
1013  *
1014  * @param hal Hardware context.
1015  * @param tsol pointer T_SOL CQE fields.
1016  *
1017  * @return Returns 0 on success, or a non-zero value otherwise.
1018  */
1019 static int32_t
1022 {
1023  int32_t rc = 0;
1024  sli4_queue_t *wq;
1025  ocs_hal_io_t *io;
1026 
1027  wq = ocs_hal_wq_find(hal, tsol->cid);
1028  if (NULL != wq) {
1029  io = sli_queue_iscsi_wqe_complete(&hal->sli, wq, tsol->wqe_index);
1030  if (NULL != io) {
1031  if (NULL != io->done) {
1032  io_cb_t *done = io->done;
1033  void *arg = io->arg;
1034 
1035  io->done = NULL;
1036  rc = done(io, io->node, tsol->code, NULL, arg);
1037  }
1038  } else {
1039  ocs_log_test(hal->os, "IO at index %d for WQ id %d was not found\n",
1040  tsol->wqe_index, wq->id);
1041  rc = -1;
1042  }
1043  } else {
1044  ocs_log_test(hal->os, "WQ for cid %d was not found, completion for WQE index 0x%x discarded\n",
1045  tsol->cid, tsol->wqe_index);
1046  rc = -1;
1047  }
1048  return rc;
1049 }
1050 
1051 
1052 /**
1053  * @brief Process an solicited initiator IO completion.
1054  *
1055  * @param hal Hardware context.
1056  * @param isol Pointer I_SOL CQE fields.
1057  *
1058  * @return Returns 0 on success, or a non-zero value otherwise.
1059  */
1060 static int32_t
1063 {
1064  int32_t rc = 0;
1065  sli4_queue_t *wq;
1066  ocs_hal_io_t *io;
1067  ocs_ini_cmpl_fields_t ini_fields;
1068 
1069  wq = ocs_hal_wq_find(hal, isol->cid);
1070  if (NULL != wq) {
1071  io = sli_queue_iscsi_wqe_complete(&hal->sli, wq, isol->wqe_index);
1072  if (NULL != io) {
1073  if (NULL != io->done) {
1074  io_cb_t *done = io->done;
1075  void *arg = io->arg;
1076 
1077  io->done = NULL;
1078  ini_fields.residual_cnt = isol->residual_cnt;
1079  ini_fields.exp_cmdsn = isol->exp_cmdsn;
1080  ini_fields.hw_status = isol->hw_status;
1081  ini_fields.status = isol->status;
1082  ini_fields.response = isol->response;
1083  ini_fields.flags = isol->flags;
1084  ini_fields.cmd_window = isol->cmd_window;
1085  ini_fields.sense_len = 0;
1086  ini_fields.sense_data = NULL;
1087  if (isol->status == 0x2) {
1088  ini_fields.sense_len = ocs_be16toh(*(uint16_t*)((uint8_t *)io->bhs.virt + 64));
1089  ini_fields.sense_data = ((uint8_t *)io->bhs.virt + 66);
1090  }
1091  rc = done(io, io->node, isol->code, &ini_fields, arg);
1092  }
1093  } else {
1094  ocs_log_test(hal->os, "IO at index %d for WQ id %d was not found\n",
1095  isol->wqe_index, wq->id);
1096  rc = -1;
1097  }
1098  } else {
1099  ocs_log_test(hal->os, "WQ for cid %d was not found, completion for WQE index 0x%x discarded\n",
1100  isol->cid, isol->wqe_index);
1101  rc = -1;
1102  }
1103  return rc;
1104 }
1105 
1106 
1107 
1108 /**
1109  * @brief Process an target command error IO completion.
1110  *
1111  * @param hal Hardware context.
1112  * @param cmdinv Pointer T_CMNDINV CQE fields.
1113  *
1114  * @return Returns 0 on success, or a non-zero value otherwise.
1115  */
1116 static int32_t
1119 {
1120  int32_t rc = 0;
1121  sli4_queue_t *wq;
1122  ocs_hal_io_t *io;
1123  uint8_t wait_for_tcp_ack;
1124 
1125  wq = ocs_hal_wq_find(hal, cmdinv->cid);
1126  if (NULL != wq) {
1127  io = sli_queue_iscsi_icd_invalid(&hal->sli, wq,
1128  cmdinv->icd_index,
1129  &wait_for_tcp_ack,
1131 
1132  if (NULL != io) {
1133  if (wait_for_tcp_ack) {
1134  /*
1135  * We need to eat this completion as this IO
1136  * was aborted due to a TM request, we need to
1137  * wait for the TCP ACK to complete the IO.
1138  */
1139  ocs_log_debug(hal->os, "IO at ICD index %d for WQ id %d waiting for TCP-ACK\n",
1140  cmdinv->icd_index, wq->id);
1141  rc = 0;
1142  } else if (NULL != io->done) {
1143  io_cb_t *done = io->done;
1144  void *arg = io->arg;
1145 
1146  io->done = NULL;
1147  // TODO pass the rest of INI fields
1148  rc = done(io, io->node, cmdinv->code, NULL, arg);
1149  }
1150  } else {
1151  ocs_log_test(hal->os, "IO at ICD index %d for WQ id %d was not found\n",
1152  cmdinv->icd_index, wq->id);
1153  rc = -1;
1154  }
1155  } else {
1156  ocs_log_test(hal->os, "WQ for cid %d was not found, completion for icd index 0x%x discarded\n",
1157  cmdinv->cid, cmdinv->cid);
1158  rc = -1;
1159  }
1160  return rc;
1161 }
1162 
1163 
1164 /**
1165  * @brief Process an Connection invalid completion entry.
1166  *
1167  * @param hal Hardware context.
1168  * @param cxn_invalid Pointer T_CNXINV CQE fields.
1169  *
1170  * @return Returns 0 on success, or a non-zero value otherwise.
1171  */
1172 static int32_t
1174  sli4_qentry_fields_cnxinv_t *cxn_invalid)
1175 {
1176  int32_t rc = 0;
1177  ocs_hal_rq_buffer_t *rq_buf = NULL;
1178  ocs_cxn_t *cxn;
1179 
1180  /* Lookup the affected connection */
1181  cxn = ocs_hal_cxn_find(hal, cxn_invalid->cid);
1182  if (cxn == NULL) {
1183  ocs_log_test(hal->os, "CXN_INVALID CQE (CID 0x%x not found)\n",
1184  cxn_invalid->cid);
1185  return -1;
1186  }
1187 
1188  /*
1189  * Check to see if there is a partial Data PDU that needs to be
1190  * freed. We only need to check for data with code = 0x1A
1191  */
1192  if (cxn_invalid->code == SLI_STATUS_HOST_CXN_INVALID_NOTIFY_WITH_PDU) {
1193  rq_buf = ocs_hal_rq_get(hal,
1194  cxn->rqindex + 1,
1195  cxn_invalid->rq_index,
1196  cxn_invalid->addr_high,
1197  cxn_invalid->addr_low,
1198  cxn_invalid->partial_data_length);
1199  }
1200 
1201  /* See if there is a PDU header stored on the connection to be freed */
1202  if (cxn->hdr_length != 0) {
1203  /*
1204  * Since the ocs_hal_rxbuffer() may fail, pass the frame back
1205  * to the transport with a zero length to have the transfer
1206  * free the frame and queue as appropriate.
1207  */
1208  if (hal->callback.unsolicited) {
1210  cxn,
1211  cxn->hdr_buf,
1212  0,
1213  rq_buf,
1214  0,
1216  cxn->hdr_buf = NULL;
1217  cxn->hdr_length = 0;
1218  }
1219  }
1220 
1221  /*
1222  * Because we can get multiple callbacks for the same
1223  * connection. Only issue the callback if it is still on
1224  * the busy list.
1225  */
1226  if (hal->callback.cxn) {
1227  ocs_hal_cxn_event_t cxn_event;
1228 
1229  cxn_event.event = OCS_HAL_CXN_INVALID;
1230  cxn_event.params.cxn_invalid.cxn = cxn;
1231  cxn_event.params.cxn_invalid.code = cxn_invalid->code;
1232 
1233  hal->callback.cxn(hal->args.cxn, &cxn_event);
1234  }
1235  return rc;
1236 }
1237 
1238 /**
1239  * @brief Process an data digest completion entry.
1240  *
1241  * @param hal Hardware context.
1242  * @param data_digest Pointer T_SOL_DATA_DIGEST CQE fields.
1243  *
1244  * @return Returns 0 on success, or a non-zero value otherwise.
1245  */
1246 static int32_t
1248  sli4_qentry_fields_data_digest_t *data_digest)
1249 {
1250  int32_t rc = 0;
1251 
1252  if (hal->callback.cxn) {
1253  ocs_cxn_t *cxn = ocs_hal_cxn_find(hal, data_digest->cid);
1254 
1255  if (cxn) {
1256  ocs_hal_cxn_event_t cxn_event;
1257  ocs_hal_tgt_data_digest_t *digest;
1258 
1259  cxn_event.event = OCS_HAL_CXN_TGT_DATA_DIGEST;
1260  digest = &cxn_event.params.tgt_digest;
1261  digest->buffer_offset = data_digest->buffer_offset;
1262  digest->exp_statsn = data_digest->exp_statsn;
1263  digest->datasn = data_digest->datasn;
1264  digest->fin = data_digest->fin;
1265  digest->data_seg_length = data_digest->data_seg_length;
1266  digest->cxn = cxn;
1267  digest->io = sli_queue_iscsi_icd_lookup(&hal->sli,
1268  &hal->wq[cxn->wq_index],
1269  data_digest->icd_index);
1270  digest->arg = (digest->io == NULL ? NULL : digest->io->arg);
1271 
1272  hal->callback.cxn(hal->args.cxn, &cxn_event);
1273  } else {
1274  ocs_log_test(hal->os, "Connection for cid 0x%x not found - dropped\n",
1275  data_digest->cid);
1276  }
1277  }
1278  return rc;
1279 }
1280 
1281 
1282 /**
1283  * @brief Process an transmit DIF error completion entry.
1284  *
1285  * @param hal Hardware context.
1286  * @param dif_err Pointer TX_DIF_ERR CQE fields.
1287  *
1288  * @return Returns 0 on success, or a non-zero value otherwise.
1289  */
1290 static int32_t
1293 {
1294  int32_t rc = 0;
1295  sli4_queue_t *wq;
1296  ocs_hal_io_t *io;
1297  uint8_t wait_for_tcp_ack;
1298 
1299  wq = ocs_hal_wq_find(hal, dif_err->cid);
1300  if (NULL != wq) {
1301  io = sli_queue_iscsi_icd_invalid(&hal->sli, wq,
1302  dif_err->icd_index,
1303  &wait_for_tcp_ack,
1305 
1306  if (NULL != io) {
1307  if (wait_for_tcp_ack) {
1308  /*
1309  * We need to eat this completion as this IO
1310  * was aborted due to a TM request, we need to
1311  * wait for the TCP ACK to complete the IO.
1312  */
1313  ocs_log_debug(hal->os, "IO at ICD index %d for WQ id %d waiting for TCP-ACK\n",
1314  dif_err->icd_index, wq->id);
1315  rc = 0;
1316  } else if (NULL != io->done) {
1317  io_cb_t *done = io->done;
1318  void *arg = io->arg;
1319 
1320  io->done = NULL;
1321  // TODO pass the rest of INI fields
1322  rc = done(io, io->node, SLI_STATUS_TX_DIF_ERROR, NULL, arg);
1323  }
1324  } else {
1325  ocs_log_test(hal->os, "IO at ICD index %d for WQ id %d was not found\n",
1326  dif_err->icd_index, wq->id);
1327  rc = -1;
1328  }
1329  } else {
1330  ocs_log_test(hal->os, "WQ for cid %d was not found, completion for icd index 0x%x discarded\n",
1331  dif_err->cid, dif_err->icd_index);
1332  rc = -1;
1333  }
1334  return rc;
1335 }
1336 
1337 
1338 /**
1339  * @brief Process entries on the give completion queue.
1340  *
1341  * @param hal Hardware context.
1342  * @param cq Pointer to the completion queue object.
1343  *
1344  * @return Returns 0 on success, or a non-zero value otherwise.
1345  */
1346 static int32_t
1348 {
1349  uint8_t cqe[sizeof(sli4_mcqe_t)];
1350  int32_t status;
1351  sli4_qentry_fields_t fields;
1352  uint32_t n_processed = 0;
1353 
1354  while (!hal->has_fw_ue &&
1355  !sli_queue_read(&hal->sli, cq, cqe)) {
1356  uint8_t log_entry = FALSE;
1357 
1358  status = sli_cq_parse(&hal->sli, cq, cqe, &fields);
1359 
1360  /*
1361  * The sign of status is significant. If status is:
1362  * == 0 : call completed correctly and the CQE indicated success
1363  * > 0 : call completed correctly and the CQE indicated an error
1364  * < 0 : call failed and no information is available about the CQE
1365  */
1366  if (status < 0) {
1367  if (status == -2) {
1368  /* Notification that an entry was consumed, but not completed */
1369  continue;
1370  }
1371 
1372  break;
1373  }
1374 
1375  switch (fields.ctype) {
1376  case SLI_CQENTRY_RQ:
1377  ocs_hal_dpdu_process(hal, &fields.msg.dpdu);
1378  break;
1379 
1380  case SLI_CQENTRY_TCP_ACK:
1381  ocs_hal_dmsg_process(hal, &fields.msg.dmsg);
1382  break;
1383 
1384  case SLI_CQENTRY_INI_IO:
1385  log_entry = TRUE;
1386  ocs_hal_isol_process(hal, &fields.msg.isol);
1387  break;
1388 
1389  case SLI_CQENTRY_TGT_IO:
1390  log_entry = TRUE;
1391  ocs_hal_tsol_process(hal, &fields.msg.tsol);
1392  break;
1393 
1395  log_entry = TRUE;
1396  ocs_hal_cmdinv_process(hal, &fields.msg.tcmdinv);
1397  break;
1398 
1399  case SLI_CQENTRY_ASYNC:
1400  log_entry = TRUE;
1401  sli_cqe_async(&hal->sli, cqe);
1402  break;
1403  case SLI_CQENTRY_MQ:
1404  /*
1405  * Process MQ entry. Note there is no way to determine
1406  * the MQ_ID from the completion entry.
1407  */
1408  ocs_hal_mq_process(hal, status, hal->mq);
1409  break;
1410 
1412  log_entry = TRUE;
1413  ocs_hal_cxn_invalid_process(hal, &fields.msg.cnxinv);
1414  break;
1415 
1417  log_entry = TRUE;
1419  break;
1420 
1422  log_entry = TRUE;
1424  break;
1425 
1426  default:
1427  ocs_log_test(hal->os, "unhandled ctype=%#x\n", fields.ctype);
1428  break;
1429  }
1430 
1431  if (log_entry) {
1432  ocs_queue_history_cqe(&hal->q_hist,
1433  fields.ctype,
1434  (void *)cqe,
1435  cq->id,
1436  ((cq->index - 1) & (cq->length - 1)));
1437  }
1438 
1439  n_processed++;
1440  if (n_processed == cq->proc_limit) {
1441  break;
1442  }
1443 
1444  if (cq->n_posted >= cq->posted_limit) {
1445  sli_queue_arm(&hal->sli, cq, FALSE);
1446  }
1447  }
1448 
1449  sli_queue_arm(&hal->sli, cq, TRUE);
1450 
1451  return 0;
1452 }
1453 
1454 
1455 static int32_t
1456 ocs_hal_command_process(ocs_hal_t *hal, int32_t status, uint8_t *mqe, size_t size)
1457 {
1458  sli4_mqe_hdr_t *mqe_hdr = (sli4_mqe_hdr_t *)mqe;
1459  uint64_t tag = ((uint64_t)mqe_hdr->tag[1] << 32) | mqe_hdr->tag[0];
1460  ocs_command_ctx_t *ctx = (ocs_command_ctx_t *)(uintptr_t)tag;
1461  int32_t rc = 0;
1462 
1463  ocs_lock(&hal->cmd_lock);
1464  hal->cmd_head_count--;
1465 
1466  /* Post any pending requests */
1468 
1469  ocs_unlock(&hal->cmd_lock);
1470 
1471  if (ctx->cb) {
1472  ocs_memcpy(ctx->cmd, mqe, size);
1473  rc = ctx->cb(hal, status, ctx);
1474  }
1475 
1476  if (rc == RC_MOVE_ASYNC) {
1477  ocs_lock(&hal->cmd_lock);
1478  ocs_list_remove(&hal->cmd_head, ctx);
1479  ocs_list_add_tail(&hal->cmd_async, ctx);
1480  ocs_unlock(&hal->cmd_lock);
1481  } else {
1482  ocs_hal_command_free_ctx(hal, ctx);
1483  }
1484 
1485  return 0;
1486 }
1487 
1488 /**
1489  * @brief Process entries on the give mailbox queue.
1490  *
1491  * @param hal Hardware context.
1492  * @param status CQE status.
1493  * @param mq Pointer to the mailbox queue object.
1494  *
1495  * @return Returns 0 on success, or a non-zero value otherwise.
1496  */
1497 static int32_t
1498 ocs_hal_mq_process(ocs_hal_t *hal, int32_t status, sli4_queue_t *mq)
1499 {
1500  uint8_t mqe[SLI4_BMBX_SIZE];
1501 
1502  if (!sli_queue_read(&hal->sli, mq, mqe)) {
1503  ocs_hal_command_process(hal, status, mqe, mq->size);
1504  }
1505 
1506  return 0;
1507 }
1508 
1509 /**
1510  * @brief Callback function for SLI link events.
1511  *
1512  * @par Description
1513  * This function allocates memory which must be freed in its callback.
1514  *
1515  * @param ctx Hardware context pointer (i.e. ocs_hal_t *).
1516  * @param e Event structure pointer (i.e. sli4_link_event_t *).
1517  *
1518  * @return Returns 0 on success, or a non-zero value otherwise.
1519  */
1520 static int32_t
1521 ocs_hal_cb_link(void *ctx, void *e)
1522 {
1523  ocs_hal_t *hal = ctx;
1524  sli4_link_event_t *event = e;
1525 
1526  ocs_memset(&hal->link, 0, sizeof(hal->link));
1527 
1528  switch (event->status) {
1529  case SLI_LINK_STATUS_UP:
1530  ocs_log_info(hal->os, "Link up, speed is %d\n", event->speed);
1531  break;
1532  case SLI_LINK_STATUS_DOWN:
1533  ocs_log_info(hal->os, "Link down\n");
1534  break;
1535  default:
1536  ocs_log_test(hal->os, "unhandled link status %#x\n", event->status);
1537  break;
1538  }
1539 
1540  hal->link.speed = event->speed;
1541 
1542  if (hal->callback.link) {
1543  hal->callback.link(hal->args.link,
1544  (event->status == SLI_LINK_STATUS_UP));
1545  }
1546 
1547  return 0;
1548 }
1549 
1550 /**
1551  * @brief Sends a bad status to the caller when an asynchronous message fails.
1552  *
1553  * @par Description
1554  * This function calls the callback function for the context and puts
1555  * it back on the free list.
1556  *
1557  * @param hal Hardware context.
1558  * @param ctx Command context from ocs_hal_command_get_ctx().
1559  * @param status Asynchronous status.
1560  * @param additional_status Asynchronous additional status.
1561  *
1562  * @return Returns 0 on success, or a non-zero value otherwise.
1563  */
1564 static int32_t
1566  ocs_command_ctx_t *ctx,
1567  uint8_t status,
1568  uint8_t additional_status)
1569 {
1570  sli4_mcqe_t *mqe = (sli4_mcqe_t*)ctx->cmd;
1571  int32_t rc = 0;
1572 
1573  ocs_log_debug(hal->os, "bad async status of 0x%x, additional 0x%x\n",
1574  status, additional_status);
1575  if (ctx->cb) {
1576  /* Update the command with the status/additional status */
1577  mqe->completion_status = status;
1578  mqe->extended_status = additional_status;
1579 
1580  /*
1581  * Since all the async contexts are wrappers for upper layer protocols,
1582  * call the normal callback and it should filter back.
1583  */
1584  rc = ctx->cb(hal, status, ctx);
1585  }
1586 
1587  ocs_hal_command_free_ctx(hal, ctx);
1588  return rc;
1589 }
1590 
1591 /**
1592  * @brief Processes the asynchronous stateless completion message.
1593  *
1594  * @par Description
1595  * This function searches the mailbox list of commands waiting for asynchronous
1596  * completions. If they are found then a new mailbox command is issued to
1597  * retrieve the IP address that was assigned.
1598  *
1599  * @param hal Hardware context.
1600  * @param event Stateless event message.
1601  * @param isv4 TRUE for IPv4 event, FALSE for IPv6.
1602  *
1603  * @return Returns 0 on success, or a non-zero value otherwise.
1604  */
1605 static int32_t
1608  uint8_t isv4)
1609 {
1610  ocs_command_ctx_t *ctx;
1611  ocs_command_ctx_t *ctx_next;
1613 
1614  ocs_lock(&hal->cmd_lock);
1615  ocs_list_foreach_safe(&hal->cmd_async, ctx, ctx_next) {
1616  req = (void*)(ctx->cmd + sizeof(sli4_mqe_hdr_t));
1617 
1620  ctx->portal == event->iface &&
1621  ((ctx->ip_type == OCS_HAL_IP_TYPE_DHCP_V4 && isv4) ||
1622  (ctx->ip_type == OCS_HAL_IP_TYPE_AUTO_V6 && !isv4))) {
1623  ocs_list_remove(&hal->cmd_async, ctx);
1624  ocs_list_add_tail(&hal->cmd_head, ctx);
1626 
1627  ocs_unlock(&hal->cmd_lock);
1628  if (event->status) {
1630  ctx,
1631  event->status,
1632  event->additional_status);
1633  } else {
1635  (&hal->sli, ctx->cmd, SLI4_BMBX_SIZE, 0,
1636  event->iface,
1637  (ctx->ip_type == OCS_HAL_IP_TYPE_DHCP_V4))) {
1638  if (ocs_hal_command_queue(hal, ctx)) {
1639  ocs_log_test(hal->os, "Error posting GET_IF_INFO\n");
1640  }
1641  } else {
1642  ocs_log_test(hal->os, "Error building GET_IF_INFO message\n");
1643  }
1644  }
1645  ocs_lock(&hal->cmd_lock);
1646  }
1647  }
1648  ocs_unlock(&hal->cmd_lock);
1649  return 0;
1650 }
1651 
1652 
1653 /**
1654  * @brief Processes the asynchronous DHCP completion message.
1655  *
1656  * @par Description
1657  * This function searches the mailbox list of commands waiting for asynchronous
1658  * completions. If they are found then a new mailbox command is issued to
1659  * retrieve the iSNS servers that were discovered.
1660  *
1661  * @param hal Hardware context.
1662  * @param event The stateless event message.
1663  *
1664  * @return Returns 0 on success, or a non-zero value otherwise.
1665  */
1666 static int32_t
1669 {
1670  ocs_command_ctx_t *ctx;
1671  ocs_command_ctx_t *ctx_next;
1673 
1674  ocs_lock(&hal->cmd_lock);
1675  ctx = ocs_list_get_head(&hal->cmd_async);
1676  while (NULL != ctx) {
1677  ctx_next = ocs_list_next(&hal->cmd_async, ctx);
1678  req = (void*)(ctx->cmd + sizeof(sli4_mqe_hdr_t));
1679 
1682  ctx->portal == event->iface) {
1683  ocs_list_remove(&hal->cmd_async, ctx);
1684  ocs_list_add_tail(&hal->cmd_head, ctx);
1686 
1687  ocs_unlock(&hal->cmd_lock);
1688  if (event->status) {
1690  ctx,
1691  event->status,
1692  event->additional_status);
1693  } else {
1695  (&hal->sli, ctx->cmd, SLI4_BMBX_SIZE, 0, event->iface)) {
1696  if (ocs_hal_command_queue(hal, ctx)) {
1697  ocs_log_test(hal->os, "Error posting DISCOVERED_ISNS\n");
1698  }
1699  } else {
1700  ocs_log_test(hal->os, "Error building DISCOVERED_ISNS message\n");
1701  }
1702  }
1703  ocs_lock(&hal->cmd_lock);
1704  }
1705  ctx = ctx_next;
1706  }
1707  ocs_unlock(&hal->cmd_lock);
1708  return 0;
1709 }
1710 
1711 
1712 /**
1713  * @brief Callback function for SLI iSCSI asynchromous events.
1714  *
1715  * @param ctx Hardware context pointer (i.e. ocs_hal_t *).
1716  * @param e Event structure pointer (i.e. sli4_iscsi_async_event_t *).
1717  *
1718  * @return Returns 0 on success, or a non-zero value otherwise.
1719  */
1720 static int32_t
1721 ocs_hal_cb_iscsi_async(void *ctx, void *e)
1722 {
1723  ocs_hal_t *hal = ctx;
1724  sli4_iscsi_async_event_t *event = e;
1725 
1726  switch(event->event) {
1728  if (hal->callback.cxn) {
1729  ocs_hal_cxn_event_t cxn_event;
1730 
1731  cxn_event.event = OCS_HAL_CXN_NEW;
1732  cxn_event.params.cxn_new.cid = event->params.new_tcp.cid;
1733  hal->callback.cxn(hal->args.cxn, &cxn_event);
1734  }
1735  break;
1738  &event->params.stateless_cmpl,
1739  TRUE);
1740  break;
1743  &event->params.stateless_cmpl,
1744  FALSE);
1745  break;
1747  ocs_hal_dhcp_async_event(hal, &event->params.dhcp_cmpl);
1748  break;
1751  default:
1752  break;
1753  }
1754 
1755  return 0;
1756 }
1757 
1758 /**
1759  * @brief Initialize the pool of HAL connection objects.
1760  *
1761  * @param hal Hardware context.
1762  *
1763  * @return Returns 0 on success, or a non-zero value otherwise.
1764  */
1765 static ocs_hal_rtn_e
1767 {
1768  uint32_t i = 0;
1769  ocs_cxn_t *cxn;
1770  uintptr_t dataout_virt = 0;
1771  uintptr_t dataout_phys = 0;
1772  iscsi_data_out_hdr_t *data_hdr;
1773  iscsi_nopout_hdr_t *nop_hdr;
1774 
1775  if (hal->sli.port_type == SLI4_PORT_TYPE_ISCSI_INI ||
1777  if (ocs_dma_alloc(hal->os, &hal->dataout_tmpl_mem,
1778  128 * hal->config.n_wq,
1779  4/*XXX what does this need to be? */)) {
1780  ocs_log_err(hal->os, "data out template buffer allocation failed\n");
1781  return OCS_HAL_RTN_NO_MEMORY;
1782  }
1783  ocs_memset(hal->dataout_tmpl_mem.virt, 0, 128 * hal->config.n_wq);
1784  dataout_virt = (uintptr_t)hal->dataout_tmpl_mem.virt;
1785  dataout_phys = hal->dataout_tmpl_mem.phys;
1786  }
1787 
1788  for (i = 0; i < hal->config.n_wq; i++) {
1789  cxn = ocs_malloc(hal->os, sizeof(ocs_cxn_t), OCS_M_ZERO | OCS_M_NOWAIT);
1790  if (cxn != NULL) {
1791  hal->wq[i].host_arg = cxn;
1792  cxn->wq_id = hal->wq[i].id;
1793  cxn->wq_index = i;
1794  cxn->rqindex = (hal->wq[i].ulp == hal->ulp_start ? 0 : 2);
1795  cxn->ocs = hal->os;
1796  cxn->cxn_state = CONN_STATE_NEW_CONN;
1797  cxn->instance_index = i;
1798  ocs_node_lock_init(cxn);
1799  ocs_lock_init(hal->os, &cxn->active_ios_lock, "active_ios[%d]", cxn->instance_index);
1800  ocs_list_init(&cxn->active_ios, ocs_io_t, link);
1801 
1802  if (hal->sli.port_type == SLI4_PORT_TYPE_ISCSI_INI ||
1804  cxn->dataout_tmpl.virt = (void*)dataout_virt;
1805  cxn->dataout_tmpl.phys = dataout_phys;
1806  cxn->dataout_tmpl.size = 128;
1807 
1808  /* Initialize the data-out and nop-out headers */
1809  data_hdr = (iscsi_data_out_hdr_t*)dataout_virt;
1810  data_hdr->opcode = ISCSI_CMD_DATA_OUT;
1811 
1812  nop_hdr = (iscsi_nopout_hdr_t*)(dataout_virt + 64);
1813  nop_hdr->opcode = ISCSI_CMD_NOOP;
1814  nop_hdr->final = 1;
1815  nop_hdr->ttt = 0xFFFFFFF;
1816 
1817  dataout_virt += 128;
1818  dataout_phys += 128;
1819  }
1820  ocs_list_add_tail(&hal->cxn_free, cxn);
1821  } else {
1822  ocs_log_err(hal->os, "connection allocation failure\n");
1823  return OCS_HAL_RTN_NO_MEMORY;
1824  }
1825  }
1826  return OCS_HAL_RTN_SUCCESS;
1827 }
1828 
1829 /**
1830  * @brief Initialize the pool of HAL IO objects.
1831  *
1832  * @param hal Hardware context.
1833  *
1834  * @return Returns 0 on success, or a non-zero value otherwise.
1835  */
1836 static ocs_hal_rtn_e
1838 {
1839  uint32_t i = 0;
1840  ocs_hal_io_t *io = NULL;
1841  ocs_hal_sgl_info_t *sgl_info = NULL;
1842  uintptr_t bhs_virt = 0;
1843  uintptr_t bhs_phys = 0;
1844 
1845  if (NULL == hal->io) {
1846 
1847  /*
1848  * The set fragnum bits only works on skyhawk and can only be
1849  * issued if we are running version 0 of the post sgl command.
1850  */
1851  if (hal->sli.is_skyhawk && hal->sli.config.post_sgl_ver == 0) {
1852  if (sli_iscsi_set_frag_bits(&hal->sli)) {
1853  ocs_log_err(hal->os, "Set fragnum bits failure\n");
1854  return ENXIO;
1855  }
1856  }
1857 
1858  if (sli_iscsi_post_sgl_pages(&hal->sli)) {
1859  ocs_log_err(hal->os, "SGL allocation failure\n");
1860  return ENXIO;
1861  }
1862 
1863  hal->io = ocs_malloc(hal->os, hal->config.n_io * sizeof(ocs_hal_io_t), OCS_M_ZERO | OCS_M_NOWAIT);
1864 
1865  if (NULL == hal->io) {
1866  ocs_log_err(hal->os, "IO memory allocation failed\n");
1867  return OCS_HAL_RTN_NO_MEMORY;
1868  }
1869  hal->sgl_info = ocs_malloc(hal->os, hal->config.n_io * sizeof(ocs_hal_sgl_info_t), OCS_M_ZERO | OCS_M_NOWAIT);
1870 
1871  if (NULL == hal->sgl_info) {
1872  ocs_log_err(hal->os, "SGL Info memory allocation failed\n");
1873  return OCS_HAL_RTN_NO_MEMORY;
1874  }
1875  } else {
1876  return OCS_HAL_RTN_SUCCESS;
1877  }
1878 
1879  if (ocs_dma_alloc(hal->os, &hal->bhs_mem,
1881  4/*XXX what does this need to be? */)) {
1882  ocs_log_err(hal->os, "BHS buffer allocation failed\n");
1883  return OCS_HAL_RTN_NO_MEMORY;
1884  }
1885  bhs_virt = (uintptr_t)hal->bhs_mem.virt;
1886  bhs_phys = hal->bhs_mem.phys;
1887 
1888  for (i = 0; i < hal->config.n_io; i++) {
1889  io = &hal->io[i];
1890  sgl_info = &hal->sgl_info[i];
1891  if (sli_iscsi_io_get_icd_and_sgl(&hal->sli, i, &io->icd, &sgl_info->sgl)) {
1892  ocs_log_err(hal->os, "ICD allocation failed on IO %d\n", i);
1893  return OCS_HAL_RTN_ERROR;
1894  }
1895 
1896  io->bhs.virt = (void *)bhs_virt;
1897  io->bhs.phys = bhs_phys;
1898  io->bhs.size = HAL_BHS_ALLOC_SIZE;
1899 
1900  sgl_info->sgl_type = OCS_HAL_SGL_NORMAL;
1901  sgl_info->num_entries = hal->sli.config.num_sges_per_icd;
1902  sgl_info->icd = io->icd;
1903  sgl_info->frag_offset = 0;
1904 
1906  ocs_list_add_head(&io->sgl_list, sgl_info);
1907 
1908  bhs_virt += HAL_BHS_ALLOC_SIZE;
1909  bhs_phys += HAL_BHS_ALLOC_SIZE;
1910  }
1911 
1912  return OCS_HAL_RTN_SUCCESS;
1913 }
1914 
1915 static ocs_hal_rtn_e
1917 {
1918  uint32_t i = 0;
1919  ocs_hal_io_t *io = NULL;
1920 
1921  for (i = 0; i < hal->config.n_io; i++) {
1922  io = &hal->io[i];
1923 
1924  ocs_list_add_tail(&hal->io_free, io);
1925  io->tag = i;
1926  io->instance_index = i;
1927  }
1928 
1929  ocs_atomic_init(&hal->io_alloc_failed_count, 0);
1930 
1931  return OCS_HAL_RTN_SUCCESS;
1932 }
1933 
1934 
1935 /**
1936  * @brief Sets the DIF mode value.
1937  *
1938  * @param hal Hardware context.
1939  *
1940  * @return Returns OCS_HAL_RTN_SUCCESS on success.
1941  */
1942 static ocs_hal_rtn_e
1944 {
1946  uint8_t buf[SLI4_BMBX_SIZE];
1948  uint32_t inline_value = sli_is_dif_inline_capable(&hal->sli);
1949  uint32_t separate_value = sli_is_dif_separate_capable(&hal->sli);
1950 
1951  /*
1952  * Note: Older FW will not set either the inline or separate bits.
1953  *
1954  * If we are the first driver loaded with newer FW, then both
1955  * bits should be set. If an earlier driver has set it to a mode,
1956  * then only that bit will be set.
1957  *
1958  * Do not issue the set_features command if it has already been
1959  * set.
1960  */
1961  if (inline_value == 0 && separate_value == 0) {
1962  /* older FW - does not support the set_features command */
1963  return rc;
1964  } else if ((inline_value == 1 && separate_value == 0) ||
1965  (inline_value == 0 && separate_value == 1)) {
1966  /* newer FW but the mode is already set */
1967  return rc;
1968  }
1969 
1970  ocs_memset(&mode_param, 0, sizeof(mode_param));
1971  mode_param.tmm = (hal->config.dif_mode == OCS_HAL_DIF_MODE_INLINE ? 0 : 1);
1972 
1973  /* send set_features command */
1976  sizeof(mode_param),
1977  (uint32_t*)&mode_param)) {
1978  rc = ocs_hal_command_bootstrap(hal, buf);
1979  if (rc) {
1980  ocs_log_test(hal->os, "ocs_hal_command returns %d\n", rc);
1981  } else {
1982  ocs_log_debug(hal->os, "DIF mode set to %s\n",
1983  (hal->config.dif_mode == OCS_HAL_DIF_MODE_INLINE ? "inline" : "separate"));
1984  }
1985  } else {
1986  ocs_log_test(hal->os, "sli_cmd_common_set_features failed\n");
1987  rc = OCS_HAL_RTN_ERROR;
1988  }
1989  return rc;
1990 }
1991 
1992 
1993 static int32_t
1995 {
1996  uint32_t i = 0;
1997 
1998  /* Process any remaining completions */
1999  for (i = 0; i < hal->config.n_eq; i++) {
2000  ocs_hal_process(hal, i, ~0);
2001  sli_queue_arm(&hal->sli, &hal->eq[i], TRUE);
2002  }
2003 
2004  return 0;
2005 }
2006 
2007 /**
2008  * @ingroup io
2009  * @brief Issue a SLI command to the bootstrap mailbox.
2010  *
2011  * @par Description
2012  * Send a mailbox command to the hardware and wait for a completion.
2013  *
2014  * @param hal Hardware context.
2015  * @param cmd Buffer containing a formatted command and results.
2016  */
2019 {
2021 
2022  /*
2023  * Check if the chip is in an error state (UE'd) before proceeding.
2024  */
2025  if (sli_fw_error_status(&hal->sli) > 0) {
2026  ocs_log_crit(hal->os, "Chip is in an error state - reset needed\n");
2027  return OCS_HAL_RTN_ERROR;
2028  }
2029 
2030  ocs_lock(&hal->cmd_lock);
2031  if (!sli_queue_is_empty(&hal->sli, hal->mq)) {
2032  /*
2033  * Can't issue Boot-strap mailbox command with other
2034  * mail-queue commands pending as this interaction is
2035  * undefined
2036  */
2037  ocs_log_test(hal->os, "Polled command with non-empty mailbox queue\n");
2038  } else {
2039  void *bmbx = hal->sli.bmbx.virt;
2040 
2041  ocs_memcpy(bmbx, cmd, SLI4_BMBX_SIZE);
2042 
2043  if (sli_bmbx_command(&hal->sli) == 0) {
2044  rc = OCS_HAL_RTN_SUCCESS;
2045  ocs_memcpy(cmd, bmbx, SLI4_BMBX_SIZE);
2046  }
2047  }
2048  ocs_unlock(&hal->cmd_lock);
2049  return rc;
2050 }
2051 
2052 
2053 /**
2054  * @ingroup io
2055  * @brief Issue a SLI command.
2056  *
2057  * @par Description
2058  * Get a mailbox context to send a queued mailbox command.
2059  *
2060  * @param hal Hardware context.
2061  *
2062  * @return Returns a pointer on success, or NULL otherwise.
2063  */
2066 {
2067  ocs_command_ctx_t *ctx;
2068 
2069  ctx = ocs_malloc(hal->os, sizeof(ocs_command_ctx_t), OCS_M_ZERO | OCS_M_NOWAIT);
2070  if (NULL != ctx) {
2071  ctx->hal = hal;
2072  ctx->use_cnt++;
2073  }
2074  return ctx;
2075 }
2076 
2077 
2078 /**
2079  * @ingroup io
2080  * @brief Issue a SLI command.
2081  *
2082  * @par Description
2083  * Free a mailbox context.
2084  *
2085  * @param hal Hardware context.
2086  * @param ctx Pointer to the command context.
2087  */
2088 void
2090 {
2091  ocs_lock(&hal->cmd_lock);
2092  ocs_list_remove(&hal->cmd_head, ctx);
2093  ocs_unlock(&hal->cmd_lock);
2094 
2095  ocs_memset(ctx, 0, sizeof(ocs_command_ctx_t));
2096  ocs_free(hal->os, ctx, sizeof(ocs_command_ctx_t));
2097 }
2098 
2099 /**
2100  * @brief Submit queued (pending) mbx commands
2101  *
2102  * @par Description
2103  * Submit queued mailbox commands.
2104  * @n @n
2105  * --- Assumes that hal->cmd_lock is held ---
2106  *
2107  * @param hal Hardware context.
2108  *
2109  * @return Returns 0 one success, or a negative error code value on failure.
2110  */
2111 static int32_t
2113 {
2114  ocs_command_ctx_t *ctx;
2115  sli4_mqe_hdr_t *hdr;
2116  uint64_t tag;
2117  int32_t rc = 0;
2118 
2119  /* Assumes lock held */
2120 
2121  /* Only submit MQE if there's room */
2122  while (hal->cmd_head_count < (hal->mq[0].length - 1U)) {
2123  ctx = ocs_list_remove_head(&hal->cmd_pending);
2124  if (ctx == NULL) {
2125  break;
2126  }
2127  ocs_list_add_tail(&hal->cmd_head, ctx);
2128  hal->cmd_head_count++;
2129 
2130  /* update the tag field with a pointer back to the context */
2131  hdr = (sli4_mqe_hdr_t*)ctx->cmd;
2132  tag = (uintptr_t)ctx;
2133  hdr->tag[0] = tag & 0xffffffff;
2134  hdr->tag[1] = tag >> 32;
2135 
2136  if (sli_queue_write(&hal->sli, hal->mq, ctx->cmd) < 0) {
2137  ocs_log_err(hal->os, "sli_queue_write failed: %d\n", rc);
2138  rc = -1;
2139  break;
2140  }
2141  }
2142  return rc;
2143 }
2144 
2145 /**
2146  * @ingroup io
2147  * @brief Issue a SLI command.
2148  *
2149  * @par Description
2150  * Send a mailbox command to the hardware and gets an optional asynchronous
2151  * completion.
2152  * @n @n
2153  * @b Note: The caller must fill in the call back pointer fields. If the
2154  * callback function pointer is NULL, the results of the command will be
2155  * silently discarded. This context is freed automatically if the function
2156  * fails.
2157  *
2158  * @param hal Hardware context.
2159  * @param ctx Command context from ocs_hal_command_get_ctx().
2160  *
2161  * @return Returns OCS_HAL_RTN_SUCCESS on success, or OCS_HAL_RTN_ERROR otherwise.
2162  */
2165 {
2167 
2168  /*
2169  * Check if the chip is in an error state (UE'd) before proceeding.
2170  */
2171  if (sli_fw_error_status(&hal->sli) > 0) {
2172  ocs_log_crit(hal->os, "Chip is in an error state - reset needed\n");
2173  return OCS_HAL_RTN_ERROR;
2174  }
2175 
2176  ocs_lock(&hal->cmd_lock);
2177 
2178  /* Add to pending list */
2179  ocs_list_add_tail(&hal->cmd_pending, ctx);
2180 
2181  /* Submit as much of the pending list as we can */
2182  if (ocs_hal_cmd_submit_pending(hal) == 0) {
2183  rc = OCS_HAL_RTN_SUCCESS;
2184  }
2185 
2186  ocs_unlock(&hal->cmd_lock);
2187 
2188  return rc;
2189 }
2190 
2191 /**
2192  * @ingroup devInitShutdown
2193  * @brief register a callback for the given event.
2194  *
2195  * @param hal Hardware context.
2196  * @param which Event of interest.
2197  * @param func Function to call when the event occurs.
2198  * @param arg Argument passed to the callback function.
2199  *
2200  * @return Returns 0 on success, or a non-zero value otherwise.
2201  */
2203 ocs_hal_callback(ocs_hal_t *hal, ocs_hal_callback_e which, void *func, void *arg)
2204 {
2205 
2206  if (!hal || !func || (which >= OCS_HAL_CB_MAX)) {
2207  if (hal) {
2208  ocs_log_err(hal->os, "bad parameter hal=%p which=%#x func=%p\n",
2209  hal, which, func);
2210  } else {
2211  ocs_log_err(NULL, "bad parameter hal=%p which=%#x func=%p\n",
2212  hal, which, func);
2213  }
2214  return OCS_HAL_RTN_ERROR;
2215  }
2216 
2217  switch (which) {
2218  case OCS_HAL_CB_LINK:
2219  hal->callback.link = func;
2220  hal->args.link = arg;
2221  break;
2222  case OCS_HAL_CB_CXN:
2223  hal->callback.cxn = func;
2224  hal->args.cxn = arg;
2225  break;
2227  hal->callback.unsolicited = func;
2228  hal->args.unsolicited = arg;
2229  break;
2230  case OCS_HAL_CB_BOUNCE:
2231  hal->callback.bounce = func;
2232  hal->args.bounce = arg;
2233  break;
2234  default:
2235  ocs_log_test(hal->os, "unknown callback %#x\n", which);
2236  return OCS_HAL_RTN_ERROR;
2237  }
2238 
2239  return OCS_HAL_RTN_SUCCESS;
2240 }
2241 
2242 
2243 /**
2244  * @ingroup io
2245  * @brief Add a receive buffer pair to the Receive Queue.
2246  *
2247  * @param hal Hardware context.
2248  * @param header DMA memory for the unsolicited header.
2249  * @param payload DMA memory for the unsolicited payload.
2250  *
2251  * @return Returns 0 on success, or a non-zero value otherwise.
2252  */
2255 {
2256  /* Verify header is not NULL and the physical address is not zeroes */
2257  if (header == NULL) {
2258  ocs_log_err(hal->os, "header is NULL\n");
2259  return OCS_HAL_RTN_ERROR;
2260  } else if (header->dma.phys == 0) {
2261  ocs_log_err(hal->os, "header physical address is zero\n");
2262  return OCS_HAL_RTN_ERROR;
2263  } else if (payload != NULL &&
2264  payload->dma.phys == 0) {
2265  ocs_log_err(hal->os, "payload physical address is zero\n");
2266  return OCS_HAL_RTN_ERROR;
2267  }
2268 
2269  /*
2270  * for iSCSI, we have have a header buffer without a data buffer.
2271  * The payload buffer here may be NULL. Check and don;t post NULL
2272  * buffers.
2273  */
2274 
2275  if (ocs_hal_rq_put(hal, header)) {
2276  return OCS_HAL_RTN_ERROR;
2277  }
2278 
2279  if (payload != NULL) {
2280  if (ocs_hal_rq_put(hal, payload)) {
2281  return OCS_HAL_RTN_ERROR;
2282  }
2283  }
2284 
2285  return OCS_HAL_RTN_SUCCESS;
2286 }
2287 
2288 
2289 static int32_t
2291 {
2292  ocs_lock(&hal->cmd_lock);
2293 
2294  /*
2295  * Manually clean up remaining commands. Note: since this calls
2296  * ocs_hal_command_process(), we'll also process the cmd_pending
2297  * list, so no need to manually clean that out.
2298  */
2299  while (!ocs_list_empty(&hal->cmd_head)) {
2300  uint8_t mqe[SLI4_BMBX_SIZE] = { 0 };
2301  sli4_mqe_hdr_t *mcqe_hdr = (sli4_mqe_hdr_t*)mqe;
2302  uint64_t tag;
2303 
2305 
2306  ocs_log_debug(hal->os, "hung command %08x\n",
2307  (NULL == ctx ? UINT32_MAX : *((uint32_t *)ctx->cmd)));
2308 
2309  /* put the context pointer into the tag */
2310  tag = (uintptr_t)ctx;
2311  mcqe_hdr->tag[0] = tag & 0xffffffff;
2312  mcqe_hdr->tag[1] = tag >> 32;
2313 
2314  ocs_unlock(&hal->cmd_lock);
2315  ocs_hal_command_process(hal, -1/*Bad status*/, mqe, SLI4_BMBX_SIZE);
2316  ocs_lock(&hal->cmd_lock);
2317  }
2318 
2319  /*
2320  * Manually clean up remaining async commands.
2321  */
2322  while (!ocs_list_empty(&hal->cmd_async)) {
2324 
2325  ocs_list_remove(&hal->cmd_async, ctx);
2326  ocs_list_add_tail(&hal->cmd_head, ctx);
2327 
2328  ocs_unlock(&hal->cmd_lock);
2329  ocs_hal_compl_async_ctx_bad_status(hal, ctx, -1, 0);
2330  ocs_lock(&hal->cmd_lock);
2331  }
2332 
2333  ocs_unlock(&hal->cmd_lock);
2334 
2335  return 0;
2336 }
2337 
2338 /**
2339  * @ingroup devInitShutdown
2340  * @brief Free the command contents.
2341  *
2342  * @par Description
2343  * Frees the command contest structures
2344  *
2345  * @param hal Hardware context allocated by caller.
2346  */
2347 static void
2349 {
2350  ocs_command_ctx_t *ctx;
2351 
2352  /* Free the command contexts */
2353  while (!ocs_list_empty(&hal->cmd_head)) {
2354  ctx = ocs_list_get_head(&hal->cmd_head);
2356  ocs_free(hal->os, ctx, sizeof(ocs_command_ctx_t));
2357  }
2358 
2359  while (!ocs_list_empty(&hal->cmd_pending)) {
2360  ctx = ocs_list_get_head(&hal->cmd_pending);
2362  ocs_free(hal->os, ctx, sizeof(ocs_command_ctx_t));
2363  }
2364 
2365  while (!ocs_list_empty(&hal->cmd_async)) {
2366  ctx = ocs_list_get_head(&hal->cmd_async);
2368  ocs_free(hal->os, ctx, sizeof(ocs_command_ctx_t));
2369  }
2370 }
2371 
2372 /**
2373  * @ingroup devInitShutdown
2374  * @brief Free the connection tracking structures.
2375  *
2376  * @par Description
2377  * Frees the connection tracking structures
2378  *
2379  * @param list Pointer to the linked list to clean up.
2380  */
2381 static void
2382 ocs_hal_cxn_cleanup(ocs_list_t *list)
2383 {
2384  ocs_cxn_t *cxn;
2385 
2386  /* Free the connection contexts */
2387  while (!ocs_list_empty(list)) {
2388  cxn = ocs_list_get_head(list);
2389  ocs_list_remove_head(list);
2390  ocs_lock_free(&cxn->active_ios_lock);
2391  ocs_node_lock_free(cxn);
2392  ocs_free(cxn->ocs, cxn, sizeof(ocs_cxn_t));
2393  }
2394 }
2395 
2396 /**
2397  * @ingroup devInitShutdown
2398  * @brief Tear down Hardware Abstraction Layer module.
2399  *
2400  * @par Description
2401  * Frees memory structures needed by the device and shuts down the device. Does
2402  * not free HAL context memory (done by caller).
2403  *
2404  * @param hal Hardware context allocated by caller.
2405  *
2406  * @return Returns 0 on success, or a non-zero value otherwise.
2407  */
2410 {
2411  uint8_t cmd[SLI4_BMBX_SIZE];
2412  uint32_t i = 0;
2413  uint32_t iters = 10;/*XXX*/
2414  ocs_sli_port_t *sport;
2415  uint16_t ulp_curr;
2416  int32_t rc;
2417 
2418  if (!hal) {
2419  ocs_log_err(NULL, "bad parameter(s) hal=%p\n", hal);
2420  return OCS_HAL_RTN_ERROR;
2421  }
2422 
2423  /* Clear the global interrupt enable bit */
2424  sli_interrupt_set(&hal->sli, FALSE);
2425 
2426  /* If there are outstanding commands, wait for them to complete */
2427  while (!ocs_list_empty(&hal->cmd_head) && iters) {
2428  ocs_delay_usec(10000);
2429  ocs_hal_flush(hal);
2430  iters--;
2431  }
2432 
2433  if (ocs_list_empty(&hal->cmd_head)) {
2434  ocs_log_debug(hal->os, "All commands completed on MQ queue\n");
2435  } else {
2436  ocs_log_debug(hal->os, "Some commands still pending on MQ queue\n");
2437  }
2438 
2439  // Cancel any remaining commands
2441  ocs_lock_free(&hal->cmd_lock);
2442 
2443  ulp_curr = hal->ulp_start;
2444  if (hal->is_hal_initialized) {
2445  for (i = 0; i < hal->config.n_rq; i += 2) {
2446  /* Issue the cleanup for the rx queues */
2447  if (hal->use_v1_multi_protocol) {
2448  rc = sli_cmd_iscsi_cleanup_v1(&hal->sli, cmd, SLI4_BMBX_SIZE, 0,
2449  ulp_curr + 1, /* uses 1 for ULP 0 */
2450  hal->rq[i].id,
2451  hal->rq[i+1].id);
2452  } else {
2453  rc = sli_cmd_iscsi_cleanup_v0(&hal->sli, cmd, SLI4_BMBX_SIZE, 0,
2454  ulp_curr + 1, /* uses 1 for ULP 0 */
2455  hal->rq[i].id,
2456  hal->rq[i+1].id);
2457  }
2458  if (rc) {
2459  if (ocs_hal_command_bootstrap(hal, cmd)) {
2460  ocs_log_test(hal->os,
2461  "iSCSI cleanup failed for queue index %d\n", i);
2462  }
2463  }
2464  ulp_curr++;
2465  }
2466 
2467  for (i = 0; i < hal->config.n_wq; i++) {
2468  sli_queue_free(&hal->sli, &hal->wq[i]);
2469  if (NULL != hal->wq[i].u.wq.wqe_context) {
2470  ocs_free(hal->os, hal->wq[i].u.wq.wqe_context,
2472  hal->wq[i].u.wq.wqe_context = NULL;
2473  }
2474  }
2475  ocs_free(hal->os, hal->wq, sizeof(sli4_queue_t) * hal->config.n_wq);
2476 
2477  for (i = 0; i < hal->config.n_rq; i++) {
2478  sli_queue_free(&hal->sli, &hal->rq[i]);
2479  }
2480 
2481  for (i = 0; i < hal->config.n_cq; i++) {
2482  sli_queue_free(&hal->sli, &hal->cq[i]);
2483  }
2484  ocs_free(hal->os, hal->cq, sizeof(sli4_queue_t) * hal->config.n_cq);
2485  for (i = 0; i < hal->config.n_eq; i++) {
2486  sli_queue_free(&hal->sli, &hal->eq[i]);
2487  ocs_free(hal->os, hal->pending_cqs[i],
2488  sizeof(sli4_queue_t*) * hal->config.n_cq);
2489  }
2490 
2491  for (i = 0; i < hal->config.n_mq; i++) {
2492  sli_queue_free(&hal->sli, &hal->mq[i]);
2493  }
2494  }
2495 
2496  hal->is_hal_initialized = FALSE;
2497 
2498  if (sli_teardown(&hal->sli)) {
2499  ocs_log_err(hal->os, "SLI teardown failed\n");
2500  }
2501 
2502  if (hal->io) {
2503  ocs_free(hal->os, hal->io, hal->config.n_io * sizeof(ocs_hal_io_t));
2504  hal->io = NULL;
2505  }
2506 
2507  if (hal->sgl_info) {
2508  ocs_free(hal->os, hal->sgl_info, hal->config.n_io * sizeof(ocs_hal_sgl_info_t));
2509  hal->sgl_info = NULL;
2510  }
2511 
2512  ocs_hal_ctx_cleanup(hal);
2514 
2515  if (hal->domain != NULL) {
2516  ocs_domain_lock(hal->domain);
2517  ocs_list_foreach(&hal->domain->sport_list, sport) {
2518  ocs_sport_lock(sport);
2519  ocs_hal_cxn_cleanup(&sport->node_list);
2520  ocs_sport_unlock(sport);
2521  }
2522  ocs_domain_unlock(hal->domain);
2523  hal->domain->node_instance_count = 0;
2524  }
2525  ocs_lock_free(&hal->cxn_lock);
2526 
2527  if (hal->sli.port_type == SLI4_PORT_TYPE_ISCSI_INI ||
2529  ocs_dma_free(hal->os, &hal->dataout_tmpl_mem);
2530  }
2531  ocs_dma_free(hal->os, &hal->bhs_mem);
2532  ocs_memset(&hal->bhs_mem, 0, sizeof(ocs_dma_t));
2533 
2534  ocs_dma_free(hal->os, &hal->isns_mem);
2535  ocs_memset(&hal->isns_mem, 0, sizeof(ocs_dma_t));
2536 
2537  ocs_queue_history_free(&hal->q_hist);
2538 
2539  ocs_lock_free(&hal->io_lock);
2540 
2541  for (i=0; i < OCS_HAL_MAX_NUM_RQ; i++) {
2542  if (hal->rq_lookup[i]) {
2543  ocs_free(hal->os, hal->rq_lookup[i], sizeof(ocs_hal_rq_lookup_t) * hal->rq[i].length);
2544  }
2545 
2546  if (hal->rq_list[i]) {
2547  ocs_free(hal->os, hal->rq_list[i], sizeof(ocs_hal_rq_list_t) * hal->rq[i].length);
2548  }
2549  }
2550 
2551  /* Free rq buffers */
2552  ocs_hal_rx_free(hal);
2553 
2554  return OCS_HAL_RTN_SUCCESS;
2555 }
2556 
2559 {
2560  ocs_sli_port_t *sport;
2561  uint32_t i;
2562  uint32_t j;
2563  uint32_t iters;
2564 
2565  /*
2566  * If an mailbox command requiring a DMA is outstanding (i.e. SFP/DDM),
2567  * then the FW will UE when the reset is issued. So attempt to complete
2568  * all mailbox commands.
2569  */
2570  iters = 10;
2571  while (!ocs_list_empty(&hal->cmd_head) && iters) {
2572  ocs_delay_usec(10000);
2573  ocs_hal_flush(hal);
2574  iters--;
2575  }
2576 
2577  if (ocs_list_empty(&hal->cmd_head)) {
2578  ocs_log_debug(hal->os, "All commands completed on MQ queue\n");
2579  } else {
2580  ocs_log_debug(hal->os, "Some commands still pending on MQ queue\n");
2581  }
2582 
2583  hal->is_hal_initialized = FALSE;
2584 
2585  switch(reset) {
2587  sli_reset(&hal->sli);
2588  break;
2590  if (sli_fw_reset(&hal->sli)) {
2591  ocs_log_err(hal->os, "sli_soft_reset failed\n");
2592  return OCS_HAL_RTN_ERROR;
2593  }
2594  return OCS_HAL_RTN_SUCCESS;
2595  break;
2596  default:
2597  ocs_log_test(hal->os, " Undefined reset type\n");
2598  return OCS_HAL_RTN_ERROR;
2599  }
2600 
2602  /* ocs_hal_io_cancel(hal); */
2603 
2604  ocs_hal_ctx_cleanup(hal);
2606 
2607  if (hal->domain != NULL) {
2608  ocs_domain_lock(hal->domain);
2609  ocs_list_foreach(&hal->domain->sport_list, sport) {
2610  ocs_sport_unlock(sport);
2611  ocs_hal_cxn_cleanup(&sport->node_list);
2612  ocs_sport_unlock(sport);
2613  }
2614  ocs_domain_unlock(hal->domain);
2615  hal->domain->node_instance_count = 0;
2616  }
2617 
2618  for (i = 0; i < hal->config.n_wq; i++) {
2619  sli_queue_reset(&hal->sli, &hal->wq[i]);
2620  if (NULL != hal->wq[i].u.wq.wqe_context) {
2621  ocs_free(hal->os, hal->wq[i].u.wq.wqe_context,
2623  hal->wq[i].u.wq.wqe_context = NULL;
2624  }
2625  sli_queue_free(&hal->sli, &hal->wq[i]);
2626  }
2627  ocs_free(hal->os, hal->wq, sizeof(sli4_queue_t) * hal->config.n_wq);
2628 
2629  for (i = 0; i < hal->config.n_rq; i++) {
2630  sli_queue_reset(&hal->sli, &hal->rq[i]);
2631  }
2632 
2633  for (i=0; i < hal->config.n_rq; i++) {
2634  ocs_list_init(&hal->rq_list_busy[i], ocs_hal_rq_list_t, link);
2635  ocs_list_init(&hal->rq_list_free[i], ocs_hal_rq_list_t, link);
2636  for (j = 0; j < hal->rq[i].length; j++) {
2638  &hal->rq_list[i][j]);
2639  }
2640  }
2641 
2642  for (i = 0; i < hal->config.n_mq; i++) {
2643  sli_queue_reset(&hal->sli, &hal->mq[i]);
2644  }
2645 
2646  for (i = 0; i < hal->config.n_cq; i++) {
2647  sli_queue_reset(&hal->sli, &hal->cq[i]);
2648  }
2649  ocs_free(hal->os, hal->cq, sizeof(sli4_queue_t) * hal->config.n_cq);
2650 
2651  for (i = 0; i < hal->config.n_eq; i++) {
2652  sli_queue_reset(&hal->sli, &hal->eq[i]);
2653  ocs_free(hal->os, hal->pending_cqs[i], sizeof(sli4_queue_t*) * hal->config.n_cq);
2654  }
2655 
2656  return OCS_HAL_RTN_SUCCESS;
2657 }
2658 
2659 int32_t
2661 {
2662  return hal->config.n_eq;
2663 }
2664 
2666 ocs_hal_get(ocs_hal_t *hal, ocs_hal_property_e prop, uint32_t *value)
2667 {
2669 
2670  if (!value) {
2671  return OCS_HAL_RTN_ERROR;
2672  }
2673 
2674  *value = 0;
2675 
2676  switch (prop) {
2677  case OCS_HAL_N_IO:
2678  *value = hal->config.n_io;
2679  break;
2680  case OCS_HAL_N_CXNS:
2681  *value = hal->config.n_wq;
2682  break;
2683  case OCS_HAL_RQ_QUEUE_SIZE:
2684  *value = sli_get_max_qentries(&hal->sli, SLI_QTYPE_RQ);
2685  break;
2687  *value = hal->config.rq_pl_size;
2688  break;
2689  case OCS_HAL_MAX_IO:
2690  *value = hal->sli.config.max_ios;
2691  break;
2692  case OCS_HAL_MAX_SGE:
2693  *value = sli_get_max_sge(&hal->sli);
2694  break;
2695  case OCS_HAL_LINK_SPEED:
2696  *value = hal->link.speed;
2697  break;
2698  case OCS_HAL_IF_TYPE:
2699  *value = sli_get_if_type(&hal->sli);
2700  break;
2701  case OCS_HAL_SLI_REV:
2702  *value = sli_get_sli_rev(&hal->sli);
2703  break;
2704  case OCS_HAL_SLI_FAMILY:
2705  *value = sli_get_sli_family(&hal->sli);
2706  break;
2707  case OCS_HAL_PCI_FUNCTION:
2708  *value = hal->sli.pf_num;
2709  break;
2711  *value = sli_is_sgl_chaining_capable(&hal->sli);
2712  break;
2714  *value = hal->config.enable_sgl_chaining;
2715  break;
2716  case OCS_HAL_DIF_CAPABLE:
2717  *value = sli_is_dif_capable(&hal->sli);
2718  break;
2719  case OCS_HAL_DIF_MODE:
2720  *value = hal->config.dif_mode;
2721  break;
2723  *value = hal->sli.config.num_sges_per_icd;
2724  break;
2726  *value = hal->sli.config.post_sgl_ver;
2727  break;
2728  case OCS_HAL_NUM_CHUTES:
2729  *value = 1;
2730  if (sli_is_dual_ulp_capable(&hal->sli) &&
2731  sli_is_ulp_enabled(&hal->sli, 0) &&
2732  sli_is_ulp_enabled(&hal->sli, 1)) {
2733  (*value)++;
2734  }
2735  break;
2736  case OCS_HAL_VPD_LEN:
2737  *value = sli_get_vpd_len(&hal->sli);
2738  break;
2740  *value = FALSE;
2741  break;
2742  case OCS_HAL_MAC_ADDR:
2743  case OCS_HAL_VPD:
2744  default:
2745  ocs_log_test(hal->os, "unsupported property %#x\n", prop);
2746  rc = OCS_HAL_RTN_ERROR;
2747  }
2748 
2749  return rc;
2750 }
2751 
2752 void *
2754 {
2755  void *rc = NULL;
2756 
2757  switch (prop) {
2758  case OCS_HAL_MAC_ADDR:
2759  rc = hal->sli.mac_addr;
2760  break;
2761  case OCS_HAL_VPD:
2762  /* make sure VPD length is non-zero */
2763  if (hal->sli.vpd.length) {
2764  rc = ((uint8_t*)hal->sli.vpd.data.virt) + sizeof(sli4_res_hdr_t);
2765  }
2766  break;
2767  case OCS_HAL_FW_REV:
2768  rc = hal->sli.config.fw_version;
2769  break;
2770  case OCS_HAL_FW_REV2:
2771  rc = hal->sli.config.fw_on_flash_version;
2772  break;
2773  case OCS_HAL_IPL:
2774  rc = sli_get_ipl_name(&hal->sli);
2775  break;
2776  case OCS_HAL_SFP_A0:
2777  rc = hal->sli.sfp_a0;
2778  break;
2779  case OCS_HAL_SFP_A2:
2780  rc = hal->sli.sfp_a2;
2781  break;
2782  default:
2783  ocs_log_test(hal->os, "unsupported property %#x\n", prop);
2784  }
2785 
2786  return rc;
2787 }
2788 
2790 ocs_hal_set(ocs_hal_t *hal, ocs_hal_property_e prop, uint32_t value)
2791 {
2793  uint32_t dif_inline;
2794  uint32_t dif_separate;
2795 
2796  switch (prop) {
2797  case OCS_HAL_N_IO:
2798  if (value > hal->sli.config.max_ios) {
2799  ocs_log_test(hal->os, "IO value out of range %d vs %d\n",
2800  value, hal->sli.config.max_ios);
2801  rc = OCS_HAL_RTN_ERROR;
2802  } else {
2803  hal->config.n_io = value;
2804  }
2805  break;
2806  case OCS_HAL_N_CXNS:
2807  if (value > sli_get_max_queue(&hal->sli, SLI_QTYPE_WQ)) {
2808  ocs_log_test(hal->os, "NODE value out of range %d vs %d\n",
2809  value, sli_get_max_queue(&hal->sli, SLI_QTYPE_WQ));
2810  rc = OCS_HAL_RTN_ERROR;
2811  } else {
2812  hal->config.n_wq = value;
2813  }
2814  break;
2816  if (value > 8192) {
2817  ocs_log_test(hal->os, "NODE value out of range %d vs %d\n",
2818  value, 8192);
2819  rc = OCS_HAL_RTN_ERROR;
2820  } else {
2821  hal->config.rq_pl_size = value;
2822  }
2823  break;
2825  if (sli_is_sgl_chaining_capable(&hal->sli)) {
2826  hal->config.enable_sgl_chaining = value;
2827  } else {
2828  ocs_log_test(hal->os, "Feature not supported\n");
2829  rc = OCS_HAL_RTN_ERROR;
2830  }
2831  break;
2833  if (value == 32 || value == 256) {
2834  hal->sli.config.num_sges_per_icd = value;
2835  } else {
2836  ocs_log_test(hal->os, "Invalid num SGEs per ICD of %d\n", value);
2837  rc = OCS_HAL_RTN_ERROR;
2838  }
2839  break;
2841  if (value == 0) {
2842  hal->sli.config.post_sgl_ver = value;
2843  } else if (value == 1) {
2844  if (hal->sli.is_skyhawk) {
2845  hal->sli.config.post_sgl_ver = value;
2846  } else {
2847  ocs_log_test(hal->os, "Post SGL version 1 not supported on this chip\n");
2848  rc = OCS_HAL_RTN_ERROR;
2849  }
2850  } else {
2851  ocs_log_test(hal->os, "Invalid post SGL version of %d\n", value);
2852  rc = OCS_HAL_RTN_ERROR;
2853  }
2854  break;
2855  case OCS_HAL_DIF_MODE:
2856  dif_inline = sli_is_dif_inline_capable(&hal->sli);
2857  dif_separate = sli_is_dif_separate_capable(&hal->sli);
2858 
2859  switch (value) {
2861  /*
2862  * Make sure we support inline DIF.
2863  *
2864  * Note: Having both bits clear means that we have old
2865  * FW that doesn't set the bits.
2866  */
2867  if (sli_is_dif_inline_capable(&hal->sli) ||
2868  (sli_is_dif_capable(&hal->sli) &&
2869  dif_inline == 0 &&
2870  dif_separate == 0)) {
2871  hal->config.dif_mode = value;
2872  } else {
2873  ocs_log_test(hal->os, "chip does not support DIF inline\n");
2874  rc = OCS_HAL_RTN_ERROR;
2875  }
2876  break;
2878  /* Make sure we support DIF separates. */
2879  if (sli_is_dif_separate_capable(&hal->sli)) {
2880  hal->config.dif_mode = value;
2881  } else {
2882  ocs_log_test(hal->os, "chip does not support DIF separate\n");
2883  rc = OCS_HAL_RTN_ERROR;
2884  }
2885  }
2886  break;
2887  default:
2888  ocs_log_test(hal->os, "unsupported property %#x\n", prop);
2889  rc = OCS_HAL_RTN_ERROR;
2890  break;
2891  }
2892 
2893  return rc;
2894 }
2895 
2898 {
2900 
2901  switch (prop) {
2902  case OCS_HAL_WAR_VERSION:
2903  hal->hal_war_version = value;
2904  break;
2905  default:
2906  ocs_log_test(hal->os, "unsupported property %#x\n", prop);
2907  rc = OCS_HAL_RTN_ERROR;
2908  break;
2909  }
2910  return rc;
2911 }
2912 
2913 
2914 /**
2915  * @ingroup interrupt
2916  * @brief Check for events associated with the interrupt vector.
2917  *
2918  * @param hal Hardware context.
2919  * @param vector Zero-based interrupt vector number.
2920  *
2921  * @return Returns 0 on success, or a non-zero value otherwise.
2922  */
2923 int32_t
2924 ocs_hal_event_check(ocs_hal_t *hal, uint32_t vector)
2925 {
2926  int32_t rc;
2927 
2928  if (!hal) {
2929  ocs_log_err(NULL, "HAL context NULL?!?\n");
2930  return -1;
2931  } else if (!hal->is_hal_initialized) {
2932  return -1;
2933  }
2934 
2935  if (vector > hal->config.n_eq) {
2936  ocs_log_err(hal->os, "vector %d. max %d\n", vector, hal->config.n_eq);
2937  return -1;
2938  }
2939  rc = sli_queue_is_empty(&hal->sli, &hal->eq[vector]);
2940 
2941  /* Re-arm queue if there are no entries */
2942  if (rc != 0) {
2943  sli_queue_arm(&hal->sli, &hal->eq[vector], TRUE);
2944  }
2945  return rc;
2946 }
2947 
2948 /**
2949  * @ingroup interrupt
2950  * @brief Process events associated with the interrupt vector.
2951  *
2952  * @par Description
2953  * Loop termination:
2954  * @n @n
2955  * Without a mechanism to terminate the completion processing loop, it
2956  * is possible under some workload conditions for the loop to never terminate
2957  * (or at least take longer than the OS is happy to have an interrupt handler
2958  * or kernel thread context hold a CPU without yielding).
2959  * @n @n
2960  * The approach taken here is to periodically check how much time we've been in this
2961  * processing loop, and if we exceed a predetermined time (multiple seconds), the
2962  * loop is terminated, and ocs_hal_process() returns.
2963  *
2964  * @param hal Hardware context.
2965  * @param vector Zero-based interrupt vector number.
2966  * @param max_isr_time_msec Maximum time, in msec, to stay in this function
2967  *
2968  * @return Returns 0 on success, or a non-zero on failure.
2969  */
2970 int32_t
2971 ocs_hal_process(ocs_hal_t *hal, uint32_t vector, uint32_t max_isr_time_msec)
2972 {
2973  uint8_t eqe[sizeof(sli4_eqe_t)] = { 0 };
2974  sli4_queue_t *eq = NULL;
2975  uint32_t done = FALSE;
2976  uint32_t tcheck_count;
2977  time_t tstart;
2978  time_t telapsed;
2979 
2980  /* Return on spurious interrupts */
2981  if (!hal->is_hal_initialized ||
2982  hal->has_fw_ue) {
2983  return -1;
2984  }
2985 
2986  eq = &hal->eq[vector];
2987 
2988  tcheck_count = OCS_HAL_TIMECHECK_ITERATIONS;
2989  tstart = ocs_msectime();
2990 
2991  while (!done && !sli_queue_read(&hal->sli, eq, eqe)) {
2992  /* EQ automatically dis-arms after generating interrupt */
2993  uint16_t cq_id = 0;
2994  int32_t index;
2995 
2996  sli_eq_parse(&hal->sli, eqe, &cq_id);
2997 
2998  index = ocs_hal_cq_find(hal, cq_id);
2999 
3000  if (likely(index >= 0)) {
3001  ocs_hal_cq_process(hal, &hal->cq[index]);
3002  } else {
3003  ocs_log_err(hal->os, "bad CQ_ID %#06x\n", cq_id);
3004  }
3005 
3006  if (eq->n_posted > eq->posted_limit) {
3007  sli_queue_arm(&hal->sli, eq, FALSE);
3008  }
3009 
3010  if (tcheck_count && (--tcheck_count == 0)) {
3011  tcheck_count = OCS_HAL_TIMECHECK_ITERATIONS;
3012  telapsed = ocs_msectime() - tstart;
3013  if (telapsed >= max_isr_time_msec) {
3014  done = TRUE;
3015  }
3016  }
3017  }
3018  sli_queue_arm(&hal->sli, eq, TRUE);
3019 
3020  return 0;
3021 }
3022 
3023 /**
3024  * @ingroup domain
3025  * @brief Adds a domain object.
3026  *
3027  * @par Description
3028  * This is a placeholder in iSCSI.
3029  *
3030  * @param hal Hardware context.
3031  * @param sport SLI port object used to connect to domain.
3032  * @param domain Pointer to domain object.
3033  *
3034  * @return Returns 0 on success, or a non-zero value otherwise.
3035  */
3037 ocs_hal_domain_add(ocs_hal_t *hal, ocs_sli_port_t *sport, ocs_domain_t *domain)
3038 {
3040 
3041  if (hal->domain == NULL) {
3042  sport->domain = domain;
3043  domain->sport = sport;
3044  hal->domain = domain;
3045  rc = OCS_HAL_RTN_SUCCESS;
3046  }
3047 
3048  return rc;
3049 }
3050 
3051 /**
3052  * @ingroup domain
3053  * @brief Free a domain object.
3054  *
3055  * @param hal Hardware context.
3056  * @param domain Pointer to the domain object.
3057  *
3058  * @return Returns 0 on success, or a non-zero value otherwise.
3059  */
3061 ocs_hal_domain_free(ocs_hal_t *hal, ocs_domain_t *domain)
3062 {
3064 
3065  if (!hal || !domain) {
3066  ocs_log_err(hal ? hal->os : NULL, "bad parameter(s) hal=%p domain=%p\n",
3067  hal, domain);
3068  rc = OCS_HAL_RTN_ERROR;
3069  } else if (domain != hal->domain) {
3070  ocs_log_err(hal->os, "domain=%p does not match hal pointer %p\n",
3071  domain, hal->domain);
3072  return OCS_HAL_RTN_ERROR;
3073  } else {
3074  hal->domain = NULL;
3075  }
3076 
3077  return rc;
3078 }
3079 
3080 /**
3081  * @brief Send the callback for a network interface delete command.
3082  *
3083  * @param hal Hardware context.
3084  * @param status Status from the MQE.
3085  * @param ctx Pointer to the command context.
3086  *
3087  * @return Returns 0 on success, or a non-zero value otherwise.
3088  */
3089 static int32_t
3091 {
3092  sli4_res_hdr_t *hdr;
3093 
3094  hdr = (sli4_res_hdr_t*)(ctx->cmd + sizeof(sli4_mqe_hdr_t));
3095 
3096  if (ctx->portal_cb) {
3097  if ((status == 0) && hdr->status) {
3098  status = hdr->status;
3099  }
3100 
3101  ctx->portal_cb(ctx->upper_arg,
3102  status,
3103  hdr->additional_status,
3104  NULL);
3105  }
3106  return 0;
3107 }
3108 
3109 
3110 /**
3111  * @ingroup port
3112  * @brief Set the MAC address on the portal.
3113  *
3114  * @param hal Hardware context.
3115  * @param mac_address MAC address to set.
3116  * @param portal_cb Pointer to the function to call when the operation completes.
3117  * @param ul_arg Pointer to the argument to pass back to portal_cb().
3118  *
3119  * @return Returns 0 on success, or a non-zero value otherwise.
3120  */
3122 ocs_hal_portal_set_mac(ocs_hal_t *hal, uint8_t *mac_address,
3123  portal_cb_t portal_cb, void* ul_arg)
3124 {
3126  ocs_command_ctx_t *ctx;
3127 
3128  if (hal->sli.is_skyhawk) {
3129  ocs_log_test(hal->os, "not implemented for skyhawk\n");
3130  return OCS_HAL_RTN_ERROR;
3131  }
3132 
3133  ctx = ocs_hal_command_get_ctx(hal);
3134  if (ctx == NULL) {
3135  ocs_log_err(hal->os, "no buffer for command\n");
3136  return OCS_HAL_RTN_NO_RESOURCES;
3137  }
3138  ctx->portal_cb = portal_cb;
3139  ctx->upper_arg = ul_arg;
3141 
3143  SLI4_BMBX_SIZE, 0,
3144  mac_address)) {
3145  rc = ocs_hal_command_queue(hal, ctx);
3146  if (rc) {
3147  ocs_log_test(hal->os, "Error posting SET_BE_CONFIG\n");
3148  }
3149  } else {
3150  ocs_hal_command_free_ctx(hal, ctx);
3151  ocs_log_test(hal->os, "Error building SET_BE_CONFIG message\n");
3152  rc = OCS_HAL_RTN_ERROR;
3153  }
3154  return rc;
3155 }
3156 
3157 
3158 /**
3159  * @ingroup port
3160  * @brief Enable Jumbo frame support on the portal.
3161  *
3162  * @param hal Hardware context.
3163  * @param is_jumbo If TRUE, then jumbo frames are enabled, otherwise the standard
3164  * Ethernet frame size is set.
3165  * @param portal_cb Pointer to the function to call when the operation completes.
3166  * @param ul_arg Pointer to the argument to pass back to portal_cb().
3167  *
3168  * @return Returns 0 on success, or a non-zero value otherwise.
3169  */
3172  uint8_t is_jumbo,
3173  portal_cb_t portal_cb, void* ul_arg)
3174 {
3176  ocs_command_ctx_t *ctx;
3177 
3178  ctx = ocs_hal_command_get_ctx(hal);
3179  if (ctx == NULL) {
3180  ocs_log_err(hal->os, "no buffer for command\n");
3181  return OCS_HAL_RTN_NO_RESOURCES;
3182  }
3183  ctx->portal_cb = portal_cb;
3184  ctx->upper_arg = ul_arg;
3186 
3187  if (sli_cmd_iscsi_ntwk_set_mtu(&hal->sli, ctx->cmd,
3188  SLI4_BMBX_SIZE, 0,
3189  (is_jumbo ? 8342 : 1500))) {
3190  rc = ocs_hal_command_queue(hal, ctx);
3191  if (rc) {
3192  ocs_log_test(hal->os, "Error posting SET_MTU\n");
3193  } else {
3194  hal->is_jumbo_set = is_jumbo;
3195  }
3196  } else {
3197  ocs_hal_command_free_ctx(hal, ctx);
3198  ocs_log_test(hal->os, "Error building SET_MTU message\n");
3199  rc = OCS_HAL_RTN_ERROR;
3200  }
3201 
3202  return rc;
3203 }
3204 
3205 
3206 /**
3207  * @ingroup port
3208  * @brief Return the default portal.
3209  *
3210  * @param hal Hardware context.
3211  *
3212  * @return Returns a pointer to the default portal.
3213  */
3216 {
3217  return hal->sli.iface_default;
3218 }
3219 
3220 /**
3221  * @brief Send the callback for a network interface create command.
3222  *
3223  * @param hal Hardware context.
3224  * @param status Status from the MQE.
3225  * @param ctx Pointer to the command context.
3226  *
3227  * @return Returns 0 on success, or a non-zero value otherwise.
3228  */
3229 static int32_t
3231 {
3233 
3235  (ctx->cmd + sizeof(sli4_mqe_hdr_t));
3236 
3237  if (ctx->portal_cb) {
3238  if ((status == 0) && resp->hdr.status) {
3239  status = resp->hdr.status;
3240  }
3241 
3242  ctx->portal_cb(ctx->upper_arg,
3243  status,
3244  resp->hdr.additional_status,
3245  (void*)(uintptr_t)resp->iface);
3246  }
3247  return 0;
3248 }
3249 
3250 
3251 /**
3252  * @ingroup port
3253  * @brief Create a new VLAN interface handle.
3254  *
3255  * @param hal Hardware context.
3256  * @param vlan_tag The vlan and priority.
3257  * @param portal_cb Pointer to the function to call when the operation completes.
3258  * @param ul_arg Pointer to the argument to pass back to portal_cb().
3259  *
3260  * @return Returns 0 on success, or a non-zero value otherwise.
3261  */
3264  unsigned int vlan_tag,
3265  portal_cb_t portal_cb,
3266  void *ul_arg)
3267 {
3269  ocs_command_ctx_t *ctx;
3270 
3271  ctx = ocs_hal_command_get_ctx(hal);
3272  if (ctx == NULL) {
3273  ocs_log_err(hal->os, "no buffer for command\n");
3274  return OCS_HAL_RTN_NO_RESOURCES;
3275  }
3276  ctx->portal_cb = portal_cb;
3277  ctx->upper_arg = ul_arg;
3279 
3280  if (sli_cmd_iscsi_common_iface_create(&hal->sli, ctx->cmd, SLI4_BMBX_SIZE, 0, vlan_tag)) {
3281  rc = ocs_hal_command_queue(hal, ctx);
3282  if (rc) {
3283  ocs_log_err(hal->os, "Error posting IFACE_CREATE\n");
3284  ocs_hal_command_free_ctx(hal, ctx);
3285  }
3286  } else {
3287  ocs_log_err(hal->os, "Error building IFACE_CREATE message\n");
3288  ocs_hal_command_free_ctx(hal, ctx);
3289  rc = OCS_HAL_RTN_ERROR;
3290  }
3291 
3292  return rc;
3293 }
3294 
3295 /**
3296  * @ingroup port
3297  * @brief Delete a VLAN interface handle.
3298  *
3299  * @param hal Hardware context.
3300  * @param portal Portal handle to remove.
3301  * @param portal_cb Pointer to the function to call when the operation completes.
3302  * @param ul_arg Pointer to the argument to pass back to portal_cb().
3303  *
3304  * @return Returns 0 on success, or a non-zero value otherwise.
3305  */
3308  portal_cb_t portal_cb, void* ul_arg)
3309 {
3311  ocs_command_ctx_t *ctx;
3312 
3313  ctx = ocs_hal_command_get_ctx(hal);
3314  if (ctx == NULL) {
3315  ocs_log_err(hal->os, "no buffer for command\n");
3316  return OCS_HAL_RTN_NO_RESOURCES;
3317  }
3318  ctx->portal_cb = portal_cb;
3319  ctx->upper_arg = ul_arg;
3321 
3322  if (sli_cmd_iscsi_common_iface_delete(&hal->sli, ctx->cmd, SLI4_BMBX_SIZE, 0, (uint32_t)portal)) {
3323  rc = ocs_hal_command_queue(hal, ctx);
3324  if (rc) {
3325  ocs_log_err(hal->os, "Error posting IFACE_DELETE\n");
3326  ocs_hal_command_free_ctx(hal, ctx);
3327  }
3328  } else {
3329  ocs_log_err(hal->os, "Error building IFACE_DELETE message\n");
3330  ocs_hal_command_free_ctx(hal, ctx);
3331  rc = OCS_HAL_RTN_ERROR;
3332  }
3333 
3334  return rc;
3335 }
3336 
3337 /**
3338  * @brief Called for the mailbox completion of command waiting for async messages.
3339  *
3340  * @par Description
3341  * We must wait for the asynchronous message completion that the operation
3342  * is complete; so we queue the request and wait for the event.
3343  *
3344  * @param hal Hardware context.
3345  * @param status Status from the MQE.
3346  * @param ctx Pointer to the command context.
3347  *
3348  * @return Returns 0 on success, or a non-zero value otherwise.
3349  */
3350 static int32_t
3352 {
3353  sli4_res_hdr_t *hdr;
3354  int32_t rc;
3355 
3356  hdr = (sli4_res_hdr_t*)(ctx->cmd + sizeof(sli4_mqe_hdr_t));
3357  if ((status == 0) && hdr->status) {
3358  status = hdr->status;
3359  }
3360 
3361  if (status) {
3362  rc = ocs_hal_portal_std_cb_no_parms(hal, status, ctx);
3363  } else {
3364  /*
3365  * We need to wait for the async message that the DHCP operation is
3366  * complete, then issue the get_if_info to retrieve the address.
3367  */
3368  rc = RC_MOVE_ASYNC;
3369  }
3370  return rc;
3371 }
3372 
3373 
3374 /**
3375  * @brief Called for the completion of retrieving the iSNS discovered list.
3376  *
3377  * @par Description
3378  * This callback is the end of the sequence. The IP address list is returned
3379  * to the caller.
3380  *
3381  * @param hal Hardware context.
3382  * @param status Status from the MQE.
3383  * @param ctx Pointer to the command context.
3384  *
3385  * @return Returns 0 on success, or a non-zero value otherwise.
3386  */
3387 static int32_t
3389 {
3391  ocs_hal_ip_address_t ip[8];
3392  uint32_t indx;
3393 
3395  (ctx->cmd + sizeof(sli4_mqe_hdr_t));
3396 
3397  if (ctx->portal_cb) {
3398  ocs_memset(ip, 0, sizeof(ocs_hal_ip_address_t) * 8);
3399 
3400  for(indx = 0; indx < resp->ip_count; indx++) {
3402  (resp->ip[indx].ip_type);
3403  ocs_memcpy(ip[indx].ip_address, resp->ip[indx].ip_addr, 16);
3404  }
3405 
3406  if ((status == 0) && resp->hdr.status) {
3407  status = resp->hdr.status;
3408  }
3409 
3410  ctx->portal_cb(ctx->upper_arg,
3411  status,
3412  resp->hdr.additional_status,
3413  (status == 0 ? ip : NULL));
3414  }
3415  return 0;
3416 }
3417 
3418 
3419 /**
3420  * @brief Called for the completion if get_if_info for a configure stateless command.
3421  *
3422  * This callback is the end of the sequence. The IP address list is searched
3423  * for the assigned IP address.
3424  *
3425  * @param hal Hardware context.
3426  * @param status Status from the MQE
3427  * @param ctx pointer to the command context
3428  *
3429  * @return Returns 0 on success, or a non-zero value otherwise.
3430  */
3431 static int32_t
3433 {
3436 
3438  (ctx->cmd + sizeof(sli4_mqe_hdr_t));
3439 
3440  if (ctx->portal_cb) {
3441  /*
3442  * Only handle a single DHCP address for now, once DHCP
3443  * client ID is exported, then this code will need to be
3444  * modified to choose the proper address.
3445  */
3446  if (resp->ip_count != 1) {
3447  ocs_log_debug(hal->os, "no IP addresses found\n");
3448  status = -1;
3449  } else {
3450  ip.ip_type = ctx->ip_type;
3451  ocs_memcpy(ip.ip_address, resp->addr[0].ip_addr, 16);
3452  ocs_memcpy(ip.subnet, resp->addr[0].subnet, 16);
3453  }
3454 
3455  if ((status == 0) && resp->hdr.status) {
3456  ocs_log_test(hal->os, "bad mailbox status of 0x%x\n",
3457  resp->hdr.status);
3458  status = resp->hdr.status;
3459  }
3460 
3461  ctx->portal_cb(ctx->upper_arg,
3462  status,
3463  resp->hdr.additional_status,
3464  (status == 0 ? &ip : NULL));
3465  }
3466  return 0;
3467 }
3468 
3469 /**
3470  * @brief Called for the completion of Set Route table command.
3471  *
3472  * @param hal Hardware context.
3473  * @param status Status from the MQE.
3474  * @param ctx Pointer to the command context.
3475  *
3476  * @return Returns 0 on success, or a non-zero value otherwise.
3477  */
3478 int32_t
3480  ocs_command_ctx_t *ctx)
3481 {
3483 
3485  ctx->non_emdedded_mem.virt;
3486 
3487  if (resp->hdr.status || resp->hdr.additional_status) {
3488  ocs_log_err(hal->os, "Set route table failed "
3489  "status 0x%x, ext_status 0x%x\n",
3490  resp->hdr.status, resp->hdr.additional_status);
3491  }
3492 
3493  if (ctx->portal_cb) {
3494  if ((status == 0) && resp->hdr.status) {
3495  status = resp->hdr.status;
3496  }
3497 
3498  ctx->portal_cb(ctx->upper_arg,
3499  status,
3500  resp->hdr.additional_status,
3501  NULL);
3502  }
3503 
3504  ocs_dma_free(hal->os, &(ctx->non_emdedded_mem));
3505  return 0;
3506 }
3507 
3508 /**
3509  * @brief Called for the completion of Get Route table command.
3510  *
3511  * @param hal Hardware context.
3512  * @param status Status from the MQE.
3513  * @param ctx Pointer to the command context.
3514  *
3515  * @return Returns 0 on success, or a non-zero value otherwise.
3516  */
3517 int32_t
3519  ocs_command_ctx_t *ctx)
3520 {
3522  ocs_iscsi_route_table_t *route_table;
3523  uint32_t inx;
3524 
3526  ctx->non_emdedded_mem.virt;
3527  if (resp->hdr.status || resp->hdr.additional_status) {
3528  ocs_log_err(hal->os, "Get route table failed "
3529  "status 0x%x, ext_status 0x%x\n",
3530  resp->hdr.status, resp->hdr.additional_status);
3531  }
3532 
3533  route_table = ocs_malloc(hal->os, sizeof(*route_table),
3534  OCS_M_ZERO|OCS_M_NOWAIT);
3535  if (route_table == NULL) {
3536  ocs_log_err(hal->os, "Failed to allocate memory\n");
3537  goto exit_free;
3538  }
3539 
3540  if (ctx->portal_cb) {
3541  if ((status == 0) && resp->hdr.status) {
3542  status = resp->hdr.status;
3543  }
3544 
3545  if (status == 0 && resp->hdr.additional_status == 0) {
3546  route_table->entry_count = resp->entry_count;
3547  for (inx = 0; inx < resp->entry_count; inx++) {
3548  route_table->entry[inx].ip_addr.ip_type =
3549  resp->entry[inx].ip_sub.ip_type;
3550  route_table->entry[inx].subnet.ip_type =
3551  resp->entry[inx].ip_sub.ip_type;
3552  route_table->entry[inx].gateway.ip_type =
3553  resp->entry[inx].gateway.ip_type;
3554 
3555  ocs_memcpy(route_table->entry[inx].ip_addr.ip_address,
3556  resp->entry[inx].ip_sub.ip_addr, 16);
3557  ocs_memcpy(route_table->entry[inx].subnet.ip_address,
3558  resp->entry[inx].ip_sub.subnet, 16);
3559  ocs_memcpy(route_table->entry[inx].gateway.ip_address,
3560  resp->entry[inx].gateway.ip_addr, 16);
3561  }
3562  }
3563 
3564  ctx->portal_cb(ctx->upper_arg,
3565  status,
3566  resp->hdr.additional_status,
3567  route_table);
3568  }
3569 
3570  if (route_table) {
3571  ocs_free(hal->os, route_table, sizeof(*route_table));
3572  }
3573 
3574 exit_free:
3575  ocs_dma_free(hal->os, &(ctx->non_emdedded_mem));
3576  return 0;
3577 }
3578 
3579 /**
3580  * @ingroup port
3581  * @brief Add/Remove an entry to routing table
3582  *
3583  * @param hal Hardware context.
3584  * @param ipsub the IP address and subnet mask to add/remove
3585  * @param gateway the gateway address to add/remove
3586  * @param add a non-zero to add, otherwise to remove
3587  * @param portal_cb pointer to the function to call when the operation completes
3588  * @param ul_arg pointer to the argument to pass back to portal_cb().
3589  *
3590  * @return Returns 0 on success, or a non-zero value otherwise.
3591  */
3594  ocs_hal_ip_address_subnet_t *hal_ipsub,
3595  ocs_hal_ip_address_t *hal_gateway,
3596  int32_t add,
3597  portal_cb_t portal_cb,
3598  void *ul_arg)
3599 {
3601  ocs_command_ctx_t *ctx;
3602  ocs_dma_t route_table;
3603  uint32_t payload_size;
3604 
3605  ctx = ocs_hal_command_get_ctx(hal);
3606  if (ctx == NULL) {
3607  ocs_log_err(hal->os, "no buffer for command\n");
3608  return OCS_HAL_RTN_NO_RESOURCES;
3609  }
3610 
3611  /* Payload length must accomodate both request and response */
3612  payload_size = max(sizeof(sli4_req_common_iscsi_ntwk_set_route_table_t),
3614 
3615  rc = ocs_dma_alloc(hal->os, &route_table, payload_size, 4);
3616  if (rc) {
3617  ocs_hal_command_free_ctx(hal, ctx);
3618  ocs_log_err(hal->os, "DMA alloc for set route table failed\n");
3619  return rc;
3620  }
3621 
3622  ctx->portal = 0;
3623  ctx->portal_cb = portal_cb;
3624  ctx->upper_arg = ul_arg;
3626  ctx->non_emdedded_mem = route_table;
3627 
3629  SLI4_BMBX_SIZE, 0, add,
3630  hal_ipsub, hal_gateway,
3631  &route_table)) {
3632  rc = ocs_hal_command_queue(hal, ctx);
3633  if (rc) {
3634  ocs_log_err(hal->os,
3635  "Error posting set route table command\n");
3636  }
3637  } else {
3638  ocs_log_err(hal->os, "Error building set route table command\n");
3639  rc = OCS_HAL_RTN_ERROR;
3640  }
3641 
3642  /* Free resources on error */
3643  if (rc) {
3644  ocs_dma_free(hal->os, &route_table);
3645  ocs_hal_command_free_ctx(hal, ctx);
3646  }
3647 
3648  return rc;
3649 }
3650 
3651 /**
3652  * @ingroup port
3653  * @brief Read routing table
3654  *
3655  * @param hal Hardware context.
3656  * @param portal_cb pointer to the function to call when the operation completes
3657  * @param ul_arg pointer to the argument to pass back to portal_cb().
3658  *
3659  * @return Returns 0 on success, or a non-zero value otherwise.
3660  */
3662  portal_cb_t portal_cb,
3663  void *ul_arg)
3664 {
3666  ocs_command_ctx_t *ctx;
3667  ocs_dma_t route_table;
3668  uint32_t payload_size;
3669 
3670  ctx = ocs_hal_command_get_ctx(hal);
3671  if (ctx == NULL) {
3672  ocs_log_err(hal->os, "no buffer for command\n");
3673  return OCS_HAL_RTN_NO_RESOURCES;
3674  }
3675 
3676  /* Payload length must accomodate both request and response */
3677  payload_size = max(sizeof(sli4_req_common_iscsi_ntwk_get_route_table_t),
3679 
3680  rc = ocs_dma_alloc(hal->os, &route_table, payload_size, 4);
3681  if (rc) {
3682  ocs_hal_command_free_ctx(hal, ctx);
3683  ocs_log_err(hal->os, "DMA alloc for set route table failed\n");
3684  return rc;
3685  }
3686 
3687  ctx->portal = 0;
3688  ctx->portal_cb = portal_cb;
3689  ctx->upper_arg = ul_arg;
3691  ctx->non_emdedded_mem = route_table;
3692 
3694  SLI4_BMBX_SIZE, 0,
3695  &route_table)) {
3696  rc = ocs_hal_command_queue(hal, ctx);
3697  if (rc) {
3698  ocs_log_err(hal->os, "Error posting set route table command\n");
3699  }
3700  } else {
3701  ocs_log_err(hal->os, "Error building set route table command\n");
3702  rc = OCS_HAL_RTN_ERROR;
3703  }
3704 
3705  /* Free resources on error */
3706  if (rc) {
3707  ocs_dma_free(hal->os, &route_table);
3708  ocs_hal_command_free_ctx(hal, ctx);
3709  }
3710 
3711  return rc;
3712 }
3713 
3714 /**
3715  * @ingroup port
3716  * @brief Add an IP address to an interface.
3717  *
3718  * @param hal Hardware context.
3719  * @param portal the portal handle
3720  * @param ipaddr the IP address to add
3721  * @param portal_cb pointer to the function to call when the operation completes
3722  * @param ul_arg pointer to the argument to pass back to portal_cb().
3723  *
3724  * @return Returns 0 on success, or a non-zero value otherwise.
3725  */
3729  portal_cb_t portal_cb, void* ul_arg)
3730 {
3731  ocs_command_ctx_t *ctx;
3732  ocs_hal_rtn_e rc;
3733  int32_t rc_cmd;
3734 
3735  /*valid the ip type before grabing a context */
3736  if (ipaddr->ip_type != OCS_HAL_IP_TYPE_DHCP_V4 &&
3737  ipaddr->ip_type != OCS_HAL_IP_TYPE_AUTO_V6 &&
3738  ipaddr->ip_type != OCS_HAL_IP_TYPE_V4 &&
3739  ipaddr->ip_type != OCS_HAL_IP_TYPE_V6) {
3740  ocs_log_test(hal->os, "Invalid IP address type %d\n", ipaddr->ip_type);
3741  return OCS_HAL_RTN_ERROR;
3742  }
3743 
3744  ctx = ocs_hal_command_get_ctx(hal);
3745  if (ctx == NULL) {
3746  ocs_log_err(hal->os, "no buffer for command\n");
3747  return OCS_HAL_RTN_NO_RESOURCES;
3748  }
3749  ctx->portal_cb = portal_cb;
3750  ctx->upper_arg = ul_arg;
3751  ctx->portal = portal;
3752  ctx->ip_type = ipaddr->ip_type;
3753 
3754  /* If IP type is DHCPv4 send configure stateless mailbox message.
3755  * If IP type is static(IPv4, IPv6) send network modify IP mailbox message.
3756  */
3757  if (ipaddr->ip_type == OCS_HAL_IP_TYPE_DHCP_V4 ||
3758  ipaddr->ip_type == OCS_HAL_IP_TYPE_AUTO_V6) {
3759  ctx->cb = ocs_hal_cb_wait_async;
3761  (&hal->sli, ctx->cmd, SLI4_BMBX_SIZE, 0,
3762  (uint32_t)portal,
3763  (ipaddr->ip_type == OCS_HAL_IP_TYPE_DHCP_V4),
3764  1);
3765  } else {
3768  (&hal->sli, ctx->cmd, SLI4_BMBX_SIZE, 0,
3769  (uint32_t)portal,
3770  TRUE, /* isadd */
3771  ipaddr);
3772  }
3773 
3774  if (rc_cmd) {
3775  rc = ocs_hal_command_queue(hal, ctx);
3776  if (rc) {
3777  ocs_log_err(hal->os, "Error posting IP Add\n");
3778  ocs_hal_command_free_ctx(hal, ctx);
3779  }
3780  } else {
3781  ocs_log_err(hal->os, "Error building message\n");
3782  ocs_hal_command_free_ctx(hal, ctx);
3783  rc = OCS_HAL_RTN_ERROR;
3784  }
3785 
3786  return rc;
3787 }
3788 
3789 /**
3790  * @ingroup port
3791  * @brief Removes an IP address from an interface.
3792  *
3793  * @param hal Hardware context.
3794  * @param portal the portal handle
3795  * @param ipaddr the IP address to remove
3796  * @param portal_cb pointer to the function to call when the operation completes
3797  * @param ul_arg pointer to the argument to pass back to portal_cb().
3798  *
3799  * @return Returns 0 on success, or a non-zero value otherwise.
3800  */
3804  portal_cb_t portal_cb, void* ul_arg)
3805 {
3807  ocs_command_ctx_t *ctx;
3808  int32_t rc_cmd;
3809 
3810  /*valid the ip type before grabing a context */
3811  if (ipaddr->ip_type != OCS_HAL_IP_TYPE_DHCP_V4 &&
3812  ipaddr->ip_type != OCS_HAL_IP_TYPE_AUTO_V6 &&
3813  ipaddr->ip_type != OCS_HAL_IP_TYPE_V4 &&
3814  ipaddr->ip_type != OCS_HAL_IP_TYPE_V6) {
3815  ocs_log_test(hal->os, "Invalid IP address type %d\n", ipaddr->ip_type);
3816  return OCS_HAL_RTN_ERROR;
3817  }
3818 
3819  ctx = ocs_hal_command_get_ctx(hal);
3820  if (ctx == NULL) {
3821  ocs_log_err(hal->os, "no buffer for command\n");
3822  return OCS_HAL_RTN_NO_RESOURCES;
3823  }
3824  ctx->portal_cb = portal_cb;
3825  ctx->upper_arg = ul_arg;
3826  ctx->portal = portal;
3827  ctx->ip_type = ipaddr->ip_type;
3828 
3829  /* If IP type is DHCPv4 send configure stateless mailbox message.
3830  * If IP type is static(IPv4, IPv6) send network modify IP mailbox message.
3831  */
3832  if (ipaddr->ip_type == OCS_HAL_IP_TYPE_DHCP_V4 ||
3833  ipaddr->ip_type == OCS_HAL_IP_TYPE_AUTO_V6) {
3836  (&hal->sli, ctx->cmd, SLI4_BMBX_SIZE, 0,
3837  (uint32_t)portal,
3838  (ipaddr->ip_type == OCS_HAL_IP_TYPE_DHCP_V4));
3839  } else {
3842  (&hal->sli, ctx->cmd, SLI4_BMBX_SIZE, 0,
3843  (uint32_t)portal,
3844  FALSE, /* isadd */
3845  ipaddr);
3846  }
3847 
3848  if (rc_cmd) {
3849  rc = ocs_hal_command_queue(hal, ctx);
3850  if (rc) {
3851  ocs_log_err(hal->os, "Error posting IP Remove\n");
3852  ocs_hal_command_free_ctx(hal, ctx);
3853  }
3854  } else {
3855  ocs_log_err(hal->os, "Error building message\n");
3856  ocs_hal_command_free_ctx(hal, ctx);
3857  rc = OCS_HAL_RTN_ERROR;
3858  }
3859 
3860  return rc;
3861 }
3862 
3863 
3864 /**
3865  * @brief Called for the completion if get_if_info for a user request.
3866  *
3867  * @param hal Hardware context.
3868  * @param status The status from the MQE
3869  * @param ctx pointer to the command context
3870  *
3871  * @return Returns 0 on success, or a non-zero value otherwise.
3872  */
3873 static int32_t
3875  ocs_command_ctx_t *ctx)
3876 {
3878  ocs_hal_get_ip_t rtn;
3879  uint32_t i;
3880 
3882  (ctx->cmd + sizeof(sli4_mqe_hdr_t));
3883 
3884  if (ctx->portal_cb) {
3885  if ((status == 0) && resp->hdr.status) {
3886  status = resp->hdr.status;
3887  }
3888 
3889  if (status == 0) {
3890  ocs_memset(&rtn, 0, sizeof(ocs_hal_get_ip_t));
3891  rtn.portal = ctx->portal;
3892  rtn.vlan_priority = resp->vlan_priority;
3894  rtn.ip_count = resp->ip_count;
3895  for (i = 0; i < 5 && i < resp->ip_count; i++) {
3896  rtn.ipsub[i].ip_type =
3898  ocs_memcpy(rtn.ipsub[i].ip_address, resp->addr[i].ip_addr, 16);
3899  ocs_memcpy(rtn.ipsub[i].subnet, resp->addr[i].subnet, 16);
3900  }
3901  }
3902 
3903  ctx->portal_cb(ctx->upper_arg,
3904  status,
3905  resp->hdr.additional_status,
3906  (status == 0 ? &rtn : NULL));
3907  }
3908  return 0;
3909 }
3910 
3911 
3912 /**
3913  * @ingroup port
3914  * @brief Retrieves the IP addresses on an interface.
3915  *
3916  * @param hal Hardware context.
3917  * @param portal the portal handle
3918  * @param ip_type the type of IP addresses to retrieve
3919  * @param portal_cb pointer to the function to call when the operation completes
3920  * @param ul_arg pointer to the argument to pass back to portal_cb().
3921  *
3922  * @return Returns 0 on success, or a non-zero value otherwise.
3923  */
3926  ocs_hal_ip_type_e ip_type,
3927  portal_cb_t portal_cb, void* ul_arg)
3928 {
3930  ocs_command_ctx_t *ctx;
3931  uint8_t isv4 = (ip_type == OCS_HAL_IP_TYPE_V4 ||
3932  ip_type == OCS_HAL_IP_TYPE_DHCP_V4);
3933 
3934  ctx = ocs_hal_command_get_ctx(hal);
3935  if (ctx == NULL) {
3936  ocs_log_err(hal->os, "no buffer for command\n");
3937  return OCS_HAL_RTN_NO_RESOURCES;
3938  }
3939  ctx->portal = portal;
3940  ctx->portal_cb = portal_cb;
3941  ctx->upper_arg = ul_arg;
3943 
3945  (&hal->sli, ctx->cmd, SLI4_BMBX_SIZE, 0,
3946  (uint32_t)portal, isv4)) {
3947  rc = ocs_hal_command_queue(hal, ctx);
3948  if (rc) {
3949  ocs_log_err(hal->os, "Error posting getting IF info\n");
3950  ocs_hal_command_free_ctx(hal, ctx);
3951  }
3952  } else {
3953  ocs_log_err(hal->os, "Error building get IF info\n");
3954  ocs_hal_command_free_ctx(hal, ctx);
3955  rc = OCS_HAL_RTN_ERROR;
3956  }
3957 
3958  return rc;
3959 }
3960 
3961 
3962 /**
3963  * @brief Called for the completion of get_default_gateway for a user request.
3964  *
3965  * @param hal Hardware context.
3966  * @param status The status from the MQE
3967  * @param ctx pointer to the command context
3968  *
3969  * @return Returns 0 on success, or a non-zero value otherwise.
3970  */
3971 static int32_t
3973  ocs_command_ctx_t *ctx)
3974 {
3977 
3979  (ctx->cmd + sizeof(sli4_mqe_hdr_t));
3980 
3981  if (ctx->portal_cb) {
3982  if ((status == 0) && resp->hdr.status) {
3983  status = resp->hdr.status;
3984  }
3985  if (status == 0) {
3986  ocs_memset(&rtn, 0, sizeof(ocs_hal_ip_address_t));
3988  ocs_memcpy(rtn.ip_address, resp->gateway.ip_addr, 16);
3989  }
3990 
3991  ctx->portal_cb(ctx->upper_arg,
3992  status,
3993  resp->hdr.additional_status,
3994  (status == 0 ? &rtn : NULL));
3995  }
3996  return 0;
3997 }
3998 
3999 
4000 /**
4001  * @ingroup port
4002  * @brief Retrieves the default gateway on an interface.
4003  *
4004  * @param hal Hardware context.
4005  * @param ip_type the type of IP interface to retrieve
4006  * @param portal_cb pointer to the function to call when the operation completes
4007  * @param ul_arg pointer to the argument to pass back to portal_cb().
4008  *
4009  * @return Returns 0 on success, or a non-zero value otherwise.
4010  */
4013  portal_cb_t portal_cb, void* ul_arg)
4014 {
4016  ocs_command_ctx_t *ctx;
4017 
4018  ctx = ocs_hal_command_get_ctx(hal);
4019  if (ctx == NULL) {
4020  ocs_log_err(hal->os, "no buffer for command\n");
4021  return OCS_HAL_RTN_NO_RESOURCES;
4022  }
4023  ctx->portal = 0;
4024  ctx->portal_cb = portal_cb;
4025  ctx->upper_arg = ul_arg;
4027 
4029  (&hal->sli, ctx->cmd, SLI4_BMBX_SIZE, 0,
4030  (ip_type == OCS_HAL_IP_TYPE_V4 ||
4031  ip_type == OCS_HAL_IP_TYPE_DHCP_V4))) {
4032  rc = ocs_hal_command_queue(hal, ctx);
4033  if (rc) {
4034  ocs_log_test(hal->os, "Error posting get default gateway\n");
4035  }
4036  } else {
4037  ocs_hal_command_free_ctx(hal, ctx);
4038  ocs_log_test(hal->os, "Error building get default gateway\n");
4039  rc = OCS_HAL_RTN_ERROR;
4040  }
4041 
4042  return rc;
4043 }
4044 
4045 /**
4046  * @ingroup port
4047  * @brief adds the default gateway on an interface.
4048  *
4049  * @param hal Hardware context.
4050  * @param gateway the IP gateway to add
4051  * @param portal_cb pointer to the function to call when the operation completes
4052  * @param ul_arg pointer to the argument to pass back to portal_cb().
4053  *
4054  * @return Returns 0 on success, or a non-zero value otherwise.
4055  */
4058  portal_cb_t portal_cb, void* ul_arg)
4059 {
4061  ocs_command_ctx_t *ctx;
4062 
4063  ctx = ocs_hal_command_get_ctx(hal);
4064  if (ctx == NULL) {
4065  ocs_log_err(hal->os, "no buffer for command\n");
4066  return OCS_HAL_RTN_NO_RESOURCES;
4067  }
4068  ctx->portal = 0;
4069  ctx->portal_cb = portal_cb;
4070  ctx->upper_arg = ul_arg;
4072 
4074  (&hal->sli, ctx->cmd, SLI4_BMBX_SIZE, 0,
4075  TRUE, gateway)) {
4076  rc = ocs_hal_command_queue(hal, ctx);
4077  if (rc) {
4078  ocs_log_test(hal->os, "Error posting modify default gateway\n");
4079  }
4080  } else {
4081  ocs_hal_command_free_ctx(hal, ctx);
4082  ocs_log_test(hal->os, "Error building modify default gateway\n");
4083  rc = OCS_HAL_RTN_ERROR;
4084  }
4085 
4086  return rc;
4087 }
4088 
4089 /**
4090  * @ingroup port
4091  * @brief removes a default gateway on an interface.
4092  *
4093  * @param hal Hardware context.
4094  * @param gateway the IP gateway to remove
4095  * @param portal_cb pointer to the function to call when the operation completes
4096  * @param ul_arg pointer to the argument to pass back to portal_cb().
4097  *
4098  * @return Returns 0 on success, or a non-zero value otherwise.
4099  */
4102  portal_cb_t portal_cb, void* ul_arg)
4103 {
4105  ocs_command_ctx_t *ctx;
4106 
4107  ctx = ocs_hal_command_get_ctx(hal);
4108  if (ctx == NULL) {
4109  ocs_log_err(hal->os, "no buffer for command\n");
4110  return OCS_HAL_RTN_NO_RESOURCES;
4111  }
4112  ctx->portal = 0;
4113  ctx->portal_cb = portal_cb;
4114  ctx->upper_arg = ul_arg;
4116 
4118  (&hal->sli, ctx->cmd, SLI4_BMBX_SIZE, 0,
4119  FALSE, gateway)) {
4120  rc = ocs_hal_command_queue(hal, ctx);
4121  if (rc) {
4122  ocs_log_test(hal->os, "Error posting modify default gateway\n");
4123  }
4124  } else {
4125  ocs_hal_command_free_ctx(hal, ctx);
4126  ocs_log_test(hal->os, "Error building modify default gateway\n");
4127  rc = OCS_HAL_RTN_ERROR;
4128  }
4129 
4130  return rc;
4131 }
4132 
4133 
4134 /**
4135  * @ingroup port
4136  * @brief Starts listening on a TCP port
4137  *
4138  * @param hal Hardware context.
4139  * @param ipaddr the IP address start listening
4140  * @param tcp_port The TCP port number
4141  * @param portal_cb pointer to the function to call when the operation completes
4142  * @param ul_arg pointer to the argument to pass back to portal_cb().
4143  *
4144  * @return Returns 0 on success, or a non-zero value otherwise.
4145  */
4148  uint32_t tcp_port,
4149  portal_cb_t portal_cb, void* ul_arg)
4150 {
4152  ocs_command_ctx_t *ctx;
4153 
4154  /*
4155  * Check the FW version
4156  */
4157  if (!ocs_hal_fw_valid(hal)) {
4158  ocs_log_err(hal->os, "ERROR: Current firmware version %s is older than the minimum supported version %s. Listen server not starting.\n",
4160  return OCS_HAL_RTN_ERROR;
4161  }
4162 
4163  ctx = ocs_hal_command_get_ctx(hal);
4164  if (ctx == NULL) {
4165  ocs_log_err(hal->os, "no buffer for command\n");
4166  return OCS_HAL_RTN_NO_RESOURCES;
4167  }
4168  ctx->portal_cb = portal_cb;
4169  ctx->upper_arg = ul_arg;
4171 
4173  SLI4_BMBX_SIZE, 0,
4174  ipaddr, tcp_port)) {
4175  rc = ocs_hal_command_queue(hal, ctx);
4176  if (rc) {
4177  ocs_log_test(hal->os, "Error posting START_LISTEN\n");
4178  }
4179  } else {
4180  ocs_hal_command_free_ctx(hal, ctx);
4181  ocs_log_test(hal->os, "Error building START_LISTEN message\n");
4182  rc = OCS_HAL_RTN_ERROR;
4183  }
4184 
4185  return rc;
4186 }
4187 
4188 /**
4189  * @ingroup port
4190  * @brief Stops listening on a TCP port
4191  *
4192  * @param hal Hardware context.
4193  * @param ipaddr the IP address stop listening
4194  * @param tcp_port The TCP port number
4195  * @param portal_cb pointer to the function to call when the operation completes
4196  * @param ul_arg pointer to the argument to pass back to portal_cb().
4197  *
4198  * @return Returns 0 on success, or a non-zero value otherwise.
4199  */
4202  uint32_t tcp_port,
4203  portal_cb_t portal_cb, void* ul_arg)
4204 {
4206  ocs_command_ctx_t *ctx;
4207 
4208  ctx = ocs_hal_command_get_ctx(hal);
4209  if (ctx == NULL) {
4210  ocs_log_err(hal->os, "no buffer for command\n");
4211  return OCS_HAL_RTN_NO_RESOURCES;
4212  }
4213  ctx->portal_cb = portal_cb;
4214  ctx->upper_arg = ul_arg;
4216 
4218  SLI4_BMBX_SIZE, 0,
4219  ipaddr, tcp_port)) {
4220  rc = ocs_hal_command_queue(hal, ctx);
4221  if (rc) {
4222  ocs_log_test(hal->os, "Error posting STOP_LISTEN\n");
4223  }
4224  } else {
4225  ocs_hal_command_free_ctx(hal, ctx);
4226  ocs_log_test(hal->os, "Error building STOP_LISTEN message\n");
4227  rc = OCS_HAL_RTN_ERROR;
4228  }
4229 
4230  return rc;
4231 }
4232 
4233 /**
4234  * @ingroup port
4235  * @brief Discovers iSNS servers via DHCP
4236  *
4237  * @param hal Hardware context.
4238  * @param portal the portal handle
4239  * @param portal_cb pointer to the function to call when the operation completes
4240  * @param ul_arg pointer to the argument to pass back to portal_cb().
4241  *
4242  * @return Returns 0 on success, or a non-zero value otherwise.
4243  */
4246  portal_cb_t portal_cb, void* ul_arg)
4247 {
4249  ocs_command_ctx_t *ctx;
4250 
4251  ctx = ocs_hal_command_get_ctx(hal);
4252  if (ctx == NULL) {
4253  ocs_log_err(hal->os, "no buffer for command\n");
4254  return OCS_HAL_RTN_NO_RESOURCES;
4255  }
4256  ctx->portal_cb = portal_cb;
4257  ctx->upper_arg = ul_arg;
4258  ctx->portal = portal;
4259  ctx->cb = ocs_hal_cb_wait_async;
4260 
4262  SLI4_BMBX_SIZE, 0,
4263  (uint32_t)portal, 1)) {
4264  rc = ocs_hal_command_queue(hal, ctx);
4265  if (rc) {
4266  ocs_log_test(hal->os, "Error posting iSNS Discover\n");
4267  }
4268  } else {
4269  ocs_hal_command_free_ctx(hal, ctx);
4270  ocs_log_test(hal->os, "Error building iSNS Discover message\n");
4271  rc = OCS_HAL_RTN_ERROR;
4272  }
4273 
4274  return rc;
4275 }
4276 
4277 
4278 /**
4279  * @brief Send the callback for the sending of an iSNS packet.
4280  *
4281  * @param hal Hardware context.
4282  * @param status The status from the MQE
4283  * @param ctx pointer to the command context
4284  *
4285  * @return Returns 0 on success, or a non-zero value otherwise.
4286  */
4287 static int32_t
4289 {
4290  sli4_mqe_hdr_t *mqe = (sli4_mqe_hdr_t *)ctx->cmd;
4291  sli4_res_hdr_t *hdr =
4292  (sli4_res_hdr_t *)(mqe->embedded ?
4293  (ctx->cmd + sizeof(sli4_mqe_hdr_t)) :
4294  hal->isns_mem.virt);
4295 
4296  if (ctx->portal_cb) {
4297  if ((status == 0) && hdr->status) {
4298  status = hdr->status;
4299  }
4300  ctx->portal_cb(ctx->upper_arg,
4301  status,
4302  hdr->additional_status,
4303  ((uint8_t*)hdr) + sizeof(sli4_res_hdr_t));
4304  }
4305  return 0;
4306 }
4307 
4308 
4309 /**
4310  * @ingroup port
4311  * @brief Sends an iSNS packet to the requested server
4312  *
4313  * @param hal Hardware context.
4314  * @param isns_server the IP of the iSNS server
4315  * @param tcp_port The TCP port number
4316  * @param packet virtual memory of the packet to send
4317  * @param pkt_len the length of the packet in bytes
4318  * @param portal_cb pointer to the function to call when the operation completes
4319  * @param ul_arg pointer to the argument to pass back to portal_cb().
4320  *
4321  * @return Returns 0 on success, or a non-zero value otherwise.
4322  */
4325  ocs_hal_ip_address_t *isns_server, uint32_t tcp_port,
4326  void *packet, uint32_t pkt_len,
4327  portal_cb_t portal_cb, void* ul_arg)
4328 {
4330  ocs_command_ctx_t *ctx;
4331 
4332  if (pkt_len > hal->isns_mem.size - sizeof(sli4_req_hdr_t)) {
4333  ocs_log_test(hal->os, "iSNS packet is too big for preallocated buffer\n");
4334  return OCS_HAL_RTN_ERROR;
4335  }
4336 
4337  ctx = ocs_hal_command_get_ctx(hal);
4338  if (ctx == NULL) {
4339  ocs_log_err(hal->os, "no buffer for command\n");
4340  return OCS_HAL_RTN_NO_RESOURCES;
4341  }
4342  ctx->portal_cb = portal_cb;
4343  ctx->upper_arg = ul_arg;
4345 
4346  if (sli_cmd_iscsi_tgt_isns_send_packet(&hal->sli, ctx->cmd,
4347  SLI4_BMBX_SIZE, 0,
4348  isns_server,
4349  tcp_port,
4350  packet,
4351  pkt_len,
4352  &hal->isns_mem)) {
4353  rc = ocs_hal_command_queue(hal, ctx);
4354  if (rc) {
4355  ocs_log_test(hal->os, "Error posting iSNS Send\n");
4356  }
4357  } else {
4358  ocs_hal_command_free_ctx(hal, ctx);
4359  ocs_log_test(hal->os, "Error building iSNS Send message\n");
4360  rc = OCS_HAL_RTN_ERROR;
4361  }
4362 
4363  return rc;
4364 }
4365 
4366 
4367 /**
4368  * @ingroup port
4369  * @brief Starts listening for iSNS ESI messages on a TCP port
4370  *
4371  * @param hal Hardware context.
4372  * @param ipaddr IP address start listening.
4373  * @param tcp_port TCP port number.
4374  * @param portal_cb Pointer to the function to call when the operation completes.
4375  * @param ul_arg Pointer to the argument to pass back to portal_cb().
4376  *
4377  * @return Returns 0 on success, or a non-zero value otherwise.
4378  */
4381  uint32_t tcp_port,
4382  portal_cb_t portal_cb, void* ul_arg)
4383 {
4385  ocs_command_ctx_t *ctx;
4386 
4387  ctx = ocs_hal_command_get_ctx(hal);
4388  if (ctx == NULL) {
4389  ocs_log_err(hal->os, "no buffer for command\n");
4390  return OCS_HAL_RTN_NO_RESOURCES;
4391  }
4392  ctx->portal_cb = portal_cb;
4393  ctx->upper_arg = ul_arg;
4395 
4396  if (sli_cmd_iscsi_tgt_start_esi_listen(&hal->sli, ctx->cmd,
4397  SLI4_BMBX_SIZE, 0,
4398  ipaddr, tcp_port)) {
4399  rc = ocs_hal_command_queue(hal, ctx);
4400  if (rc) {
4401  ocs_log_test(hal->os, "Error posting START_ESI_LISTEN\n");
4402  }
4403  } else {
4404  ocs_hal_command_free_ctx(hal, ctx);
4405  ocs_log_test(hal->os, "Error building START_ESI_LISTEN message\n");
4406  rc = OCS_HAL_RTN_ERROR;
4407  }
4408 
4409  return rc;
4410 }
4411 
4412 /**
4413  * @ingroup port
4414  * @brief Stops listening on an iSNS ESI TCP port.
4415  *
4416  * @param hal Hardware context.
4417  * @param ipaddr IP address to stop listening to.
4418  * @param tcp_port TCP port number.
4419  * @param portal_cb Pointer to the function to call when the operation completes.
4420  * @param ul_arg Pointer to the argument to pass back to portal_cb().
4421  *
4422  * @return Returns 0 on success, or a non-zero value otherwise.
4423  */
4426  uint32_t tcp_port,
4427  portal_cb_t portal_cb, void* ul_arg)
4428 {
4430  ocs_command_ctx_t *ctx;
4431 
4432  ctx = ocs_hal_command_get_ctx(hal);
4433  if (ctx == NULL) {
4434  ocs_log_err(hal->os, "no buffer for command\n");
4435  return OCS_HAL_RTN_NO_RESOURCES;
4436  }
4437  ctx->portal_cb = portal_cb;
4438  ctx->upper_arg = ul_arg;
4440 
4441  if (sli_cmd_iscsi_tgt_stop_esi_listen(&hal->sli, ctx->cmd,
4442  SLI4_BMBX_SIZE, 0,
4443  ipaddr, tcp_port)) {
4444  rc = ocs_hal_command_queue(hal, ctx);
4445  if (rc) {
4446  ocs_log_test(hal->os, "Error posting STOP_ESI_LISTEN\n");
4447  }
4448  } else {
4449  ocs_hal_command_free_ctx(hal, ctx);
4450  ocs_log_test(hal->os, "Error building STOP_ESI_LISTEN message\n");
4451  rc = OCS_HAL_RTN_ERROR;
4452  }
4453 
4454  return rc;
4455 }
4456 
4457 
4458 /**
4459  * @ingroup node
4460  * @brief Gets a free connection structure.
4461  *
4462  * @param hal Hardware context.
4463  * @param conn_hdl Connection handle received from the FW.
4464  *
4465  * @return Returns the connection pointer, or NULL if out of resources.
4466  */
4467 ocs_cxn_t *
4468 ocs_hal_cxn_alloc(ocs_hal_t *hal, uint32_t conn_hdl)
4469 {
4470  ocs_sli_port_t *sport;
4471  ocs_cxn_t * cxn = NULL;
4472 
4473  if (hal->domain != NULL) {
4474  ocs_domain_lock(hal->domain);
4475  sport = ocs_list_get_head(&hal->domain->sport_list);
4476  ocs_domain_unlock(hal->domain);
4477 
4478  ocs_lock(&hal->cxn_lock);
4479  cxn = ocs_list_get_head(&hal->cxn_free);
4480  if (NULL != cxn) {
4482  hal->domain->node_instance_count++;
4483  ocs_unlock(&hal->cxn_lock);
4484 
4485  cxn->conn_hdl = conn_hdl;
4486  cxn->tcp_mss = 0;
4487  cxn->sport = sport;
4488  cxn->is_ini_cxn = FALSE;
4489 
4490  ocs_sport_lock(sport);
4491  ocs_list_add_tail(&sport->node_list, cxn);
4492  ocs_sport_unlock(sport);
4493  } else {
4494  ocs_unlock(&hal->cxn_lock);
4495  ocs_log_err(hal->os, "failed to allocate a connection\n");
4496  }
4497  }
4498 
4499  return cxn;
4500 }
4501 
4502 
4503 /**
4504  * @brief Process the completion of a request for a new tcp connection.
4505  *
4506  * @param hal Hardware context.
4507  * @param status Status from the MQE.
4508  * @param ctx Pointer to the command context.
4509  *
4510  * @return Returns 0 on success, or a non-zero value otherwise.
4511  */
4512 static int32_t
4514 {
4515  ocs_cxn_t *cxn = ctx->cxn;
4518  (ctx->cmd + sizeof(sli4_mqe_hdr_t));
4519 
4520  cxn->conn_hdl = resp->conn_handle;
4521 
4522  if (ctx->cxn_cb) {
4523  if ((status == 0) && resp->hdr.status) {
4524  status = resp->hdr.status;
4525  }
4526  ctx->cxn_cb(ctx->upper_arg,
4527  status,
4528  resp->hdr.additional_status,
4529  NULL);
4530  }
4531  return 0;
4532 }
4533 
4534 
4535 /**
4536  * @ingroup node
4537  * @brief Establish a TCP connection from an initiator to a target.
4538  *
4539  * @param hal Hardware context.
4540  * @param cxn Pointer to the connection object.
4541  * @param ipaddr Target IP address.
4542  * @param tcp_port Target TCP port.
4543  * @param window_size TCP Window size to use for the connection.
4544  * @param window_scale TCP window scale value to use for the connection.
4545  * @param cxn_cb Pointer to the function to call when the operation completes.
4546  * @param ul_arg Pointer to the argument to pass back to cxn_cb().
4547  *
4548  * @return Returns 0 on success, or a non-zero value otherwise.
4549  */
4551 ocs_hal_cxn_connect(ocs_hal_t *hal, ocs_cxn_t *cxn,
4552  ocs_hal_ip_address_t *ipaddr, uint32_t tcp_port,
4553  uint16_t window_size, uint8_t window_scale,
4554  cxn_cb_t cxn_cb, void *ul_arg)
4555 {
4557  ocs_command_ctx_t *ctx;
4558  int32_t cmd_rc;
4559 
4560  /*
4561  * Check the FW version
4562  */
4563  if (!ocs_hal_fw_valid(hal)) {
4564  ocs_log_err(hal->os, "ERROR: Current firmware version %s is older than the minimum supported version %s. Connection rejected.\n",
4566  return OCS_HAL_RTN_ERROR;
4567  }
4568 
4569  ctx = ocs_hal_command_get_ctx(hal);
4570  if (ctx == NULL) {
4571  ocs_log_err(hal->os, "no buffer for command\n");
4572  return OCS_HAL_RTN_NO_RESOURCES;
4573  }
4574  ctx->cxn = cxn;
4575  ctx->cxn_cb = cxn_cb;
4576  ctx->upper_arg = ul_arg;
4578 
4579  /*
4580  * Set the cq_index to the appropraite initiator CQ.
4581  *
4582  * Note: We are splitting the ULPs onto separate interrupts. So we have
4583  * alternated the CQs between the EQs. Based on the ULP number
4584  * assigned to this WQ, we must map this to a CQ that is mapped to
4585  * the EQ for that ULP. This is strictly a driver desire for
4586  * balancing load across CPU cores.
4587  */
4588  cxn->cq_index = hal->cq_index_wq_ini +
4589  ((cxn->wq_index / (2 * OCS_HAL_CQ_NUM_FOR_INI)) % OCS_HAL_CQ_NUM_FOR_INI);
4590  if (hal->wq[cxn->wq_index].ulp != hal->cq[cxn->cq_index].ulp) {
4591  if ((cxn->cq_index + 1U) == hal->cq_index_mq) {
4592  cxn->cq_index = hal->cq_index_wq_ini;
4593  } else {
4594  cxn->cq_index++;
4595  }
4596  }
4597 
4598  ocs_log_debug(hal->os, "CQ[%d] on ULP %d assigned to WQ[%d], CQ id %d, WQ id %d/ULP %d, RQ[%d]\n",
4599  cxn->cq_index, hal->cq[cxn->cq_index].ulp,
4600  cxn->wq_index, hal->cq[cxn->cq_index].id,
4601  hal->wq[cxn->wq_index].id, hal->wq[cxn->wq_index].ulp,
4602  cxn->rqindex);
4603 
4604  if (hal->sli.is_skyhawk) {
4605  cmd_rc = sli_cmd_iscsi_tcp_connect_v1(&hal->sli, ctx->cmd, SLI4_BMBX_SIZE, 0,
4606  ipaddr, tcp_port, cxn->wq_id,
4607  hal->cq[cxn->cq_index].id,
4608  &cxn->dataout_tmpl,
4609  hal->rq[cxn->rqindex].id,
4610  hal->rq[cxn->rqindex+1].id,
4611  TRUE,
4612  window_size,
4613  window_scale,
4614  (hal->is_jumbo_set ? 8342 : 1500));
4615  } else {
4616  cmd_rc = sli_cmd_iscsi_tcp_connect_v0(&hal->sli, ctx->cmd, SLI4_BMBX_SIZE, 0,
4617  ipaddr, tcp_port, cxn->wq_id,
4618  hal->cq[cxn->cq_index].id,
4619  &cxn->dataout_tmpl,
4620  hal->rq[cxn->rqindex].id,
4621  hal->rq[cxn->rqindex+1].id,
4622  TRUE);
4623  }
4624  if (cmd_rc) {
4625  rc = ocs_hal_command_queue(hal, ctx);
4626  if (rc) {
4627  ocs_log_test(hal->os, "Error posting tcp connect\n");
4628  } else {
4629  cxn->is_ini_cxn = TRUE;
4630  }
4631  } else {
4632  ocs_hal_command_free_ctx(hal, ctx);
4633  ocs_log_test(hal->os, "Error building tcp connect message\n");
4634  rc = OCS_HAL_RTN_ERROR;
4635  }
4636 
4637  return rc;
4638 }
4639 
4640 
4641 /**
4642  * @brief Send the connection callback with no parameters passed back.
4643  *
4644  * @param hal Hardware context.
4645  * @param status Status from the MQE.
4646  * @param ctx Pointer to the command context.
4647  *
4648  * @return Returns 0 on success, or a non-zero value otherwise.
4649  */
4650 static int32_t
4652 {
4653  sli4_res_hdr_t *hdr;
4654 
4655  hdr = (sli4_res_hdr_t*)(ctx->cmd + sizeof(sli4_mqe_hdr_t));
4656 
4657  if (ctx->cxn_cb) {
4658  ctx->cxn_cb(ctx->upper_arg,
4659  hdr->status,
4660  hdr->additional_status,
4661  NULL);
4662  }
4663  return 0;
4664 }
4665 
4666 
4667 /**
4668  * @ingroup node
4669  * @brief Rejects an incoming connection on a target.
4670  *
4671  * @par Description
4672  * @b Note: This function is not using the ocs_cxn_t since most likely it is being
4673  * rejected because we are out of connection objects. No callback is
4674  * provided because we should not have allocated anything.
4675  *
4676  * @param hal Hardware context.
4677  * @param conn_hdl Connection handle received from the firmware.
4678  * @param cxn_cb Pointer to the function to call when the operation completes.
4679  * Parameter may be NULL.
4680  * @param ul_arg Pointer to the argument to pass back to cxn_cb().
4681  *
4682  * @return Returns 0 on success, or a non-zero value otherwise.
4683  */
4685 ocs_hal_cxn_reject(ocs_hal_t *hal, uint32_t conn_hdl,
4686  cxn_cb_t cxn_cb, void *ul_arg)
4687 {
4689  ocs_command_ctx_t *ctx;
4690 
4691  ctx = ocs_hal_command_get_ctx(hal);
4692  if (ctx == NULL) {
4693  ocs_log_err(hal->os, "no buffer for command\n");
4694  return OCS_HAL_RTN_NO_RESOURCES;
4695  }
4696  ctx->cxn = NULL;
4697  ctx->cxn_cb = cxn_cb;
4698  ctx->upper_arg = ul_arg;
4701  SLI4_BMBX_SIZE, 0,
4702  conn_hdl)) {
4703  rc = ocs_hal_command_queue(hal, ctx);
4704  if (rc) {
4705  ocs_log_test(hal->os, "Error posting connection reject\n");
4706  }
4707  } else {
4708  ocs_hal_command_free_ctx(hal, ctx);
4709  ocs_log_test(hal->os, "Error building connection reject message\n");
4710  rc = OCS_HAL_RTN_ERROR;
4711  }
4712 
4713  return rc;
4714 }
4715 
4716 
4717 /**
4718  * @brief Process the completion of a request for connection information.
4719  *
4720  * @param hal Hardware context.
4721  * @param status Status from the MQE.
4722  * @param ctx Pointer to the command context.
4723  *
4724  * @return Returns 0 on success, or a non-zero value otherwise.
4725  */
4726 static int32_t
4728 {
4729  ocs_cxn_t *cxn = ctx->cxn;
4730  uint8_t msg_status;
4731  uint8_t msg_addl_status;
4732 
4733 
4734  if (hal->sli.is_skyhawk) {
4737  (ctx->cmd + sizeof(sli4_mqe_hdr_t));
4738 
4739  msg_status = resp->hdr.status;
4740  msg_addl_status = resp->hdr.additional_status;
4741 
4742  ocs_memcpy(cxn->source_ip, resp->src_ip.ip_addr, 16);
4743  ocs_memcpy(cxn->dest_ip, resp->dest_ip.ip_addr, 16);
4744 
4745  cxn->source_ip_type = sli_iscsi_conv_hal_ip_addr_type(resp->src_ip.ip_type);
4746  cxn->source_port = resp->src_port;
4747  cxn->dest_ip_type = sli_iscsi_conv_hal_ip_addr_type(resp->dest_ip.ip_type);
4748  cxn->dest_port = resp->dest_port;
4749  cxn->tcp_mss = resp->tcp_mss;
4750  cxn->tcp_wscale = resp->wscale;
4751  } else {
4754  (ctx->cmd + sizeof(sli4_mqe_hdr_t));
4755 
4756  msg_status = resp->hdr.status;
4757  msg_addl_status = resp->hdr.additional_status;
4758 
4759  ocs_memcpy(cxn->source_ip, resp->src_ip.ip_addr, 16);
4760  ocs_memcpy(cxn->dest_ip, resp->dest_ip.ip_addr, 16);
4761 
4762  cxn->source_ip_type = sli_iscsi_conv_hal_ip_addr_type(resp->src_ip.ip_type);
4763  cxn->source_port = resp->src_port;
4764  cxn->dest_ip_type = sli_iscsi_conv_hal_ip_addr_type(resp->dest_ip.ip_type);
4765  cxn->dest_port = resp->dest_port;
4766  cxn->tcp_mss = resp->tcp_mss;
4767  cxn->tcp_wscale = 0;
4768  }
4769 
4770  if (ctx->cxn_cb) {
4771  if ((status == 0) && msg_status) {
4772  status = msg_status;
4773  }
4774  ctx->cxn_cb(ctx->upper_arg,
4775  status,
4776  msg_addl_status,
4777  NULL);
4778  }
4779  return 0;
4780 }
4781 
4782 
4783 /**
4784  * @ingroup node
4785  * @brief Retrieves information about an incoming context.
4786  *
4787  * @param hal Hardware context.
4788  * @param cxn Pointer to the connection object.
4789  * @param cxn_cb Pointer to the function to call when the operation completes.
4790  * @param ul_arg Pointer to the argument to pass back to cxn_cb().
4791  *
4792  * @return Returns 0 on success, or a non-zero value otherwise.
4793  */
4795 ocs_hal_cxn_get_info(ocs_hal_t *hal, ocs_cxn_t *cxn,
4796  cxn_cb_t cxn_cb, void *ul_arg)
4797 {
4799  ocs_command_ctx_t *ctx;
4800  int32_t cmd_rc;
4801 
4802  ctx = ocs_hal_command_get_ctx(hal);
4803  if (ctx == NULL) {
4804  ocs_log_err(hal->os, "no buffer for command\n");
4805  return OCS_HAL_RTN_NO_RESOURCES;
4806  }
4807  ctx->cxn = cxn;
4808  ctx->cxn_cb = cxn_cb;
4809  ctx->upper_arg = ul_arg;
4810  ctx->cb = ocs_hal_cxn_get_info_cb;
4811 
4812  if (hal->sli.is_skyhawk) {
4813  cmd_rc = sli_cmd_iscsi_get_connection_info(&hal->sli, ctx->cmd,
4814  SLI4_BMBX_SIZE, 0,
4815  cxn->conn_hdl);
4816  } else {
4817  cmd_rc = sli_cmd_iscsi_tgt_get_connection_info(&hal->sli, ctx->cmd,
4818  SLI4_BMBX_SIZE, 0,
4819  cxn->conn_hdl);
4820  }
4821 
4822  if (cmd_rc) {
4823  rc = ocs_hal_command_queue(hal, ctx);
4824  if (rc) {
4825  ocs_log_test(hal->os, "Error posting connection info\n");
4826  }
4827  } else {
4828  ocs_hal_command_free_ctx(hal, ctx);
4829  ocs_log_test(hal->os, "Error building connection info message\n");
4830  rc = OCS_HAL_RTN_ERROR;
4831  }
4832 
4833  return rc;
4834 }
4835 
4836 /**
4837  * @ingroup node
4838  * @brief Assign a CQ for the connection.
4839  *
4840  * @par Description
4841  * This function will attempt to find the CQ on the correct ULP with the least
4842  * number of connections.
4843  *
4844  * @param hal Hardware context.
4845  * @param cxn Pointer to the connection object.
4846  */
4847 static void
4848 ocs_hal_cxn_cq_select(ocs_hal_t *hal, ocs_cxn_t *cxn)
4849 {
4850  uint32_t lowest_inuse_count = 0xFFFFFFFF;
4851  uint8_t lowest_inuse_index = hal->cq_index_wq_tgt;
4852  uint32_t i;
4853 
4854  /*
4855  * Note: We are splitting the ULPs onto separate interrupts. So we have
4856  * alternated the CQs between the EQs. Based on the ULP number
4857  * assigned to this WQ, we must map this to a CQ that is mapped to
4858  * the EQ for that ULP. This is strictly a driver desire for
4859  * balancing load across CPU cores.
4860  */
4861  for (i = hal->cq_index_wq_tgt; i < hal->cq_index_wq_ini; i++) {
4862  ocs_lock(&hal->cq[i].lock);
4863  if (hal->wq[cxn->wq_index].ulp == hal->cq[i].ulp &&
4864  hal->cq[i].cxn_cnt < lowest_inuse_count &&
4865  hal->cq[i].cxn_cnt < hal->num_wq_per_cq) {
4866  lowest_inuse_count = hal->cq[i].cxn_cnt;
4867  lowest_inuse_index = i;
4868  }
4869  ocs_unlock(&hal->cq[i].lock);
4870  }
4871 
4872  ocs_lock(&hal->cq[lowest_inuse_index].lock);
4873  hal->cq[lowest_inuse_index].cxn_cnt++;
4874  cxn->cq_index = lowest_inuse_index;
4875  ocs_unlock(&hal->cq[lowest_inuse_index].lock);
4876 
4877  ocs_log_debug(hal->os, "CQ[%d], id %d on ULP %d assigned to WQ[%d], id %d on ULP %d, RQ[%d]\n",
4878  cxn->cq_index, hal->cq[cxn->cq_index].id,
4879  hal->cq[cxn->cq_index].ulp,
4880  cxn->wq_index, hal->wq[cxn->wq_index].id,
4881  hal->wq[cxn->wq_index].ulp,
4882  cxn->rqindex);
4883 }
4884 
4885 /**
4886  * @ingroup node
4887  * @brief Release a CQ for the connection.
4888  *
4889  * @par Description
4890  * This function will de-link the usage of a CQ for this connection.
4891  *
4892  * @param hal Hardware context.
4893  * @param cxn Pointer to the connection object.
4894  */
4895 static void
4896 ocs_hal_cxn_cq_release(ocs_hal_t *hal, ocs_cxn_t *cxn)
4897 {
4898  ocs_lock(&hal->cq[cxn->cq_index].lock);
4899  hal->cq[cxn->cq_index].cxn_cnt--;
4900  ocs_unlock(&hal->cq[cxn->cq_index].lock);
4901 }
4902 
4903 /**
4904  * @ingroup node
4905  * @brief Offloads an incoming connection on a target.
4906  *
4907  * @param hal Hardware context.
4908  * @param cxn Pointer to the connection object.
4909  * @param tcp_window_size TCP window size.
4910  * @param data_digest Set to 1 to enable data digests.
4911  * @param hdr_digest Set to 1 to enable header digests.
4912  * @param max_rcv_dsl Maximum receive data segment length.
4913  * @param cxn_cb Pointer to the function to call when the operation completes.
4914  * @param ul_arg Pointer to the argument to pass back to cxn_cb().
4915  *
4916  * @return Returns 0 on success, or a non-zero value otherwise.
4917  */
4919 ocs_hal_cxn_offload(ocs_hal_t *hal, ocs_cxn_t *cxn,
4920  uint32_t tcp_window_size,
4921  uint8_t data_digest,
4922  uint8_t hdr_digest,
4923  uint32_t max_rcv_dsl,
4924  cxn_cb_t cxn_cb, void *ul_arg)
4925 {
4927  ocs_command_ctx_t *ctx;
4928  ocs_hal_target_login_options_t lgn_options;
4929  int32_t msg_rc;
4930 
4931  ctx = ocs_hal_command_get_ctx(hal);
4932  if (ctx == NULL) {
4933  ocs_log_err(hal->os, "no buffer for command\n");
4934  return OCS_HAL_RTN_NO_RESOURCES;
4935  }
4936  ctx->cxn = cxn;
4937  ctx->cxn_cb = cxn_cb;
4938  ctx->upper_arg = ul_arg;
4940 
4941  /* No session established, so just use defaults */
4942  lgn_options.session_options.initial_r2t = 1;
4943  lgn_options.session_options.immediate_data = 0;
4944  lgn_options.session_options.data_pdu_in_order = 1;
4945  lgn_options.session_options.data_sequence_in_order = 1;
4946  lgn_options.session_options.error_recovery_level = 0;
4947  lgn_options.session_options.first_burst = 8192;
4948  lgn_options.session_options.max_burst = 65536;
4949  lgn_options.session_options.max_connections = 1;
4950  lgn_options.session_options.max_r2t = 1;
4951  lgn_options.session_options.def_time_to_wait = 2;
4952  lgn_options.session_options.def_time_to_retain = 0;
4953  lgn_options.data_digest = data_digest;
4954  lgn_options.hdr_digest = hdr_digest;
4955  lgn_options.max_rcv_dsl = max_rcv_dsl;
4956  lgn_options.max_send_dsl = max_rcv_dsl;
4957 
4958  ocs_hal_cxn_cq_select(hal, cxn);
4959 
4960  if (hal->use_v1_multi_protocol) {
4961  msg_rc = sli_cmd_iscsi_tgt_offload_connection_v1(&hal->sli, ctx->cmd,
4962  SLI4_BMBX_SIZE, 0,
4963  cxn->conn_hdl,
4964  tcp_window_size,
4965  hal->wq[cxn->wq_index].ulp + 1, /* Uses 1 for ULP 0 */
4966  cxn->wq_id,
4967  hal->cq[cxn->cq_index].id,
4968  hal->rq[cxn->rqindex].id,
4969  hal->rq[cxn->rqindex+1].id,
4970  1, /* NRS */
4971  &lgn_options);
4972  } else {
4973  msg_rc = sli_cmd_iscsi_tgt_offload_connection_v0(&hal->sli, ctx->cmd,
4974  SLI4_BMBX_SIZE, 0,
4975  cxn->conn_hdl,
4976  tcp_window_size,
4977  hal->wq[cxn->wq_index].ulp + 1, /* Uses 1 for ULP 0 */
4978  cxn->wq_id,
4979  hal->cq[cxn->cq_index].id,
4980  hal->rq[cxn->rqindex].id,
4981  hal->rq[cxn->rqindex+1].id,
4982  1, /* NRS */
4983  &lgn_options);
4984  }
4985  if (msg_rc) {
4986  rc = ocs_hal_command_queue(hal, ctx);
4987  if (rc) {
4988  ocs_log_test(hal->os, "Error posting connection offload\n");
4989  } else {
4990  cxn->is_ini_cxn = FALSE;
4991  }
4992  } else {
4993  ocs_hal_command_free_ctx(hal, ctx);
4994  ocs_log_test(hal->os, "Error building connection offload message\n");
4995  rc = OCS_HAL_RTN_ERROR;
4996  }
4997 
4998  return rc;
4999 }
5000 
5001 
5002 /**
5003  * @ingroup node
5004  * @brief Returns the number of free entries on the work queue for this
5005  * connection.
5006  *
5007  * @param hal Hardware context.
5008  * @param cxn Pointer to the connection object.
5009  *
5010  * @return Returns the number of free work queue entries.
5011  */
5012 uint32_t
5014 {
5015  if (hal != NULL &&
5016  cxn != NULL) {
5017  return sli_queue_iscsi_free_cnt(&hal->sli,
5018  &hal->wq[cxn->wq_index]);
5019  } else {
5020  return 0;
5021  }
5022 }
5023 
5024 
5025 /**
5026  * @ingroup node
5027  * @brief Invalidates a connection and optionally sends a TCP Reset
5028  *
5029  * @param hal Hardware context.
5030  * @param cxn Pointer to the connection object.
5031  * @param sendRst Non-zero sends a TCP reset on the connection.
5032  * @param cxn_cb Pointer to the function to call when the operation completes.
5033  * @param ul_arg Pointer to the argument to pass back to cxn_cb().
5034  *
5035  * @return Returns 0 on success, or a non-zero value otherwise.
5036  */
5038 ocs_hal_cxn_close(ocs_hal_t *hal, ocs_cxn_t *cxn, uint8_t sendRst,
5039  cxn_cb_t cxn_cb, void *ul_arg)
5040 {
5042  ocs_command_ctx_t *ctx;
5043 
5044  ctx = ocs_hal_command_get_ctx(hal);
5045  if (ctx == NULL) {
5046  ocs_log_err(hal->os, "no buffer for command\n");
5047  return OCS_HAL_RTN_NO_RESOURCES;
5048  }
5049  ctx->cxn = cxn;
5050  ctx->cxn_cb = cxn_cb;
5051  ctx->upper_arg = ul_arg;
5053 
5054  if (cxn->is_ini_cxn) {
5056  SLI4_BMBX_SIZE, 0,
5057  cxn->conn_hdl,
5058  cxn->wq_id,
5059  sendRst);
5060  } else {
5062  SLI4_BMBX_SIZE, 0,
5063  cxn->conn_hdl,
5064  cxn->wq_id,
5065  sendRst);
5066  }
5067  if (rc) {
5068  /* successfully constructed invalidate mbx request, now queue it */
5069  rc = ocs_hal_command_queue(hal, ctx);
5070  if (rc) {
5071  ocs_log_test(hal->os, "Error posting invalidate connection\n");
5072  }
5073  } else {
5074  ocs_hal_command_free_ctx(hal, ctx);
5075  ocs_log_test(hal->os, "Error building invalidate connection message\n");
5076  rc = OCS_HAL_RTN_ERROR;
5077  }
5078 
5079  return rc;
5080 }
5081 
5082 
5083 /**
5084  * @ingroup node
5085  * @brief uploads an incoming connection on a target.
5086  *
5087  * @param hal Hardware context.
5088  * @param cxn Pointer to the connection object.
5089  * @param graceful If TRUE, then a graceful teardown of the socket is performed.
5090  * @param cxn_cb Pointer to the function to call when the operation completes.
5091  * @param ul_arg Pointer to the argument to pass back to cxn_cb().
5092  *
5093  * @return Returns 0 on success, or a non-zero value otherwise.
5094  */
5096 ocs_hal_cxn_upload(ocs_hal_t *hal, ocs_cxn_t *cxn, uint8_t graceful,
5097  cxn_cb_t cxn_cb, void *ul_arg)
5098 {
5100  ocs_command_ctx_t *ctx;
5101 
5102  ctx = ocs_hal_command_get_ctx(hal);
5103  if (ctx == NULL) {
5104  ocs_log_err(hal->os, "no buffer for command\n");
5105  return OCS_HAL_RTN_NO_RESOURCES;
5106  }
5107  ctx->cxn = cxn;
5108  ctx->cxn_cb = cxn_cb;
5109  ctx->upper_arg = ul_arg;
5111 
5112  if (sli_cmd_common_tcp_upload(&hal->sli, ctx->cmd,
5113  SLI4_BMBX_SIZE, 0,
5114  cxn->wq_id,
5115  graceful)) {
5116  rc = ocs_hal_command_queue(hal, ctx);
5117  if (rc) {
5118  ocs_log_test(hal->os, "Error posting connection upload\n");
5119  } else {
5120  ocs_hal_cxn_cq_release(hal, cxn);
5121  }
5122  } else {
5123  ocs_hal_command_free_ctx(hal, ctx);
5124  ocs_log_test(hal->os, "Error building connection upload message\n");
5125  rc = OCS_HAL_RTN_ERROR;
5126  }
5127 
5128  return rc;
5129 }
5130 
5131 /**
5132  * @ingroup node
5133  * @brief Frees a connection object for re-use.
5134  *
5135  * @param hal Hardware context.
5136  * @param cxn Pointer to the connection object.
5137  *
5138  * @return Returns 0 on success, or a non-zero value otherwise.
5139  */
5141 ocs_hal_cxn_free(ocs_hal_t *hal, ocs_cxn_t *cxn)
5142 {
5143  ocs_sport_lock(cxn->sport);
5144  ocs_list_remove(&cxn->sport->node_list, cxn);
5145  hal->domain->node_instance_count--;
5146  ocs_sport_unlock(cxn->sport);
5147 
5148  /*
5149  * Some WQEs may still be on the busy list. we need to clean them up and
5150  * place them back on the free list now.
5151  */
5152  sli_queue_iscsi_cleanup(hal, &hal->sli, &hal->wq[cxn->wq_index]);
5153 
5154  ocs_lock(&hal->cxn_lock);
5155  ocs_list_add_tail(&hal->cxn_free, cxn);
5156  ocs_unlock(&hal->cxn_lock);
5157 
5158  return OCS_HAL_RTN_SUCCESS;
5159 }
5160 
5161 /**
5162  * @ingroup io
5163  * @brief Allocate a HAL IO object.
5164  *
5165  * @param hal Hardware context.
5166  *
5167  * @return Returns io pointer, or NULL if out of resources.
5168  */
5169 ocs_hal_io_t *
5171 {
5172  ocs_hal_io_t * io = NULL;
5173 
5174  ocs_lock(&hal->io_lock);
5175  io = ocs_list_get_head(&hal->io_free);
5176  if (NULL != io) {
5178  ocs_unlock(&hal->io_lock);
5179  io->node = NULL;
5180  io->busy = TRUE;
5181  io->itt = 0xffffffff;
5182  io->aborted = FALSE;
5183  io->chained = FALSE;
5184  io->uses_dif= FALSE;
5185  io->was_tgt_write = FALSE;
5186  io->type = 0xFFFF;
5187  io->wq_ctx = NULL;
5188  } else {
5189  ocs_atomic_add_return(&hal->io_alloc_failed_count, 1);
5190  ocs_unlock(&hal->io_lock);
5191  }
5192 
5193  return io;
5194 }
5195 
5196 /**
5197  * @ingroup io
5198  * @brief If there are more than 4 objects on the quarantine list, then free
5199  * IOs until there are at most 4 left on the list.
5200  *
5201  * @par Description
5202  * @b Note: Assumes that the hal->io_lock is held.
5203  *
5204  * @param hal Hardware context.
5205  * @param quarantine_cnt Pointer to the current count of the list elements.
5206  * @param quarantine_list Pointer to the quarantine list.
5207  */
5208 static void
5210  uint32_t *quarantine_cnt,
5211  ocs_list_t *quarantine_list)
5212 {
5213  ocs_hal_io_t *io;
5214 
5215  while (*quarantine_cnt > 4) {
5216  io = ocs_list_get_head(quarantine_list);
5217  ocs_list_remove_head(quarantine_list);
5218  ocs_list_add_tail(&hal->io_free, io);
5219  (*quarantine_cnt)--;
5220  }
5221 }
5222 
5223 /**
5224  * @ingroup io
5225  * @brief Free a previously allocated HAL IO object.
5226  *
5227  * @param hal Hardware context.
5228  * @param io Pointer to the IO object.
5229  */
5230 void
5232 {
5233  ocs_hal_sgl_info_t *sgl_info;
5234  ocs_hal_sgl_info_t *sgl_next;
5235 
5236  ocs_lock(&hal->io_lock);
5237  io->busy = FALSE;
5238  io->wq_ctx = NULL;
5239 
5240  if (io->chained) {
5241  io->chained = 0;
5242  /* Free the chained SGLs */
5243  ocs_list_foreach_safe(&io->sgl_list, sgl_info, sgl_next) {
5244  if (sgl_info->sgl_type == OCS_HAL_SGL_CHAINED) {
5245  ocs_list_remove(&io->sgl_list, sgl_info);
5246  ocs_hal_sgl_info_free(hal, sgl_info);
5247  }
5248  }
5249  }
5250 
5251  /*
5252  * BZ 160124 - If this is a target write or an initiator read using
5253  * DIF, then we must add the ICD to a quarantine list until we receive
5254  * 4 more completions of this same type.
5255  */
5256  if (io->uses_dif &&
5257  (io->type == OCS_HAL_IO_TARGET_WRITE ||
5258  (io->type == OCS_HAL_IO_TARGET_RSP &&
5259  io->was_tgt_write))) {
5264  &hal->io_tgt_write_quarantine);
5265  } else if (io->uses_dif &&
5271  &hal->io_ini_read_quarantine);
5272  } else {
5273  ocs_list_add_tail(&hal->io_free, io);
5274  }
5275 
5276  ocs_unlock(&hal->io_lock);
5277 }
5278 
5279 
5280 /**
5281  * @ingroup io
5282  * @brief Allocate a HAL SGL Chaining object.
5283  *
5284  * @par Description
5285  * Note: The hal->io_lock should already be locked.
5286  *
5287  * @param hal Hardware context.
5288  *
5289  * @return Returns sgl_info pointer, or NULL if out of resources.
5290  */
5291 static ocs_hal_sgl_info_t *
5293 {
5294  ocs_hal_sgl_info_t * sgl_info = NULL;
5295  ocs_hal_io_t * chain_io = NULL;
5296 
5297  /* TODO - Fix once chain only SGL ranges are available from FW. */
5298  chain_io = ocs_hal_io_alloc(hal);
5299  if (NULL != chain_io) {
5300  sgl_info = ocs_list_get_head(&chain_io->sgl_list);
5301  /*
5302  * Each IO always has its allocated IO object, so it will never
5303  * be NULL.
5304  */
5305  ocs_list_remove_head(&chain_io->sgl_list);
5306  sgl_info->sgl_type = OCS_HAL_SGL_CHAINED;
5307  sgl_info->io = chain_io;
5308  sgl_info->n_sge = 0;
5309  } else {
5310  ocs_log_err(hal->os, "failed to allocate a chained sgl_info object\n");
5311  }
5312 
5313  return sgl_info;
5314 }
5315 
5316 /**
5317  * @ingroup io
5318  * @brief Free a previously allocated HAL SGL Chaining object.
5319  *
5320  * @par Description
5321  * @b Note: The hal->io_lock should already be locked.
5322  *
5323  * @param hal Hardware context.
5324  * @param sgl_info pointer to the SGL chaining object.
5325  */
5326 static void
5328 {
5329  ocs_hal_io_t * io = sgl_info->io;
5330 
5331  /* TODO - Fix once chain only SGL ranges are available from FW. */
5332  sgl_info->sgl_type = OCS_HAL_SGL_NORMAL;
5333  // ocs_list_add_tail(&hal->chained_sgl_free, sgl_info, link);
5334  ocs_list_add_tail(&io->sgl_list, sgl_info);
5335 
5336  io->busy = FALSE;
5337  ocs_list_add_tail(&hal->io_free, io);
5338 }
5339 
5340 
5341 /**
5342  * @ingroup io
5343  * @brief Send a read, write, or response IO
5344  *
5345  * @par Description
5346  * This routine supports sending higher level IO (e.g. FCP) between two endpoints
5347  * as a target or initiator. Examples of this are
5348  * - sending read data and good response (target).
5349  * - sending a response (target with no data or after receiving write data).
5350  * @n @n
5351  * The routine assumes all IOs use the SGL associated with the HAL IO. Prior to
5352  * calling this routine, the data should be loaded using ocs_hal_io_sgl().
5353  *
5354  * @param hal Hardware context.
5355  * @param type Type of IO (target read, target response, ...).
5356  * @param io Previously-allocated HAL IO object.
5357  * @param len Length in bytes of data to send.
5358  * @param iparam IO parameters.
5359  * @param cxn Pointer to the connection object.
5360  * @param cb Function call upon completion of sending data (may be NULL).
5361  * @param arg Argument to pass to IO completion function.
5362  *
5363  * @todo
5364  * - support specifying relative offset.
5365  * - use a WQ other than 0.
5366  *
5367  * @return Returns 0 on success, or a non-zero value otherwise.
5368  */
5371  ocs_hal_io_t *io, uint32_t len,
5372  ocs_hal_io_param_t *iparam,
5373  ocs_cxn_t *cxn,
5374  io_cb_t cb, void *arg)
5375 {
5376  uint8_t wqe[SLI4_ISCSI_WQE_SIZE];
5377  int32_t rc = 0;
5378  ocs_hal_rtn_e hal_rtn;
5379  iscsi_nopout_hdr_t *nop_hdr;
5380  sli4_t *sli = &hal->sli;
5381  ocs_hal_sgl_info_t *sgl_info;
5382 
5383  sgl_info = ocs_list_get_head(&io->sgl_list);
5384 
5385  /*
5386  * Save state needed during later stages
5387  */
5388  io->node = cxn;
5389  io->type = type;
5390  io->done = cb;
5391  io->arg = arg;
5392 
5393  /*
5394  * Format the work queue entry used to send the IO
5395  */
5396  switch (type) {
5398  rc = sli->wqe_handlers->wqe_tgt_datain(&hal->sli,
5399  wqe,
5401  &io->bhs,
5402  0,
5403  TRUE,
5404  iparam->tgt_read.underrun,
5405  iparam->tgt_read.overrun,
5406  len,
5407  io->icd,
5408  io->icd, /* No multi phase for now */
5409  iparam->tgt_read.data_sn,
5410  iparam->tgt_read.piggy_back_status,
5411  iparam->tgt_read.dif_info,
5412  sgl_info->sgl,
5413  io->n_sge);
5414  break;
5415 
5417  io->was_tgt_write = TRUE;
5418  rc = sli->wqe_handlers->wqe_tgt_sts(&hal->sli,
5419  wqe,
5421  &io->bhs,
5422  iparam->tgt_write.lun,
5423  len,
5424  iparam->tgt_write.exp_data_sn,
5425  iparam->tgt_write.itt,
5426  io->icd,
5427  io->icd, /* No multi R2T for now */
5428  iparam->tgt_write.dif_info,
5429  iparam->tgt_write.r2t_offset,
5430  sgl_info->sgl,
5431  io->n_sge);
5432  break;
5433 
5434  case OCS_HAL_IO_TARGET_RSP:
5435  rc = sli->wqe_handlers->wqe_tgt_sos(&hal->sli,
5436  wqe,
5438  &io->bhs,
5439  iparam->tgt_rsp.payload1,
5440  iparam->tgt_rsp.payload2,
5441  0,
5442  TRUE,
5443  len,
5444  io->icd);
5445  break;
5446 
5447  case OCS_HAL_IO_UNASSISTED:
5448  rc = sli->wqe_handlers->wqe_unassisted(&hal->sli,
5449  wqe,
5451  iparam->unassisted.set_dm,
5452  iparam->unassisted.incr_statsn,
5453  iparam->unassisted.is_login,
5454  iparam->unassisted.bhs,
5455  iparam->unassisted.payload1,
5456  iparam->unassisted.payload2,
5457  len,
5458  io->icd);
5459  break;
5460 
5462  rc = sli->wqe_handlers->wqe_update_context(&hal->sli,
5463  wqe,
5465  &iparam->context_upd.lgn_options,
5466  iparam->context_upd.statsn);
5467  break;
5468 
5471  rc = sli->wqe_handlers->wqe_ini_read(&hal->sli,
5472  wqe,
5474  iparam->ini_io.lun,
5475  len,
5476  iparam->ini_io.cmdsn,
5477  io->icd,
5478  iparam->ini_io.dif_info,
5479  sgl_info->sgl,
5480  io->n_sge);
5481  break;
5482 
5484  rc= sli->wqe_handlers->wqe_ini_write(&hal->sli,
5485  wqe,
5487  iparam->ini_io.lun,
5488  len,
5489  iparam->ini_io.cmdsn,
5490  io->icd,
5491  iparam->ini_io.dif_info,
5492  sgl_info->sgl,
5493  io->n_sge);
5494  break;
5495 
5497  rc = sli->wqe_handlers->wqe_ini_tmf(&hal->sli,
5498  wqe,
5500  iparam->ini_tmf.lun,
5501  iparam->ini_tmf.cmdsn,
5502  io->icd,
5503  sgl_info->sgl,
5504  io->n_sge);
5505  break;
5506 
5508  nop_hdr = (iscsi_nopout_hdr_t *)iparam->ini_nop.bhs->virt;
5509 
5510  rc = sli->wqe_handlers->wqe_unassisted(&hal->sli,
5511  wqe,
5513  (nop_hdr->itt == 0xffffffff),
5514  FALSE,
5515  FALSE,
5516  iparam->ini_nop.bhs,
5517  iparam->ini_nop.payload1,
5518  iparam->ini_nop.payload2,
5519  len,
5520  io->icd);
5521  break;
5522 
5523  default:
5524  ocs_log_test(hal->os, "unsupported IO type %#x\n", type);
5525  rc = -1;
5526  }
5527 
5528  if (0 == rc) {
5529  rc = sli->wqe_handlers->queue_iscsi_wq_write(&hal->sli,
5530  &hal->wq[cxn->wq_index], wqe, io);
5531 
5532  if (rc == 0) {
5533  ocs_queue_history_wq(&hal->q_hist, (void *) wqe, hal->wq[cxn->wq_index].id,
5534  hal_io->wq_ctx->wrb_index);
5535  }
5536 
5537  /*
5538  * Note: The only reason the queue write will fail is if the
5539  * there is no room on the WQ. So return this as the
5540  * no resources status.
5541  */
5542  hal_rtn = (rc ? OCS_HAL_RTN_NO_RESOURCES : OCS_HAL_RTN_SUCCESS);
5543  } else {
5544  hal_rtn = OCS_HAL_RTN_ERROR;
5545  }
5546 
5547  return hal_rtn;
5548 }
5549 
5550 /**
5551  * @ingroup io
5552  * @brief Initialize the Scatter Gather List entries of an IO.
5553  *
5554  * @param hal Hardware context.
5555  * @param io Previously-allocated HAL IO object.
5556  * @param type Type of IO (target read, target response, ...).
5557  * @param offset Offset used to initialize the phase.
5558  *
5559  * @return Returns 0 on success, or a non-zero value otherwise.
5560  */
5563  uint32_t offset)
5564 {
5565  sli4_sge_t *data = NULL;
5566  uint32_t i = 0;
5567  uint32_t skips = 0;
5568  ocs_hal_sgl_info_t *sgl_info;
5569 
5570  if (!hal || !io) {
5571  ocs_log_err(hal ? hal->os : NULL, "bad parameter hal=%p io=%p\n",
5572  hal, io);
5573  return OCS_HAL_RTN_ERROR;
5574  }
5575 
5576  sgl_info = ocs_list_get_head(&io->sgl_list);
5577  io->type = type;
5578 
5579  // Clear / reset the scatter-gather list
5580  ocs_memset(sgl_info->sgl, 0, sizeof(sli4_sge_t) * 2);
5581  io->n_sge = 0;
5582  io->sge_offset = offset;
5583 
5584  /*
5585  * Some IO types have underlying hardware requirements on the order
5586  * of SGEs. Process all special entries here.
5587  */
5588  data = sgl_info->sgl;
5589  switch (type) {
5593  /*
5594  * 1 skip, 1 special for initiator I/Os
5595  */
5596  // setup command/Response pointer
5597  data->sge_type = SLI4_SGE_TYPE_DATA;
5598  data->buffer_address_high = ocs_addr32_hi(io->bhs.phys);
5599  data->buffer_address_low = ocs_addr32_lo(io->bhs.phys);
5600  data->buffer_length = io->bhs.size;
5601 
5602  if (OCS_HAL_IO_INITIATOR_NODATA == type) {
5603  data->last = TRUE;
5604  }
5605  data++;
5606 
5607 
5608  io->n_sge = 1;
5609  skips = 1;
5610  break;
5611 
5614  /*
5615  * 1 special for initiator TMF
5616  */
5617  // setup command/Response pointer
5618  data->sge_type = SLI4_SGE_TYPE_DATA;
5619  data->buffer_address_high = ocs_addr32_hi(io->bhs.phys);
5620  data->buffer_address_low = ocs_addr32_lo(io->bhs.phys);
5621  data->buffer_length = io->bhs.size;
5622  data->last = TRUE;
5623  data++;
5624 
5625  io->n_sge = 1;
5626  break;
5627 
5630  case OCS_HAL_IO_TARGET_RSP:
5631  case OCS_HAL_IO_UNASSISTED:
5633  /*
5634  * No skips, etc.
5635  */
5636  break;
5637 
5638  default:
5639  ocs_log_test(hal->os, "unsupported IO type %#x\n", type);
5640  return OCS_HAL_RTN_ERROR;
5641  }
5642 
5643  /*
5644  * Write skip entries
5645  */
5646  for (i = 0; i < skips; i++) {
5647  data->sge_type = SLI4_SGE_TYPE_SKIP;
5648  data++;
5649  }
5650 
5651  io->n_sge += skips;
5652 
5653  /*
5654  * Set last
5655  */
5656  data->last = TRUE;
5657  sgl_info->n_sge = io->n_sge;
5658 
5659  return OCS_HAL_RTN_SUCCESS;
5660 }
5661 
5662 /**
5663  * @ingroup io
5664  * @brief Find the correct position to add an SGL.
5665  * This may result in the allocation of a chained SGL List.
5666  *
5667  * @param hal Hardware context.
5668  * @param io Previously-allocated HAL IO object.
5669  *
5670  * @return Returns pointer to the SGL info structure, or NULL otherwise.
5671  */
5672 static ocs_hal_sgl_info_t *
5674 {
5675  ocs_hal_sgl_info_t *sgl_info = NULL;
5676  ocs_hal_sgl_info_t *sgl_prev = NULL;
5677  sli4_sge_t *data = NULL;
5678  sli4_sge_t last_sge;
5679  sli4_chain_sge_t *chain;
5680 
5681  sgl_info = ocs_list_get_tail(&io->sgl_list);
5682 
5683  /*
5684  * We have run out of sgl_info structures, get another one.
5685  */
5686  if (sgl_info->n_sge == sgl_info->num_entries) {
5687  if (hal->config.enable_sgl_chaining) {
5688  sgl_prev = sgl_info;
5689  sgl_info = ocs_hal_sgl_info_alloc(hal);
5690  if (sgl_info == NULL ) {
5691  ocs_log_err(hal->os, "No chaining ICDs available\n");
5692  return NULL;
5693  }
5694  ocs_list_add_tail(&io->sgl_list, sgl_info);
5695  io->chained = 1;
5696 
5697  /*
5698  * Move the last SGE of the previous block so we have
5699  * room to insert the chaining entry.
5700  */
5701  data = sgl_prev->sgl;
5702  last_sge = data[sgl_prev->num_entries - 1];
5703  chain = (sli4_chain_sge_t *)&data[sgl_prev->num_entries - 1];
5704  sli_chain_sge_build(&hal->sli, chain, sgl_info->icd,
5705  sgl_info->frag_offset, 0);
5706  data = sgl_info->sgl;
5707  *data = last_sge;
5708  io->n_sge++;
5709  sgl_info->n_sge = 1;
5710  } else {
5711  ocs_log_err(hal->os, "Exceeded %d SGEs for IO\n", sgl_info->num_entries);
5712  return NULL;
5713  }
5714  }
5715 
5716  return sgl_info;
5717 }
5718 
5719 
5720 /**
5721  * @ingroup io
5722  * @brief Add a Scatter Gather list Entry to an IO.
5723  *
5724  * @param hal Hardware context.
5725  * @param io Previously allocated HAL IO object.
5726  * @param addr Physical address.
5727  * @param length Length of memory pointed to be addr.
5728  *
5729  * @return Returns 0 on success, or a non-zero value otherwise.
5730  */
5732 ocs_hal_io_add_sge(ocs_hal_t *hal, ocs_hal_io_t *io, uintptr_t addr,
5733  uint32_t length)
5734 {
5735  ocs_hal_sgl_info_t *sgl_info;
5736  sli4_sge_t *data = NULL;
5737 
5738  if (!hal || !io || !addr || !length) {
5739  ocs_log_err(hal ? hal->os : NULL,
5740  "bad parameter hal=%p io=%p addr=%lx length=%u\n",
5741  hal, io, addr, length);
5742  return OCS_HAL_RTN_ERROR;
5743  }
5744 
5745  if (length > HW_MAX_SGLE_SIZE) {
5746  ocs_log_err(hal->os, "length of SGE %d bigger than allowed %d\n",
5747  length, HW_MAX_SGLE_SIZE);
5748  return OCS_HAL_RTN_ERROR;
5749  }
5750 
5751  sgl_info = ocs_hal_io_get_sgl_info(hal, io);
5752  if (sgl_info == NULL ) {
5753  return OCS_HAL_RTN_ERROR;
5754  }
5755 
5756  data = sgl_info->sgl;
5757  data += sgl_info->n_sge;
5758 
5759  data->sge_type = SLI4_SGE_TYPE_DATA;
5760  data->buffer_address_high = ocs_addr32_hi(addr);
5761  data->buffer_address_low = ocs_addr32_lo(addr);
5762  data->buffer_length = length;
5763  data->data_offset = io->sge_offset;
5764  /*
5765  * Always assume this is the last entry and mark as such.
5766  * If this is not the first entry unset the "last SGE"
5767  * indication for the previous entry
5768  */
5769  data->last = TRUE;
5770  if (sgl_info->n_sge) {
5771  data[-1].last = FALSE;
5772  }
5773 
5774  io->sge_offset += length;
5775  io->n_sge++;
5776  sgl_info->n_sge++;
5777 
5778  return OCS_HAL_RTN_SUCCESS;
5779 }
5780 
5781 
5782 /**
5783  * @ingroup io
5784  * @brief Add a T10 PI seed scatter gather list entry.
5785  *
5786  * @param hal Hardware context.
5787  * @param io Previously-allocated HAL IO object.
5788  * @param dif_info Pointer to T10 DIF fields, or NULL if no DIF.
5789  *
5790  * @return Returns 0 on success, or a non-zero on failure.
5791  */
5794 {
5795  ocs_hal_sgl_info_t *sgl_info;
5796  sli4_sge_t *data = NULL;
5797  sli4_diseed_sge_t *dif_seed;
5798 
5799  /* If no dif_info, or dif_oper is disabled, then just return success */
5800  if ((dif_info == NULL) || (dif_info->dif_oper == OCS_HAL_DIF_OPER_DISABLED)) {
5801  return OCS_HAL_RTN_SUCCESS;
5802  }
5803 
5804  if (!hal || !io) {
5805  ocs_log_err(hal ? hal->os : NULL, "bad parameter hal=%p io=%p dif_info=%p\n",
5806  hal, io, dif_info);
5807  return OCS_HAL_RTN_ERROR;
5808  }
5809 
5810  sgl_info = ocs_hal_io_get_sgl_info(hal, io);
5811  if (sgl_info == NULL ) {
5812  return OCS_HAL_RTN_ERROR;
5813  }
5814 
5815  data = sgl_info->sgl;
5816  data += sgl_info->n_sge;
5817 
5818  /* If we are doing T10 DIF add the DIF Seed SGE */
5819  ocs_memset(data, 0, sizeof(sli4_diseed_sge_t));
5820  dif_seed = (sli4_diseed_sge_t *)data;
5821  dif_seed->ref_tag_cmp = dif_info->ref_tag_cmp;
5822  dif_seed->ref_tag_repl = dif_info->ref_tag_repl;
5823  dif_seed->atrt = dif_info->disable_app_ref_ffff;
5824  dif_seed->at = dif_info->disable_app_ffff;
5825  dif_seed->sge_type = SLI4_SGE_TYPE_DISEED;
5826  dif_seed->app_tag_cmp = dif_info->app_tag_cmp;
5827  dif_seed->dif_blk_size = dif_info->blk_size;
5828  dif_seed->auto_incr_ref_tag = dif_info->auto_incr_ref_tag;
5829  dif_seed->check_app_tag = dif_info->check_app_tag;
5830  dif_seed->check_ref_tag = dif_info->check_ref_tag;
5831  dif_seed->check_crc = dif_info->check_guard;
5832  dif_seed->new_ref_tag = dif_info->repl_ref_tag;
5833 
5834  switch(dif_info->dif_oper) {
5838  break;
5842  break;
5846  break;
5847  default:
5848  ocs_log_test(hal->os, "unsupported DIF operation %#x\n",
5849  dif_info->dif_oper);
5850  return OCS_HAL_RTN_ERROR;
5851  }
5852 
5853  /*
5854  * Set last, clear previous last
5855  */
5856  data->last = TRUE;
5857  if (sgl_info->n_sge) {
5858  data[-1].last = FALSE;
5859  }
5860 
5861  io->n_sge++;
5862  io->uses_dif = TRUE;
5863  sgl_info->n_sge++;
5864 
5865  return OCS_HAL_RTN_SUCCESS;
5866 }
5867 
5868 
5869 /**
5870  * @ingroup io
5871  * @brief Add a T10 DIF scatter gather list entry to an IO.
5872  *
5873  * @param hal Hardware context.
5874  * @param io Previously-allocated HAL IO object.
5875  * @param addr DIF physical address.
5876  *
5877  * @return Returns 0 on success, or a non-zero on failure.
5878  */
5881 {
5882  ocs_hal_sgl_info_t *sgl_info;
5883  sli4_dif_sge_t *data = NULL;
5884 
5885  if (!hal || !io || !addr) {
5886  ocs_log_err(hal ? hal->os : NULL,
5887  "bad parameter hal=%p io=%p addr=%lx\n",
5888  hal, io, addr);
5889  return OCS_HAL_RTN_ERROR;
5890  }
5891 
5892  sgl_info = ocs_hal_io_get_sgl_info(hal, io);
5893  if (sgl_info == NULL ) {
5894  return OCS_HAL_RTN_ERROR;
5895  }
5896 
5897  data = sgl_info->sgl;
5898  data += sgl_info->n_sge;
5899 
5900  data->sge_type = SLI4_SGE_TYPE_DIF;
5901  data->buffer_address_high = ocs_addr32_hi(addr);
5902  data->buffer_address_low = ocs_addr32_lo(addr);
5903 
5904  /*
5905  * Always assume this is the last entry and mark as such.
5906  * If this is not the first entry unset the "last SGE"
5907  * indication for the previous entry
5908  */
5909  data->last = TRUE;
5910  if (sgl_info->n_sge) {
5911  data[-1].last = FALSE;
5912  }
5913 
5914  io->n_sge++;
5915  io->uses_dif = TRUE;
5916  sgl_info->n_sge++;
5917 
5918  return OCS_HAL_RTN_SUCCESS;
5919 }
5920 
5921 /**
5922  * @brief Receives the callback for an invalidate commands mailbox cmd.
5923  *
5924  * @param hal Hardware context.
5925  * @param status Status from the MQE.
5926  * @param ctx Pointer to the command context for this request.
5927  *
5928  * @return Returns 0 on success, or a non-zero value otherwise.
5929  */
5930 static int32_t
5932 {
5934 
5935  /*
5936  * Note: The io_tbl is sized based on the number of ICDs passed to the
5937  * command. We assume that the FW will always give us the same
5938  * number in the response.
5939  */
5940  ocs_hal_io_t **io_tbl = ctx->cb_arg;
5941 
5943 
5944  if ((status == 0) && rsp->hdr.status) {
5945  status = rsp->hdr.status;
5946  }
5947  if (status != 0) {
5948  ocs_log_test(hal->os, "Bad abort status of 0x%x\n", status);
5949  } else {
5950  uint32_t index;
5951 
5952  for (index = 0; index < rsp->icd_count; index++) {
5953  ocs_hal_io_t *io = io_tbl[index];
5954  ocs_cxn_t *cxn = io->node;
5955 
5956  if ((rsp->status[index] & 0xFFFF) !=
5958  ocs_log_test(hal->os,
5959  "IO at index %d, bad abort status of 0x%x\n",
5960  index, rsp->status[index]);
5961  } else if (cxn != NULL && cxn->is_ini_cxn) {
5962  /* Clear the WQ context */
5963  if (io->wq_ctx != NULL) {
5965  &hal->wq[cxn->wq_index],
5966  io->wq_ctx->wrb_index);
5967  }
5968 
5969  /*
5970  * For initiator connections, the firware does not
5971  * issue any completion on the IO, so issue them
5972  * here to compensate.
5973  */
5974  if (NULL != io->done) {
5975  io_cb_t *done = io->done;
5976  void *arg = io->arg;
5977 
5978  io->done = NULL;
5979  done(io, cxn, -1, NULL, arg);
5980  }
5981  }
5982  }
5983  }
5984  ocs_dma_free(hal->os, &ctx->non_emdedded_mem);
5985  ocs_free(hal->os, io_tbl, sizeof(ocs_hal_io_t*) * rsp->icd_count);
5986  return 0;
5987 }
5988 
5989 
5990 /**
5991  * @ingroup io
5992  * @brief Abort a list of IOs.
5993  *
5994  * @par Description
5995  * This function formats the ISCSI_ERROR_RECOVERY_INVALIDATE_COMMANDS mailbox
5996  * command for a list of IOs and sends it to the FW.
5997  *
5998  * @param hal Hardware context.
5999  * @param ios Pointer to an array of IOs to abort.
6000  * @param num_ios Number of IOs to abort.
6001  * @param abort_type Type of abort requested.
6002  *
6003  * @return Returns 0 on success, or a non-zero value otherwise.
6004  */
6005 static ocs_hal_rtn_e
6006 ocs_hal_io_abort_send_cmd(ocs_hal_t *hal, ocs_hal_io_t **ios, uint16_t num_ios,
6007  ocs_hal_abort_type_e abort_type)
6008 {
6010  ocs_command_ctx_t *ctx;
6011  ocs_dma_t dma_mem;
6012  uint32_t index;
6013  ocs_hal_io_t **io_tbl;
6014 
6015  /* Get the DMA memory for the command */
6016  if (ocs_dma_alloc(hal->os,
6017  &dma_mem,
6019  4)) {
6020  ocs_log_err(hal->os, "DMA malloc failed\n");
6021  return OCS_HAL_RTN_NO_MEMORY;
6022  }
6023 
6024  /*
6025  * Allocate memory so that we can issue initiator IO completions on the
6026  * callback. Assume that open-iscsi issues TM and then aborts the IO.
6027  */
6028  io_tbl = ocs_malloc(hal->os, sizeof(ocs_hal_io_t*) * num_ios, OCS_M_ZERO | OCS_M_NOWAIT);
6029  if (io_tbl == NULL) {
6030  ocs_log_err(hal->os, "failed allocating IO table memory\n");
6031  ocs_dma_free(hal->os, &dma_mem);
6032  return OCS_HAL_RTN_NO_MEMORY;
6033  }
6034  ocs_memcpy(io_tbl, ios, sizeof(ocs_hal_io_t*) * num_ios);
6035 
6036  ctx = ocs_hal_command_get_ctx(hal);
6037  if (ctx == NULL) {
6038  ocs_log_err(hal->os, "no buffer for command\n");
6039  ocs_dma_free(hal->os, &dma_mem);
6040  ocs_free(hal->os, io_tbl, sizeof(ocs_hal_io_t*) * num_ios);
6041  return OCS_HAL_RTN_NO_RESOURCES;
6042  }
6043 
6044 
6045  ctx->non_emdedded_mem = dma_mem;
6046  ctx->cb = ocs_hal_io_abort_cb;
6047  ctx->cb_arg = io_tbl;
6048 
6050  ctx->cmd,
6052  0,
6053  &ctx->non_emdedded_mem,
6054  ios,
6055  num_ios,
6056  abort_type)) {
6057  rc = ocs_hal_command_queue(hal, ctx);
6058  if (rc) {
6059  ocs_log_test(hal->os, "Error posting Invalidate Cmd\n");
6060  ocs_dma_free(hal->os, &dma_mem);
6061  } else {
6062  /*
6063  * Flag IOs as aborted so we don't attempt to abort
6064  * them twice
6065  */
6066  for (index = 0; index < num_ios; index++) {
6067  ios[index]->aborted = TRUE;
6068  }
6069  }
6070  } else {
6071  ocs_hal_command_free_ctx(hal, ctx);
6072  ocs_log_test(hal->os, "Error building Invalidate Cmd message\n");
6073  ocs_dma_free(hal->os, &dma_mem);
6074  ocs_free(hal->os, io_tbl, sizeof(ocs_hal_io_t*) * num_ios);
6075  rc = OCS_HAL_RTN_ERROR;
6076  }
6077  return rc;
6078 }
6079 
6080 
6081 /**
6082  * @ingroup io
6083  * @brief Abort a list of IOs
6084  *
6085  * @par Description
6086  * This function sets the WQE invalid bit to 1 and places the IO in the
6087  * abort list.
6088  *
6089  * @param hal Hardware context.
6090  * @param io Pointer to an IO to abort.
6091  * @param ios Pointer to an array of IOs to abort.
6092  * @param io_index Index to place the next IO in.
6093  * @param abort_type Type of abort requested.
6094  *
6095  * @return Returns 0 on success, or a non-zero value otherwise.
6096  */
6097 static ocs_hal_rtn_e
6099  ocs_hal_io_t **ios, uint16_t *io_index,
6100  ocs_hal_abort_type_e abort_type)
6101 {
6103  ocs_cxn_t *cxn = io->node;
6104  sli4_t *sli = &hal->sli;
6105  uint8_t is_for_tm = (abort_type == OCS_HAL_IO_ABORT_TYPE_TMF ? TRUE : FALSE);
6106 
6107  if (io->aborted) {
6108  return OCS_HAL_RTN_SUCCESS;
6109  }
6110 
6111  /* Invalidate the WQE */
6112  if (sli->wqe_handlers->queue_iscsi_wqe_invalidate(&hal->sli,
6113  &hal->wq[cxn->wq_index],
6114  io, is_for_tm)) {
6115  ocs_log_test(hal->os, "Active IO, icd=%d, is not found in WQE\n",
6116  io->icd);
6117  return OCS_HAL_RTN_ERROR;
6118  }
6119 
6120  ios[(*io_index)++] = io;
6121 
6122  if (*io_index == OCS_HAL_MAX_ABORT_IOS) {
6123  rc = ocs_hal_io_abort_send_cmd(hal, ios, *io_index, abort_type);
6124  *io_index = 0;
6125  }
6126  return rc;
6127 }
6128 
6129 
6130 
6131 /**
6132  * @ingroup io
6133  * @brief Abort a currently running IO.
6134  *
6135  * @par Description
6136  * This function must set the WQE invalid bit to 1 and post a
6137  * IOCTL_COMMON_ISCSI_ERROR_RECOVERY_INVALIDATE_COMMANDS mailbox command.
6138  * The transport software must send a NOP/TM to force a TCP acknowledgement.
6139  *
6140  * @param hal Hardware context.
6141  * @param io Previously-allocated HAL IO object (only used for SCOPE_IO).
6142  * @param abort_scope Used to automatically select IOs to abort.
6143  * @param abort_type Type of abort requested.
6144  *
6145  * @return Returns 0 on success, or a non-zero value otherwise.
6146  */
6149 {
6151  ocs_sli_port_t *sport;
6152  ocs_cxn_t *cxn;
6153  ocs_io_t *os_io;
6154  uint16_t io_index = 0;
6155  ocs_hal_io_t **io_tbl;
6156 
6157  io_tbl = ocs_malloc(hal->os, sizeof(ocs_hal_io_t*) * OCS_HAL_MAX_ABORT_IOS,
6158  OCS_M_ZERO | OCS_M_NOWAIT);
6159  if (io_tbl == NULL) {
6160  ocs_log_err(hal->os, "failed allocating IP table memory\n");
6161  return OCS_HAL_RTN_NO_MEMORY;
6162  }
6163 
6164  /* select the Ios to abort */
6165  switch(abort_scope) {
6167  rc = ocs_hal_io_abort_add_entry(hal, io, io_tbl, &io_index, abort_type);
6168  break;
6170  cxn = io->node;
6171  ocs_node_lock(cxn);
6172  ocs_list_foreach(&cxn->active_ios, os_io) {
6173  if (os_io->hio) {
6174  (void)ocs_hal_io_abort_add_entry(hal, os_io->hio, io_tbl, &io_index, abort_type);
6175  }
6176  }
6177  ocs_node_unlock(cxn);
6178  break;
6181  ocs_domain_lock(hal->domain);
6182  ocs_list_foreach(&hal->domain->sport_list, sport) {
6183  ocs_sport_lock(sport);
6184  ocs_list_foreach(&sport->node_list, cxn) {
6185  ocs_node_lock(cxn);
6186  ocs_list_foreach(&cxn->active_ios, os_io) {
6187  if (os_io->hio) {
6188  (void)ocs_hal_io_abort_add_entry(hal, os_io->hio, io_tbl, &io_index, abort_type);
6189  }
6190  }
6191  ocs_node_unlock(cxn);
6192  }
6193  ocs_sport_unlock(sport);
6194  }
6195  ocs_domain_unlock(hal->domain);
6196  break;
6197  default:
6198  ocs_log_err(hal->os, "bad parameter(s) abort_scope=%d\n", abort_scope);
6199  ocs_free(hal->os, io_tbl, sizeof(ocs_hal_io_t*) * OCS_HAL_MAX_ABORT_IOS);
6200  return OCS_HAL_RTN_ERROR;
6201  }
6202 
6203  if (rc == 0 && io_index > 0) {
6204  rc = ocs_hal_io_abort_send_cmd(hal, io_tbl, io_index, abort_type);
6205  }
6206 
6207  ocs_free(hal->os, io_tbl, sizeof(ocs_hal_io_t*) * OCS_HAL_MAX_ABORT_IOS);
6208 
6209  return rc;
6210 }
6211 
6212 /**
6213  * @brief Write a portion of a firmware image to the device
6214  *
6215  * @param hal Hardware context.
6216  * @param dma DMA structure containing the firmware image chunk.
6217  * @param size Size of the firmware image chunk.
6218  * @param offset Offset in bytes from the beginning of the firmware image.
6219  * @param last True if this is the last chunk of the image. Causes the image to be committed to flash.
6220  * @param cb Pointer to a callback function that will be called when the command completes.
6221  * The callback function prototype is void cb(int32_t status, uint32_t bytes_written, void *arg).
6222  * @param arg Pointer to be passed to the callback function.
6223  *
6224  * @return Returns 0 on success, or a non-zero value otherwise.
6225  *
6226  *
6227  */
6229 ocs_hal_firmware_write(ocs_hal_t *hal, ocs_dma_t *dma, uint32_t size, uint32_t offset, int last, ocs_hal_fw_cb_t cb, void *arg)
6230 {
6231  // TODO: Write firmware_write for BE3/Skyhawk
6232  return -1;
6233 }
6234 
6235 /**
6236  * @brief Called for the completion of get_profile_list for a
6237  * user request.
6238  *
6239  * @par Description
6240  * This function is called when the COMMMON_GET_PROFILE_LIST
6241  * mailbox completes. The response will be in
6242  * ctx->non_embedded_mem.virt. This function parses the
6243  * response and creates a ocs_hal_profile_list, then calls the
6244  * mgmt_cb callback function and passes that list to it.
6245  *
6246  * @param hal Hardware context.
6247  * @param status Status from the MQE.
6248  * @param ctx Pointer to the command context.
6249  *
6250  * @return Returns 0 on success, or a non-zero value otherwise.
6251  */
6252 static int32_t
6254  ocs_command_ctx_t *ctx)
6255 {
6256  ocs_hal_profile_list_t *list;
6258  int i;
6259  int num_descriptors;
6260 
6261  list = ocs_malloc(hal->os, sizeof(ocs_hal_profile_list_t), OCS_M_ZERO);
6262  list->num_descriptors = response->profile_descriptor_count;
6263 
6264  num_descriptors = list->num_descriptors;
6265  if (num_descriptors > OCS_HAL_MAX_PROFILES) {
6266  num_descriptors = OCS_HAL_MAX_PROFILES;
6267  }
6268 
6269  for (i=0; i<num_descriptors; i++) {
6270  list->descriptors[i].profile_id = response->profile_descriptor[i].profile_id;
6272  ocs_strcpy(list->descriptors[i].profile_description, (char *)response->profile_descriptor[i].profile_description);
6273  }
6274 
6275  if (ctx->mgmt_cb) {
6276  ctx->mgmt_cb(ctx->upper_arg, status, 0, list);
6277  }
6278 
6279  return 0;
6280 }
6281 
6282 /**
6283  * @ingroup io
6284  * @brief Get a list of available profiles.
6285  * @par Description
6286  * Issues a SLI4 COMMON_GET_PROFILE_LIST mailbox. When the
6287  * command completes the provided mgmt callback function is
6288  * called.
6289  *
6290  * @param hal The HAL hardware context.
6291  * @param mgmt_cb Callback function to be called when the
6292  * command completes.
6293  * @param ul_arg An argument that is passed to the callback
6294  * function.
6295  *
6296  * @return
6297  * - OCS_HAL_RTN_SUCCESS on success.
6298  * - OCS_HAL_RTN_NO_MEMORY if a malloc fails.
6299  * - OCS_HAL_RTN_NO_RESOURCES if unable to get a command
6300  * context.
6301  * - OCS_HAL_RTN_ERROR on any other error.
6302  */
6304 ocs_hal_get_profile_list(ocs_hal_t *hal, mgmt_cb_t mgmt_cb, void* ul_arg)
6305 {
6307  ocs_command_ctx_t *ctx;
6308  ocs_dma_t dma_mem;
6309 
6310  if (!hal->sli.is_skyhawk) {
6311  return OCS_HAL_RTN_ERROR;
6312  }
6313 
6314  if (ocs_dma_alloc(hal->os, &dma_mem, sizeof(sli4_res_common_get_profile_list_t), 4)) {
6315  ocs_log_err(hal->os, "Failed to allocate DMA buffer\n");
6316  return OCS_HAL_RTN_NO_MEMORY;
6317  }
6318 
6319  ctx = ocs_hal_command_get_ctx(hal);
6320  if (ctx == NULL) {
6321  ocs_log_err(hal->os, "no buffer for command\n");
6322  return OCS_HAL_RTN_NO_RESOURCES;
6323  }
6324 
6325  ctx->non_emdedded_mem = dma_mem;
6326  ctx->mgmt_cb = mgmt_cb;
6327  ctx->upper_arg = ul_arg;
6329 
6331  ctx->cmd,
6333  0,
6334  0,
6335  &ctx->non_emdedded_mem)) {
6336  rc = ocs_hal_command_queue(hal, ctx);
6337  if (rc) {
6338  ocs_log_test(hal->os, "Error posting Get Profile List Cmd\n");
6339  ocs_dma_free(hal->os, &dma_mem);
6340  }
6341  } else {
6342  ocs_hal_command_free_ctx(hal, ctx);
6343  ocs_log_test(hal->os, "Error building Get Profile List Cmd message\n");
6344  ocs_dma_free(hal->os, &dma_mem);
6345  rc = OCS_HAL_RTN_ERROR;
6346  }
6347  return rc;
6348 }
6349 
6350 /**
6351  * @brief Called for the completion of get_active_profile for a
6352  * user request.
6353  *
6354  * @param hal Hardware context.
6355  * @param status Status from the MQE.
6356  * @param ctx Pointer to the command context.
6357  *
6358  * @return Returns 0 on success, or a non-zero value otherwise.
6359  */
6360 static int32_t
6362  ocs_command_ctx_t *ctx)
6363 {
6365  uint32_t active_profile;
6366 
6367  active_profile = response->active_profile_id;
6368 
6369  if (ctx->mgmt_cb) {
6370  ctx->mgmt_cb(ctx->upper_arg, status, 0, (void *)&active_profile);
6371  }
6372 
6373  return 0;
6374 }
6375 
6376 /**
6377  * @ingroup io
6378  * @brief Get the currently active profile.
6379  *
6380  * @par Description
6381  * Issues a SLI4 COMMON_GET_ACTIVE_PROFILE mailbox. When the
6382  * command completes the provided mgmt callback function is
6383  * called.
6384  *
6385  * @param hal HAL hardware context.
6386  * @param cb Callback function to be called when the
6387  * command completes.
6388  * @param ul_arg An argument that is passed to the callback
6389  * function.
6390  *
6391  * @return
6392  * - OCS_HAL_RTN_SUCCESS on success.
6393  * - OCS_HAL_RTN_NO_MEMORY if a malloc fails.
6394  * - OCS_HAL_RTN_NO_RESOURCES if unable to get a command
6395  * context.
6396  * - OCS_HAL_RTN_ERROR on any other error.
6397  */
6398 int32_t ocs_hal_get_active_profile(ocs_hal_t *hal, mgmt_cb_t cb, void* ul_arg) {
6400  ocs_command_ctx_t *ctx;
6401  int32_t cmd_rc;
6402 
6403  if (!hal->sli.is_skyhawk) {
6404  return OCS_HAL_RTN_ERROR;
6405  }
6406 
6407  ctx = ocs_hal_command_get_ctx(hal);
6408  if (ctx == NULL) {
6409  ocs_log_err(hal->os, "no buffer for command\n");
6410  return OCS_HAL_RTN_NO_RESOURCES;
6411  }
6412 
6414  ctx->mgmt_cb = cb;
6415  ctx->upper_arg = ul_arg;
6416 
6417  cmd_rc = sli_cmd_common_get_active_profile(&hal->sli, ctx->cmd, SLI4_BMBX_SIZE, 0);
6418  if (cmd_rc) {
6419  rc = ocs_hal_command_queue(hal, ctx);
6420  if (rc) {
6421  ocs_log_test(hal->os, "Error posting COMMON_GET_ACTIVE_PROFILE\n");
6422  }
6423  } else {
6424  ocs_hal_command_free_ctx(hal, ctx);
6425  ocs_log_test(hal->os, "Error building COMMON_GET_ACTIVE_PROFILE\n");
6426  rc = OCS_HAL_RTN_ERROR;
6427  }
6428 
6429  return rc;
6430 
6431 }
6432 
6433 /**
6434  * @brief Called for the completion of set_active_profile for a
6435  * user request.
6436  *
6437  * @param hal Hardware context.
6438  * @param status Status from the MQE
6439  * @param ctx Pointer to the command context.
6440  *
6441  * @return Returns 0 on success, or a non-zero value otherwise.
6442  */
6443 static int32_t
6445  ocs_command_ctx_t *ctx)
6446 {
6447 
6448  if (ctx->mgmt_cb) {
6449  ctx->mgmt_cb(ctx->upper_arg, status, 0, NULL);
6450  }
6451 
6452  return 0;
6453 }
6454 
6455 /**
6456  * @ingroup io
6457  * @brief Set the currently active profile.
6458  *
6459  * @par Description
6460  * Issues a SLI4 COMMON_GET_ACTIVE_PROFILE mailbox. When the
6461  * command completes the provided mgmt callback function is
6462  * called.
6463  *
6464  * @param hal HAL hardware context.
6465  * @param cb Callback function to be called when the
6466  * command completes.
6467  * @param profile_id Profile ID that should be set as the
6468  * active profile.
6469  * @param ul_arg Argument that is passed to the callback
6470  * function.
6471  *
6472  * @return
6473  * - OCS_HAL_RTN_SUCCESS on success.
6474  * - OCS_HAL_RTN_NO_MEMORY if a malloc fails.
6475  * - OCS_HAL_RTN_NO_RESOURCES if unable to get a command
6476  * context.
6477  * - OCS_HAL_RTN_ERROR on any other error.
6478  */
6479 ocs_hal_rtn_e ocs_hal_set_active_profile(ocs_hal_t *hal, mgmt_cb_t cb, uint32_t profile_id, void *ul_arg) {
6481  ocs_command_ctx_t *ctx;
6482  int32_t cmd_rc;
6483 
6484  if (!hal->sli.is_skyhawk) {
6485  return OCS_HAL_RTN_ERROR;
6486  }
6487 
6488  ctx = ocs_hal_command_get_ctx(hal);
6489  if (ctx == NULL) {
6490  ocs_log_err(hal->os, "no buffer for command\n");
6491  return OCS_HAL_RTN_NO_RESOURCES;
6492  }
6493 
6494  ctx->mgmt_cb = cb;
6495  ctx->upper_arg = ul_arg;
6497 
6499  0, 0, profile_id);
6500  if (cmd_rc) {
6501  rc = ocs_hal_command_queue(hal, ctx);
6502  if (rc) {
6503  ocs_log_test(hal->os, "Error posting COMMON_SET_ACTIVE_PROFILE\n");
6504  }
6505  } else {
6506  ocs_hal_command_free_ctx(hal, ctx);
6507  ocs_log_test(hal->os, "Error building COMMON_SET_ACTIVE_PROFILE\n");
6508  rc = OCS_HAL_RTN_ERROR;
6509  }
6510 
6511  return rc;
6512 }
6513 
6514 /**
6515  * @brief HAL link configuration enum to Skyhawk link config ID mapping.
6516  *
6517  * @par Description
6518  * This structure provides a mapping from the ocs_hal_linkcfg_e
6519  * enum (enum exposed for the OCS_HAL_PORT_SET_LINK_CONFIG port
6520  * control) to the link config ID numbers used by Skyhawk.
6521  */
6522 typedef struct ocs_hal_skyhawk_linkcfg_map_s {
6524  uint32_t config_id;
6526 
6527 /**
6528  * @brief Mapping from the HAL linkcfg enum to the Skyhawk link config IDs
6529  */
6531  {OCS_HAL_LINKCFG_4X10G, 0x0a},
6532  {OCS_HAL_LINKCFG_1X40G, 0x09},
6533 };
6534 
6535 /**
6536  * @brief Helper function for getting a Skyhawk link config ID from the HAL
6537  * linkcfg enum.
6538  *
6539  * @param linkcfg HAL linkcfg enum.
6540  *
6541  * @return Returns the Skyhawk link config ID corresponding to
6542  * given linkcfg.
6543  */
6544 static uint32_t
6546 {
6547  uint32_t i;
6548  for (i = 0; i < ARRAY_SIZE(skyhawk_linkcfg_map); i++) {
6549  if (skyhawk_linkcfg_map[i].linkcfg == linkcfg) {
6550  return skyhawk_linkcfg_map[i].config_id;
6551  }
6552  }
6553  return 0;
6554 }
6555 
6556 /**
6557  * @brief Helper function for getting the HAL linkcfg enum from a
6558  * Skyhawk config ID
6559  *
6560  * @param config_id Skyhawk link config ID.
6561  *
6562  * @return Returns the HAL linkcfg enum corresponding to config_id.
6563  */
6564 static ocs_hal_linkcfg_e
6565 ocs_hal_linkcfg_from_config_id(const uint32_t config_id)
6566 {
6567  uint32_t i;
6568  for (i = 0; i < ARRAY_SIZE(skyhawk_linkcfg_map); i++) {
6569  if (skyhawk_linkcfg_map[i].config_id == config_id) {
6570  return skyhawk_linkcfg_map[i].linkcfg;
6571  }
6572  }
6573  return OCS_HAL_LINKCFG_NA;
6574 }
6575 
6576 
6577 /**
6578  * @brief Called for the completion of get_linkcfg for a
6579  * user request.
6580  *
6581  * @param hal Hardware context.
6582  * @param status Status from the MQE
6583  * @param ctx Pointer to the command context
6584  *
6585  * @return Returns 0 on success, or a non-zero value otherwise.
6586  */
6587 static int32_t
6588 ocs_hal_get_linkcfg_cb(ocs_hal_t *hal, int32_t status,
6589  ocs_command_ctx_t *ctx)
6590 {
6593  uint32_t config_id;
6594  ocs_hal_linkcfg_e linkcfg;
6595 
6596  config_id = response->active_link_config_id;
6597  linkcfg = ocs_hal_linkcfg_from_config_id(config_id);
6598 
6599  if (ctx->mgmt_cb) {
6600  ctx->mgmt_cb(ctx->upper_arg, status, 0, (void *)linkcfg);
6601  }
6602 
6603  return 0;
6604 }
6605 
6606 /**
6607  * @ingroup io
6608  * @brief Get the current link configuration.
6609  *
6610  * @par Description
6611  * Issues a SLI4 COMMON_GET_RECONFIG_INFO mailbox. When the
6612  * command completes the provided mgmt callback function is
6613  * called.
6614  *
6615  * @param hal HAL hardware context.
6616  * @param cb Callback function to be called when the
6617  * command completes.
6618  * @param ul_arg Argument that is passed to the callback
6619  * function.
6620  *
6621  * @return
6622  * - OCS_HAL_RTN_SUCCESS on success.
6623  * - OCS_HAL_RTN_NO_MEMORY if a malloc fails.
6624  * - OCS_HAL_RTN_NO_RESOURCES if unable to get a command
6625  * context.
6626  * - OCS_HAL_RTN_ERROR on any other error.
6627  */
6628 int32_t ocs_hal_get_linkcfg(ocs_hal_t *hal, mgmt_cb_t cb, void* ul_arg) {
6630  ocs_command_ctx_t *ctx;
6631  ocs_dma_t dma_mem;
6632  int32_t cmd_rc;
6633 
6634  if (!hal->sli.is_skyhawk) {
6635  return OCS_HAL_RTN_ERROR;
6636  }
6637 
6638  if (ocs_dma_alloc(hal->os, &dma_mem, sizeof(sli4_res_common_get_reconfig_link_info_t), 4)) {
6639  ocs_log_err(hal->os, "Failed to allocate DMA buffer\n");
6640  return OCS_HAL_RTN_NO_MEMORY;
6641  }
6642 
6643  ctx = ocs_hal_command_get_ctx(hal);
6644  if (ctx == NULL) {
6645  ocs_log_err(hal->os, "no buffer for command\n");
6646  return OCS_HAL_RTN_NO_RESOURCES;
6647  }
6648 
6649  ctx->non_emdedded_mem = dma_mem;
6650  ctx->cb = ocs_hal_get_linkcfg_cb;
6651  ctx->mgmt_cb = cb;
6652  ctx->upper_arg = ul_arg;
6653 
6655  &ctx->non_emdedded_mem);
6656  if (cmd_rc) {
6657  rc = ocs_hal_command_queue(hal, ctx);
6658  if (rc) {
6659  ocs_log_test(hal->os, "Error posting COMMON_GET_RECONFIG_LINK_INFO\n");
6660  }
6661  } else {
6662  ocs_hal_command_free_ctx(hal, ctx);
6663  ocs_log_test(hal->os, "Error building COMMON_GET_RECONFIG_LINK_INFO\n");
6664  rc = OCS_HAL_RTN_ERROR;
6665  }
6666 
6667  return rc;
6668 
6669 }
6670 
6671 /**
6672  * @brief Called for the completion of set_linkcfg for a
6673  * user request.
6674  *
6675  * @param hal Hardware context.
6676  * @param status Status from the MQE.
6677  * @param ctx Pointer to the command context.
6678  *
6679  * @return Returns 0 on success, or a non-zero value otherwise.
6680  */
6681 static int32_t
6682 ocs_hal_set_linkcfg_cb(ocs_hal_t *hal, int32_t status,
6683  ocs_command_ctx_t *ctx)
6684 {
6685 
6686  if (ctx->mgmt_cb) {
6687  ctx->mgmt_cb(ctx->upper_arg, status, 0, NULL);
6688  }
6689 
6690  return 0;
6691 }
6692 
6693 /**
6694  * @ingroup io
6695  * @brief Set the link configuration (Skyhawk only).
6696  *
6697  * @par Description
6698  * Issues a SLI4 COMMON_SET_RECONFIG_LINK_ID mailbox. When the
6699  * command completes the provided mgmt callback function is
6700  * called.
6701  *
6702  * @param hal HAL hardware context.
6703  * @param cb Callback function to be called when the
6704  * command completes.
6705  * @param ul_arg An argument that is passed to the callback
6706  * function.
6707  * @param value TBD.
6708  *
6709  * @return
6710  * - OCS_HAL_RTN_SUCCESS on success.
6711  * - OCS_HAL_RTN_NO_MEMORY if a malloc fails.
6712  * - OCS_HAL_RTN_NO_RESOURCES if unable to get a command
6713  * context.
6714  * - OCS_HAL_RTN_ERROR on any other error.
6715  */
6717  void *ul_arg) {
6719  ocs_command_ctx_t *ctx;
6720  int32_t cmd_rc;
6721  uint32_t config_id;
6722 
6723  if (!hal->sli.is_skyhawk) {
6724  return OCS_HAL_RTN_ERROR;
6725  }
6726 
6727  config_id = ocs_hal_config_id_from_linkcfg(value);
6728 
6729  ctx = ocs_hal_command_get_ctx(hal);
6730  if (ctx == NULL) {
6731  ocs_log_err(hal->os, "no buffer for command\n");
6732  return OCS_HAL_RTN_NO_RESOURCES;
6733  }
6734 
6735  ctx->mgmt_cb = cb;
6736  ctx->upper_arg = ul_arg;
6737  ctx->cb = ocs_hal_set_linkcfg_cb;
6738 
6739  cmd_rc = sli_cmd_common_set_reconfig_link_id(&hal->sli, ctx->cmd, SLI4_BMBX_SIZE, 0,
6740  NULL, 0, config_id);
6741  if (cmd_rc) {
6742  rc = ocs_hal_command_queue(hal, ctx);
6743  if (rc) {
6744  ocs_log_test(hal->os, "Error posting COMMON_SET_RECONFIG_LINK_ID\n");
6745  }
6746  } else {
6747  ocs_hal_command_free_ctx(hal, ctx);
6748  ocs_log_test(hal->os, "Error building COMMON_SET_RECONFIG_LINK_ID\n");
6749  rc = OCS_HAL_RTN_ERROR;
6750  }
6751 
6752  return rc;
6753 }
6754 
6755 typedef struct port_protocol_args_s {
6756  uint32_t new_protocol;
6757  uint32_t pci_func;
6759 
6760 /**
6761  * @brief Called for the completion of get_port_profile for a
6762  * user request.
6763  *
6764  * @param hal Hardware context.
6765  * @param status Status from the MQE.
6766  * @param ctx Pointer to the command context.
6767  *
6768  * @return Returns 0 on success, or a non-zero value otherwise.
6769  */
6770 static int32_t
6772  ocs_command_ctx_t *ctx)
6773 {
6775  ocs_hal_port_protocol_e port_protocol;
6776  int num_descriptors;
6779  int i;
6780  port_protocol_args_t *protocol_args;
6781  uint32_t pci_func;
6782 
6783  protocol_args = ctx->mgmt_cb_arg;
6784  pci_func = protocol_args->pci_func;
6785 
6786  port_protocol = OCS_HAL_PORT_PROTOCOL_UNKNOWN;
6787 
6788  num_descriptors = response->desc_count;
6789  desc_p = (sli4_resource_descriptor_v1_t *)response->desc;
6790  for (i=0; i<num_descriptors; i++) {
6791  if (desc_p->descriptor_type == SLI4_RESOURCE_DESCRIPTOR_TYPE_PCIE) {
6792  pcie_desc_p = (sli4_pcie_resource_descriptor_v1_t*) desc_p;
6793  if (pcie_desc_p->pf_number == pci_func) {
6794  switch(pcie_desc_p->pf_type) {
6795  case 0x02:
6796  port_protocol = OCS_HAL_PORT_PROTOCOL_ISCSI;
6797  break;
6798  case 0x04:
6799  port_protocol = OCS_HAL_PORT_PROTOCOL_FCOE;
6800  break;
6801  case 0x10:
6802  port_protocol = OCS_HAL_PORT_PROTOCOL_FC;
6803  break;
6804  default:
6805  port_protocol = OCS_HAL_PORT_PROTOCOL_OTHER;
6806  break;
6807  }
6808  }
6809  }
6810 
6811  desc_p = (sli4_resource_descriptor_v1_t *) ((uint8_t *)desc_p + desc_p->descriptor_length);
6812  }
6813 
6814  if (ctx->mgmt_cb) {
6815  ctx->mgmt_cb(ctx->upper_arg, status, 0, (void *)&port_protocol);
6816  }
6817  ocs_dma_free(hal->os, &(ctx->non_emdedded_mem));
6818  ocs_free(hal->os, protocol_args, sizeof(port_protocol_args_t));
6819 
6820  return 0;
6821 }
6822 
6823 /**
6824  * @ingroup io
6825  * @brief Get the current port protocol.
6826  *
6827  * @par Description
6828  * Issues a SLI4 COMMON_GET_PROFILE_CONFIG mailbox. When the
6829  * command completes the provided mgmt callback function is
6830  * called.
6831  *
6832  * @param hal HAL hardware context.
6833  * @param pci_func TBD.
6834  * @param cb Callback function to be called when the
6835  * command completes.
6836  * @param ul_arg Argument that is passed to the callback
6837  * function.
6838  *
6839  * @return
6840  * - OCS_HAL_RTN_SUCCESS on success.
6841  * - OCS_HAL_RTN_NO_MEMORY if a malloc fails.
6842  * - OCS_HAL_RTN_NO_RESOURCES if unable to get a command
6843  * context.
6844  * - OCS_HAL_RTN_ERROR on any other error.
6845  */
6846 int32_t ocs_hal_get_port_protocol(ocs_hal_t *hal, uint32_t pci_func, mgmt_cb_t cb, void* ul_arg) {
6848  port_protocol_args_t *protocol_args;
6849  ocs_command_ctx_t *ctx;
6850  ocs_dma_t dma_mem;
6851  int32_t cmd_rc;
6852 
6853  if (!hal->sli.is_skyhawk) {
6854  return OCS_HAL_RTN_ERROR;
6855  }
6856 
6857  if (ocs_dma_alloc(hal->os, &dma_mem, 4096, 4)) {
6858  ocs_log_err(hal->os, "Failed to allocate DMA buffer\n");
6859  return OCS_HAL_RTN_NO_MEMORY;
6860  }
6861 
6862  ctx = ocs_hal_command_get_ctx(hal);
6863  if (ctx == NULL) {
6864  ocs_log_err(hal->os, "no buffer for command\n");
6865  ocs_dma_free(hal->os, &dma_mem);
6866  return OCS_HAL_RTN_NO_RESOURCES;
6867  }
6868 
6869  protocol_args = ocs_malloc(hal->os, sizeof(port_protocol_args_t), OCS_M_ZERO | OCS_M_NOWAIT);
6870  if (protocol_args == NULL) {
6871  ocs_log_err(hal->os, "no memory for args\n");
6872  ocs_dma_free(hal->os, &dma_mem);
6873  return OCS_HAL_RTN_NO_RESOURCES;
6874  }
6875 
6876  ctx->non_emdedded_mem = dma_mem;
6878  ctx->mgmt_cb = cb;
6879  protocol_args->pci_func = pci_func;
6880  ctx->mgmt_cb_arg = protocol_args;
6881  ctx->upper_arg = ul_arg;
6882 
6883  cmd_rc = sli_cmd_common_get_profile_config(&hal->sli, ctx->cmd, SLI4_BMBX_SIZE, 0, &ctx->non_emdedded_mem);
6884  if (cmd_rc) {
6885  rc = ocs_hal_command_queue(hal, ctx);
6886  if (rc) {
6887  ocs_log_test(hal->os, "Error posting COMMON_GET_PROFILE_CONFIG\n");
6888  ocs_dma_free(hal->os, &dma_mem);
6889  ocs_free(hal->os, protocol_args, sizeof(port_protocol_args_t));
6890  }
6891  } else {
6892  ocs_hal_command_free_ctx(hal, ctx);
6893  ocs_log_test(hal->os, "Error building COMMON_GET_PROFILE_CONFIG\n");
6894  ocs_dma_free(hal->os, &dma_mem);
6895  ocs_free(hal->os, protocol_args, sizeof(port_protocol_args_t));
6896  rc = OCS_HAL_RTN_ERROR;
6897  }
6898 
6899  return rc;
6900 
6901 }
6902 
6903 /**
6904  * @brief Called for the completion of set_port_profile for a
6905  * user request.
6906  *
6907  * @par Description
6908  * This is the second of 2 callbacks for the set_port_protocol
6909  * function. The set operation is a read-modify-write. This
6910  * callback is called when the write (SET_PROFILE_CONFIG)
6911  * completes.
6912  *
6913  * @param hal Hardware context.
6914  * @param status Status from the MQE.
6915  * @param ctx Pointer to the command context.
6916  *
6917  * @return Returns 0 on success, or a non-zero value otherwise.
6918  */
6919 static int32_t
6921  ocs_command_ctx_t *ctx)
6922 {
6923  if (ctx->mgmt_cb) {
6924  ctx->mgmt_cb(ctx->upper_arg, status, 0, 0);
6925  }
6926 
6927  ocs_dma_free(hal->os, &(ctx->non_emdedded_mem));
6928  ocs_free(hal->os, ctx->mgmt_cb_arg, sizeof(port_protocol_args_t));
6929 
6930  return 0;
6931 }
6932 
6933 /**
6934  * @brief Called for the completion of set_port_profile for a
6935  * user request.
6936  *
6937  * @par Description
6938  * This is the first of 2 callbacks for the set_port_protocol
6939  * function. The set operation is a read-modify-write. This
6940  * callback is called when the read completes
6941  * (GET_PROFILE_CONFG). It will updated the resource
6942  * descriptors, then queue the write (SET_PROFILE_CONFIG).
6943  *
6944  * @param hal Hardware context.
6945  * @param status Status from the MQE.
6946  * @param ctx Pointer to the command context.
6947  *
6948  * @return Returns 0 on success, or a non-zero value otherwise.
6949  */
6950 static int32_t
6952  ocs_command_ctx_t *ctx)
6953 {
6955  int num_descriptors;
6958  int i;
6959  uint32_t pci_func;
6960  ocs_hal_port_protocol_e new_protocol;
6961  uint8_t *dst;
6962  sli4_isap_resouce_descriptor_v1_t *isap_desc_p;
6963  ocs_command_ctx_t *new_ctx;
6964  ocs_dma_t dma_mem;
6965  int pci_descriptor_count;
6967  int num_fcoe_ports = 0;
6968  int num_iscsi_ports = 0;
6969  port_protocol_args_t *protocol_args;
6970 
6971  protocol_args = ctx->mgmt_cb_arg;
6972 
6973  new_protocol = protocol_args->new_protocol;
6974  pci_func = protocol_args->pci_func;
6975 
6976  num_descriptors = response->desc_count;
6977 
6978  // Count PCI descriptors
6979  pci_descriptor_count = 0;
6980  desc_p = (sli4_resource_descriptor_v1_t *)response->desc;
6981  for (i=0; i<num_descriptors; i++) {
6982  if (desc_p->descriptor_type == SLI4_RESOURCE_DESCRIPTOR_TYPE_PCIE) {
6983  ++pci_descriptor_count;
6984  }
6985  desc_p = (sli4_resource_descriptor_v1_t *) ((uint8_t *)desc_p + desc_p->descriptor_length);
6986  }
6987 
6988  // Allocate memory for the descriptors we're going to send. This is
6989  // one for each PCI descriptor plus one ISAP descriptor.
6990  if (ocs_dma_alloc(hal->os, &dma_mem, sizeof(sli4_req_common_set_profile_config_t) +
6991  (pci_descriptor_count * sizeof(sli4_pcie_resource_descriptor_v1_t)) +
6992  sizeof(sli4_isap_resouce_descriptor_v1_t), 4)) {
6993  ocs_log_err(hal->os, "Failed to allocate DMA buffer\n");
6994  return OCS_HAL_RTN_NO_MEMORY;
6995  }
6996 
6997  // ctx is the context for the GET_PROFILE_CONFIG that has completed. We're starting
6998  // a new commnad, SET_PROFILE_CONFIG, so we need a new context
6999  new_ctx = ocs_hal_command_get_ctx(hal);
7000  if (!new_ctx) {
7001  ocs_log_err(hal->os, "no buffer for command\n");
7002  return OCS_HAL_RTN_NO_RESOURCES;
7003  }
7004 
7005  new_ctx->mgmt_cb = ctx->mgmt_cb;
7006  new_ctx->mgmt_cb_arg = ctx->mgmt_cb_arg;
7007  new_ctx->upper_arg = ctx->upper_arg;
7008  new_ctx->cb = ocs_hal_set_port_protocol_cb2;
7009  new_ctx->non_emdedded_mem = dma_mem;
7010 
7012  0, &new_ctx->non_emdedded_mem,
7013  0, pci_descriptor_count+1, 1);
7014 
7015  // Point dst to the first descriptor entry in the SET_PROFILE_CONFIG command
7016  dst = (uint8_t *)&(((sli4_req_common_set_profile_config_t *) dma_mem.virt)->desc);
7017 
7018  // Loop over all descriptors. If the descriptor is a PCIe descriptor, copy it
7019  // to the SET_PROFILE_CONFIG command to be written back. If it's the descriptor
7020  // that we're trying to change also set its pf_type.
7021 
7022  desc_p = (sli4_resource_descriptor_v1_t *)response->desc;
7023  for (i=0; i<num_descriptors; i++) {
7024  if (desc_p->descriptor_type == SLI4_RESOURCE_DESCRIPTOR_TYPE_PCIE) {
7025  pcie_desc_p = (sli4_pcie_resource_descriptor_v1_t*) desc_p;
7026  if (pcie_desc_p->pf_number == pci_func) {
7027  // This is the PCIe descriptor for this OCS instance.
7028  // Update it with the new pf_type
7029  switch(new_protocol) {
7031  pcie_desc_p->pf_type = SLI4_PORT_TYPE_FC;
7032  break;
7034  pcie_desc_p->pf_type = SLI4_PORT_TYPE_FCOE;
7035  break;
7037  pcie_desc_p->pf_type = SLI4_PORT_TYPE_ISCSI;
7038  break;
7039  default:
7040  pcie_desc_p->pf_type = SLI4_PORT_TYPE_DEFAULT;
7041  break;
7042  }
7043 
7044  }
7045  if (pcie_desc_p->pf_type == SLI4_PORT_TYPE_FCOE) {
7046  ++num_fcoe_ports;
7047  }
7048  if (pcie_desc_p->pf_type == SLI4_PORT_TYPE_ISCSI) {
7049  ++num_iscsi_ports;
7050  }
7051  ocs_memcpy(dst, pcie_desc_p, sizeof(sli4_pcie_resource_descriptor_v1_t));
7052  dst += sizeof(sli4_pcie_resource_descriptor_v1_t);
7053  }
7054 
7055  desc_p = (sli4_resource_descriptor_v1_t *) ((uint8_t *)desc_p + desc_p->descriptor_length);
7056  }
7057 
7058  // Create an ISAP resource descriptor
7059  isap_desc_p = (sli4_isap_resouce_descriptor_v1_t*)dst;
7060  isap_desc_p->descriptor_type = SLI4_RESOURCE_DESCRIPTOR_TYPE_ISAP;
7061  isap_desc_p->descriptor_length = sizeof(sli4_isap_resouce_descriptor_v1_t);
7062  if (num_iscsi_ports > 0) {
7063  isap_desc_p->iscsi_tgt = 1;
7064  isap_desc_p->iscsi_ini = 1;
7065  isap_desc_p->iscsi_dif = 1;
7066  }
7067  if (num_fcoe_ports > 0) {
7068  isap_desc_p->fcoe_tgt = 1;
7069  isap_desc_p->fcoe_ini = 1;
7070  isap_desc_p->fcoe_dif = 1;
7071  }
7072 
7073  ocs_dma_free(hal->os, &(ctx->non_emdedded_mem));
7074 
7075  // Send a SET_PROFILE_CONFIG mailbox command with the new descriptors
7076  rc = ocs_hal_command_queue(hal, new_ctx);
7077  if (rc) {
7078  ocs_log_test(hal->os, "Error posting COMMON_SET_PROFILE_CONFIG\n");
7079  // Call the upper level callback to report a failure
7080  if (ctx->mgmt_cb) {
7081  ctx->mgmt_cb(ctx->upper_arg, rc, 0, 0);
7082  }
7083 
7084  ocs_dma_free(hal->os, &(ctx->non_emdedded_mem));
7085  ocs_free(hal->os, protocol_args, sizeof(port_protocol_args_t));
7086  }
7087 
7088  return rc;
7089 }
7090 
7091 /**
7092  * @ingroup io
7093  * @brief Set the port protocol.
7094  *
7095  * @par Description
7096  * Setting the port protocol is a read-modify-write operation.
7097  * This function submits a GET_PROFILE_CONFIG command to read
7098  * the current settings. The callback function will modify the
7099  * settings and issue the write.
7100  *
7101  * @param hal HAL hardware context.
7102  * @param pci_func TBD.
7103  * @param cb Callback function to be called when the
7104  * command completes.
7105  * @param ul_arg An argument that is passed to the callback
7106  * function.
7107  * @param new_protocol TBD.
7108  *
7109  * @return
7110  * - OCS_HAL_RTN_SUCCESS on success.
7111  * - OCS_HAL_RTN_NO_MEMORY if a malloc fails.
7112  * - OCS_HAL_RTN_NO_RESOURCES if unable to get a command
7113  * context.
7114  * - OCS_HAL_RTN_ERROR on any other error.
7115  */
7117  mgmt_cb_t cb, void *ul_arg) {
7119  ocs_command_ctx_t *ctx;
7120  int32_t cmd_rc;
7121  ocs_dma_t dma_mem;
7122  port_protocol_args_t *protocol_args;
7123 
7124  if (!hal->sli.is_skyhawk) {
7125  return OCS_HAL_RTN_ERROR;
7126  }
7127 
7128  if (new_protocol == OCS_HAL_PORT_PROTOCOL_FC) {
7129  // No chips that support this operation support FC
7130  return OCS_HAL_RTN_ERROR;
7131  }
7132 
7133  if (ocs_dma_alloc(hal->os, &dma_mem, 4096, 4)) {
7134  ocs_log_err(hal->os, "Failed to allocate DMA buffer\n");
7135  return OCS_HAL_RTN_NO_MEMORY;
7136  }
7137 
7138  protocol_args = ocs_malloc(hal->os, sizeof(port_protocol_args_t), OCS_M_NOWAIT | OCS_M_ZERO);
7139  if (protocol_args == NULL) {
7140  ocs_log_err(hal->os, "Failed to allocate protocol args\n");
7141  ocs_dma_free(hal->os, &dma_mem);
7142  return OCS_HAL_RTN_NO_MEMORY;
7143  }
7144 
7145  ctx = ocs_hal_command_get_ctx(hal);
7146  if (ctx == NULL) {
7147  ocs_log_err(hal->os, "no buffer for command\n");
7148  return OCS_HAL_RTN_NO_RESOURCES;
7149  }
7150 
7151  ctx->mgmt_cb = cb;
7152  protocol_args->new_protocol = new_protocol;
7153  protocol_args->pci_func = pci_func;
7154  ctx->mgmt_cb_arg = protocol_args;
7155  ctx->upper_arg = ul_arg;
7157  ctx->non_emdedded_mem = dma_mem;
7158 
7160  0, &ctx->non_emdedded_mem);
7161  if (cmd_rc) {
7162  rc = ocs_hal_command_queue(hal, ctx);
7163  if (rc) {
7164  ocs_log_test(hal->os, "Error posting COMMON_GET_FUNCTION_CONFIG\n");
7165  ocs_dma_free(hal->os, &dma_mem);
7166  ocs_free(hal->os, protocol_args, sizeof(port_protocol_args_t));
7167  }
7168  } else {
7169  ocs_hal_command_free_ctx(hal, ctx);
7170  ocs_log_test(hal->os, "Error building COMMON_GET_FUNCTION_CONFIG\n");
7171  ocs_dma_free(hal->os, &dma_mem);
7172  ocs_free(hal->os, protocol_args, sizeof(port_protocol_args_t));
7173  rc = OCS_HAL_RTN_ERROR;
7174  }
7175 
7176  return rc;
7177 }
7178 
7179 
7180 
7181 /**
7182  * @ingroup io
7183  * @brief Find an IO based on the initiator task tag.
7184  *
7185  * @param hal Hardware context.
7186  * @param itt Initiator task tag to find.
7187  *
7188  * @return Pointer to the IO on success, NULL otherwise.
7189  */
7190 ocs_hal_io_t *
7191 ocs_hal_io_find_itt(ocs_hal_t *hal, uint32_t itt)
7192 {
7193  ocs_hal_io_t *rc = NULL;
7194  uint32_t i = 0;
7195 
7196  for (i = 0; i < hal->config.n_io; i++) {
7197  if (hal->io[i].busy &&
7198  hal->io[i].itt == itt) {
7199  rc = &hal->io[i];
7200  break;
7201  }
7202  }
7203  return rc;
7204 }
7205 /*
7206  * remnent for HAL based threading, not implemented yet in the iSCSI HAL
7207  */
7208 uint32_t
7210 {
7211  return 0;
7212 }
7213 
7214 /**
7215  * @brief Allocate an ocs_hal_rx_buffer_t array
7216  *
7217  * @par Description
7218  * An ocs_hal_rx_buffer_t array is allocated, along with the required DMA memory
7219  *
7220  * @param hal Pointer to HAL object.
7221  * @param rqindex RQ index for this buffer.
7222  * @param count Count of buffers in array.
7223  * @param size Size of buffer.
7224  *
7225  * @return Pointer to allocated ocs_hal_rq_buffer_t array.
7226  */
7227 static ocs_hal_rq_buffer_t *
7228 ocs_hal_rx_buffer_alloc(ocs_hal_t *hal, uint32_t rqindex, uint32_t count, uint32_t size)
7229 {
7230  ocs_t *ocs = hal->os;
7231  ocs_hal_rq_buffer_t *rq_buf = NULL;
7232  ocs_hal_rq_buffer_t *prq;
7233  uint32_t i;
7234 
7235  ocs_log_debug(hal->os, "allocate %d buffers of 0x%x size for rqindex %d\n",
7236  count, size, rqindex);
7237 
7238  if (count != 0) {
7239  rq_buf = ocs_malloc(hal->os, sizeof(*rq_buf) * count, OCS_M_NOWAIT | OCS_M_ZERO);
7240  if (rq_buf == NULL) {
7241  ocs_log_err(hal->os, "Failure to allocate unsolicited DMA trackers\n");
7242  return NULL;
7243  }
7244 
7245  for (i = 0, prq = rq_buf; i < count; i ++, prq++) {
7246  prq->rqindex = rqindex;
7247  if (ocs_dma_alloc(ocs, &prq->dma, size, OCS_MIN_DMA_ALIGNMENT)) {
7248  uint32_t j;
7249 
7250  ocs_log_err(hal->os, "DMA allocation failed\n");
7251  /* Free any previous DMA allocs. */
7252  for (j = 0; j < i; j++) {
7253  ocs_dma_free(ocs, &rq_buf[j].dma);
7254  }
7255 
7256  ocs_free(hal->os, rq_buf, sizeof(*rq_buf) * count);
7257  rq_buf = NULL;
7258  break;
7259  }
7260  }
7261  }
7262  return rq_buf;
7263 }
7264 
7265 /**
7266  * @brief Free an ocs_hal_rx_buffer_t array
7267  *
7268  * @par Description
7269  * The ocs_hal_rx_buffer_t array is freed, along with allocated DMA memory.
7270  *
7271  * @param hal Pointer to HAL object.
7272  * @param rq_buf Pointer to ocs_hal_rx_buffer_t array.
7273  * @param count Count of buffers in array.
7274  *
7275  * @return none
7276  */
7277 static void
7279 {
7280  ocs_t *ocs = hal->os;
7281  uint32_t i;
7282  ocs_hal_rq_buffer_t *prq;
7283 
7284  if (rq_buf != NULL) {
7285  for (i = 0, prq = rq_buf; i < count; i++, prq++) {
7286  ocs_dma_free(ocs, &prq->dma);
7287  }
7288  ocs_free(hal->os, rq_buf, sizeof(*rq_buf) * count);
7289  }
7290 }
7291 
7292 /**
7293  * @brief Allocate the RQ data buffers.
7294  *
7295  * @param hal Pointer to HAL object.
7296  *
7297  * @return Returns 0 on success, or a non-zero value otherwise.
7298  */
7299 static ocs_hal_rtn_e
7301 {
7302  ocs_t *ocs = hal->os;
7303  uint32_t num_chutes;
7304  uint32_t max_hal_rq;
7305  uint32_t i;
7306  int32_t rc = OCS_HAL_RTN_SUCCESS;
7307  uint32_t rqindex = 0;
7308 
7309  /* Capture the buffer sizes into a table */
7312 
7313  /*
7314  * Figure out how many chutes are running. We need to allocate the
7315  * specified number of buffers per chute.
7316  */
7317  if (ocs_hal_get(hal, OCS_HAL_NUM_CHUTES, &num_chutes) != OCS_HAL_RTN_SUCCESS) {
7318  ocs_log_test(ocs, "Failed to determine the number of chutes, a value of 1 is used\n");
7319  num_chutes = 1;
7320  }
7321 
7322  max_hal_rq = sli_get_max_qentries(&hal->sli, SLI_QTYPE_RQ);
7323 
7324  /*
7325  * Figure out the number of RQ buffers. Do not allow then to exceed
7326  * The RQ queue size. We need to allocate enough for both chutes. Store
7327  * the original number locally to set the chute field within this
7328  * function.
7329  */
7332 
7333  ocs_log_debug(ocs, "(%d chutes) allocate %d hdr buffers at 0x%x, %d data at 0x%x\n",
7334  num_chutes,
7339 
7340  /* Allocate hal_rq buffers */
7341  rqindex = 0;
7342  for (i = 0; i < num_chutes; i++) {
7343  if (hal->rq_buf_cnts[OCS_HAL_RQ_BUFFER_TYPE_HDR] != 0) {
7344  hal->rq_buf[rqindex] =
7346  rqindex,
7349  if (hal->rq_buf[rqindex] == NULL) {
7350  ocs_log_err(ocs, "ocs_hal_rx_buffer_alloc hdr_buf failed\n");
7351  rc = OCS_HAL_RTN_ERROR;
7352  break;
7353  }
7354  rqindex++;
7355  }
7356 
7357  if (hal->rq_buf_cnts[OCS_HAL_RQ_BUFFER_TYPE_DATA] != 0) {
7358  hal->rq_buf[rqindex] =
7360  rqindex,
7363  if (hal->rq_buf[rqindex] == NULL) {
7364  ocs_log_err(ocs, "ocs_hal_rx_buffer_alloc fb_buf failed\n");
7365  rc = OCS_HAL_RTN_ERROR;
7366  break;
7367  }
7368  rqindex++;
7369  }
7370  }
7371 
7372  return rc ? OCS_HAL_RTN_ERROR : OCS_HAL_RTN_SUCCESS;
7373 }
7374 
7375 /**
7376  * @brief Post the RQ data buffers to the chip.
7377  *
7378  * @param hal Pointer to the HAL object.
7379  *
7380  * @return Returns 0 on success, or a non-zero value otherwise.
7381  */
7382 static ocs_hal_rtn_e
7384 {
7385  uint32_t max_bufs;
7386  uint32_t i;
7387  uint32_t j;
7388  int32_t rc = 0;
7389  uint32_t rqindex = 0;
7390  uint32_t num_chutes;
7391 
7392  /* Post the buffers to the HAL */
7393  max_bufs = (hal->rq_buf_cnts[OCS_HAL_RQ_BUFFER_TYPE_HDR] >
7397 
7398  /*
7399  * Figure out how many chutes are running. We need to allocate the
7400  * specified number of buffers per chute.
7401  */
7402  if (ocs_hal_get(hal, OCS_HAL_NUM_CHUTES, &num_chutes) != OCS_HAL_RTN_SUCCESS) {
7403  ocs_log_test(hal->os, "Failed to determine the number of chutes, a value of 1 is used\n");
7404  num_chutes = 1;
7405  }
7406 
7407  /*
7408  * Post all buffer types in a single call to ocs_hal_rxbuffer().
7409  */
7410  rqindex = 0;
7411  for (i = 0; i < num_chutes; i++) {
7412  for (j = 0; j < max_bufs; j++) {
7413  ocs_hal_rq_buffer_t *hdr = NULL;
7414  ocs_hal_rq_buffer_t *data = NULL;
7415 
7416  if (j < hal->rq_buf_cnts[OCS_HAL_RQ_BUFFER_TYPE_HDR]) {
7417  hdr = &hal->rq_buf[rqindex][j];
7418  }
7419 
7420  if (j < hal->rq_buf_cnts[OCS_HAL_RQ_BUFFER_TYPE_DATA]) {
7421  data = &hal->rq_buf[rqindex + 1][j];
7422  }
7423 
7424  rc = ocs_hal_rxbuffer(hal, hdr, data);
7425  if (rc) {
7426  break;
7427  }
7428  }
7429  rqindex += 2;
7430  if (rc) {
7431  break;
7432  }
7433  }
7434 
7435  return rc;
7436 }
7437 
7438 /**
7439  * @brief Free the RQ data buffers.
7440  *
7441  * @param hal Pointer to HAL object.
7442  *
7443  */
7444 static void
7446 {
7447  uint32_t rqindex = 0;
7448  uint32_t num_chutes;
7449  uint32_t i;
7450 
7451  /*
7452  * Figure out how many chutes are running. We need to allocate the
7453  * specified number of buffers per chute.
7454  */
7455  if (ocs_hal_get(hal, OCS_HAL_NUM_CHUTES, &num_chutes) != OCS_HAL_RTN_SUCCESS) {
7456  ocs_log_test(hal->os, "Failed to determine the number of chutes, a value of 1 is used\n");
7457  num_chutes = 1;
7458  }
7459 
7460  /* Free hal_rq buffers */
7461  rqindex = 0;
7462  for (i = 0; i < num_chutes; i++) {
7464  hal->rq_buf[rqindex],
7467  hal->rq_buf[rqindex + 1],
7469  hal->rq_buf[rqindex] = NULL;
7470  hal->rq_buf[rqindex + 1] = NULL;
7471  rqindex += 2;
7472  }
7473 }
7474 
7475 /**
7476  * @brief Check pending error asynchronous callback function.
7477  *
7478  * @par Description
7479  * Invoke the HAL callback function for a given IO. This function is called
7480  * from the NOP mailbox completion context.
7481  *
7482  * @param hal Pointer to HAL object.
7483  * @param status Completion status.
7484  * @param ctx Pointer to command context.
7485  *
7486  * @return 0
7487  */
7488 static int32_t
7489 ocs_scsi_async_cb(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx)
7490 {
7491  if (ctx != NULL) {
7492  if (ctx->async_cb != NULL) {
7493  ocs_hal_async_cb_t cb = ctx->async_cb;
7494 
7495  ctx->async_cb = NULL;
7496  cb(hal, status, ctx->async_cb_arg);
7497  }
7498 
7499  ocs_hal_command_free_ctx(hal, ctx);
7500  }
7501  return 0;
7502 }
7503 
7504 /**
7505  * @brief Make an async callback using NOP mailbox command
7506  *
7507  * @par Description
7508  * Post a NOP mailbox command; the callback with argument is invoked upon completion
7509  * while in the event processing context.
7510  *
7511  * @param hal Pointer to HAL object.
7512  * @param callback Pointer to callback function.
7513  * @param arg Caller-provided callback.
7514  *
7515  * @return Returns 0 on success, or a negative error code value on failure.
7516  */
7517 int32_t
7519 {
7520  int32_t rc = 0;
7521  ocs_command_ctx_t *ctx;
7522 
7523  ctx = ocs_hal_command_get_ctx(hal);
7524  if (ctx == NULL) {
7525  ocs_log_err(hal->os, "no buffer for command\n");
7526  return OCS_HAL_RTN_NO_RESOURCES;
7527  }
7528  ctx->cb = ocs_scsi_async_cb;
7529 
7530  ctx->async_cb = callback;
7531  ctx->async_cb_arg = arg;
7532 
7533  if (sli_cmd_common_nop(&hal->sli, ctx->cmd, SLI4_BMBX_SIZE, 0, (uintptr_t)hal)) {
7534  rc = ocs_hal_command_queue(hal, ctx);
7535  if (rc) {
7536  ocs_log_test(hal->os, "Error posting NOP\n");
7537  }
7538  } else {
7539  ocs_hal_command_free_ctx(hal, ctx);
7540  ocs_log_test(hal->os, "Error building NOP message\n");
7541  rc = OCS_HAL_RTN_ERROR;
7542  }
7543 
7544  return rc;
7545 }
7546 
7547 void ocs_hal_cxn_req_invalidate(ocs_list_t *list_cxn)
7548 {
7549  ocs_cxn_t *cxn;
7550 
7551  ocs_list_foreach(list_cxn, cxn) {
7552  if (cxn->is_ini_cxn) {
7553  continue;
7554  }
7556  }
7557 }
7558 
7559 /* vim: set noexpandtab textwidth=120: */
7560 
7561 /**
7562  * @page iscsi_hal_api_overview HAL APIs
7563  * - @ref devInitShutdown
7564  * - @ref domain
7565  * - @ref port
7566  * - @ref node
7567  * - @ref io
7568  * - @ref interrupt
7569  *
7570  * <div class="overview">
7571  * The Hardware Abstraction Layer (HAL) insulates the higher-level code from the SLI-4
7572  * message details, but the higher level code must still manage domains, ports,
7573  * IT nexuses, and IOs. The HAL API is designed to help the higher level manage
7574  * these objects.<br><br>
7575  *
7576  * The HAL uses function callbacks to notify the higher-level code of events
7577  * that are received from the chip. There are currently three types of
7578  * functions that may be registered:
7579  *
7580  * <ul><li>link – This function is called whenever a link event is generated
7581  * within the HAL. This is generated whenever the link is disrupted or established.</li>
7582  * <li>unsolicited – This function is called whenever new data is received in
7583  * the SLI-4 receive queue.</li>
7584  * <li>connection – This function is called for remote node events, such as
7585  * a new incoming connection, a target data disgest occurred, or the
7586  * firmware has invalidated the connection.</li></ul>
7587  *
7588  * Upper layer functions may be registered by using the ocs_hal_callback() function.
7589  *
7590  * <img src="elx_iscsi_hal.jpg" alt="iSCSI HAL" title="iSCSI HAL" align="right"/>
7591  * <h2>iSCSI HAL API</h2>
7592  * The iSCSI HAL component builds upon the SLI-4 component to establish a flexible
7593  * interface for creating the necessary common objects and sending I/Os. It may be used
7594  * ā€œas isā€ in customer implementations or it can serve as an example of typical interactions
7595  * between a driver and the SLI-4 hardware. The broad categories of functionality include:
7596  * <ul><li>Setting-up and tearing-down of the HAL.</li>
7597  * <li>Allocating and using the common objects (SLI Port, domain, connections).</li>
7598  * <li>Sending and receiving I/Os.</li></ul>
7599  *
7600  * <h3>HAL Setup</h3>
7601  * To set up the HAL:
7602  *
7603  * <ol>
7604  * <li>Set up the HAL object using ocs_hal_setup().<br>
7605  * This step performs a basic configuration of the SLI-4 component and the HAL to
7606  * enable querying the hardware for its capabilities. At this stage, the HAL is not
7607  * capable of general operations (such as, receiving events or sending I/Os).</li><br><br>
7608  * <li>Configure the HAL according to the driver requirements.<br>
7609  * The HAL provides functions to discover hardware capabilities (ocs_hal_get()), as
7610  * well as configures the amount of resources required (ocs_hal_set()). The driver
7611  * must also register callback functions (ocs_hal_callback()) to receive notification of
7612  * various asynchronous events.<br><br>
7613  * @b Note: Once configured, the driver must initialize the HAL (ocs_hal_init()). This
7614  * step creates the underlying queues, commits resources to the hardware, and
7615  * prepares the hardware for operation.</li><br><br>
7616  * <li>After initializing the device, the driver can provide buffers to receive unsolicited
7617  * frames (ocs_hal_rxbuffer()).</li><br><br>
7618  * <li>The driver must also configure the IP network. The simplest way is to add a static
7619  * IP address using ocs_hal_portal_portal_ip_add() and to start listening on that
7620  * address using ocs_hal_portal_listen_start().
7621  * When the link comes up, the HAL notifies the driver using the link callback
7622  * function. This is the starting point of the driverĆ­s interaction with the common
7623  * objects.</li>
7624  * </ol>
7625  *
7626  * <h3>Allocating and Using Common Objects</h3>
7627  * Common objects provide a mechanism through which the various OneCore Storage
7628  * driver components share and track information. The main objects are:
7629  *
7630  * <ul><li>SCSI domain – For iSCSI, the SCSI domain is maintained internally by the
7631  * driver, and typically contains information on available iSCSI targets. The
7632  * creation of domains is under the control of the iSCSI driver. However, a pointer
7633  * to the domain must be registered with the HAL via the ocs_hal_domain_add()
7634  * function.</li>
7635  * <li>SLI Port (sport) – Represents the SLI Port and tracks the various VLANs. The
7636  * creation of SLI Port objects is under the control of the iSCSI driver.</li>
7637  * <li>Connection – the connection between the SLI Port and another device in the
7638  * SCSI domain.</li></ul>
7639  *
7640  * Before the driver can send I/Os, it must allocate the SCSI domain, SLI Port, and remote
7641  * node common objects and establish the connections between them. The goal is to
7642  * connect the driver to the SCSI domain to exchange I/Os with other devices. These
7643  * common object connections are shown in the following figure, iSCSI Driver Common Objects:
7644  * <img src="elx_iscsi_common_objects.jpg"
7645  * alt="iSCSI Driver Common Objects" title="iSCSI Driver Common Objects" align="center"/>
7646  *
7647  * The first step to create a connection to the SCSI domain is by allocating an SLI Port
7648  * object. The iSCSI device creates a default interface handle that may be used if no
7649  * VLANs are desired. The value of this handle may be retrieved by the driver through
7650  * the ocs_hal_portal_get_default() function. On identifying a domain, the driver allocates
7651  * a domain object and attaches to it using the previous SLI Port object.
7652  * Once attached to the domain, the driver can discover and attach to other devices
7653  * (remote nodes). The exact discovery method depends on the driver, but it typically
7654  * includes sending a request for available targets, querying an iSNS server, or an using an
7655  * out-of-band method. It is necessary to log in with devices before performing I/Os. Prior
7656  * to sending login-related protocol data units (PDUs) by using ocs_hal_io_send(), the
7657  * driver must allocate a remote node object (ocs_hal_cxn_alloc()). If the login negotiation
7658  * is successful, then the driver may start exchanging I/Os.
7659  *
7660  * <h3>Sending and Receiving I/Os</h3>
7661  * Since commands complete asynchronously, the caller must provide a HAL I/O object
7662  * that maintains the I/O state, as well as provide a callback function. The driver may use
7663  * the same callback function for all I/O operations, but each operation must use a unique
7664  * HAL I/O object. In the SLI-4 architecture, there is a direct association between the HAL
7665  * I/O object and the SGL used to describe the data. Therefore, a driver typically performs
7666  * the following operations:
7667  *
7668  * <ul><li>Allocates a HAL I/O object (ocs_hal_io_alloc()).</li>
7669  * <li>Formats the SGL, specifying both the HAL I/O object and the SGL.
7670  * (ocs_hal_io_init_sges() and ocs_hal_io_add_sge()).</li>
7671  * <li>Sends the HAL I/O (ocs_hal_io_send()).</li></ul>
7672  *
7673  * <h3>HAL Tear Down</h3>
7674  * To tear-down the HAL:
7675  *
7676  * <ol><li>Disable the interrupts to prevent receiving further data and events.</li>
7677  * <li>Destroy the HAL object (ocs_hal_teardown()).</li>
7678  * <li>Free any memory used by the HAL, such as buffers for unsolicited data.</li></ol>
7679  *
7680  * <br>
7681  * </div><!-- overview -->
7682  *
7683  */
ocs_sgl_type_e sgl_type
Definition: ocs_hal.h:453
This structure contains the type and associated fields for a CQE completion.
Definition: sli4.h:2017
uint8_t is_skyhawk
Definition: sli4.h:2208
Mailbox Completion Queue Entry.
Definition: sli4.h:1773
char * hal_war_version
Definition: ocs_hal.h:827
uint32_t atrt
Definition: sli4.h:419
ocs_hal_io_t * io
Definition: ocs_hal.h:615
int ocs_hal_fw_valid(ocs_hal_t *hal)
Check that firmware version meets minimum requirements.
Definition: ocs_hal.c:624
uint32_t sge_type
Definition: sli4.h:383
static int32_t ocs_hal_set_active_profile_cb(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx)
Called for the completion of set_active_profile for a user request.
Definition: ocs_hal.c:6444
uint32_t buffer_length
Definition: sli4.h:386
static void ocs_hal_cxn_cq_select(ocs_hal_t *hal, ocs_cxn_t *cxn)
Assign a CQ for the connection.
Definition: ocs_hal.c:4848
static ocs_cxn_t * ocs_hal_cxn_find(ocs_hal_t *hal, uint16_t wq_id)
Find the connection structure given the WQ_ID.
Definition: ocs_hal.c:714
int32_t(* cxn)(void *, ocs_hal_cxn_event_t *)
Definition: ocs_hal.h:789
sli4_port_type_e port_type
Definition: sli4.h:2203
uint32_t ref_tag_cmp
Definition: sli4.h:417
sli4_wqe_context_t * wq_ctx
Definition: ocs_hal.h:495
ocs_hal_rq_buffer_t * rq_buf
Definition: ocs_hal.h:712
uint32_t cq_index_mq
Definition: ocs_hal.h:758
ocs_hal_ip_type_e ip_type
Definition: ocs_hal.h:268
static void ocs_sport_unlock(ocs_sport_t *sport)
Definition: ocs_common.h:136
ocs_lock_t io_lock
Definition: ocs_hal.h:805
void * sli_queue_iscsi_icd_lookup(sli4_t *sli4, sli4_queue_t *q, uint16_t icd_index)
Returns the IO tied to a specific ICD index.
Definition: sli4.c:3604
Structure to track RQ buffers submitted to the chip.
Definition: ocs_hal.h:710
int32_t sli_iscsi_set_frag_bits(sli4_t *sli4)
Allocate the SGL pages assigned to the ICD table and post them to the chip.
Definition: sli4_iscsi.c:2253
void * upper_arg
Definition: ocs_hal.h:388
static int32_t ocs_hal_discovered_isns_cb(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx)
Called for the completion of retrieving the iSNS discovered list.
Definition: ocs_hal.c:3388
ocs_os_handle_t os
Definition: ocs_hal.h:725
ocs_hal_rtn_e ocs_hal_portal_gateway_add(ocs_hal_t *hal, ocs_hal_ip_address_t *gateway, portal_cb_t portal_cb, void *ul_arg)
adds the default gateway on an interface.
Definition: ocs_hal.c:4057
static ocs_hal_rtn_e ocs_hal_init_io(ocs_hal_t *)
Definition: ocs_hal.c:1916
SGL information structure.
Definition: ocs_hal.h:451
uint32_t ocs_hal_cxn_get_free_wq_cnt(ocs_hal_t *hal, ocs_cxn_t *cxn)
Returns the number of free entries on the work queue for this connection.
Definition: ocs_hal.c:5013
This structure contains the fields in a T_DATA_DIGEST completion.
Definition: sli4.h:2008
uint32_t length
Definition: sli4.h:2265
ocs_iscsi_route_table_entry_t entry[OCS_ISCSI_ROUTE_TABLE_ENTRIES_MAX]
Definition: ocs_iscsi.h:178
uint32_t n_sge
Definition: ocs_hal.h:489
uint32_t uses_dif
Definition: ocs_hal.h:479
static int32_t ocs_hal_portal_get_default_gateway_cb(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx)
Called for the completion of get_default_gateway for a user request.
Definition: ocs_hal.c:3972
ocs_hal_rtn_e ocs_hal_cxn_connect(ocs_hal_t *hal, ocs_cxn_t *cxn, ocs_hal_ip_address_t *ipaddr, uint32_t tcp_port, uint16_t window_size, uint8_t window_scale, cxn_cb_t cxn_cb, void *ul_arg)
Establish a TCP connection from an initiator to a target.
Definition: ocs_hal.c:4551
ocs_list_t io_ini_read_quarantine
Definition: ocs_hal.h:817
static int32_t ocs_hal_portal_ip_get_cb(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx)
Called for the completion if get_if_info for a user request.
Definition: ocs_hal.c:3874
uint32_t additional_status
Definition: sli4.h:606
uint16_t tag
Definition: ocs_hal.h:486
static int32_t ocs_hal_portal_std_cb_no_parms(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx)
Send the callback for a network interface delete command.
Definition: ocs_hal.c:3090
int32_t sli_fw_error_status(sli4_t *sli4)
Read the SLIPORT_SEMAPHORE and SLIPORT_STATUS registers to check if the port status indicates that a ...
Definition: sli4.c:4070
uint32_t data_offset
Definition: sli4.h:383
int32_t ocs_hal_get_active_profile(ocs_hal_t *hal, mgmt_cb_t cb, void *ul_arg)
Get the currently active profile.
Definition: ocs_hal.c:6398
uint32_t ref_tag_repl
Definition: ocs_hal.h:205
ocs_hal_rtn_e ocs_hal_cxn_close(ocs_hal_t *hal, ocs_cxn_t *cxn, uint8_t sendRst, cxn_cb_t cxn_cb, void *ul_arg)
Invalidates a connection and optionally sends a TCP Reset.
Definition: ocs_hal.c:5038
ocs_list_t io_free
Definition: ocs_hal.h:806
static void sli_chain_sge_build(sli4_t *sli4, sli4_chain_sge_t *sge, uint32_t icd_index, uint32_t frag_num, uint32_t offset)
Definition: sli4.h:2341
int32_t sli_cmd_iscsi_tgt_invalidate_connection(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint32_t conn_hdl, uint16_t cid, uint8_t sendRst)
write a ISCSI_TGT_INVALIDATE_CONNECTION command
Definition: sli4_iscsi.c:1152
uint8_t is_jumbo_set
Definition: ocs_hal.h:728
#define SLI4_OPC_ISCSI_NTWK_DISCOVER_ISNS_SERVER
Definition: sli4_iscsi.h:174
int32_t sli_cmd_common_tcp_upload(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint16_t wq_id, uint8_t graceful)
Write a COMMON_TCP_UPLOAD command.
Definition: sli4.c:1196
int32_t sli_cmd_iscsi_common_get_default_gateway(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint8_t isv4)
write a COMMON_ISCSI_NTWK_GET_DEFAULT_GATEWAY command
Definition: sli4_iscsi.c:509
uint32_t repl_ref_tag
Definition: ocs_hal.h:208
uint16_t size
Definition: sli4.h:2051
static ocs_hal_skyhawk_linkcfg_map_t skyhawk_linkcfg_map[]
Mapping from the HAL linkcfg enum to the Skyhawk link config IDs.
Definition: ocs_hal.c:6530
int32_t sli_cmd_iscsi_common_modify_default_gateway(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint8_t isadd, ocs_hal_ip_address_t *gateway)
write a COMMON_ISCSI_NTWK_MODIFY_DEFAULT_GATEWAY command
Definition: sli4_iscsi.c:549
uint32_t new_protocol
Definition: ocs_hal.c:6756
static int32_t ocs_hal_io_abort_cb(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx)
Receives the callback for an invalidate commands mailbox cmd.
Definition: ocs_hal.c:5931
sli4_ip_addr_subnet_t addr[5]
Definition: sli4_iscsi.h:558
ocs_hal_rtn_e ocs_hal_portal_isns_send_packet(ocs_hal_t *hal, ocs_hal_ip_address_t *isns_server, uint32_t tcp_port, void *packet, uint32_t pkt_len, portal_cb_t portal_cb, void *ul_arg)
Sends an iSNS packet to the requested server.
Definition: ocs_hal.c:4324
mailbox queue Element header
Definition: sli4.h:564
ocs_hal_rq_lookup_t * rq_lookup[OCS_HAL_MAX_NUM_RQ]
Definition: ocs_hal.h:772
#define SLI4_RESOURCE_DESCRIPTOR_TYPE_PCIE
Resource descriptor.
Definition: sli4.h:1386
ocs_hal_sgl_info_t * sgl_info
Definition: ocs_hal.h:803
ocs_hal_rtn_e ocs_hal_init(ocs_hal_t *hal)
Set up Hardware Abstraction Layer module.
Definition: ocs_hal.c:201
ocs_hal_property_e
enum identifying the HAL properties.
Definition: ocs_hal.h:97
static int32_t ocs_hal_get_linkcfg_cb(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx)
Called for the completion of get_linkcfg for a user request.
Definition: ocs_hal.c:6588
static int32_t ocs_hal_cxn_tcp_connect_cb(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx)
Process the completion of a request for a new tcp connection.
Definition: ocs_hal.c:4513
ocs_hal_rtn_e ocs_hal_command_queue(ocs_hal_t *hal, ocs_command_ctx_t *ctx)
Issue a SLI command.
Definition: ocs_hal.c:2164
cxn_cb_t * cxn_cb
Definition: ocs_hal.h:385
uint32_t n_cq
Definition: ocs_hal.h:738
uint32_t extended_status
Definition: sli4.h:1775
static int32_t ocs_hal_cb_wait_async(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx)
Called for the mailbox completion of command waiting for async messages.
Definition: ocs_hal.c:3351
#define ocs_queue_history_wq(...)
Definition: ocs_debug.h:146
This structure contains the fields in a DMSG completion.
Definition: sli4.h:1965
int32_t ocs_hal_portal_get_route_table_cb(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx)
Called for the completion of Get Route table command.
Definition: ocs_hal.c:3518
ocs_hal_io_t * io
Definition: ocs_hal.h:802
ocs_dma_t * payload2
Definition: ocs_hal.h:523
ocs_hal_rq_buffer_t * rq_buf[OCS_HAL_MAX_NUM_RQ]
Definition: ocs_hal.h:780
static ocs_hal_rtn_e ocs_hal_io_abort_send_cmd(ocs_hal_t *hal, ocs_hal_io_t **ios, uint16_t num_ios, ocs_hal_abort_type_e abort_type)
Abort a list of IOs.
Definition: ocs_hal.c:6006
int32_t sli_cmd_iscsi_cleanup_v0(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint16_t ulp_no, uint8_t hdrq_id, uint8_t dataq_id)
write a COMMON_ISCSI_CLEANUP (version 0) command
Definition: sli4_iscsi.c:671
static int32_t ocs_hal_cmd_submit_pending(ocs_hal_t *hal)
Submit queued (pending) mbx commands.
Definition: ocs_hal.c:2112
static uint32_t sli_is_dif_separate_capable(sli4_t *sli4)
Definition: sli4.h:2316
ocs_list_t io_tgt_write_quarantine
Definition: ocs_hal.h:815
uint8_t subnet[16]
Definition: sli4_iscsi.h:97
static void ocs_hal_sgl_info_free(ocs_hal_t *hal, ocs_hal_sgl_info_t *sgl_info)
Free a previously allocated HAL SGL Chaining object.
Definition: ocs_hal.c:5327
int32_t sli_eq_modify_delay(sli4_t *sli4, sli4_queue_t *eq, uint32_t num_eq, uint32_t shift, uint32_t delay_mult)
Modify the delay timer for all the EQs.
Definition: sli4.c:3098
static int32_t ocs_list_empty(ocs_list_t *list)
Test if a list is empty.
Definition: ocs_list.h:125
static void ocs_sport_lock(ocs_sport_t *sport)
Definition: ocs_common.h:131
uint8_t ip_address[16]
Definition: ocs_hal.h:261
ocs_dma_t non_emdedded_mem
Definition: ocs_hal.h:377
ocs_hal_rtn_e ocs_hal_domain_add(ocs_hal_t *hal, ocs_sli_port_t *sport, ocs_domain_t *domain)
Adds a domain object.
Definition: ocs_hal.c:3037
#define ocs_queue_history_init(...)
Definition: ocs_debug.h:149
Event Queue Entry.
Definition: sli4.h:1757
struct ocs_hal_io_param_t::@10 ini_io
T10 DIF information passed to the transport.
Definition: ocs_hal.h:201
ocs_hal_rtn_e ocs_hal_portal_gateway_remove(ocs_hal_t *hal, ocs_hal_ip_address_t *gateway, portal_cb_t portal_cb, void *ul_arg)
removes a default gateway on an interface.
Definition: ocs_hal.c:4101
int32_t sli_cmd_iscsi_common_get_if_info(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint32_t iface, uint8_t isv4)
write a COMMON_ISCSI_NTWK_GET_IF_INFO command
Definition: sli4_iscsi.c:629
struct sli4_queue_t::@33::@35 wq
int32_t sli_cmd_common_set_features(sli4_t *sli4, void *buf, size_t size, uint32_t feature, uint32_t param_len, void *parameter)
Write a COMMON_SET_FEATURES command.
Definition: sli4.c:1778
ocs_dma_t bhs_mem
Definition: ocs_hal.h:822
static uint32_t sli_is_sgl_chaining_capable(sli4_t *sli4)
Definition: sli4.h:2322
int32_t sli_fw_reset(sli4_t *sli4)
Definition: sli4.c:2822
int32_t ocs_hal_get_num_eq(ocs_hal_t *hal)
Definition: ocs_hal.c:2660
uint32_t n_sge
Definition: ocs_hal.h:459
void * mgmt_cb_arg
Definition: ocs_hal.h:387
int32_t ocs_hal_get_linkcfg(ocs_hal_t *hal, mgmt_cb_t cb, void *ul_arg)
Get the current link configuration.
Definition: ocs_hal.c:6628
ocs_hal_rtn_e ocs_hal_teardown(ocs_hal_t *hal)
Tear down Hardware Abstraction Layer module.
Definition: ocs_hal.c:2409
uint32_t rq_pl_size
Definition: ocs_hal.h:743
struct ocs_hal_io_param_t::@14 tgt_write
static ocs_hal_rtn_e ocs_hal_io_abort_add_entry(ocs_hal_t *hal, ocs_hal_io_t *io, ocs_hal_io_t **ios, uint16_t *io_index, ocs_hal_abort_type_e abort_type)
Abort a list of IOs.
Definition: ocs_hal.c:6098
uint8_t ip_addr[16]
Definition: sli4_iscsi.h:65
int32_t sli_setup(sli4_t *sli4, ocs_os_handle_t os, sli4_port_type_e port_type)
Setup the SLI context.
Definition: sli4.c:2531
uint32_t at
Definition: sli4.h:419
static ocs_hal_sgl_info_t * ocs_hal_io_get_sgl_info(ocs_hal_t *hal, ocs_hal_io_t *io)
Find the correct position to add an SGL. This may result in the allocation of a chained SGL List...
Definition: ocs_hal.c:5673
ocs_cxn_t * ocs_hal_cxn_alloc(ocs_hal_t *hal, uint32_t conn_hdl)
Gets a free connection structure.
Definition: ocs_hal.c:4468
#define OCS_HAL_CQ_NUM_FOR_INI
Definition: ocs_hal.c:61
sli4_queue_t ** pending_cqs[OCS_HAL_MAX_NUM_EQ]
Definition: ocs_hal.h:762
mgmt_cb_t * mgmt_cb
Definition: ocs_hal.h:386
int32_t sli_cmd_common_get_profile_config(sli4_t *sli4, void *buf, size_t size, uint64_t tag, ocs_dma_t *dma)
Write a COMMON_COMMON_GET_PROFILE_CONFIG command.
Definition: sli4.c:1454
uint32_t dif_op_rx
Definition: sli4.h:426
int32_t sli_cmd_iscsi_common_discovered_isns_servers(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint32_t iface)
write a COMMON_ISCSI_NTWK_DISCOVERED_ISNS_SERVERS command
Definition: sli4_iscsi.c:269
uint32_t was_tgt_write
Definition: ocs_hal.h:479
struct ocs_hal_t::@20 callback
#define SLI4_PORT_TYPE_DEFAULT
Definition: sli4.h:1399
uint32_t dif_blk_size
Definition: sli4.h:426
int32_t sli_cmd_iscsi_tgt_offload_connection_v1(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint32_t conn_hdl, uint32_t tcp_window_size, uint16_t ulp_no, uint16_t wq_id, uint16_t cq_id, uint16_t hdrq_id, uint16_t dataq_id, uint8_t nrs, ocs_hal_target_login_options_t *lgn_options)
write a ISCSI_TGT_OFFLOAD_CONNECTION command (version 1)
Definition: sli4_iscsi.c:1069
ocs_hal_rtn_e ocs_hal_set_linkcfg(ocs_hal_t *hal, mgmt_cb_t cb, ocs_hal_linkcfg_e value, void *ul_arg)
Set the link configuration (Skyhawk only).
Definition: ocs_hal.c:6716
static int32_t ocs_hal_stateless_cb_if_info(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx)
Called for the completion if get_if_info for a configure stateless command.
Definition: ocs_hal.c:3432
uint32_t app_tag_cmp
Definition: ocs_hal.h:206
COMMON_ISCSI_NTWK_GET_ROUTE_TABLE.
Definition: sli4_iscsi.h:448
int32_t sli_cmd_common_get_active_profile(sli4_t *sli4, void *buf, size_t size, uint64_t tag)
Write a COMMON_COMMON_GET_ACTIVE_PROFILE command.
Definition: sli4.c:1603
structure wrapping an IP address and subnet together with their type.
Definition: ocs_hal.h:267
int32_t sli_queue_write(sli4_t *sli4, sli4_queue_t *q, uint8_t *entry)
Write an entry to the queue object.
Definition: sli4.c:3469
uint32_t posted_limit
Definition: sli4.h:2064
static void * ocs_list_get_head(ocs_list_t *list)
Return the first item in the list.
Definition: ocs_list.h:292
#define ocs_queue_history_cqe(...)
Definition: ocs_debug.h:147
#define SLI_PAGE_SIZE
Definition: sli4.h:43
uint32_t list_cnt
Definition: ocs_hal.h:704
ocs_lock_t cmd_lock
Definition: ocs_hal.h:765
struct sli4_queue_t::@33::@34 flag
Structure to hold the fields returned on a target data digest error event.
Definition: ocs_hal.h:608
ocs_dma_t * bhs
Definition: ocs_hal.h:521
uint8_t fw_on_flash_version[32]
Definition: sli4.h:2244
#define OCS_HAL_MAX_NUM_RQ
Definition: ocs_hal.h:72
static ocs_hal_rtn_e ocs_hal_setup_cxns(ocs_hal_t *hal)
Initialize the pool of HAL connection objects.
Definition: ocs_hal.c:1766
uint32_t partial_data_length
Definition: sli4.h:1990
#define OCS_HAL_RQ_SIZE_HDR
Defines the size of the RQ buffers used for each RQ.
ocs_command_ctx_t * ocs_hal_command_get_ctx(ocs_hal_t *hal)
Issue a SLI command.
Definition: ocs_hal.c:2065
ocs_dma_t data
Definition: sli4.h:2264
static int32_t ocs_hal_cxn_std_cb_no_parms(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx)
Send the connection callback with no parameters passed back.
Definition: ocs_hal.c:4651
static ocs_hal_rtn_e ocs_hal_rx_allocate(ocs_hal_t *hal)
Allocate the RQ data buffers.
Definition: ocs_hal.c:7300
T10 DIF Seed Scatter-Gather Entry (SGE)
Definition: sli4.h:415
#define OCS_FW_VER_STR(x)
ocs_hal_rtn_e ocs_hal_cxn_reject(ocs_hal_t *hal, uint32_t conn_hdl, cxn_cb_t cxn_cb, void *ul_arg)
Rejects an incoming connection on a target.
Definition: ocs_hal.c:4685
union sli4_qentry_fields_t::@32 msg
ocs_dma_t isns_mem
Definition: ocs_hal.h:825
int32_t sli_cmd_common_set_profile_config(sli4_t *sli4, void *buf, size_t size, uint64_t tag, ocs_dma_t *dma, uint8_t profile_id, uint32_t descriptor_count, uint8_t isap)
Write a COMMON_COMMON_SET_PROFILE_CONFIG command.
Definition: sli4.c:1504
ocs_hal_ip_type_e
enum identifying the types of IP addresses.
Definition: ocs_hal.h:244
static ocs_hal_rq_buffer_t * ocs_hal_rx_buffer_alloc(ocs_hal_t *hal, uint32_t rqindex, uint32_t count, uint32_t size)
Allocate an ocs_hal_rx_buffer_t array.
Definition: ocs_hal.c:7228
ocs_hal_rtn_e ocs_hal_portal_esi_listen_stop(ocs_hal_t *hal, ocs_hal_ip_address_t *ipaddr, uint32_t tcp_port, portal_cb_t portal_cb, void *ul_arg)
Stops listening on an iSNS ESI TCP port.
Definition: ocs_hal.c:4425
uint32_t busy
Definition: ocs_hal.h:479
sli4_qentry_e ctype
Definition: sli4.h:2018
#define SLI4_SGE_DIF_OP_IN_CRC_OUT_NODIF
Definition: sli4.h:459
uint16_t sense_len
Definition: ocs_hal.h:424
ocs_hal_target_login_options_t lgn_options
Definition: ocs_hal.h:563
static int32_t ocs_hal_portal_isns_send_packet_cb(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx)
Send the callback for the sending of an iSNS packet.
Definition: ocs_hal.c:4288
ocs_hal_dhcp_state_t dhcp_state
Definition: ocs_hal.h:293
uint32_t index
Definition: sli4.h:2050
ocs_hal_rtn_e ocs_hal_set_active_profile(ocs_hal_t *hal, mgmt_cb_t cb, uint32_t profile_id, void *ul_arg)
Set the currently active profile.
Definition: ocs_hal.c:6479
ocs_hal_rtn_e ocs_hal_io_add_seed_sge(ocs_hal_t *hal, ocs_hal_io_t *io, ocs_hal_dif_info_t *dif_info)
Add a T10 PI seed scatter gather list entry.
Definition: ocs_hal.c:5793
ocs_hal_rtn_e ocs_hal_portal_listen_start(ocs_hal_t *hal, ocs_hal_ip_address_t *ipaddr, uint32_t tcp_port, portal_cb_t portal_cb, void *ul_arg)
Starts listening on a TCP port.
Definition: ocs_hal.c:4147
ocs_hal_rtn_e
defines common HAL return statuses.
Definition: ocs_hal.h:78
ocs_hal_portal_t portal
Definition: ocs_hal.h:291
ocs_hal_rtn_e ocs_hal_portal_ip_add(ocs_hal_t *hal, ocs_hal_portal_t portal, ocs_hal_ip_address_subnet_t *ipaddr, portal_cb_t portal_cb, void *ul_arg)
Add an IP address to an interface.
Definition: ocs_hal.c:3727
static uint32_t sli_is_dif_inline_capable(sli4_t *sli4)
Definition: sli4.h:2310
#define OCS_HAL_RQ_SIZE_DATA
ocs_hal_rtn_e ocs_hal_io_init_sges(ocs_hal_t *hal, ocs_hal_io_t *io, ocs_hal_io_type_e type, uint32_t offset)
Initialize the Scatter Gather List entries of an IO.
Definition: ocs_hal.c:5562
int32_t sli_iscsi_io_get_icd_and_sgl(sli4_t *sli4, uint32_t io_offset, uint16_t *icd, void **sgl)
return the ICD and virtual SGL pointer for an IO at the specified offset into the ICD table...
Definition: sli4_iscsi.c:2609
sli4_t sli
Definition: ocs_hal.h:726
ocs_hal_abort_type_e
HAL abort types.
Definition: ocs_hal.h:675
static uint32_t sli_is_ulp_enabled(sli4_t *sli4, uint16_t ulp)
Definition: sli4.h:2334
#define OCS_HAL_WQ_ENTRIES
Definition: ocs_hal.c:59
int32_t sli_queue_is_empty(sli4_t *sli4, sli4_queue_t *q)
Check if the given queue is empty.
Definition: sli4.c:3327
ocs_hal_rtn_e ocs_hal_command_bootstrap(ocs_hal_t *hal, uint8_t *cmd)
Issue a SLI command to the bootstrap mailbox.
Definition: ocs_hal.c:2018
ocs_cxn_t * cxn
Definition: ocs_hal.h:381
ocs_hal_reset_e
defines the types of resets.
Definition: ocs_hal.h:88
sli4_qentry_fields_tx_dif_error_t tx_dif_err
Definition: sli4.h:2027
uint8_t is_login
Definition: ocs_hal.h:554
uint32_t max_ios
Definition: sli4.h:2247
uint32_t uint32_t profile_description[128]
Definition: sli4.h:1518
static void ocs_hal_rx_buffer_free(ocs_hal_t *hal, ocs_hal_rq_buffer_t *rq_buf, uint32_t count)
Free an ocs_hal_rx_buffer_t array.
Definition: ocs_hal.c:7278
uint32_t itt
Definition: ocs_hal.h:491
static int32_t ocs_hal_command_process(ocs_hal_t *, int32_t, uint8_t *, size_t)
Definition: ocs_hal.c:1456
COMMON_ISCSI_ERROR_RECOVERY_INVALIDATE_CMDS.
Definition: sli4_iscsi.h:197
#define SLI4_SGE_TYPE_DISEED
Definition: sli4.h:470
#define SLI4_SGE_TYPE_DIF
Definition: sli4.h:469
ocs_hal_ip_address_t subnet
Definition: ocs_iscsi.h:172
ocs_domain_t * domain
Definition: ocs_hal.h:727
Structure to define what connection event occurred and it&#39;s parameters.
Definition: ocs_hal.h:637
bool enable_sgl_chaining
Definition: ocs_hal.h:744
HAL object.
Definition: ocs_hal.h:724
uint16_t lun
Definition: ocs_hal.h:508
uint16_t icd
Definition: ocs_hal.h:474
ocs_list_t cmd_pending
Definition: ocs_hal.h:767
uint32_t sge_type
Definition: sli4.h:419
#define OCS_HAL_TIMECHECK_ITERATIONS
Definition: ocs_hal.h:70
ocs_hal_rtn_e ocs_hal_io_add_sge(ocs_hal_t *hal, ocs_hal_io_t *io, uintptr_t addr, uint32_t length)
Add a Scatter Gather list Entry to an IO.
Definition: ocs_hal.c:5732
struct ocs_hal_io_param_t::@16 unassisted
uint32_t vlan_priority
Definition: ocs_hal.h:292
void ocs_hal_cxn_req_invalidate(ocs_list_t *list_cxn)
Definition: ocs_hal.c:7547
uint8_t dif_mode
Definition: ocs_hal.h:745
uint32_t profile_index
Definition: sli4.h:1518
int32_t sli_cmd_common_get_reconfig_link_info(sli4_t *sli4, void *buf, size_t size, uint64_t tag, ocs_dma_t *dma)
Write a COMMON_COMMON_GET_RECONFIG_LINK_INFO command.
Definition: sli4.c:1683
int32_t sli_cmd_iscsi_common_discover_isns_server(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint32_t iface, uint32_t retries)
write a COMMON_ISCSI_NTWK_DISCOVER_ISNS_SERVER command
Definition: sli4_iscsi.c:228
ocs_hal_rtn_e ocs_hal_portal_set_mac(ocs_hal_t *hal, uint8_t *mac_address, portal_cb_t portal_cb, void *ul_arg)
Set the MAC address on the portal.
Definition: ocs_hal.c:3122
ocs_hal_rtn_e ocs_hal_callback(ocs_hal_t *hal, ocs_hal_callback_e which, void *func, void *arg)
register a callback for the given event.
Definition: ocs_hal.c:2203
int32_t sli_queue_read(sli4_t *sli4, sli4_queue_t *q, uint8_t *entry)
Read an entry from the queue object.
Definition: sli4.c:3825
ocs_cxn_t * cxn
Definition: ocs_hal.h:623
sli4_qentry_fields_tsol_t tsol
Definition: sli4.h:2022
sli4_queue_t mq[1]
Definition: ocs_hal.h:751
int32_t sli_cmd_iscsi_tcp_connect_v0(sli4_t *sli4, void *buf, size_t size, uint64_t tag, ocs_hal_ip_address_t *ipaddr, uint32_t tcp_port, uint16_t cid, uint16_t cq_id, ocs_dma_t *data_out, uint16_t hdr_ring_id, uint16_t data_ring_id, uint8_t do_offload)
write a ISCSI_TCP_CONNECT_AND_OFFLOAD V0 command
Definition: sli4_iscsi.c:1549
#define ISCSI_CQE_CODE_UNSOL_HDR_NOTIFY
Definition: sli4_iscsi.h:1111
#define SLI4_SUBSYSTEM_COMMON_ISCSI
Definition: sli4.h:508
static uint32_t sli_get_max_sge(sli4_t *sli4)
Definition: sli4.h:2298
T10 DIF Scatter-Gather Entry (SGE)
Definition: sli4.h:443
ocs_hal_rq_list_t * rq_list[OCS_HAL_MAX_NUM_RQ]
Definition: ocs_hal.h:773
int32_t sli_teardown(sli4_t *sli4)
Tear down a SLI context.
Definition: sli4.c:2865
#define CONN_STATE_NEW_CONN
sli4_link_event_t link
Definition: ocs_hal.h:782
defines the parameters for an IO based on the IO type.
Definition: ocs_hal.h:501
int32_t sli_cmd_iscsi_tgt_stop_listen_server(sli4_t *sli4, void *buf, size_t size, uint64_t tag, ocs_hal_ip_address_t *ipaddr, uint32_t tcp_port)
write a ISCSI_TGT_STOP_LISTEN_SERVER command
Definition: sli4_iscsi.c:845
#define SLI4_SGE_DIF_OP_IN_CRC_OUT_CRC
Definition: sli4.h:462
#define SLI4_PORT_TYPE_FC
Definition: sli4.h:1398
#define SLI4_SGE_DIF_OP_IN_NODIF_OUT_CRC
Definition: sli4.h:458
uint32_t ocs_hal_portal_t
Definition: ocs_common.h:204
HAL command context.
Definition: ocs_hal.h:360
sli4_profile_descriptor_t profile_descriptor[MAX_PRODUCT_DESCRIPTORS]
Definition: sli4.h:1551
uint32_t check_app_tag
Definition: sli4.h:426
static int32_t ocs_hal_flush(ocs_hal_t *hal)
Definition: ocs_hal.c:1994
uint16_t instance_index
Definition: ocs_hal.h:487
ocs_dma_t * payload1
Definition: ocs_hal.h:522
ocs_hal_async_cb_t async_cb
Definition: ocs_hal.h:391
uint8_t sli_iscsi_conv_hal_ip_addr_type(ocs_hal_ip_type_e ip_type)
Converts the IP address type field to the SLI4 equivalent value.
Definition: sli4_iscsi.c:305
int32_t sli_cmd_iscsi_common_iface_delete(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint32_t iface)
write a COMMON_ISCSI_NTWK_IFACE_CREATE command
Definition: sli4_iscsi.c:103
ocs_lock_t cxn_lock
Definition: ocs_hal.h:819
void ocs_hal_command_free_ctx(ocs_hal_t *hal, ocs_command_ctx_t *ctx)
Issue a SLI command.
Definition: ocs_hal.c:2089
static int32_t ocs_hal_dhcp_async_event(ocs_hal_t *hal, sli4_dhcp_op_cmpl_event_t *event)
Processes the asynchronous DHCP completion message.
Definition: ocs_hal.c:1667
ocs_hal_port_protocol_e
Port protocols.
Definition: ocs_hal.h:142
ocs_hal_profile_descriptor_t descriptors[OCS_HAL_MAX_PROFILES]
Definition: ocs_hal.h:313
static int32_t ocs_hal_dmsg_process(ocs_hal_t *hal, sli4_qentry_fields_dmsg_t *dmsg)
Process an TCK acknowledgement(DMSG).
Definition: ocs_hal.c:994
uint32_t ref_tag_repl
Definition: sli4.h:418
struct ocs_hal_io_param_t::@12 ini_nop
static void * ocs_list_remove(ocs_list_t *list, void *item)
Remove an item from the list.
Definition: ocs_list.h:385
union ocs_hal_cxn_event_t::@18 params
uint32_t n_mq
Definition: ocs_hal.h:739
union sli4_queue_t::@33 u
static int32_t ocs_hal_dpdu_process(ocs_hal_t *hal, sli4_qentry_fields_dpdu_t *dpdu)
Process an unsolicited hdr/data.
Definition: ocs_hal.c:889
static uint32_t sli_get_max_queue(sli4_t *sli4, sli4_qtype_e qtype)
Definition: sli4.h:2282
static int32_t ocs_hal_cb_iscsi_async(void *, void *)
Callback function for SLI iSCSI asynchromous events.
Definition: ocs_hal.c:1721
uint32_t itt
Definition: ocs_hal.h:540
uint32_t status
Definition: sli4.h:606
uint32_t io_tgt_write_quarantine_cnt
Definition: ocs_hal.h:814
uint32_t completion_status
Definition: sli4.h:1775
int32_t sli_cmd_iscsi_tgt_get_connection_info(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint32_t conn_hdl)
write a ISCSI_TGT_GET_CONNECTION_INFO command
Definition: sli4_iscsi.c:889
uint16_t ulp
Definition: sli4.h:2055
COMMON_ISCSI_NTWK_SET_ROUTE_TABLE.
Definition: sli4_iscsi.h:421
#define OCS_HAL_WQ_ENTRIES_USED
Definition: ocs_hal.c:60
ocs_hal_rtn_e ocs_hal_portal_ip_remove(ocs_hal_t *hal, ocs_hal_portal_t portal, ocs_hal_ip_address_subnet_t *ipaddr, portal_cb_t portal_cb, void *ul_arg)
Removes an IP address from an interface.
Definition: ocs_hal.c:3802
static ocs_hal_rtn_e ocs_hal_rx_post(ocs_hal_t *hal)
Post the RQ data buffers to the chip.
Definition: ocs_hal.c:7383
uint32_t opcode
Definition: sli4.h:584
static int32_t ocs_scsi_async_cb(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx)
Check pending error asynchronous callback function.
Definition: ocs_hal.c:7489
ocs_hal_callback_e
enum identifying the types of callbacks that can be registered.
Definition: ocs_hal.h:653
#define SLI4_RESOURCE_DESCRIPTOR_TYPE_ISAP
Definition: sli4.h:1392
int32_t sli_cqe_async(sli4_t *sli4, void *buf)
Check asynchronous event completion entry.
Definition: sli4.c:1866
ocs_list_t rq_list_busy[OCS_HAL_MAX_NUM_RQ]
Definition: ocs_hal.h:774
Definition: sli4.h:2201
static void ocs_hal_cxn_cq_release(ocs_hal_t *hal, ocs_cxn_t *cxn)
Release a CQ for the connection.
Definition: ocs_hal.c:4896
ocs_hal_io_t * ocs_hal_io_alloc(ocs_hal_t *hal)
Allocate a HAL IO object.
Definition: ocs_hal.c:5170
int32_t sli_cmd_iscsi_get_connection_info(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint32_t conn_hdl)
write a ISCSI_GET_CONNECTION_INFO command
Definition: sli4_iscsi.c:1695
int32_t sli_cmd_iscsi_tgt_start_esi_listen(sli4_t *sli4, void *buf, size_t size, uint64_t tag, ocs_hal_ip_address_t *ipaddr, uint32_t tcp_port)
write a ISCSI_TGT_START_ESI_LISTEN command
Definition: sli4_iscsi.c:1197
#define SLI4_BMBX_SIZE
Definition: sli4.h:128
static uint32_t sli_is_dual_ulp_capable(sli4_t *sli4)
Definition: sli4.h:2328
ocs_hal_io_type_e
enum identifying IO types.
Definition: ocs_hal.h:227
ocs_lock_t lock
Definition: sli4.h:2049
uint8_t underrun
Definition: ocs_hal.h:531
static int32_t ocs_hal_set_linkcfg_cb(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx)
Called for the completion of set_linkcfg for a user request.
Definition: ocs_hal.c:6682
ocs_hal_io_t * ocs_hal_io_find_itt(ocs_hal_t *hal, uint32_t itt)
Find an IO based on the initiator task tag.
Definition: ocs_hal.c:7191
static void * ocs_list_get_tail(ocs_list_t *list)
Return the first item in the list.
Definition: ocs_list.h:308
uint16_t ulp_max
Definition: ocs_hal.h:733
sli4_queue_t rq[OCS_HAL_MAX_NUM_RQ]
Definition: ocs_hal.h:750
static uint32_t sli_get_max_qentries(sli4_t *sli4, sli4_qtype_e qtype)
Definition: sli4.h:2291
#define ocs_list_init(head, type, link)
Definition: ocs_list.h:113
uint32_t num_descriptors
Definition: ocs_hal.h:312
uint32_t sge_type
Definition: sli4.h:447
int32_t(* ocs_hal_async_cb_t)(struct ocs_hal_s *hal, int32_t status, void *arg)
Definition: ocs_hal.h:353
ocs_hal_rtn_e ocs_hal_reset(ocs_hal_t *hal, ocs_hal_reset_e reset)
Definition: ocs_hal.c:2558
sli4_qentry_fields_dpdu_t dpdu
Definition: sli4.h:2020
uint32_t num_entries
Definition: ocs_hal.h:456
static sli4_queue_t * ocs_hal_wq_find(ocs_hal_t *, uint16_t)
Find the WQ structure given the CQ_ID.
Definition: ocs_hal.c:670
int32_t sli_cmd_common_nop(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint64_t context)
Write a COMMON_NOP command.
Definition: sli4.c:1236
int32_t ocs_hal_portal_set_route_table_cb(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx)
Called for the completion of Set Route table command.
Definition: ocs_hal.c:3479
uint16_t rqindex
Definition: ocs_hal.h:695
sli4_queue_t eq[OCS_HAL_MAX_NUM_EQ]
Definition: ocs_hal.h:753
uint8_t frag_offset
Definition: ocs_hal.h:455
ocs_hal_rtn_e ocs_hal_io_abort(ocs_hal_t *hal, ocs_hal_io_t *io, ocs_hal_abort_scope_e abort_scope, ocs_hal_abort_type_e abort_type)
Abort a currently running IO.
Definition: ocs_hal.c:6148
ocs_hal_rtn_e ocs_hal_portal_delete(ocs_hal_t *hal, ocs_hal_portal_t portal, portal_cb_t portal_cb, void *ul_arg)
Delete a VLAN interface handle.
Definition: ocs_hal.c:3307
portal_cb_t * portal_cb
Definition: ocs_hal.h:384
uint32_t ip_type
Definition: ocs_hal.h:382
uint8_t piggy_back_status
Definition: ocs_hal.h:530
uint8_t post_sgl_ver
Definition: sli4.h:2242
static ocs_hal_rq_buffer_t * ocs_hal_rq_get(ocs_hal_t *hal, uint16_t rqindex, uint16_t bufindex, uint32_t addr_high, uint32_t addr_low, uint32_t length)
Process an unsolicited hdr/data.
Definition: ocs_hal.c:794
int32_t ocs_hal_process(ocs_hal_t *hal, uint32_t vector, uint32_t max_isr_time_msec)
Process events associated with the interrupt vector.
Definition: ocs_hal.c:2971
uint32_t proc_limit
Definition: sli4.h:2063
#define ocs_list_foreach_safe(list, item, nxt)
Iterate a linked list safely.
Definition: ocs_list.h:446
io_cb_t * done
Definition: ocs_hal.h:493
COMMON_SET_PROFILE_CONFIG.
Definition: sli4.h:1494
void * sli_queue_iscsi_icd_invalid(sli4_t *sli4, sli4_queue_t *q, uint16_t icd_index, uint8_t *wait_for_tcp_ack, uint8_t tcp_ack_status)
Processes a target command invalidation IO completion. Moves the WRB to the free list.
Definition: sli4.c:3651
uint32_t rq_buf_size[OCS_HAL_RQ_BUFFER_TYPE_MAX]
Definition: ocs_hal.h:779
ocs_hal_rtn_e ocs_hal_io_send(ocs_hal_t *hal, ocs_hal_io_type_e type, ocs_hal_io_t *io, uint32_t len, ocs_hal_io_param_t *iparam, ocs_cxn_t *cxn, io_cb_t cb, void *arg)
Send a read, write, or response IO.
Definition: ocs_hal.c:5370
void * host_arg
Definition: sli4.h:2065
int32_t sli_eq_parse(sli4_t *sli4, uint8_t *buf, uint16_t *cq_id)
Parse an EQ entry to retrieve the CQ_ID for this event.
Definition: sli4.c:3982
int32_t sli_cmd_iscsi_common_configure_stateless_ip_addr(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint32_t iface, uint8_t isv4, uint32_t retries)
write a COMMON_ISCSI_NTWK_CONFIGURE_STATELESS_IP_ADDR command
Definition: sli4_iscsi.c:142
ocs_hal_linkcfg_e
Link configurations.
Definition: ocs_hal.h:184
static uint32_t sli_get_sli_rev(sli4_t *sli4)
Definition: sli4.h:2356
struct sli4_t::@39 vpd
uint32_t embedded
Definition: sli4.h:566
ocs_hal_rtn_e ocs_hal_io_add_dif_sge(ocs_hal_t *hal, ocs_hal_io_t *io, uintptr_t addr)
Add a T10 DIF scatter gather list entry to an IO.
Definition: ocs_hal.c:5880
ocs_hal_ip_address_subnet_t ipsub[5]
Definition: ocs_hal.h:295
ocs_hal_rtn_e ocs_hal_get(ocs_hal_t *hal, ocs_hal_property_e prop, uint32_t *value)
Definition: ocs_hal.c:2666
#define SLI4_PORT_TYPE_ISCSI
Definition: sli4.h:1395
int32_t sli_queue_free(sli4_t *sli4, sli4_queue_t *q)
Free a queue.
Definition: sli4.c:3218
uint8_t has_fw_ue
Definition: ocs_hal.h:731
uint32_t disable_app_ffff
Definition: ocs_hal.h:208
int32_t sli_cmd_iscsi_ntwk_set_mtu(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint32_t mtu)
write a ISCSI_NTWK_SET_MTU command
Definition: sli4_iscsi.c:1504
ocs_hal_cxn_new_t cxn_new
Definition: ocs_hal.h:642
uint8_t fw_version[32]
Definition: sli4.h:2243
uint16_t ulp_start
Definition: ocs_hal.h:732
#define ocs_queue_history_free(...)
Definition: ocs_debug.h:150
ocs_hal_ip_address_t ip_addr
Definition: ocs_iscsi.h:171
static void ocs_node_lock_init(ocs_node_t *node)
Definition: ocs_common.h:417
#define ISCSI_CMD_NOOP
static int32_t ocs_hal_mq_process(ocs_hal_t *, int32_t, sli4_queue_t *)
Process entries on the give mailbox queue.
Definition: ocs_hal.c:1498
ocs_hal_rtn_e ocs_hal_set_ptr(ocs_hal_t *hal, ocs_hal_property_e prop, void *value)
Definition: ocs_hal.c:2897
int32_t _sli_queue_peek(sli4_t *sli4, sli4_queue_t *q, uint32_t index, uint8_t *entry)
Definition: sli4.c:3941
#define RC_MOVE_ASYNC
Definition: ocs_hal.c:58
#define OCS_HAL_RQ_NUM_DATA
#define SLI4_ISCSI_WQE_SIZE
Definition: sli4_iscsi.h:1045
int32_t sli_cmd_iscsi_invalidate_cmds(sli4_t *sli4, void *buf, size_t size, uint64_t tag, ocs_dma_t *msg_mem, ocs_hal_io_t **ios, uint16_t num_ios, ocs_hal_abort_type_e abort_type)
write a COMMON_ISCSI_INVALIDATE_COMMANDS command
Definition: sli4_iscsi.c:1739
uint32_t n_wq
Definition: ocs_hal.h:741
ocs_hal_ip_type_e ip_type
Definition: ocs_hal.h:260
int32_t sli_cmd_iscsi_common_modify_ip_addr(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint32_t iface, uint8_t isadd, ocs_hal_ip_address_subnet_t *ipaddr)
write a COMMON_ISCSI_NTWK_MODIFY_IP_ADDR command
Definition: sli4_iscsi.c:462
sli4_qentry_fields_isol_t isol
Definition: sli4.h:2021
uint8_t use_v1_multi_protocol
Definition: ocs_hal.h:730
uint32_t dif_op_tx
Definition: sli4.h:426
Defines a wrapper for the RQ payload buffers so that we can place it back on the proper queue...
Definition: ocs_hal.h:694
sli4_qentry_fields_tcmdinv_t tcmdinv
Definition: sli4.h:2026
HAL IO object.
Definition: ocs_hal.h:471
static int32_t ocs_hal_cxn_get_info_cb(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx)
Process the completion of a request for connection information.
Definition: ocs_hal.c:4727
uint16_t wrb_index
Definition: sli4.h:2037
sli4_ip_addr_subnet_t ip_sub
Definition: sli4_iscsi.h:110
This structure is used to track the WQEs for iSCSI.
Definition: sli4.h:2034
int32_t(* bounce)(void(*)(void *arg), void *arg, uint32_t cpu)
Definition: ocs_hal.h:793
#define ISCSI_CQE_CODE_UNSOL_DATA_DIGEST_ERROR
Definition: sli4_iscsi.h:1113
static int32_t ocs_hal_tsol_process(ocs_hal_t *hal, sli4_qentry_fields_tsol_t *tsol)
Process an solicited target IO completion.
Definition: ocs_hal.c:1020
uint32_t buffer_address_low
Definition: sli4.h:446
A Profile List.
Definition: ocs_hal.h:311
void * async_cb_arg
Definition: ocs_hal.h:392
uint16_t length
Definition: sli4.h:2052
#define HW_MAX_SGLE_SIZE
Definition: sli4_iscsi.h:44
This structure contains the fields in a T_DATA_DIGEST completion.
Definition: sli4.h:1974
uint16_t id
Definition: sli4.h:2054
ocs_dma_t dataout_tmpl_mem
Definition: ocs_hal.h:823
This structure contains the fields in a CNXINV completion.
Definition: sli4.h:1987
int32_t ocs_hal_event_check(ocs_hal_t *hal, uint32_t vector)
Check for events associated with the interrupt vector.
Definition: ocs_hal.c:2924
Defines the iSCSI nop-out PDU header.
uint32_t sge_offset
Definition: ocs_hal.h:490
COMMON_ISCSI_NTWK_DISCOVER_ISNS_SERVER.
Definition: sli4_iscsi.h:363
static int32_t ocs_hal_isol_process(ocs_hal_t *hal, sli4_qentry_fields_isol_t *isol)
Process an solicited initiator IO completion.
Definition: ocs_hal.c:1061
int32_t sli_iscsi_post_sgl_pages(sli4_t *sli4)
Allocate the SGL pages assigned to the ICD table and post them to the chip.
Definition: sli4_iscsi.c:2545
static uint32_t sli_get_sli_family(sli4_t *sli4)
Definition: sli4.h:2362
struct ocs_hal_io_param_t::@15 tgt_rsp
sli4_qentry_fields_cnxinv_t cnxinv
Definition: sli4.h:2025
struct ocs_hal_io_param_t::@17 context_upd
static uint32_t sli_get_vpd_len(sli4_t *sli4)
Definition: sli4.h:2380
uint32_t check_crc
Definition: sli4.h:426
ocs_list_t sgl_list
Definition: ocs_hal.h:488
uint32_t ocs_instance(void *os)
Return the instance index of an opaque ocs structure.
Definition: ocs_driver.c:160
int32_t sli_cmd_iscsi_common_set_route_table(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint8_t isadd, ocs_hal_ip_address_subnet_t *hal_ipsub, ocs_hal_ip_address_t *hal_gateway, ocs_dma_t *dma)
write a COMMON_ISCSI_NTWK_SET_ROUTE_TABLE command
Definition: sli4_iscsi.c:385
Used for returning IP information in return from ocs_hal_portal_ip_get()
Definition: ocs_hal.h:290
void ocs_hal_workaround_setup(struct ocs_hal_s *hal)
Setup HAL runtime workarounds.
ocs_cxn_t * node
Definition: ocs_hal.h:475
int32_t sli_cmd_iscsi_tcp_connect_v1(sli4_t *sli4, void *buf, size_t size, uint64_t tag, ocs_hal_ip_address_t *ipaddr, uint32_t tcp_port, uint16_t cid, uint16_t cq_id, ocs_dma_t *data_out, uint16_t hdr_ring_id, uint16_t data_ring_id, uint8_t do_offload, uint16_t window_size, uint8_t window_scale, uint32_t tcp_mss)
Definition: sli4_iscsi.c:1593
#define SLI4_SET_FEATURES_DIF_MEMORY_MODE
Definition: sli4.h:1733
static int32_t ocs_hal_portal_create_cb(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx)
Send the callback for a network interface create command.
Definition: ocs_hal.c:3230
ocs_hal_rtn_e ocs_hal_cxn_offload(ocs_hal_t *hal, ocs_cxn_t *cxn, uint32_t tcp_window_size, uint8_t data_digest, uint8_t hdr_digest, uint32_t max_rcv_dsl, cxn_cb_t cxn_cb, void *ul_arg)
Offloads an incoming connection on a target.
Definition: ocs_hal.c:4919
static ocs_hal_linkcfg_e ocs_hal_linkcfg_from_config_id(const uint32_t config_id)
Helper function for getting the HAL linkcfg enum from a Skyhawk config ID.
Definition: ocs_hal.c:6565
uint32_t subsystem
Definition: sli4.h:584
uint32_t auto_incr_ref_tag
Definition: sli4.h:426
int32_t sli_cmd_iscsi_tgt_isns_send_packet(sli4_t *sli4, void *buf, size_t size, uint64_t tag, ocs_hal_ip_address_t *isns_server, uint32_t tcp_port, void *packet, uint32_t pkt_length, ocs_dma_t *pkt_mem)
write a ISCSI_TGT_ISNS_SEND_PACKET command
Definition: sli4_iscsi.c:1344
ocs_hal_rtn_e ocs_hal_cxn_free(ocs_hal_t *hal, ocs_cxn_t *cxn)
Frees a connection object for re-use.
Definition: ocs_hal.c:5141
int32_t sli_queue_arm(sli4_t *sli4, sli4_queue_t *q, uint8_t arm)
Arm or dis-arm a queue.
Definition: sli4.c:3356
uint16_t n_posted
Definition: sli4.h:2053
HAL link configuration enum to Skyhawk link config ID mapping.
Definition: ocs_hal.c:6522
int32_t sli_iscsi_defq_alloc(sli4_t *sli4, sli4_queue_t *header, sli4_queue_t *payload, uint32_t n_entries, uint32_t hsize, uint32_t psize, sli4_queue_t *cq, uint16_t ulp)
allocate a receive queue
Definition: sli4_iscsi.c:2173
uint32_t cq_index_wq_ini
Definition: ocs_hal.h:757
sli4_qentry_fields_data_digest_t data_digest
Definition: sli4.h:2024
Structure to track RQ buffers submitted to the chip.
Definition: ocs_hal.h:702
struct sli4_t::@38 config
int32_t sli_reset(sli4_t *sli4)
Definition: sli4.c:2809
uint32_t residual_cnt
Definition: ocs_hal.h:417
ocs_list_t cxn_free
Definition: ocs_hal.h:820
static ocs_hal_rtn_e ocs_hal_set_dif_mode(ocs_hal_t *hal)
Sets the DIF mode value.
Definition: ocs_hal.c:1943
static int32_t ocs_hal_get_active_profile_cb(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx)
Called for the completion of get_active_profile for a user request.
Definition: ocs_hal.c:6361
uint8_t is_hal_initialized
Definition: ocs_hal.h:729
ocs_hal_rtn_e ocs_hal_portal_esi_listen_start(ocs_hal_t *hal, ocs_hal_ip_address_t *ipaddr, uint32_t tcp_port, portal_cb_t portal_cb, void *ul_arg)
Starts listening for iSNS ESI messages on a TCP port.
Definition: ocs_hal.c:4380
ocs_hal_rtn_e ocs_hal_get_profile_list(ocs_hal_t *hal, mgmt_cb_t mgmt_cb, void *ul_arg)
Get a list of available profiles.
Definition: ocs_hal.c:6304
ocs_hal_abort_scope_e
HAL abort types.
Definition: ocs_hal.h:664
static int32_t ocs_hal_cmdinv_process(ocs_hal_t *hal, sli4_qentry_fields_tcmdinv_t *cmdinv)
Process an target command error IO completion.
Definition: ocs_hal.c:1117
static int32_t ocs_hal_compl_async_ctx_bad_status(ocs_hal_t *hal, ocs_command_ctx_t *ctx, uint8_t status, uint8_t additional_status)
Sends a bad status to the caller when an asynchronous message fails.
Definition: ocs_hal.c:1565
static uint32_t sli_is_dif_capable(sli4_t *sli4)
Definition: sli4.h:2304
uint32_t ip_type
Definition: sli4_iscsi.h:62
ocs_hal_rtn_e ocs_hal_set(ocs_hal_t *hal, ocs_hal_property_e prop, uint32_t value)
Definition: ocs_hal.c:2790
uint16_t icd
Definition: ocs_hal.h:454
struct ocs_hal_io_param_t::@11 ini_tmf
sli4_ip_addr_t gateway
Definition: sli4_iscsi.h:111
int32_t sli_cmd_iscsi_cleanup_v1(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint16_t ulp_no, uint16_t hdrq_id, uint16_t dataq_id)
write a COMMON_ISCSI_CLEANUP (version 1) command
Definition: sli4_iscsi.c:716
static void ocs_list_add_tail(ocs_list_t *list, void *item)
Add an item to the tail of the list.
Definition: ocs_list.h:263
void ocs_hal_io_free(ocs_hal_t *hal, ocs_hal_io_t *io)
Free a previously allocated HAL IO object.
Definition: ocs_hal.c:5231
ocs_hal_rtn_e ocs_hal_portal_gateway_get(ocs_hal_t *hal, ocs_hal_ip_type_e ip_type, portal_cb_t portal_cb, void *ul_arg)
Retrieves the default gateway on an interface.
Definition: ocs_hal.c:4012
static void ocs_node_lock_free(ocs_node_t *node)
Definition: ocs_common.h:422
uint32_t auto_incr_ref_tag
Definition: ocs_hal.h:208
uint32_t ref_tag_cmp
Definition: ocs_hal.h:204
ocs_hal_dif_oper_e dif_oper
Definition: ocs_hal.h:202
int32_t(* cb)(struct ocs_hal_s *, int32_t, struct ocs_command_ctx_s *)
Definition: ocs_hal.h:373
This structure is used to track the SLI4 queues.
Definition: sli4.h:2046
sli4_queue_t * cq
Definition: ocs_hal.h:752
static void ocs_hal_io_check_quarantine_list(ocs_hal_t *hal, uint32_t *quarantine_cnt, ocs_list_t *quarantine_list)
If there are more than 4 objects on the quarantine list, then free IOs until there are at most 4 left...
Definition: ocs_hal.c:5209
#define ocs_list_remove_head(list)
Remove and return an item from the head of the list.
Definition: ocs_list.h:374
uint32_t cmd_head_count
Definition: ocs_hal.h:769
TARGET_LOGIN_OPTIONS.
Definition: ocs_hal.h:321
uint8_t ip_addr[16]
Definition: sli4_iscsi.h:96
ocs_hal_rtn_e ocs_hal_domain_free(ocs_hal_t *hal, ocs_domain_t *domain)
Free a domain object.
Definition: ocs_hal.c:3061
static void ocs_list_add_head(ocs_list_t *list, void *item)
Add an item to the head of the list.
Definition: ocs_list.h:235
structure wrapping an IP address together with it&#39;s type.
Definition: ocs_hal.h:259
uint32_t aborted
Definition: ocs_hal.h:479
int32_t sli_cmd_common_set_active_profile(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint32_t fd, uint32_t active_profile_id)
Write a COMMON_COMMON_SET_ACTIVE_PROFILE command.
Definition: sli4.c:1642
uint32_t num_wq_per_cq
Definition: ocs_hal.h:759
void cxn_cb_t(void *ul_arg, int32_t status, uint32_t ext_status, void *params)
connection callback function prototype.
Definition: ocs_hal.h:340
static void ocs_node_lock(ocs_node_t *node)
Definition: ocs_common.h:432
uint32_t rq_buf_cnts[OCS_HAL_RQ_BUFFER_TYPE_MAX]
Definition: ocs_hal.h:778
uint32_t index
Definition: ocs_hal.h:713
#define ISCSI_CMD_DATA_OUT
uint32_t buffer_address_low
Definition: sli4.h:382
#define SLI4_SGE_TYPE_DATA
Definition: sli4.h:467
static void ocs_hal_rx_free(ocs_hal_t *hal)
Free the RQ data buffers.
Definition: ocs_hal.c:7445
uint8_t set_dm
Definition: ocs_hal.h:553
ocs_hal_dif_info_t * dif_info
Definition: ocs_hal.h:510
ocs_hal_rtn_e ocs_hal_portal_listen_stop(ocs_hal_t *hal, ocs_hal_ip_address_t *ipaddr, uint32_t tcp_port, portal_cb_t portal_cb, void *ul_arg)
Stops listening on a TCP port.
Definition: ocs_hal.c:4201
defines a structure to contain the fields specific to an initiator IO completion. ...
Definition: ocs_hal.h:416
int32_t sli_cmd_iscsi_ini_invalidate_connection(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint32_t conn_hdl, uint16_t cid, uint8_t sendRst)
write a ISCSI_INI_INVALIDATE_CONNECTION command
Definition: sli4_iscsi.c:1288
ocs_hal_workaround_t workaround
Definition: ocs_hal.h:828
int32_t sli_cq_parse(sli4_t *sli4, sli4_queue_t *cq, uint8_t *cqe, sli4_qentry_fields_t *fields)
Parse a CQ entry to retrieve event type and associated queue.
Definition: sli4.c:4009
ocs_hal_rtn_e ocs_hal_cxn_get_info(ocs_hal_t *hal, ocs_cxn_t *cxn, cxn_cb_t cxn_cb, void *ul_arg)
Retrieves information about an incoming context.
Definition: ocs_hal.c:4795
static int32_t ocs_hal_cxn_invalid_process(ocs_hal_t *hal, sli4_qentry_fields_cnxinv_t *cxn_invalid)
Process an Connection invalid completion entry.
Definition: ocs_hal.c:1173
static void * ocs_list_next(ocs_list_t *list, void *item)
Get the next item on the list.
Definition: ocs_list.h:339
uint32_t check_app_tag
Definition: ocs_hal.h:208
struct ocs_hal_s * hal
Definition: ocs_hal.h:363
ocs_list_t cmd_async
Definition: ocs_hal.h:768
uint32_t app_tag_cmp
Definition: sli4.h:426
uint8_t additional_status
Definition: sli4.h:2132
uint32_t chained
Definition: ocs_hal.h:479
struct ocs_hal_t::@21 args
ocs_hal_rtn_e ocs_hal_portal_isns_discover(ocs_hal_t *hal, ocs_hal_portal_t portal, portal_cb_t portal_cb, void *ul_arg)
Discovers iSNS servers via DHCP.
Definition: ocs_hal.c:4245
void(* ocs_hal_fw_cb_t)(int32_t status, uint32_t bytes_written, void *arg)
Definition: ocs_hal.h:926
void sli_queue_iscsi_cleanup(void *hal, sli4_t *sli4, sli4_queue_t *q)
Moves any WQE entries from the busy back to the free list when a connection is uploaded.
Definition: sli4.c:3718
ocs_list_t rq_list_free[OCS_HAL_MAX_NUM_RQ]
Definition: ocs_hal.h:775
int32_t sli_queue_iscsi_tcp_ack(sli4_t *sli4, sli4_queue_t *q, uint8_t wqe_index)
Processes a TCP ACK completion.
Definition: sli4.c:3532
static char * sli_get_ipl_name(sli4_t *sli4)
Definition: sli4.h:2386
int32_t _sli_queue_poke(sli4_t *sli4, sli4_queue_t *q, uint32_t index, uint8_t *entry)
Definition: sli4.c:3908
ocs_dma_t bmbx
Definition: sli4.h:2262
#define OCS_HAL_MAX_ABORT_IOS
Definition: ocs_hal.c:62
struct ocs_hal_io_param_t::@13 tgt_read
static void ocs_node_unlock(ocs_node_t *node)
Definition: ocs_common.h:437
COMMON_ISCSI_NTWK_CONFIGURE_STATELESS_IP_ADDR.
Definition: sli4_iscsi.h:331
uint32_t statsn
Definition: ocs_hal.h:564
uint8_t mac_addr[6]
Definition: sli4.h:2210
sli4_qentry_fields_dmsg_t dmsg
Definition: sli4.h:2023
#define OCS_HAL_RQ_NUM_HDR
Defines the number of the RQ buffers for each RQ.
uint32_t n_eq
Definition: ocs_hal.h:737
uint32_t check_ref_tag
Definition: sli4.h:426
uint32_t tcmd_thread_id(void)
Definition: ocs_hal.c:7209
Defines the iSCSI data-out PDU header.
uint8_t pf_num
Definition: sli4.h:2209
int32_t sli_queue_reset(sli4_t *sli4, sli4_queue_t *q)
Zero all queue entries and reset the indexes.
Definition: sli4.c:3294
uint32_t n_rq
Definition: ocs_hal.h:740
ocs_hal_rtn_e ocs_hal_portal_get_route_table(ocs_hal_t *hal, portal_cb_t portal_cb, void *ul_arg)
Read routing table.
Definition: ocs_hal.c:3661
This structure contains the fields in a DPDU completion.
Definition: sli4.h:1926
ocs_dma_t dma
Definition: ocs_hal.h:696
uint32_t last
Definition: sli4.h:383
uint8_t cmd[SLI4_BMBX_SIZE]
Definition: ocs_hal.h:370
static void ocs_domain_lock(ocs_domain_t *domain)
Definition: ocs_common.h:186
ocs_hal_rtn_e ocs_hal_set_port_protocol(ocs_hal_t *hal, uint32_t pci_func, ocs_hal_port_protocol_e new_protocol, mgmt_cb_t cb, void *ul_arg)
Set the port protocol.
Definition: ocs_hal.c:7116
ocs_hal_ip_address_t gateway
Definition: ocs_iscsi.h:173
ocs_hal_unsol_cb_t unsolicited
Definition: ocs_hal.h:791
sli4_queue_t * wq
Definition: ocs_hal.h:749
uint32_t check_ref_tag
Definition: ocs_hal.h:208
static int32_t ocs_hal_cq_find(ocs_hal_t *, uint16_t)
Find the CQ structure given the CQ_ID.
Definition: ocs_hal.c:637
uint32_t buffer_address_high
Definition: sli4.h:381
int32_t sli_queue_alloc(sli4_t *sli4, uint32_t qtype, sli4_queue_t *q, uint32_t n_entries, sli4_queue_t *assoc, uint16_t ulp)
Allocate a queue.
Definition: sli4.c:3135
int32_t sli_cmd_iscsi_tgt_stop_esi_listen(sli4_t *sli4, void *buf, size_t size, uint64_t tag, ocs_hal_ip_address_t *ipaddr, uint32_t tcp_port)
write a ISCSI_TGT_STOP_ESI_LISTEN command
Definition: sli4_iscsi.c:1242
uint32_t ip_count
Definition: ocs_hal.h:294
uint32_t data_sn
Definition: ocs_hal.h:529
uint32_t buffer_address_high
Definition: sli4.h:445
int32_t ocs_hal_async_call(ocs_hal_t *hal, ocs_hal_async_cb_t callback, void *arg)
Make an async callback using NOP mailbox command.
Definition: ocs_hal.c:7518
ocs_hal_rtn_e ocs_hal_portal_set_route_table(ocs_hal_t *hal, ocs_hal_ip_address_subnet_t *hal_ipsub, ocs_hal_ip_address_t *hal_gateway, int32_t add, portal_cb_t portal_cb, void *ul_arg)
Add/Remove an entry to routing table.
Definition: ocs_hal.c:3593
int32_t sli_bmbx_command(sli4_t *sli4)
Submit a command to the bootstrap mailbox and check the status.
Definition: sli4.c:405
ocs_hal_cxn_event_e event
Definition: ocs_hal.h:638
ocs_hal_linkcfg_e linkcfg
Definition: ocs_hal.c:6523
static ocs_hal_rtn_e ocs_hal_setup_io(ocs_hal_t *)
Initialize the pool of HAL IO objects.
Definition: ocs_hal.c:1837
int32_t sli_cmd_iscsi_tgt_offload_connection_v0(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint32_t conn_hdl, uint32_t tcp_window_size, uint16_t ulp_no, uint16_t wq_id, uint16_t cq_id, uint8_t hdrq_id, uint8_t dataq_id, uint8_t nrs, ocs_hal_target_login_options_t *lgn_options)
write a ISCSI_TGT_OFFLOAD_CONNECTION command (version 0)
Definition: sli4_iscsi.c:979
int32_t sli_cmd_common_set_be_configuration_and_resources(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint8_t *mac_addr)
Write a COMMON_COMMON_SET_BE_CONFIGURATION_AND_RESOURCES command.
Definition: sli4.c:1362
int32_t ocs_hal_get_port_protocol(ocs_hal_t *hal, uint32_t pci_func, mgmt_cb_t cb, void *ul_arg)
Get the current port protocol.
Definition: ocs_hal.c:6846
ocs_hal_rtn_e ocs_hal_setup(ocs_hal_t *hal, ocs_os_handle_t os, sli4_port_type_e port_type)
Set up the Hardware Abstraction Layer module.
Definition: ocs_hal.c:100
uint32_t sli_queue_iscsi_free_cnt(sli4_t *sli4, sli4_queue_t *q)
Return the number of free WRB entries.
Definition: sli4.c:3702
int32_t sli_cmd_common_get_profile_list(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint32_t start_profile_index, ocs_dma_t *dma)
Write a COMMON_COMMON_GET_PROFILE_LIST command.
Definition: sli4.c:1555
uint32_t sfp_a0[64]
Definition: sli4.h:2211
uint16_t cxn_cnt
Definition: sli4.h:2056
int32_t sli_callback(sli4_t *sli4, sli4_callback_e which, void *func, void *arg)
Register a callback for the given event.
Definition: sli4.c:2905
uint16_t num_sges_per_icd
Definition: sli4.h:2241
static ocs_hal_sgl_info_t * ocs_hal_sgl_info_alloc(ocs_hal_t *hal)
Allocate a HAL SGL Chaining object.
Definition: ocs_hal.c:5292
uint32_t last
Definition: sli4.h:447
int32_t io_cb_t(struct ocs_hal_io_s *io, ocs_cxn_t *cxn, int32_t status, ocs_ini_cmpl_fields_t *ini_fields, void *ul_arg)
IO Completion function prototype.
Definition: ocs_hal.h:432
struct ocs_hal_t::@19 config
uint32_t r2t_offset
Definition: ocs_hal.h:541
Scatter-Gather Entry (SGE)
Definition: sli4.h:379
uint32_t cmdsn
Definition: ocs_hal.h:509
void portal_cb_t(void *ul_arg, int32_t status, uint32_t ext_status, void *params)
Portal callback function prototype.
Definition: ocs_hal.h:332
static void ocs_hal_cxn_cleanup(ocs_list_t *list)
Free the connection tracking structures.
Definition: ocs_hal.c:2382
static int32_t ocs_hal_get_port_profile_cb(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx)
Called for the completion of get_port_profile for a user request.
Definition: ocs_hal.c:6771
ocs_hal_ip_type_e sli_iscsi_conv_sli4_ip_addr_type(uint8_t ip_type)
Converts the SLI4 IP address type field to the HAL equivalent value.
Definition: sli4_iscsi.c:342
uint32_t exp_data_sn
Definition: ocs_hal.h:539
uint8_t overrun
Definition: ocs_hal.h:532
uint32_t cq_index_wq_tgt
Definition: ocs_hal.h:756
static int32_t ocs_hal_cb_link(void *, void *)
Callback function for SLI link events.
Definition: ocs_hal.c:1521
static uint32_t sli_get_if_type(sli4_t *sli4)
Definition: sli4.h:2368
ocs_hal_rtn_e ocs_hal_rxbuffer(ocs_hal_t *hal, ocs_hal_rq_buffer_t *header, ocs_hal_rq_buffer_t *payload)
Add a receive buffer pair to the Receive Queue.
Definition: ocs_hal.c:2254
#define OCS_MIN_FW_VER
ocs_list_t cmd_head
Definition: ocs_hal.h:766
#define SLI4_SGE_TYPE_SKIP
Definition: sli4.h:471
uint16_t type
Definition: ocs_hal.h:477
void * ocs_hal_get_ptr(ocs_hal_t *hal, ocs_hal_property_e prop)
Definition: ocs_hal.c:2753
uint32_t new_ref_tag
Definition: sli4.h:426
static int32_t ocs_hal_set_port_protocol_cb1(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx)
Called for the completion of set_port_profile for a user request.
Definition: ocs_hal.c:6951
#define SLI4_PORT_TYPE_FCOE
Definition: sli4.h:1396
static int32_t ocs_hal_data_digest_process(ocs_hal_t *hal, sli4_qentry_fields_data_digest_t *data_digest)
Process an data digest completion entry.
Definition: ocs_hal.c:1247
ocs_dma_t bhs
Definition: ocs_hal.h:476
int32_t sli_cmd_iscsi_common_get_route_table(sli4_t *sli4, void *buf, size_t size, uint64_t tag, ocs_dma_t *dma)
write a COMMON_ISCSI_NTWK_GET_ROUTE_TABLE command
Definition: sli4_iscsi.c:427
Generic Command Request header.
Definition: sli4.h:582
void sli_interrupt_set(sli4_t *sli, uint8_t enable)
Definition: sli4.c:4037
uint8_t incr_statsn
Definition: ocs_hal.h:555
ocs_hal_cxn_invalid_t cxn_invalid
Definition: ocs_hal.h:641
#define ocs_list_foreach(list, item)
Iterate a linked list.
Definition: ocs_list.h:428
static void ocs_hal_ctx_cleanup(ocs_hal_t *hal)
Free the command contents.
Definition: ocs_hal.c:2348
static uint32_t ocs_hal_config_id_from_linkcfg(ocs_hal_linkcfg_e linkcfg)
Helper function for getting a Skyhawk link config ID from the HAL linkcfg enum.
Definition: ocs_hal.c:6545
struct sli_wqe_handlers * wqe_handlers
Definition: sli4.h:2270
Generic Command Response header.
Definition: sli4.h:600
sli4_route_table_entry_t entry[SLI4_ISCSI_ROUTE_TABLE_ENTRIES_MAX]
Definition: sli4_iscsi.h:464
void mgmt_cb_t(void *ul_arg, int32_t status, uint32_t ext_status, void *params)
management callback function prototype.
Definition: ocs_hal.h:348
ocs_hal_dif_blk_size_e blk_size
Definition: ocs_hal.h:203
void * sli_queue_iscsi_wqe_complete(sli4_t *sli4, sli4_queue_t *q, uint8_t wqe_index)
Processes a solicited IO completion. Moves the WRB to the free list.
Definition: sli4.c:3489
uint32_t io_ini_read_quarantine_cnt
Definition: ocs_hal.h:816
ocs_hal_portal_t portal
Definition: ocs_hal.h:380
static int32_t ocs_hal_set_port_protocol_cb2(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx)
Called for the completion of set_port_profile for a user request.
Definition: ocs_hal.c:6920
int32_t sli_cmd_common_set_reconfig_link_id(sli4_t *sli4, void *buf, size_t size, uint64_t tag, ocs_dma_t *dma, uint32_t fd, uint32_t active_link_config_id)
Write a COMMON_COMMON_SET_RECONFIG_LINK_ID command.
Definition: sli4.c:1729
ocs_atomic_t io_alloc_failed_count
Definition: ocs_hal.h:830
uint32_t check_guard
Definition: ocs_hal.h:208
int32_t sli_cmd_iscsi_tgt_start_listen_server(sli4_t *sli4, void *buf, size_t size, uint64_t tag, ocs_hal_ip_address_t *ipaddr, uint32_t tcp_port)
write a ISCSI_TGT_START_LISTEN_SERVER command
Definition: sli4_iscsi.c:800
uint32_t exp_cmdsn
Definition: ocs_hal.h:418
uint32_t disable_app_ref_ffff
Definition: ocs_hal.h:208
#define SLI4_OPC_ISCSI_NTWK_CONFIGURE_STATELESS_IP_ADDR
Definition: sli4_iscsi.h:172
int32_t _sli_queue_write(sli4_t *sli4, sli4_queue_t *q, uint8_t *entry)
Write an entry to the queue object.
Definition: sli4.c:3397
static int32_t ocs_hal_tx_dif_error_process(ocs_hal_t *hal, sli4_qentry_fields_tx_dif_error_t *dif_err)
Process an transmit DIF error completion entry.
Definition: ocs_hal.c:1291
static int32_t ocs_hal_get_profile_list_cb(ocs_hal_t *hal, int32_t status, ocs_command_ctx_t *ctx)
Called for the completion of get_profile_list for a user request.
Definition: ocs_hal.c:6253
ocs_hal_dhcp_state_t
enum identifying the DHCP states.
Definition: ocs_hal.h:276
static int32_t ocs_hal_cq_process(ocs_hal_t *, sli4_queue_t *)
Process entries on the give completion queue.
Definition: ocs_hal.c:1347
int32_t sli_init(sli4_t *sli4)
Definition: sli4.c:2803
ocs_hal_rq_buffer_t * rq_buf
Definition: ocs_hal.h:703
uint32_t cid
Definition: ocs_hal.h:631
This structure contains the fields in a I_SOL completion.
Definition: sli4.h:1939
ocs_hal_tgt_data_digest_t tgt_digest
Definition: ocs_hal.h:640
uint32_t sfp_a2[64]
Definition: sli4.h:2212
#define SLI4_ISCSI_INVALIDATE_CMDS_STATUS_SUCCESS
Definition: sli4_iscsi.h:213
ocs_hal_rtn_e ocs_hal_portal_create(ocs_hal_t *hal, unsigned int vlan_tag, portal_cb_t portal_cb, void *ul_arg)
Create a new VLAN interface handle.
Definition: ocs_hal.c:3263
ocs_hal_rtn_e ocs_hal_portal_set_mtu(ocs_hal_t *hal, uint8_t is_jumbo, portal_cb_t portal_cb, void *ul_arg)
Enable Jumbo frame support on the portal.
Definition: ocs_hal.c:3171
static int32_t ocs_hal_stateless_async_event(ocs_hal_t *hal, sli4_stateless_op_cmpl_event_t *event, uint8_t isv4)
Processes the asynchronous stateless completion message.
Definition: ocs_hal.c:1606
ocs_session_login_options_t session_options
Definition: ocs_hal.h:322
uint32_t n_io
Definition: ocs_hal.h:742
int32_t sli_cmd_iscsi_common_iface_create(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint32_t vlan)
write a COMMON_ISCSI_NTWK_IFACE_CREATE command
Definition: sli4_iscsi.c:65
static void ocs_domain_unlock(ocs_domain_t *domain)
Definition: ocs_common.h:191
sli4_port_type_e
Definition: sli4.h:2156
static int32_t ocs_hal_command_cancel(ocs_hal_t *hal)
Definition: ocs_hal.c:2290
This structure contains the fields in a T_SOL completion.
Definition: sli4.h:1955
ocs_hal_rtn_e ocs_hal_firmware_write(ocs_hal_t *hal, ocs_dma_t *dma, uint32_t size, uint32_t offset, int last, ocs_hal_fw_cb_t cb, void *arg)
Write a portion of a firmware image to the device.
Definition: ocs_hal.c:6229
int32_t sli_cmd_iscsi_tgt_connection_reject(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint32_t conn_hdl)
write a ISCSI_TGT_CONNECTION_REJECT command
Definition: sli4_iscsi.c:929
static int32_t ocs_hal_rq_put(ocs_hal_t *hal, ocs_hal_rq_buffer_t *buffer)
Posts an RX buffer to a queue and update the verification structures.
Definition: ocs_hal.c:736
#define HAL_BHS_ALLOC_SIZE
Definition: ocs_hal.h:410
ocs_dma_t dma
Definition: sli4.h:2048
uint32_t use_cnt
Definition: ocs_hal.h:364
This structure contains the fields in a CMNDINV completion.
Definition: sli4.h:1999
ocs_hal_rtn_e ocs_hal_portal_ip_get(ocs_hal_t *hal, ocs_hal_portal_t portal, ocs_hal_ip_type_e ip_type, portal_cb_t portal_cb, void *ul_arg)
Retrieves the IP addresses on an interface.
Definition: ocs_hal.c:3925
ocs_hal_rtn_e ocs_hal_cxn_upload(ocs_hal_t *hal, ocs_cxn_t *cxn, uint8_t graceful, cxn_cb_t cxn_cb, void *ul_arg)
uploads an incoming connection on a target.
Definition: ocs_hal.c:5096
uint32_t tag[2]
Definition: sli4.h:572
ocs_hal_portal_t ocs_hal_portal_get_default(ocs_hal_t *hal)
Return the default portal.
Definition: ocs_hal.c:3215
uint32_t iface_default
Definition: sli4.h:2205
struct ocs_hal_io_s * io
Definition: ocs_hal.h:462
void * arg
Definition: ocs_hal.h:494
void ocs_tgt_cxn_invalidate(ocs_cxn_t *cxn)
Definition: ocs_cxn.c:1617
#define OCS_HAL_MAX_PROFILES
Definition: ocs_hal.h:298
int32_t sli_cmd_iscsi_common_release_stateless_ip_addr(sli4_t *sli4, void *buf, size_t size, uint64_t tag, uint32_t iface, uint8_t isv4)
write a COMMON_ISCSI_NTWK_RELEASE_STATELESS_IP_ADDR command
Definition: sli4_iscsi.c:187