xref: /freebsd/sys/dev/ocs_fc/ocs_hw_queues.c (revision 95ee2897)
1ef270ab1SKenneth D. Merry /*-
2ef270ab1SKenneth D. Merry  * Copyright (c) 2017 Broadcom. All rights reserved.
3ef270ab1SKenneth D. Merry  * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
4ef270ab1SKenneth D. Merry  *
5ef270ab1SKenneth D. Merry  * Redistribution and use in source and binary forms, with or without
6ef270ab1SKenneth D. Merry  * modification, are permitted provided that the following conditions are met:
7ef270ab1SKenneth D. Merry  *
8ef270ab1SKenneth D. Merry  * 1. Redistributions of source code must retain the above copyright notice,
9ef270ab1SKenneth D. Merry  *    this list of conditions and the following disclaimer.
10ef270ab1SKenneth D. Merry  *
11ef270ab1SKenneth D. Merry  * 2. Redistributions in binary form must reproduce the above copyright notice,
12ef270ab1SKenneth D. Merry  *    this list of conditions and the following disclaimer in the documentation
13ef270ab1SKenneth D. Merry  *    and/or other materials provided with the distribution.
14ef270ab1SKenneth D. Merry  *
15ef270ab1SKenneth D. Merry  * 3. Neither the name of the copyright holder nor the names of its contributors
16ef270ab1SKenneth D. Merry  *    may be used to endorse or promote products derived from this software
17ef270ab1SKenneth D. Merry  *    without specific prior written permission.
18ef270ab1SKenneth D. Merry  *
19ef270ab1SKenneth D. Merry  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20ef270ab1SKenneth D. Merry  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21ef270ab1SKenneth D. Merry  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22ef270ab1SKenneth D. Merry  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23ef270ab1SKenneth D. Merry  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24ef270ab1SKenneth D. Merry  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25ef270ab1SKenneth D. Merry  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26ef270ab1SKenneth D. Merry  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27ef270ab1SKenneth D. Merry  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28ef270ab1SKenneth D. Merry  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29ef270ab1SKenneth D. Merry  * POSSIBILITY OF SUCH DAMAGE.
30ef270ab1SKenneth D. Merry  */
31ef270ab1SKenneth D. Merry 
32ef270ab1SKenneth D. Merry /**
33ef270ab1SKenneth D. Merry  * @file
34ef270ab1SKenneth D. Merry  *
35ef270ab1SKenneth D. Merry  */
36ef270ab1SKenneth D. Merry 
37ef270ab1SKenneth D. Merry #include "ocs_os.h"
38ef270ab1SKenneth D. Merry #include "ocs_hw.h"
39ef270ab1SKenneth D. Merry #include "ocs_hw_queues.h"
40ef270ab1SKenneth D. Merry 
41ef270ab1SKenneth D. Merry #define HW_QTOP_DEBUG		0
42ef270ab1SKenneth D. Merry 
43ef270ab1SKenneth D. Merry /**
44ef270ab1SKenneth D. Merry  * @brief Initialize queues
45ef270ab1SKenneth D. Merry  *
46ef270ab1SKenneth D. Merry  * Given the parsed queue topology spec, the SLI queues are created and
47ef270ab1SKenneth D. Merry  * initialized
48ef270ab1SKenneth D. Merry  *
49ef270ab1SKenneth D. Merry  * @param hw pointer to HW object
50ef270ab1SKenneth D. Merry  * @param qtop pointer to queue topology
51ef270ab1SKenneth D. Merry  *
52ef270ab1SKenneth D. Merry  * @return returns 0 for success, an error code value for failure.
53ef270ab1SKenneth D. Merry  */
54ef270ab1SKenneth D. Merry ocs_hw_rtn_e
ocs_hw_init_queues(ocs_hw_t * hw,ocs_hw_qtop_t * qtop)55ef270ab1SKenneth D. Merry ocs_hw_init_queues(ocs_hw_t *hw, ocs_hw_qtop_t *qtop)
56ef270ab1SKenneth D. Merry {
57ef270ab1SKenneth D. Merry 	uint32_t i, j;
58ef270ab1SKenneth D. Merry 	uint32_t default_lengths[QTOP_LAST], len;
59ef270ab1SKenneth D. Merry 	uint32_t rqset_len = 0, rqset_ulp = 0, rqset_count = 0;
60ef270ab1SKenneth D. Merry 	uint8_t rqset_filter_mask = 0;
61ef270ab1SKenneth D. Merry 	hw_eq_t *eqs[hw->config.n_rq];
62ef270ab1SKenneth D. Merry 	hw_cq_t *cqs[hw->config.n_rq];
63ef270ab1SKenneth D. Merry 	hw_rq_t *rqs[hw->config.n_rq];
64ef270ab1SKenneth D. Merry 	ocs_hw_qtop_entry_t *qt, *next_qt;
65ef270ab1SKenneth D. Merry 	ocs_hw_mrq_t mrq;
66ef270ab1SKenneth D. Merry 	bool use_mrq = FALSE;
67ef270ab1SKenneth D. Merry 
68ef270ab1SKenneth D. Merry 	hw_eq_t *eq = NULL;
69ef270ab1SKenneth D. Merry 	hw_cq_t *cq = NULL;
70ef270ab1SKenneth D. Merry 	hw_wq_t *wq = NULL;
71ef270ab1SKenneth D. Merry 	hw_rq_t *rq = NULL;
72ef270ab1SKenneth D. Merry 	hw_mq_t *mq = NULL;
73ef270ab1SKenneth D. Merry 
74ef270ab1SKenneth D. Merry 	mrq.num_pairs = 0;
75ef270ab1SKenneth D. Merry 	default_lengths[QTOP_EQ] = 1024;
76ef270ab1SKenneth D. Merry 	default_lengths[QTOP_CQ] = hw->num_qentries[SLI_QTYPE_CQ];
77ef270ab1SKenneth D. Merry 	default_lengths[QTOP_WQ] = hw->num_qentries[SLI_QTYPE_WQ];
78ef270ab1SKenneth D. Merry 	default_lengths[QTOP_RQ] = hw->num_qentries[SLI_QTYPE_RQ];
79ef270ab1SKenneth D. Merry 	default_lengths[QTOP_MQ] = OCS_HW_MQ_DEPTH;
80ef270ab1SKenneth D. Merry 
81ef270ab1SKenneth D. Merry 	ocs_hw_verify(hw != NULL, OCS_HW_RTN_INVALID_ARG);
82ef270ab1SKenneth D. Merry 
83ef270ab1SKenneth D. Merry 	hw->eq_count = 0;
84ef270ab1SKenneth D. Merry 	hw->cq_count = 0;
85ef270ab1SKenneth D. Merry 	hw->mq_count = 0;
86ef270ab1SKenneth D. Merry 	hw->wq_count = 0;
87ef270ab1SKenneth D. Merry 	hw->rq_count = 0;
88ef270ab1SKenneth D. Merry 	hw->hw_rq_count = 0;
89ef270ab1SKenneth D. Merry 	ocs_list_init(&hw->eq_list, hw_eq_t, link);
90ef270ab1SKenneth D. Merry 
91ef270ab1SKenneth D. Merry 	/* If MRQ is requested, Check if it is supported by SLI. */
92ef270ab1SKenneth D. Merry 	if ((hw->config.n_rq > 1 ) && !hw->sli.config.features.flag.mrqp) {
93ef270ab1SKenneth D. Merry 		ocs_log_err(hw->os, "MRQ topology not supported by SLI4.\n");
94ef270ab1SKenneth D. Merry 		return OCS_HW_RTN_ERROR;
95ef270ab1SKenneth D. Merry 	}
96ef270ab1SKenneth D. Merry 
97ef270ab1SKenneth D. Merry 	if (hw->config.n_rq > 1)
98ef270ab1SKenneth D. Merry 		use_mrq = TRUE;
99ef270ab1SKenneth D. Merry 
100ef270ab1SKenneth D. Merry 	/* Allocate class WQ pools */
101ef270ab1SKenneth D. Merry 	for (i = 0; i < ARRAY_SIZE(hw->wq_class_array); i++) {
102ef270ab1SKenneth D. Merry 		hw->wq_class_array[i] = ocs_varray_alloc(hw->os, OCS_HW_MAX_NUM_WQ);
103ef270ab1SKenneth D. Merry 		if (hw->wq_class_array[i] == NULL) {
104ef270ab1SKenneth D. Merry 			ocs_log_err(hw->os, "ocs_varray_alloc for wq_class failed\n");
105ef270ab1SKenneth D. Merry 			return OCS_HW_RTN_NO_MEMORY;
106ef270ab1SKenneth D. Merry 		}
107ef270ab1SKenneth D. Merry 	}
108ef270ab1SKenneth D. Merry 
109ef270ab1SKenneth D. Merry 	/* Allocate per CPU WQ pools */
110ef270ab1SKenneth D. Merry 	for (i = 0; i < ARRAY_SIZE(hw->wq_cpu_array); i++) {
111ef270ab1SKenneth D. Merry 		hw->wq_cpu_array[i] = ocs_varray_alloc(hw->os, OCS_HW_MAX_NUM_WQ);
112ef270ab1SKenneth D. Merry 		if (hw->wq_cpu_array[i] == NULL) {
113ef270ab1SKenneth D. Merry 			ocs_log_err(hw->os, "ocs_varray_alloc for wq_class failed\n");
114ef270ab1SKenneth D. Merry 			return OCS_HW_RTN_NO_MEMORY;
115ef270ab1SKenneth D. Merry 		}
116ef270ab1SKenneth D. Merry 	}
117ef270ab1SKenneth D. Merry 
118ef270ab1SKenneth D. Merry 	ocs_hw_assert(qtop != NULL);
119ef270ab1SKenneth D. Merry 
120ef270ab1SKenneth D. Merry 	for (i = 0, qt = qtop->entries; i < qtop->inuse_count; i++, qt++) {
121ef270ab1SKenneth D. Merry 		if (i == qtop->inuse_count - 1)
122ef270ab1SKenneth D. Merry 			next_qt = NULL;
123ef270ab1SKenneth D. Merry 		else
124ef270ab1SKenneth D. Merry 			next_qt = qt + 1;
125ef270ab1SKenneth D. Merry 
126ef270ab1SKenneth D. Merry 		switch(qt->entry) {
127ef270ab1SKenneth D. Merry 		case QTOP_EQ:
128ef270ab1SKenneth D. Merry 			len = (qt->len) ? qt->len : default_lengths[QTOP_EQ];
129ef270ab1SKenneth D. Merry 
130ef270ab1SKenneth D. Merry 			if (qt->set_default) {
131ef270ab1SKenneth D. Merry 				default_lengths[QTOP_EQ] = len;
132ef270ab1SKenneth D. Merry 				break;
133ef270ab1SKenneth D. Merry 			}
134ef270ab1SKenneth D. Merry 
135ef270ab1SKenneth D. Merry 			eq = hw_new_eq(hw, len);
136ef270ab1SKenneth D. Merry 			if (eq == NULL) {
137ef270ab1SKenneth D. Merry 				hw_queue_teardown(hw);
138ef270ab1SKenneth D. Merry 				return OCS_HW_RTN_NO_MEMORY;
139ef270ab1SKenneth D. Merry 			}
140ef270ab1SKenneth D. Merry 			break;
141ef270ab1SKenneth D. Merry 
142ef270ab1SKenneth D. Merry 		case QTOP_CQ:
143ef270ab1SKenneth D. Merry 			len = (qt->len) ? qt->len : default_lengths[QTOP_CQ];
144ef270ab1SKenneth D. Merry 
145ef270ab1SKenneth D. Merry 			if (qt->set_default) {
146ef270ab1SKenneth D. Merry 				default_lengths[QTOP_CQ] = len;
147ef270ab1SKenneth D. Merry 				break;
148ef270ab1SKenneth D. Merry 			}
149ef270ab1SKenneth D. Merry 
1504915e5c7SRam Kishore Vegesna 			if (!eq || !next_qt) {
1514915e5c7SRam Kishore Vegesna 				goto fail;
1524915e5c7SRam Kishore Vegesna 			}
1534915e5c7SRam Kishore Vegesna 
154ef270ab1SKenneth D. Merry 			/* If this CQ is for MRQ, then delay the creation */
155ef270ab1SKenneth D. Merry 			if (!use_mrq || next_qt->entry != QTOP_RQ) {
156ef270ab1SKenneth D. Merry 				cq = hw_new_cq(eq, len);
157ef270ab1SKenneth D. Merry 				if (cq == NULL) {
1584915e5c7SRam Kishore Vegesna 					goto fail;
159ef270ab1SKenneth D. Merry 				}
160ef270ab1SKenneth D. Merry 			}
161ef270ab1SKenneth D. Merry 			break;
162ef270ab1SKenneth D. Merry 
163ef270ab1SKenneth D. Merry 		case QTOP_WQ: {
164ef270ab1SKenneth D. Merry 			len = (qt->len) ? qt->len : default_lengths[QTOP_WQ];
165ef270ab1SKenneth D. Merry 			if (qt->set_default) {
166ef270ab1SKenneth D. Merry 				default_lengths[QTOP_WQ] = len;
167ef270ab1SKenneth D. Merry 				break;
168ef270ab1SKenneth D. Merry 			}
169ef270ab1SKenneth D. Merry 
170ef270ab1SKenneth D. Merry 			if ((hw->ulp_start + qt->ulp) > hw->ulp_max) {
171ef270ab1SKenneth D. Merry 				ocs_log_err(hw->os, "invalid ULP %d for WQ\n", qt->ulp);
172ef270ab1SKenneth D. Merry 				hw_queue_teardown(hw);
173ef270ab1SKenneth D. Merry 				return OCS_HW_RTN_NO_MEMORY;
174ef270ab1SKenneth D. Merry 			}
175ef270ab1SKenneth D. Merry 
1764915e5c7SRam Kishore Vegesna 			if (cq == NULL)
1774915e5c7SRam Kishore Vegesna 				goto fail;
1784915e5c7SRam Kishore Vegesna 
179ef270ab1SKenneth D. Merry 			wq = hw_new_wq(cq, len, qt->class, hw->ulp_start + qt->ulp);
180ef270ab1SKenneth D. Merry 			if (wq == NULL) {
1814915e5c7SRam Kishore Vegesna 				goto fail;
182ef270ab1SKenneth D. Merry 			}
183ef270ab1SKenneth D. Merry 
184ef270ab1SKenneth D. Merry 			/* Place this WQ on the EQ WQ array */
185ef270ab1SKenneth D. Merry 			if (ocs_varray_add(eq->wq_array, wq)) {
186ef270ab1SKenneth D. Merry 				ocs_log_err(hw->os, "QTOP_WQ: EQ ocs_varray_add failed\n");
187ef270ab1SKenneth D. Merry 				hw_queue_teardown(hw);
188ef270ab1SKenneth D. Merry 				return OCS_HW_RTN_ERROR;
189ef270ab1SKenneth D. Merry 			}
190ef270ab1SKenneth D. Merry 
191ef270ab1SKenneth D. Merry 			/* Place this WQ on the HW class array */
192ef270ab1SKenneth D. Merry 			if (qt->class < ARRAY_SIZE(hw->wq_class_array)) {
193ef270ab1SKenneth D. Merry 				if (ocs_varray_add(hw->wq_class_array[qt->class], wq)) {
194ef270ab1SKenneth D. Merry 					ocs_log_err(hw->os, "HW wq_class_array ocs_varray_add failed\n");
195ef270ab1SKenneth D. Merry 					hw_queue_teardown(hw);
196ef270ab1SKenneth D. Merry 					return OCS_HW_RTN_ERROR;
197ef270ab1SKenneth D. Merry 				}
198ef270ab1SKenneth D. Merry 			} else {
199ef270ab1SKenneth D. Merry 				ocs_log_err(hw->os, "Invalid class value: %d\n", qt->class);
200ef270ab1SKenneth D. Merry 				hw_queue_teardown(hw);
201ef270ab1SKenneth D. Merry 				return OCS_HW_RTN_ERROR;
202ef270ab1SKenneth D. Merry 			}
203ef270ab1SKenneth D. Merry 
204ef270ab1SKenneth D. Merry 			/*
205ef270ab1SKenneth D. Merry 			 * Place this WQ on the per CPU list, asumming that EQs are mapped to cpu given
206ef270ab1SKenneth D. Merry 			 * by the EQ instance modulo number of CPUs
207ef270ab1SKenneth D. Merry 			 */
208ef270ab1SKenneth D. Merry 			if (ocs_varray_add(hw->wq_cpu_array[eq->instance % ocs_get_num_cpus()], wq)) {
209ef270ab1SKenneth D. Merry 				ocs_log_err(hw->os, "HW wq_cpu_array ocs_varray_add failed\n");
210ef270ab1SKenneth D. Merry 				hw_queue_teardown(hw);
211ef270ab1SKenneth D. Merry 				return OCS_HW_RTN_ERROR;
212ef270ab1SKenneth D. Merry 			}
213ef270ab1SKenneth D. Merry 
214ef270ab1SKenneth D. Merry 			break;
215ef270ab1SKenneth D. Merry 		}
216ef270ab1SKenneth D. Merry 		case QTOP_RQ: {
217ef270ab1SKenneth D. Merry 			len = (qt->len) ? qt->len : default_lengths[QTOP_RQ];
218ef270ab1SKenneth D. Merry 			if (qt->set_default) {
219ef270ab1SKenneth D. Merry 				default_lengths[QTOP_RQ] = len;
220ef270ab1SKenneth D. Merry 				break;
221ef270ab1SKenneth D. Merry 			}
222ef270ab1SKenneth D. Merry 
223ef270ab1SKenneth D. Merry 			if ((hw->ulp_start + qt->ulp) > hw->ulp_max) {
224ef270ab1SKenneth D. Merry 				ocs_log_err(hw->os, "invalid ULP %d for RQ\n", qt->ulp);
225ef270ab1SKenneth D. Merry 				hw_queue_teardown(hw);
226ef270ab1SKenneth D. Merry 				return OCS_HW_RTN_NO_MEMORY;
227ef270ab1SKenneth D. Merry 			}
228ef270ab1SKenneth D. Merry 
229ef270ab1SKenneth D. Merry 			if (use_mrq) {
230ef270ab1SKenneth D. Merry 				mrq.rq_cfg[mrq.num_pairs].len = len;
231ef270ab1SKenneth D. Merry 				mrq.rq_cfg[mrq.num_pairs].ulp = hw->ulp_start + qt->ulp;
232ef270ab1SKenneth D. Merry 				mrq.rq_cfg[mrq.num_pairs].filter_mask = qt->filter_mask;
233ef270ab1SKenneth D. Merry 				mrq.rq_cfg[mrq.num_pairs].eq = eq;
234ef270ab1SKenneth D. Merry 				mrq.num_pairs ++;
235ef270ab1SKenneth D. Merry 			} else {
236ef270ab1SKenneth D. Merry 				rq = hw_new_rq(cq, len, hw->ulp_start + qt->ulp);
237ef270ab1SKenneth D. Merry 				if (rq == NULL) {
238ef270ab1SKenneth D. Merry 					hw_queue_teardown(hw);
239ef270ab1SKenneth D. Merry 					return OCS_HW_RTN_NO_MEMORY;
240ef270ab1SKenneth D. Merry 				}
241ef270ab1SKenneth D. Merry 				rq->filter_mask = qt->filter_mask;
242ef270ab1SKenneth D. Merry 			}
243ef270ab1SKenneth D. Merry 			break;
244ef270ab1SKenneth D. Merry 		}
245ef270ab1SKenneth D. Merry 
246ef270ab1SKenneth D. Merry 		case QTOP_MQ:
247ef270ab1SKenneth D. Merry 			len = (qt->len) ? qt->len : default_lengths[QTOP_MQ];
248ef270ab1SKenneth D. Merry 			if (qt->set_default) {
249ef270ab1SKenneth D. Merry 				default_lengths[QTOP_MQ] = len;
250ef270ab1SKenneth D. Merry 				break;
251ef270ab1SKenneth D. Merry 			}
252ef270ab1SKenneth D. Merry 
2534915e5c7SRam Kishore Vegesna 			if (cq == NULL)
2544915e5c7SRam Kishore Vegesna 				goto fail;
2554915e5c7SRam Kishore Vegesna 
256ef270ab1SKenneth D. Merry 			mq = hw_new_mq(cq, len);
257ef270ab1SKenneth D. Merry 			if (mq == NULL) {
2584915e5c7SRam Kishore Vegesna 				goto fail;
259ef270ab1SKenneth D. Merry 			}
260ef270ab1SKenneth D. Merry 			break;
261ef270ab1SKenneth D. Merry 
262ef270ab1SKenneth D. Merry 		default:
263ef270ab1SKenneth D. Merry 			ocs_hw_assert(0);
264ef270ab1SKenneth D. Merry 			break;
265ef270ab1SKenneth D. Merry 		}
266ef270ab1SKenneth D. Merry 	}
267ef270ab1SKenneth D. Merry 
268ef270ab1SKenneth D. Merry 	if (mrq.num_pairs) {
269ef270ab1SKenneth D. Merry 		/* First create normal RQs. */
270ef270ab1SKenneth D. Merry 		for (i = 0; i < mrq.num_pairs; i++) {
271ef270ab1SKenneth D. Merry 			for (j = 0; j < mrq.num_pairs; j++) {
272ef270ab1SKenneth D. Merry 				if ((i != j) && (mrq.rq_cfg[i].filter_mask == mrq.rq_cfg[j].filter_mask)) {
273ef270ab1SKenneth D. Merry 					/* This should be created using set */
274ef270ab1SKenneth D. Merry 					if (rqset_filter_mask && (rqset_filter_mask != mrq.rq_cfg[i].filter_mask)) {
275ef270ab1SKenneth D. Merry 						ocs_log_crit(hw->os, "Cant create morethan one RQ Set\n");
276ef270ab1SKenneth D. Merry 						hw_queue_teardown(hw);
277ef270ab1SKenneth D. Merry 						return OCS_HW_RTN_ERROR;
278ef270ab1SKenneth D. Merry 					} else if (!rqset_filter_mask){
279ef270ab1SKenneth D. Merry 						rqset_filter_mask = mrq.rq_cfg[i].filter_mask;
280ef270ab1SKenneth D. Merry 						rqset_len = mrq.rq_cfg[i].len;
281ef270ab1SKenneth D. Merry 						rqset_ulp = mrq.rq_cfg[i].ulp;
282ef270ab1SKenneth D. Merry 					}
283ef270ab1SKenneth D. Merry 					eqs[rqset_count] = mrq.rq_cfg[i].eq;
284ef270ab1SKenneth D. Merry 					rqset_count++;
285ef270ab1SKenneth D. Merry 					break;
286ef270ab1SKenneth D. Merry 				}
287ef270ab1SKenneth D. Merry 			}
288ef270ab1SKenneth D. Merry 			if (j == mrq.num_pairs) {
289ef270ab1SKenneth D. Merry 				/* Normal RQ */
290ef270ab1SKenneth D. Merry 				cq = hw_new_cq(mrq.rq_cfg[i].eq, default_lengths[QTOP_CQ]);
291ef270ab1SKenneth D. Merry 				if (cq == NULL) {
292ef270ab1SKenneth D. Merry 					hw_queue_teardown(hw);
293ef270ab1SKenneth D. Merry 					return OCS_HW_RTN_NO_MEMORY;
294ef270ab1SKenneth D. Merry 				}
295ef270ab1SKenneth D. Merry 
296ef270ab1SKenneth D. Merry 				rq = hw_new_rq(cq, mrq.rq_cfg[i].len, mrq.rq_cfg[i].ulp);
297ef270ab1SKenneth D. Merry 				if (rq == NULL) {
298ef270ab1SKenneth D. Merry 					hw_queue_teardown(hw);
299ef270ab1SKenneth D. Merry 					return OCS_HW_RTN_NO_MEMORY;
300ef270ab1SKenneth D. Merry 				}
301ef270ab1SKenneth D. Merry 				rq->filter_mask = mrq.rq_cfg[i].filter_mask;
302ef270ab1SKenneth D. Merry 			}
303ef270ab1SKenneth D. Merry 		}
304ef270ab1SKenneth D. Merry 
305ef270ab1SKenneth D. Merry 		/* Now create RQ Set */
306ef270ab1SKenneth D. Merry 		if (rqset_count) {
307ef270ab1SKenneth D. Merry 			if (rqset_count > OCE_HW_MAX_NUM_MRQ_PAIRS) {
308ef270ab1SKenneth D. Merry 				ocs_log_crit(hw->os,
309ef270ab1SKenneth D. Merry 					     "Max Supported MRQ pairs = %d\n",
310ef270ab1SKenneth D. Merry 					     OCE_HW_MAX_NUM_MRQ_PAIRS);
311ef270ab1SKenneth D. Merry 				hw_queue_teardown(hw);
312ef270ab1SKenneth D. Merry 				return OCS_HW_RTN_ERROR;
313ef270ab1SKenneth D. Merry 			}
314ef270ab1SKenneth D. Merry 
315ef270ab1SKenneth D. Merry 			/* Create CQ set */
316ef270ab1SKenneth D. Merry 			if (hw_new_cq_set(eqs, cqs, rqset_count, default_lengths[QTOP_CQ])) {
317ef270ab1SKenneth D. Merry 				hw_queue_teardown(hw);
318ef270ab1SKenneth D. Merry 				return OCS_HW_RTN_ERROR;
319ef270ab1SKenneth D. Merry 			}
320ef270ab1SKenneth D. Merry 
321ef270ab1SKenneth D. Merry 			/* Create RQ set */
322ef270ab1SKenneth D. Merry 			if (hw_new_rq_set(cqs, rqs, rqset_count, rqset_len, rqset_ulp)) {
323ef270ab1SKenneth D. Merry 				hw_queue_teardown(hw);
324ef270ab1SKenneth D. Merry 				return OCS_HW_RTN_ERROR;
325ef270ab1SKenneth D. Merry 			}
326ef270ab1SKenneth D. Merry 
327ef270ab1SKenneth D. Merry 			for (i = 0; i < rqset_count ; i++) {
328ef270ab1SKenneth D. Merry 				rqs[i]->filter_mask = rqset_filter_mask;
329ef270ab1SKenneth D. Merry 				rqs[i]->is_mrq = TRUE;
330ef270ab1SKenneth D. Merry 				rqs[i]->base_mrq_id = rqs[0]->hdr->id;
331ef270ab1SKenneth D. Merry 			}
332ef270ab1SKenneth D. Merry 
333ef270ab1SKenneth D. Merry 			hw->hw_mrq_count = rqset_count;
334ef270ab1SKenneth D. Merry 		}
335ef270ab1SKenneth D. Merry 	}
336ef270ab1SKenneth D. Merry 
337ef270ab1SKenneth D. Merry 	return OCS_HW_RTN_SUCCESS;
3384915e5c7SRam Kishore Vegesna fail:
3394915e5c7SRam Kishore Vegesna 	hw_queue_teardown(hw);
3404915e5c7SRam Kishore Vegesna 	return OCS_HW_RTN_NO_MEMORY;
341ef270ab1SKenneth D. Merry 
342ef270ab1SKenneth D. Merry }
343ef270ab1SKenneth D. Merry 
344ef270ab1SKenneth D. Merry /**
345ef270ab1SKenneth D. Merry  * @brief Allocate a new EQ object
346ef270ab1SKenneth D. Merry  *
347ef270ab1SKenneth D. Merry  * A new EQ object is instantiated
348ef270ab1SKenneth D. Merry  *
349ef270ab1SKenneth D. Merry  * @param hw pointer to HW object
350ef270ab1SKenneth D. Merry  * @param entry_count number of entries in the EQ
351ef270ab1SKenneth D. Merry  *
352ef270ab1SKenneth D. Merry  * @return pointer to allocated EQ object
353ef270ab1SKenneth D. Merry  */
354ef270ab1SKenneth D. Merry hw_eq_t*
hw_new_eq(ocs_hw_t * hw,uint32_t entry_count)355ef270ab1SKenneth D. Merry hw_new_eq(ocs_hw_t *hw, uint32_t entry_count)
356ef270ab1SKenneth D. Merry {
357ef270ab1SKenneth D. Merry 	hw_eq_t *eq = ocs_malloc(hw->os, sizeof(*eq), OCS_M_ZERO | OCS_M_NOWAIT);
358ef270ab1SKenneth D. Merry 
359ef270ab1SKenneth D. Merry 	if (eq != NULL) {
360ef270ab1SKenneth D. Merry 		eq->type = SLI_QTYPE_EQ;
361ef270ab1SKenneth D. Merry 		eq->hw = hw;
362ef270ab1SKenneth D. Merry 		eq->entry_count = entry_count;
363ef270ab1SKenneth D. Merry 		eq->instance = hw->eq_count++;
364ef270ab1SKenneth D. Merry 		eq->queue = &hw->eq[eq->instance];
365ef270ab1SKenneth D. Merry 		ocs_list_init(&eq->cq_list, hw_cq_t, link);
366ef270ab1SKenneth D. Merry 
367ef270ab1SKenneth D. Merry 		eq->wq_array = ocs_varray_alloc(hw->os, OCS_HW_MAX_NUM_WQ);
368ef270ab1SKenneth D. Merry 		if (eq->wq_array == NULL) {
369ef270ab1SKenneth D. Merry 			ocs_free(hw->os, eq, sizeof(*eq));
370ef270ab1SKenneth D. Merry 			eq = NULL;
371ef270ab1SKenneth D. Merry 		} else {
372ef270ab1SKenneth D. Merry 			if (sli_queue_alloc(&hw->sli, SLI_QTYPE_EQ, eq->queue, entry_count, NULL, 0)) {
373ef270ab1SKenneth D. Merry 				ocs_log_err(hw->os, "EQ[%d] allocation failure\n", eq->instance);
374ef270ab1SKenneth D. Merry 				ocs_free(hw->os, eq, sizeof(*eq));
375ef270ab1SKenneth D. Merry 				eq = NULL;
376ef270ab1SKenneth D. Merry 			} else {
377ef270ab1SKenneth D. Merry 				sli_eq_modify_delay(&hw->sli, eq->queue, 1, 0, 8);
378ef270ab1SKenneth D. Merry 				hw->hw_eq[eq->instance] = eq;
379ef270ab1SKenneth D. Merry 				ocs_list_add_tail(&hw->eq_list, eq);
380ef270ab1SKenneth D. Merry 				ocs_log_debug(hw->os, "create eq[%2d] id %3d len %4d\n", eq->instance, eq->queue->id,
381ef270ab1SKenneth D. Merry 					eq->entry_count);
382ef270ab1SKenneth D. Merry 			}
383ef270ab1SKenneth D. Merry 		}
384ef270ab1SKenneth D. Merry 	}
385ef270ab1SKenneth D. Merry 	return eq;
386ef270ab1SKenneth D. Merry }
387ef270ab1SKenneth D. Merry 
388ef270ab1SKenneth D. Merry /**
389ef270ab1SKenneth D. Merry  * @brief Allocate a new CQ object
390ef270ab1SKenneth D. Merry  *
391ef270ab1SKenneth D. Merry  * A new CQ object is instantiated
392ef270ab1SKenneth D. Merry  *
393ef270ab1SKenneth D. Merry  * @param eq pointer to parent EQ object
394ef270ab1SKenneth D. Merry  * @param entry_count number of entries in the CQ
395ef270ab1SKenneth D. Merry  *
396ef270ab1SKenneth D. Merry  * @return pointer to allocated CQ object
397ef270ab1SKenneth D. Merry  */
398ef270ab1SKenneth D. Merry hw_cq_t*
hw_new_cq(hw_eq_t * eq,uint32_t entry_count)399ef270ab1SKenneth D. Merry hw_new_cq(hw_eq_t *eq, uint32_t entry_count)
400ef270ab1SKenneth D. Merry {
401ef270ab1SKenneth D. Merry 	ocs_hw_t *hw = eq->hw;
402ef270ab1SKenneth D. Merry 	hw_cq_t *cq = ocs_malloc(hw->os, sizeof(*cq), OCS_M_ZERO | OCS_M_NOWAIT);
403ef270ab1SKenneth D. Merry 
404ef270ab1SKenneth D. Merry 	if (cq != NULL) {
405ef270ab1SKenneth D. Merry 		cq->eq = eq;
406ef270ab1SKenneth D. Merry 		cq->type = SLI_QTYPE_CQ;
407ef270ab1SKenneth D. Merry 		cq->instance = eq->hw->cq_count++;
408ef270ab1SKenneth D. Merry 		cq->entry_count = entry_count;
409ef270ab1SKenneth D. Merry 		cq->queue = &hw->cq[cq->instance];
410ef270ab1SKenneth D. Merry 
411ef270ab1SKenneth D. Merry 		ocs_list_init(&cq->q_list, hw_q_t, link);
412ef270ab1SKenneth D. Merry 
413ef270ab1SKenneth D. Merry 		if (sli_queue_alloc(&hw->sli, SLI_QTYPE_CQ, cq->queue, cq->entry_count, eq->queue, 0)) {
414ef270ab1SKenneth D. Merry 			ocs_log_err(hw->os, "CQ[%d] allocation failure len=%d\n",
415ef270ab1SKenneth D. Merry 				eq->instance,
416ef270ab1SKenneth D. Merry 				eq->entry_count);
417ef270ab1SKenneth D. Merry 			ocs_free(hw->os, cq, sizeof(*cq));
418ef270ab1SKenneth D. Merry 			cq = NULL;
419ef270ab1SKenneth D. Merry 		} else {
420ef270ab1SKenneth D. Merry 			hw->hw_cq[cq->instance] = cq;
421ef270ab1SKenneth D. Merry 			ocs_list_add_tail(&eq->cq_list, cq);
422ef270ab1SKenneth D. Merry 			ocs_log_debug(hw->os, "create cq[%2d] id %3d len %4d\n", cq->instance, cq->queue->id,
423ef270ab1SKenneth D. Merry 				cq->entry_count);
424ef270ab1SKenneth D. Merry 		}
425ef270ab1SKenneth D. Merry 	}
426ef270ab1SKenneth D. Merry 	return cq;
427ef270ab1SKenneth D. Merry }
428ef270ab1SKenneth D. Merry 
429ef270ab1SKenneth D. Merry /**
430ef270ab1SKenneth D. Merry  * @brief Allocate a new CQ Set of objects.
431ef270ab1SKenneth D. Merry  *
432ef270ab1SKenneth D. Merry  * @param eqs pointer to a set of EQ objects.
433ef270ab1SKenneth D. Merry  * @param cqs pointer to a set of CQ objects to be returned.
434ef270ab1SKenneth D. Merry  * @param num_cqs number of CQ queues in the set.
435ef270ab1SKenneth D. Merry  * @param entry_count number of entries in the CQ.
436ef270ab1SKenneth D. Merry  *
437ef270ab1SKenneth D. Merry  * @return 0 on success and -1 on failure.
438ef270ab1SKenneth D. Merry  */
439ef270ab1SKenneth D. Merry uint32_t
hw_new_cq_set(hw_eq_t * eqs[],hw_cq_t * cqs[],uint32_t num_cqs,uint32_t entry_count)440ef270ab1SKenneth D. Merry hw_new_cq_set(hw_eq_t *eqs[], hw_cq_t *cqs[], uint32_t num_cqs, uint32_t entry_count)
441ef270ab1SKenneth D. Merry {
442ef270ab1SKenneth D. Merry 	uint32_t i;
443ef270ab1SKenneth D. Merry 	ocs_hw_t *hw = eqs[0]->hw;
444ef270ab1SKenneth D. Merry 	sli4_t *sli4 = &hw->sli;
445ef270ab1SKenneth D. Merry 	hw_cq_t *cq = NULL;
446ef270ab1SKenneth D. Merry 	sli4_queue_t *qs[SLI_MAX_CQ_SET_COUNT], *assocs[SLI_MAX_CQ_SET_COUNT];
447ef270ab1SKenneth D. Merry 
448ef270ab1SKenneth D. Merry 	/* Initialise CQS pointers to NULL */
449ef270ab1SKenneth D. Merry 	for (i = 0; i < num_cqs; i++) {
450ef270ab1SKenneth D. Merry 		cqs[i] = NULL;
451ef270ab1SKenneth D. Merry 	}
452ef270ab1SKenneth D. Merry 
453ef270ab1SKenneth D. Merry 	for (i = 0; i < num_cqs; i++) {
454ef270ab1SKenneth D. Merry 		cq = ocs_malloc(hw->os, sizeof(*cq), OCS_M_ZERO | OCS_M_NOWAIT);
455ef270ab1SKenneth D. Merry 		if (cq == NULL)
456ef270ab1SKenneth D. Merry 			goto error;
457ef270ab1SKenneth D. Merry 
458ef270ab1SKenneth D. Merry 		cqs[i]          = cq;
459ef270ab1SKenneth D. Merry 		cq->eq          = eqs[i];
460ef270ab1SKenneth D. Merry 		cq->type        = SLI_QTYPE_CQ;
461ef270ab1SKenneth D. Merry 		cq->instance    = hw->cq_count++;
462ef270ab1SKenneth D. Merry 		cq->entry_count = entry_count;
463ef270ab1SKenneth D. Merry 		cq->queue       = &hw->cq[cq->instance];
464ef270ab1SKenneth D. Merry 		qs[i]           = cq->queue;
465ef270ab1SKenneth D. Merry 		assocs[i]       = eqs[i]->queue;
466ef270ab1SKenneth D. Merry 		ocs_list_init(&cq->q_list, hw_q_t, link);
467ef270ab1SKenneth D. Merry 	}
468ef270ab1SKenneth D. Merry 
469ef270ab1SKenneth D. Merry 	if (sli_cq_alloc_set(sli4, qs, num_cqs, entry_count, assocs)) {
470ef270ab1SKenneth D. Merry 		ocs_log_err(NULL, "Failed to create CQ Set. \n");
471ef270ab1SKenneth D. Merry 		goto error;
472ef270ab1SKenneth D. Merry 	}
473ef270ab1SKenneth D. Merry 
474ef270ab1SKenneth D. Merry 	for (i = 0; i < num_cqs; i++) {
475ef270ab1SKenneth D. Merry 		hw->hw_cq[cqs[i]->instance] = cqs[i];
476ef270ab1SKenneth D. Merry 		ocs_list_add_tail(&cqs[i]->eq->cq_list, cqs[i]);
477ef270ab1SKenneth D. Merry 	}
478ef270ab1SKenneth D. Merry 
479ef270ab1SKenneth D. Merry 	return 0;
480ef270ab1SKenneth D. Merry 
481ef270ab1SKenneth D. Merry error:
482ef270ab1SKenneth D. Merry 	for (i = 0; i < num_cqs; i++) {
483ef270ab1SKenneth D. Merry 		if (cqs[i]) {
484ef270ab1SKenneth D. Merry 			ocs_free(hw->os, cqs[i], sizeof(*cqs[i]));
485ef270ab1SKenneth D. Merry 			cqs[i] = NULL;
486ef270ab1SKenneth D. Merry 		}
487ef270ab1SKenneth D. Merry 	}
488ef270ab1SKenneth D. Merry 	return -1;
489ef270ab1SKenneth D. Merry }
490ef270ab1SKenneth D. Merry 
491ef270ab1SKenneth D. Merry /**
492ef270ab1SKenneth D. Merry  * @brief Allocate a new MQ object
493ef270ab1SKenneth D. Merry  *
494ef270ab1SKenneth D. Merry  * A new MQ object is instantiated
495ef270ab1SKenneth D. Merry  *
496ef270ab1SKenneth D. Merry  * @param cq pointer to parent CQ object
497ef270ab1SKenneth D. Merry  * @param entry_count number of entries in the MQ
498ef270ab1SKenneth D. Merry  *
499ef270ab1SKenneth D. Merry  * @return pointer to allocated MQ object
500ef270ab1SKenneth D. Merry  */
501ef270ab1SKenneth D. Merry hw_mq_t*
hw_new_mq(hw_cq_t * cq,uint32_t entry_count)502ef270ab1SKenneth D. Merry hw_new_mq(hw_cq_t *cq, uint32_t entry_count)
503ef270ab1SKenneth D. Merry {
504ef270ab1SKenneth D. Merry 	ocs_hw_t *hw = cq->eq->hw;
505ef270ab1SKenneth D. Merry 	hw_mq_t *mq = ocs_malloc(hw->os, sizeof(*mq), OCS_M_ZERO | OCS_M_NOWAIT);
506ef270ab1SKenneth D. Merry 
507ef270ab1SKenneth D. Merry 	if (mq != NULL) {
508ef270ab1SKenneth D. Merry 		mq->cq = cq;
509ef270ab1SKenneth D. Merry 		mq->type = SLI_QTYPE_MQ;
510ef270ab1SKenneth D. Merry 		mq->instance = cq->eq->hw->mq_count++;
511ef270ab1SKenneth D. Merry 		mq->entry_count = entry_count;
512ef270ab1SKenneth D. Merry 		mq->entry_size = OCS_HW_MQ_DEPTH;
513ef270ab1SKenneth D. Merry 		mq->queue = &hw->mq[mq->instance];
514ef270ab1SKenneth D. Merry 
515ef270ab1SKenneth D. Merry 		if (sli_queue_alloc(&hw->sli, SLI_QTYPE_MQ,
516ef270ab1SKenneth D. Merry 				    mq->queue,
517ef270ab1SKenneth D. Merry 				    mq->entry_size,
518ef270ab1SKenneth D. Merry 				    cq->queue, 0)) {
519ef270ab1SKenneth D. Merry 			ocs_log_err(hw->os, "MQ allocation failure\n");
520ef270ab1SKenneth D. Merry 			ocs_free(hw->os, mq, sizeof(*mq));
521ef270ab1SKenneth D. Merry 			mq = NULL;
522ef270ab1SKenneth D. Merry 		} else {
523ef270ab1SKenneth D. Merry 			hw->hw_mq[mq->instance] = mq;
524ef270ab1SKenneth D. Merry 			ocs_list_add_tail(&cq->q_list, mq);
525ef270ab1SKenneth D. Merry 			ocs_log_debug(hw->os, "create mq[%2d] id %3d len %4d\n", mq->instance, mq->queue->id,
526ef270ab1SKenneth D. Merry 				mq->entry_count);
527ef270ab1SKenneth D. Merry 		}
528ef270ab1SKenneth D. Merry 	}
529ef270ab1SKenneth D. Merry 	return mq;
530ef270ab1SKenneth D. Merry }
531ef270ab1SKenneth D. Merry 
532ef270ab1SKenneth D. Merry /**
533ef270ab1SKenneth D. Merry  * @brief Allocate a new WQ object
534ef270ab1SKenneth D. Merry  *
535ef270ab1SKenneth D. Merry  * A new WQ object is instantiated
536ef270ab1SKenneth D. Merry  *
537ef270ab1SKenneth D. Merry  * @param cq pointer to parent CQ object
538ef270ab1SKenneth D. Merry  * @param entry_count number of entries in the WQ
539ef270ab1SKenneth D. Merry  * @param class WQ class
540ef270ab1SKenneth D. Merry  * @param ulp index of chute
541ef270ab1SKenneth D. Merry  *
542ef270ab1SKenneth D. Merry  * @return pointer to allocated WQ object
543ef270ab1SKenneth D. Merry  */
544ef270ab1SKenneth D. Merry hw_wq_t*
hw_new_wq(hw_cq_t * cq,uint32_t entry_count,uint32_t class,uint32_t ulp)545ef270ab1SKenneth D. Merry hw_new_wq(hw_cq_t *cq, uint32_t entry_count, uint32_t class, uint32_t ulp)
546ef270ab1SKenneth D. Merry {
547ef270ab1SKenneth D. Merry 	ocs_hw_t *hw = cq->eq->hw;
548ef270ab1SKenneth D. Merry 	hw_wq_t *wq = ocs_malloc(hw->os, sizeof(*wq), OCS_M_ZERO | OCS_M_NOWAIT);
549ef270ab1SKenneth D. Merry 
550ef270ab1SKenneth D. Merry 	if (wq != NULL) {
551ef270ab1SKenneth D. Merry 		wq->hw = cq->eq->hw;
552ef270ab1SKenneth D. Merry 		wq->cq = cq;
553ef270ab1SKenneth D. Merry 		wq->type = SLI_QTYPE_WQ;
554ef270ab1SKenneth D. Merry 		wq->instance = cq->eq->hw->wq_count++;
555ef270ab1SKenneth D. Merry 		wq->entry_count = entry_count;
556ef270ab1SKenneth D. Merry 		wq->queue = &hw->wq[wq->instance];
557ef270ab1SKenneth D. Merry 		wq->ulp = ulp;
558ef270ab1SKenneth D. Merry 		wq->wqec_set_count = OCS_HW_WQEC_SET_COUNT;
559ef270ab1SKenneth D. Merry 		wq->wqec_count = wq->wqec_set_count;
560ef270ab1SKenneth D. Merry 		wq->free_count = wq->entry_count - 1;
561ef270ab1SKenneth D. Merry 		wq->class = class;
562ef270ab1SKenneth D. Merry 		ocs_list_init(&wq->pending_list, ocs_hw_wqe_t, link);
563ef270ab1SKenneth D. Merry 
564ef270ab1SKenneth D. Merry 		if (sli_queue_alloc(&hw->sli, SLI_QTYPE_WQ, wq->queue, wq->entry_count, cq->queue, ulp)) {
565ef270ab1SKenneth D. Merry 			ocs_log_err(hw->os, "WQ allocation failure\n");
566ef270ab1SKenneth D. Merry 			ocs_free(hw->os, wq, sizeof(*wq));
567ef270ab1SKenneth D. Merry 			wq = NULL;
568ef270ab1SKenneth D. Merry 		} else {
569ef270ab1SKenneth D. Merry 			hw->hw_wq[wq->instance] = wq;
570ef270ab1SKenneth D. Merry 			ocs_list_add_tail(&cq->q_list, wq);
571ef270ab1SKenneth D. Merry 			ocs_log_debug(hw->os, "create wq[%2d] id %3d len %4d cls %d ulp %d\n", wq->instance, wq->queue->id,
572ef270ab1SKenneth D. Merry 				wq->entry_count, wq->class, wq->ulp);
573ef270ab1SKenneth D. Merry 		}
574ef270ab1SKenneth D. Merry 	}
575ef270ab1SKenneth D. Merry 	return wq;
576ef270ab1SKenneth D. Merry }
577ef270ab1SKenneth D. Merry 
578ef270ab1SKenneth D. Merry /**
579ef270ab1SKenneth D. Merry  * @brief Allocate a hw_rq_t object
580ef270ab1SKenneth D. Merry  *
581ef270ab1SKenneth D. Merry  * Allocate an RQ object, which encapsulates 2 SLI queues (for rq pair)
582ef270ab1SKenneth D. Merry  *
583ef270ab1SKenneth D. Merry  * @param cq pointer to parent CQ object
584ef270ab1SKenneth D. Merry  * @param entry_count number of entries in the RQs
585ef270ab1SKenneth D. Merry  * @param ulp ULP index for this RQ
586ef270ab1SKenneth D. Merry  *
587ef270ab1SKenneth D. Merry  * @return pointer to newly allocated hw_rq_t
588ef270ab1SKenneth D. Merry  */
589ef270ab1SKenneth D. Merry hw_rq_t*
hw_new_rq(hw_cq_t * cq,uint32_t entry_count,uint32_t ulp)590ef270ab1SKenneth D. Merry hw_new_rq(hw_cq_t *cq, uint32_t entry_count, uint32_t ulp)
591ef270ab1SKenneth D. Merry {
592ef270ab1SKenneth D. Merry 	ocs_hw_t *hw = cq->eq->hw;
593ef270ab1SKenneth D. Merry 	hw_rq_t *rq = ocs_malloc(hw->os, sizeof(*rq), OCS_M_ZERO | OCS_M_NOWAIT);
594ef270ab1SKenneth D. Merry 	uint32_t max_hw_rq;
595ef270ab1SKenneth D. Merry 
596ef270ab1SKenneth D. Merry 	ocs_hw_get(hw, OCS_HW_MAX_RQ_ENTRIES, &max_hw_rq);
597ef270ab1SKenneth D. Merry 
598ef270ab1SKenneth D. Merry 	if (rq != NULL) {
599ef270ab1SKenneth D. Merry 		rq->instance = hw->hw_rq_count++;
600ef270ab1SKenneth D. Merry 		rq->cq = cq;
601ef270ab1SKenneth D. Merry 		rq->type = SLI_QTYPE_RQ;
602ef270ab1SKenneth D. Merry 		rq->ulp = ulp;
603ef270ab1SKenneth D. Merry 
604ef270ab1SKenneth D. Merry 		rq->entry_count = OCS_MIN(entry_count, OCS_MIN(max_hw_rq, OCS_HW_RQ_NUM_HDR));
605ef270ab1SKenneth D. Merry 
606ef270ab1SKenneth D. Merry 		/* Create the header RQ */
607ef270ab1SKenneth D. Merry 		ocs_hw_assert(hw->rq_count < ARRAY_SIZE(hw->rq));
608ef270ab1SKenneth D. Merry 		rq->hdr = &hw->rq[hw->rq_count];
609ef270ab1SKenneth D. Merry 		rq->hdr_entry_size = OCS_HW_RQ_HEADER_SIZE;
610ef270ab1SKenneth D. Merry 
611ef270ab1SKenneth D. Merry 		if (sli_fc_rq_alloc(&hw->sli, rq->hdr,
612ef270ab1SKenneth D. Merry 				    rq->entry_count,
613ef270ab1SKenneth D. Merry 				    rq->hdr_entry_size,
614ef270ab1SKenneth D. Merry 				    cq->queue,
615ef270ab1SKenneth D. Merry 				    ulp, TRUE)) {
616ef270ab1SKenneth D. Merry 			ocs_log_err(hw->os, "RQ allocation failure - header\n");
617ef270ab1SKenneth D. Merry 			ocs_free(hw->os, rq, sizeof(*rq));
618ef270ab1SKenneth D. Merry 			return NULL;
619ef270ab1SKenneth D. Merry 		}
620ef270ab1SKenneth D. Merry 		hw->hw_rq_lookup[hw->rq_count] = rq->instance;	/* Update hw_rq_lookup[] */
621ef270ab1SKenneth D. Merry 		hw->rq_count++;
622ef270ab1SKenneth D. Merry 		ocs_log_debug(hw->os, "create rq[%2d] id %3d len %4d hdr  size %4d ulp %d\n",
623ef270ab1SKenneth D. Merry 			rq->instance, rq->hdr->id, rq->entry_count, rq->hdr_entry_size, rq->ulp);
624ef270ab1SKenneth D. Merry 
625ef270ab1SKenneth D. Merry 		/* Create the default data RQ */
626ef270ab1SKenneth D. Merry 		ocs_hw_assert(hw->rq_count < ARRAY_SIZE(hw->rq));
627ef270ab1SKenneth D. Merry 		rq->data = &hw->rq[hw->rq_count];
628ef270ab1SKenneth D. Merry 		rq->data_entry_size = hw->config.rq_default_buffer_size;
629ef270ab1SKenneth D. Merry 
630ef270ab1SKenneth D. Merry 		if (sli_fc_rq_alloc(&hw->sli, rq->data,
631ef270ab1SKenneth D. Merry 				    rq->entry_count,
632ef270ab1SKenneth D. Merry 				    rq->data_entry_size,
633ef270ab1SKenneth D. Merry 				    cq->queue,
634ef270ab1SKenneth D. Merry 				    ulp, FALSE)) {
635ef270ab1SKenneth D. Merry 			ocs_log_err(hw->os, "RQ allocation failure - first burst\n");
636ef270ab1SKenneth D. Merry 			ocs_free(hw->os, rq, sizeof(*rq));
637ef270ab1SKenneth D. Merry 			return NULL;
638ef270ab1SKenneth D. Merry 		}
639ef270ab1SKenneth D. Merry 		hw->hw_rq_lookup[hw->rq_count] = rq->instance;	/* Update hw_rq_lookup[] */
640ef270ab1SKenneth D. Merry 		hw->rq_count++;
641ef270ab1SKenneth D. Merry 		ocs_log_debug(hw->os, "create rq[%2d] id %3d len %4d data size %4d ulp %d\n", rq->instance,
642ef270ab1SKenneth D. Merry 			rq->data->id, rq->entry_count, rq->data_entry_size, rq->ulp);
643ef270ab1SKenneth D. Merry 
644ef270ab1SKenneth D. Merry 		hw->hw_rq[rq->instance] = rq;
645ef270ab1SKenneth D. Merry 		ocs_list_add_tail(&cq->q_list, rq);
646ef270ab1SKenneth D. Merry 
647ef270ab1SKenneth D. Merry 		rq->rq_tracker = ocs_malloc(hw->os, sizeof(ocs_hw_sequence_t*) *
648ef270ab1SKenneth D. Merry 					    rq->entry_count, OCS_M_ZERO | OCS_M_NOWAIT);
649ef270ab1SKenneth D. Merry 		if (rq->rq_tracker == NULL) {
650ef270ab1SKenneth D. Merry 			ocs_log_err(hw->os, "RQ tracker buf allocation failure\n");
651ef270ab1SKenneth D. Merry 			return NULL;
652ef270ab1SKenneth D. Merry 		}
653ef270ab1SKenneth D. Merry 	}
654ef270ab1SKenneth D. Merry 	return rq;
655ef270ab1SKenneth D. Merry }
656ef270ab1SKenneth D. Merry 
657ef270ab1SKenneth D. Merry /**
658ef270ab1SKenneth D. Merry  * @brief Allocate a hw_rq_t object SET
659ef270ab1SKenneth D. Merry  *
660ef270ab1SKenneth D. Merry  * Allocate an RQ object SET, where each element in set
661ef270ab1SKenneth D. Merry  * encapsulates 2 SLI queues (for rq pair)
662ef270ab1SKenneth D. Merry  *
663ef270ab1SKenneth D. Merry  * @param cqs pointers to be associated with RQs.
664ef270ab1SKenneth D. Merry  * @param rqs RQ pointers to be returned on success.
665ef270ab1SKenneth D. Merry  * @param num_rq_pairs number of rq pairs in the Set.
666ef270ab1SKenneth D. Merry  * @param entry_count number of entries in the RQs
667ef270ab1SKenneth D. Merry  * @param ulp ULP index for this RQ
668ef270ab1SKenneth D. Merry  *
669ef270ab1SKenneth D. Merry  * @return 0 in success and -1 on failure.
670ef270ab1SKenneth D. Merry  */
671ef270ab1SKenneth D. Merry uint32_t
hw_new_rq_set(hw_cq_t * cqs[],hw_rq_t * rqs[],uint32_t num_rq_pairs,uint32_t entry_count,uint32_t ulp)672ef270ab1SKenneth D. Merry hw_new_rq_set(hw_cq_t *cqs[], hw_rq_t *rqs[], uint32_t num_rq_pairs, uint32_t entry_count, uint32_t ulp)
673ef270ab1SKenneth D. Merry {
674ef270ab1SKenneth D. Merry 	ocs_hw_t *hw = cqs[0]->eq->hw;
675ef270ab1SKenneth D. Merry 	hw_rq_t *rq = NULL;
676ef270ab1SKenneth D. Merry 	sli4_queue_t *qs[SLI_MAX_RQ_SET_COUNT * 2] = { NULL };
677ef270ab1SKenneth D. Merry 	uint32_t max_hw_rq, i, q_count;
678ef270ab1SKenneth D. Merry 
679ef270ab1SKenneth D. Merry 	ocs_hw_get(hw, OCS_HW_MAX_RQ_ENTRIES, &max_hw_rq);
680ef270ab1SKenneth D. Merry 
681ef270ab1SKenneth D. Merry 	/* Initialise RQS pointers */
682ef270ab1SKenneth D. Merry 	for (i = 0; i < num_rq_pairs; i++) {
683ef270ab1SKenneth D. Merry 		rqs[i] = NULL;
684ef270ab1SKenneth D. Merry 	}
685ef270ab1SKenneth D. Merry 
686ef270ab1SKenneth D. Merry 	for (i = 0, q_count = 0; i < num_rq_pairs; i++, q_count += 2) {
687ef270ab1SKenneth D. Merry 		rq = ocs_malloc(hw->os, sizeof(*rq), OCS_M_ZERO | OCS_M_NOWAIT);
688ef270ab1SKenneth D. Merry 		if (rq == NULL)
689ef270ab1SKenneth D. Merry 			goto error;
690ef270ab1SKenneth D. Merry 
691ef270ab1SKenneth D. Merry 		rqs[i] = rq;
692ef270ab1SKenneth D. Merry 		rq->instance = hw->hw_rq_count++;
693ef270ab1SKenneth D. Merry 		rq->cq = cqs[i];
694ef270ab1SKenneth D. Merry 		rq->type = SLI_QTYPE_RQ;
695ef270ab1SKenneth D. Merry 		rq->ulp = ulp;
696ef270ab1SKenneth D. Merry 		rq->entry_count = OCS_MIN(entry_count, OCS_MIN(max_hw_rq, OCS_HW_RQ_NUM_HDR));
697ef270ab1SKenneth D. Merry 
698ef270ab1SKenneth D. Merry 		/* Header RQ */
699ef270ab1SKenneth D. Merry 		rq->hdr = &hw->rq[hw->rq_count];
700ef270ab1SKenneth D. Merry 		rq->hdr_entry_size = OCS_HW_RQ_HEADER_SIZE;
701ef270ab1SKenneth D. Merry 		hw->hw_rq_lookup[hw->rq_count] = rq->instance;
702ef270ab1SKenneth D. Merry 		hw->rq_count++;
703ef270ab1SKenneth D. Merry 		qs[q_count] = rq->hdr;
704ef270ab1SKenneth D. Merry 
705ef270ab1SKenneth D. Merry 		/* Data RQ */
706ef270ab1SKenneth D. Merry 		rq->data = &hw->rq[hw->rq_count];
707ef270ab1SKenneth D. Merry 		rq->data_entry_size = hw->config.rq_default_buffer_size;
708ef270ab1SKenneth D. Merry 		hw->hw_rq_lookup[hw->rq_count] = rq->instance;
709ef270ab1SKenneth D. Merry 		hw->rq_count++;
710ef270ab1SKenneth D. Merry 		qs[q_count + 1] = rq->data;
711ef270ab1SKenneth D. Merry 
712ef270ab1SKenneth D. Merry 		rq->rq_tracker = NULL;
713ef270ab1SKenneth D. Merry 	}
714ef270ab1SKenneth D. Merry 
715ef270ab1SKenneth D. Merry 	if (sli_fc_rq_set_alloc(&hw->sli, num_rq_pairs, qs,
716ef270ab1SKenneth D. Merry 			    cqs[0]->queue->id,
717ef270ab1SKenneth D. Merry 			    rqs[0]->entry_count,
718ef270ab1SKenneth D. Merry 			    rqs[0]->hdr_entry_size,
719ef270ab1SKenneth D. Merry 			    rqs[0]->data_entry_size,
720ef270ab1SKenneth D. Merry 			    ulp)) {
721ef270ab1SKenneth D. Merry 		ocs_log_err(hw->os, "RQ Set allocation failure for base CQ=%d\n", cqs[0]->queue->id);
722ef270ab1SKenneth D. Merry 		goto error;
723ef270ab1SKenneth D. Merry 	}
724ef270ab1SKenneth D. Merry 
725ef270ab1SKenneth D. Merry 	for (i = 0; i < num_rq_pairs; i++) {
726ef270ab1SKenneth D. Merry 		hw->hw_rq[rqs[i]->instance] = rqs[i];
727ef270ab1SKenneth D. Merry 		ocs_list_add_tail(&cqs[i]->q_list, rqs[i]);
728ef270ab1SKenneth D. Merry 		rqs[i]->rq_tracker = ocs_malloc(hw->os, sizeof(ocs_hw_sequence_t*) *
729ef270ab1SKenneth D. Merry 					    rqs[i]->entry_count, OCS_M_ZERO | OCS_M_NOWAIT);
730ef270ab1SKenneth D. Merry 		if (rqs[i]->rq_tracker == NULL) {
731ef270ab1SKenneth D. Merry 			ocs_log_err(hw->os, "RQ tracker buf allocation failure\n");
732ef270ab1SKenneth D. Merry 			goto error;
733ef270ab1SKenneth D. Merry 		}
734ef270ab1SKenneth D. Merry 	}
735ef270ab1SKenneth D. Merry 
736ef270ab1SKenneth D. Merry 	return 0;
737ef270ab1SKenneth D. Merry 
738ef270ab1SKenneth D. Merry error:
739ef270ab1SKenneth D. Merry 	for (i = 0; i < num_rq_pairs; i++) {
740ef270ab1SKenneth D. Merry 		if (rqs[i] != NULL) {
741ef270ab1SKenneth D. Merry 			if (rqs[i]->rq_tracker != NULL) {
7424915e5c7SRam Kishore Vegesna 				ocs_free(hw->os, rqs[i]->rq_tracker,
7434915e5c7SRam Kishore Vegesna 					 sizeof(ocs_hw_sequence_t*) *
7444915e5c7SRam Kishore Vegesna 					 rqs[i]->entry_count);
745ef270ab1SKenneth D. Merry 			}
746ef270ab1SKenneth D. Merry 			ocs_free(hw->os, rqs[i], sizeof(*rqs[i]));
747ef270ab1SKenneth D. Merry 		}
748ef270ab1SKenneth D. Merry 	}
749ef270ab1SKenneth D. Merry 
750ef270ab1SKenneth D. Merry 	return -1;
751ef270ab1SKenneth D. Merry }
752ef270ab1SKenneth D. Merry 
753ef270ab1SKenneth D. Merry /**
754ef270ab1SKenneth D. Merry  * @brief Free an EQ object
755ef270ab1SKenneth D. Merry  *
756ef270ab1SKenneth D. Merry  * The EQ object and any child queue objects are freed
757ef270ab1SKenneth D. Merry  *
758ef270ab1SKenneth D. Merry  * @param eq pointer to EQ object
759ef270ab1SKenneth D. Merry  *
760ef270ab1SKenneth D. Merry  * @return none
761ef270ab1SKenneth D. Merry  */
762ef270ab1SKenneth D. Merry void
hw_del_eq(hw_eq_t * eq)763ef270ab1SKenneth D. Merry hw_del_eq(hw_eq_t *eq)
764ef270ab1SKenneth D. Merry {
765ef270ab1SKenneth D. Merry 	if (eq != NULL) {
766ef270ab1SKenneth D. Merry 		hw_cq_t *cq;
767ef270ab1SKenneth D. Merry 		hw_cq_t *cq_next;
768ef270ab1SKenneth D. Merry 
769ef270ab1SKenneth D. Merry 		ocs_list_foreach_safe(&eq->cq_list, cq, cq_next) {
770ef270ab1SKenneth D. Merry 			hw_del_cq(cq);
771ef270ab1SKenneth D. Merry 		}
772ef270ab1SKenneth D. Merry 		ocs_varray_free(eq->wq_array);
773ef270ab1SKenneth D. Merry 		ocs_list_remove(&eq->hw->eq_list, eq);
774ef270ab1SKenneth D. Merry 		eq->hw->hw_eq[eq->instance] = NULL;
775ef270ab1SKenneth D. Merry 		ocs_free(eq->hw->os, eq, sizeof(*eq));
776ef270ab1SKenneth D. Merry 	}
777ef270ab1SKenneth D. Merry }
778ef270ab1SKenneth D. Merry 
779ef270ab1SKenneth D. Merry /**
780ef270ab1SKenneth D. Merry  * @brief Free a CQ object
781ef270ab1SKenneth D. Merry  *
782ef270ab1SKenneth D. Merry  * The CQ object and any child queue objects are freed
783ef270ab1SKenneth D. Merry  *
784ef270ab1SKenneth D. Merry  * @param cq pointer to CQ object
785ef270ab1SKenneth D. Merry  *
786ef270ab1SKenneth D. Merry  * @return none
787ef270ab1SKenneth D. Merry  */
788ef270ab1SKenneth D. Merry void
hw_del_cq(hw_cq_t * cq)789ef270ab1SKenneth D. Merry hw_del_cq(hw_cq_t *cq)
790ef270ab1SKenneth D. Merry {
791ef270ab1SKenneth D. Merry 	if (cq != NULL) {
792ef270ab1SKenneth D. Merry 		hw_q_t *q;
793ef270ab1SKenneth D. Merry 		hw_q_t *q_next;
794ef270ab1SKenneth D. Merry 
795ef270ab1SKenneth D. Merry 		ocs_list_foreach_safe(&cq->q_list, q, q_next) {
796ef270ab1SKenneth D. Merry 			switch(q->type) {
797ef270ab1SKenneth D. Merry 			case SLI_QTYPE_MQ:
798ef270ab1SKenneth D. Merry 				hw_del_mq((hw_mq_t*) q);
799ef270ab1SKenneth D. Merry 				break;
800ef270ab1SKenneth D. Merry 			case SLI_QTYPE_WQ:
801ef270ab1SKenneth D. Merry 				hw_del_wq((hw_wq_t*) q);
802ef270ab1SKenneth D. Merry 				break;
803ef270ab1SKenneth D. Merry 			case SLI_QTYPE_RQ:
804ef270ab1SKenneth D. Merry 				hw_del_rq((hw_rq_t*) q);
805ef270ab1SKenneth D. Merry 				break;
806ef270ab1SKenneth D. Merry 			default:
807ef270ab1SKenneth D. Merry 				break;
808ef270ab1SKenneth D. Merry 			}
809ef270ab1SKenneth D. Merry 		}
810ef270ab1SKenneth D. Merry 		ocs_list_remove(&cq->eq->cq_list, cq);
811ef270ab1SKenneth D. Merry 		cq->eq->hw->hw_cq[cq->instance] = NULL;
812ef270ab1SKenneth D. Merry 		ocs_free(cq->eq->hw->os, cq, sizeof(*cq));
813ef270ab1SKenneth D. Merry 	}
814ef270ab1SKenneth D. Merry }
815ef270ab1SKenneth D. Merry 
816ef270ab1SKenneth D. Merry /**
817ef270ab1SKenneth D. Merry  * @brief Free a MQ object
818ef270ab1SKenneth D. Merry  *
819ef270ab1SKenneth D. Merry  * The MQ object is freed
820ef270ab1SKenneth D. Merry  *
821ef270ab1SKenneth D. Merry  * @param mq pointer to MQ object
822ef270ab1SKenneth D. Merry  *
823ef270ab1SKenneth D. Merry  * @return none
824ef270ab1SKenneth D. Merry  */
825ef270ab1SKenneth D. Merry void
hw_del_mq(hw_mq_t * mq)826ef270ab1SKenneth D. Merry hw_del_mq(hw_mq_t *mq)
827ef270ab1SKenneth D. Merry {
828ef270ab1SKenneth D. Merry 	if (mq != NULL) {
829ef270ab1SKenneth D. Merry 		ocs_list_remove(&mq->cq->q_list, mq);
830ef270ab1SKenneth D. Merry 		mq->cq->eq->hw->hw_mq[mq->instance] = NULL;
831ef270ab1SKenneth D. Merry 		ocs_free(mq->cq->eq->hw->os, mq, sizeof(*mq));
832ef270ab1SKenneth D. Merry 	}
833ef270ab1SKenneth D. Merry }
834ef270ab1SKenneth D. Merry 
835ef270ab1SKenneth D. Merry /**
836ef270ab1SKenneth D. Merry  * @brief Free a WQ object
837ef270ab1SKenneth D. Merry  *
838ef270ab1SKenneth D. Merry  * The WQ object is freed
839ef270ab1SKenneth D. Merry  *
840ef270ab1SKenneth D. Merry  * @param wq pointer to WQ object
841ef270ab1SKenneth D. Merry  *
842ef270ab1SKenneth D. Merry  * @return none
843ef270ab1SKenneth D. Merry  */
844ef270ab1SKenneth D. Merry void
hw_del_wq(hw_wq_t * wq)845ef270ab1SKenneth D. Merry hw_del_wq(hw_wq_t *wq)
846ef270ab1SKenneth D. Merry {
847ef270ab1SKenneth D. Merry 	if (wq != NULL) {
848ef270ab1SKenneth D. Merry 		ocs_list_remove(&wq->cq->q_list, wq);
849ef270ab1SKenneth D. Merry 		wq->cq->eq->hw->hw_wq[wq->instance] = NULL;
850ef270ab1SKenneth D. Merry 		ocs_free(wq->cq->eq->hw->os, wq, sizeof(*wq));
851ef270ab1SKenneth D. Merry 	}
852ef270ab1SKenneth D. Merry }
853ef270ab1SKenneth D. Merry 
854ef270ab1SKenneth D. Merry /**
855ef270ab1SKenneth D. Merry  * @brief Free an RQ object
856ef270ab1SKenneth D. Merry  *
857ef270ab1SKenneth D. Merry  * The RQ object is freed
858ef270ab1SKenneth D. Merry  *
859ef270ab1SKenneth D. Merry  * @param rq pointer to RQ object
860ef270ab1SKenneth D. Merry  *
861ef270ab1SKenneth D. Merry  * @return none
862ef270ab1SKenneth D. Merry  */
863ef270ab1SKenneth D. Merry void
hw_del_rq(hw_rq_t * rq)864ef270ab1SKenneth D. Merry hw_del_rq(hw_rq_t *rq)
865ef270ab1SKenneth D. Merry {
866ef270ab1SKenneth D. Merry 
867ef270ab1SKenneth D. Merry 	if (rq != NULL) {
8684915e5c7SRam Kishore Vegesna 		ocs_hw_t *hw = rq->cq->eq->hw;
869ef270ab1SKenneth D. Merry 		/* Free RQ tracker */
870ef270ab1SKenneth D. Merry 		if (rq->rq_tracker != NULL) {
871ef270ab1SKenneth D. Merry 			ocs_free(hw->os, rq->rq_tracker, sizeof(ocs_hw_sequence_t*) * rq->entry_count);
872ef270ab1SKenneth D. Merry 			rq->rq_tracker = NULL;
873ef270ab1SKenneth D. Merry 		}
874ef270ab1SKenneth D. Merry 		ocs_list_remove(&rq->cq->q_list, rq);
875ef270ab1SKenneth D. Merry 		hw->hw_rq[rq->instance] = NULL;
876ef270ab1SKenneth D. Merry 		ocs_free(hw->os, rq, sizeof(*rq));
877ef270ab1SKenneth D. Merry 	}
878ef270ab1SKenneth D. Merry }
879ef270ab1SKenneth D. Merry 
880ef270ab1SKenneth D. Merry /**
881ef270ab1SKenneth D. Merry  * @brief Display HW queue objects
882ef270ab1SKenneth D. Merry  *
883ef270ab1SKenneth D. Merry  * The HW queue objects are displayed using ocs_log
884ef270ab1SKenneth D. Merry  *
885ef270ab1SKenneth D. Merry  * @param hw pointer to HW object
886ef270ab1SKenneth D. Merry  *
887ef270ab1SKenneth D. Merry  * @return none
888ef270ab1SKenneth D. Merry  */
889ef270ab1SKenneth D. Merry void
hw_queue_dump(ocs_hw_t * hw)890ef270ab1SKenneth D. Merry hw_queue_dump(ocs_hw_t *hw)
891ef270ab1SKenneth D. Merry {
892ef270ab1SKenneth D. Merry 	hw_eq_t *eq;
893ef270ab1SKenneth D. Merry 	hw_cq_t *cq;
894ef270ab1SKenneth D. Merry 	hw_q_t *q;
895ef270ab1SKenneth D. Merry 	hw_mq_t *mq;
896ef270ab1SKenneth D. Merry 	hw_wq_t *wq;
897ef270ab1SKenneth D. Merry 	hw_rq_t *rq;
898ef270ab1SKenneth D. Merry 
899ef270ab1SKenneth D. Merry 	ocs_list_foreach(&hw->eq_list, eq) {
900ef270ab1SKenneth D. Merry 		ocs_printf("eq[%d] id %2d\n", eq->instance, eq->queue->id);
901ef270ab1SKenneth D. Merry 		ocs_list_foreach(&eq->cq_list, cq) {
902ef270ab1SKenneth D. Merry 			ocs_printf("  cq[%d] id %2d current\n", cq->instance, cq->queue->id);
903ef270ab1SKenneth D. Merry 			ocs_list_foreach(&cq->q_list, q) {
904ef270ab1SKenneth D. Merry 				switch(q->type) {
905ef270ab1SKenneth D. Merry 				case SLI_QTYPE_MQ:
906ef270ab1SKenneth D. Merry 					mq = (hw_mq_t *) q;
907ef270ab1SKenneth D. Merry 					ocs_printf("    mq[%d] id %2d\n", mq->instance, mq->queue->id);
908ef270ab1SKenneth D. Merry 					break;
909ef270ab1SKenneth D. Merry 				case SLI_QTYPE_WQ:
910ef270ab1SKenneth D. Merry 					wq = (hw_wq_t *) q;
911ef270ab1SKenneth D. Merry 					ocs_printf("    wq[%d] id %2d\n", wq->instance, wq->queue->id);
912ef270ab1SKenneth D. Merry 					break;
913ef270ab1SKenneth D. Merry 				case SLI_QTYPE_RQ:
914ef270ab1SKenneth D. Merry 					rq = (hw_rq_t *) q;
915ef270ab1SKenneth D. Merry 					ocs_printf("    rq[%d] hdr id %2d\n", rq->instance, rq->hdr->id);
916ef270ab1SKenneth D. Merry 					break;
917ef270ab1SKenneth D. Merry 				default:
918ef270ab1SKenneth D. Merry 					break;
919ef270ab1SKenneth D. Merry 				}
920ef270ab1SKenneth D. Merry 			}
921ef270ab1SKenneth D. Merry 		}
922ef270ab1SKenneth D. Merry 	}
923ef270ab1SKenneth D. Merry }
924ef270ab1SKenneth D. Merry 
925ef270ab1SKenneth D. Merry /**
926ef270ab1SKenneth D. Merry  * @brief Teardown HW queue objects
927ef270ab1SKenneth D. Merry  *
928ef270ab1SKenneth D. Merry  * The HW queue objects are freed
929ef270ab1SKenneth D. Merry  *
930ef270ab1SKenneth D. Merry  * @param hw pointer to HW object
931ef270ab1SKenneth D. Merry  *
932ef270ab1SKenneth D. Merry  * @return none
933ef270ab1SKenneth D. Merry  */
934ef270ab1SKenneth D. Merry void
hw_queue_teardown(ocs_hw_t * hw)935ef270ab1SKenneth D. Merry hw_queue_teardown(ocs_hw_t *hw)
936ef270ab1SKenneth D. Merry {
937ef270ab1SKenneth D. Merry 	uint32_t i;
938ef270ab1SKenneth D. Merry 	hw_eq_t *eq;
939ef270ab1SKenneth D. Merry 	hw_eq_t *eq_next;
940ef270ab1SKenneth D. Merry 
941ef270ab1SKenneth D. Merry 	if (ocs_list_valid(&hw->eq_list)) {
942ef270ab1SKenneth D. Merry 		ocs_list_foreach_safe(&hw->eq_list, eq, eq_next) {
943ef270ab1SKenneth D. Merry 			hw_del_eq(eq);
944ef270ab1SKenneth D. Merry 		}
945ef270ab1SKenneth D. Merry 	}
946ef270ab1SKenneth D. Merry 	for (i = 0; i < ARRAY_SIZE(hw->wq_cpu_array); i++) {
947ef270ab1SKenneth D. Merry 		ocs_varray_free(hw->wq_cpu_array[i]);
948ef270ab1SKenneth D. Merry 		hw->wq_cpu_array[i] = NULL;
949ef270ab1SKenneth D. Merry 	}
950ef270ab1SKenneth D. Merry 	for (i = 0; i < ARRAY_SIZE(hw->wq_class_array); i++) {
951ef270ab1SKenneth D. Merry 		ocs_varray_free(hw->wq_class_array[i]);
952ef270ab1SKenneth D. Merry 		hw->wq_class_array[i] = NULL;
953ef270ab1SKenneth D. Merry 	}
954ef270ab1SKenneth D. Merry }
955ef270ab1SKenneth D. Merry 
956ef270ab1SKenneth D. Merry /**
957ef270ab1SKenneth D. Merry  * @brief Allocate a WQ to an IO object
958ef270ab1SKenneth D. Merry  *
959ef270ab1SKenneth D. Merry  * The next work queue index is used to assign a WQ to an IO.
960ef270ab1SKenneth D. Merry  *
961ef270ab1SKenneth D. Merry  * If wq_steering is OCS_HW_WQ_STEERING_CLASS, a WQ from io->wq_class is
962ef270ab1SKenneth D. Merry  * selected.
963ef270ab1SKenneth D. Merry  *
964ef270ab1SKenneth D. Merry  * If wq_steering is OCS_HW_WQ_STEERING_REQUEST, then a WQ from the EQ that
965ef270ab1SKenneth D. Merry  * the IO request came in on is selected.
966ef270ab1SKenneth D. Merry  *
96716b71d98SGordon Bergling  * If wq_steering is OCS_HW_WQ_STEERING_CPU, then a WQ associated with the
968ef270ab1SKenneth D. Merry  * CPU the request is made on is selected.
969ef270ab1SKenneth D. Merry  *
970ef270ab1SKenneth D. Merry  * @param hw pointer to HW object
971ef270ab1SKenneth D. Merry  * @param io pointer to IO object
972ef270ab1SKenneth D. Merry  *
973ef270ab1SKenneth D. Merry  * @return Return pointer to next WQ
974ef270ab1SKenneth D. Merry  */
975ef270ab1SKenneth D. Merry hw_wq_t *
ocs_hw_queue_next_wq(ocs_hw_t * hw,ocs_hw_io_t * io)976ef270ab1SKenneth D. Merry ocs_hw_queue_next_wq(ocs_hw_t *hw, ocs_hw_io_t *io)
977ef270ab1SKenneth D. Merry {
978ef270ab1SKenneth D. Merry 	hw_eq_t *eq;
979ef270ab1SKenneth D. Merry 	hw_wq_t *wq = NULL;
980ef270ab1SKenneth D. Merry 
981ef270ab1SKenneth D. Merry 	switch(io->wq_steering) {
982ef270ab1SKenneth D. Merry 	case OCS_HW_WQ_STEERING_CLASS:
983ef270ab1SKenneth D. Merry 		if (likely(io->wq_class < ARRAY_SIZE(hw->wq_class_array))) {
984ef270ab1SKenneth D. Merry 			wq = ocs_varray_iter_next(hw->wq_class_array[io->wq_class]);
985ef270ab1SKenneth D. Merry 		}
986ef270ab1SKenneth D. Merry 		break;
987ef270ab1SKenneth D. Merry 	case OCS_HW_WQ_STEERING_REQUEST:
988ef270ab1SKenneth D. Merry 		eq = io->eq;
989ef270ab1SKenneth D. Merry 		if (likely(eq != NULL)) {
990ef270ab1SKenneth D. Merry 			wq = ocs_varray_iter_next(eq->wq_array);
991ef270ab1SKenneth D. Merry 		}
992ef270ab1SKenneth D. Merry 		break;
993ef270ab1SKenneth D. Merry 	case OCS_HW_WQ_STEERING_CPU: {
994ef270ab1SKenneth D. Merry 		uint32_t cpuidx = ocs_thread_getcpu();
995ef270ab1SKenneth D. Merry 
996ef270ab1SKenneth D. Merry 		if (likely(cpuidx < ARRAY_SIZE(hw->wq_cpu_array))) {
997ef270ab1SKenneth D. Merry 			wq = ocs_varray_iter_next(hw->wq_cpu_array[cpuidx]);
998ef270ab1SKenneth D. Merry 		}
999ef270ab1SKenneth D. Merry 		break;
1000ef270ab1SKenneth D. Merry 	}
1001ef270ab1SKenneth D. Merry 	}
1002ef270ab1SKenneth D. Merry 
1003ef270ab1SKenneth D. Merry 	if (unlikely(wq == NULL)) {
1004ef270ab1SKenneth D. Merry 		wq = hw->hw_wq[0];
1005ef270ab1SKenneth D. Merry 	}
1006ef270ab1SKenneth D. Merry 
1007ef270ab1SKenneth D. Merry 	return wq;
1008ef270ab1SKenneth D. Merry }
1009ef270ab1SKenneth D. Merry 
1010ef270ab1SKenneth D. Merry /**
1011ef270ab1SKenneth D. Merry  * @brief Return count of EQs for a queue topology object
1012ef270ab1SKenneth D. Merry  *
1013ef270ab1SKenneth D. Merry  * The EQ count for in the HWs queue topology (hw->qtop) object is returned
1014ef270ab1SKenneth D. Merry  *
1015ef270ab1SKenneth D. Merry  * @param hw pointer to HW object
1016ef270ab1SKenneth D. Merry  *
1017ef270ab1SKenneth D. Merry  * @return count of EQs
1018ef270ab1SKenneth D. Merry  */
1019ef270ab1SKenneth D. Merry uint32_t
ocs_hw_qtop_eq_count(ocs_hw_t * hw)1020ef270ab1SKenneth D. Merry ocs_hw_qtop_eq_count(ocs_hw_t *hw)
1021ef270ab1SKenneth D. Merry {
1022ef270ab1SKenneth D. Merry 	return hw->qtop->entry_counts[QTOP_EQ];
1023ef270ab1SKenneth D. Merry }
1024ef270ab1SKenneth D. Merry 
1025ef270ab1SKenneth D. Merry #define TOKEN_LEN		32
1026ef270ab1SKenneth D. Merry 
1027ef270ab1SKenneth D. Merry /**
1028ef270ab1SKenneth D. Merry  * @brief return string given a QTOP entry
1029ef270ab1SKenneth D. Merry  *
1030ef270ab1SKenneth D. Merry  * @param entry QTOP entry
1031ef270ab1SKenneth D. Merry  *
1032ef270ab1SKenneth D. Merry  * @return returns string or "unknown"
1033ef270ab1SKenneth D. Merry  */
1034ef270ab1SKenneth D. Merry #if HW_QTOP_DEBUG
1035ef270ab1SKenneth D. Merry static char *
qtopentry2s(ocs_hw_qtop_entry_e entry)1036ef270ab1SKenneth D. Merry qtopentry2s(ocs_hw_qtop_entry_e entry) {
1037ef270ab1SKenneth D. Merry 	switch(entry) {
1038ef270ab1SKenneth D. Merry 	#define P(x)	case x: return #x;
1039ef270ab1SKenneth D. Merry 	P(QTOP_EQ)
1040ef270ab1SKenneth D. Merry 	P(QTOP_CQ)
1041ef270ab1SKenneth D. Merry 	P(QTOP_WQ)
1042ef270ab1SKenneth D. Merry 	P(QTOP_RQ)
1043ef270ab1SKenneth D. Merry 	P(QTOP_MQ)
1044ef270ab1SKenneth D. Merry 	P(QTOP_THREAD_START)
1045ef270ab1SKenneth D. Merry 	P(QTOP_THREAD_END)
1046ef270ab1SKenneth D. Merry 	P(QTOP_LAST)
1047ef270ab1SKenneth D. Merry 	#undef P
1048ef270ab1SKenneth D. Merry 	}
1049ef270ab1SKenneth D. Merry 	return "unknown";
1050ef270ab1SKenneth D. Merry }
1051ef270ab1SKenneth D. Merry #endif
1052ef270ab1SKenneth D. Merry 
1053ef270ab1SKenneth D. Merry /**
1054ef270ab1SKenneth D. Merry  * @brief Declare token types
1055ef270ab1SKenneth D. Merry  */
1056ef270ab1SKenneth D. Merry typedef enum {
1057ef270ab1SKenneth D. Merry 	TOK_LPAREN = 1,
1058ef270ab1SKenneth D. Merry 	TOK_RPAREN,
1059ef270ab1SKenneth D. Merry 	TOK_COLON,
1060ef270ab1SKenneth D. Merry 	TOK_EQUALS,
1061ef270ab1SKenneth D. Merry 	TOK_QUEUE,
1062ef270ab1SKenneth D. Merry 	TOK_ATTR_NAME,
1063ef270ab1SKenneth D. Merry 	TOK_NUMBER,
1064ef270ab1SKenneth D. Merry 	TOK_NUMBER_VALUE,
1065ef270ab1SKenneth D. Merry 	TOK_NUMBER_LIST,
1066ef270ab1SKenneth D. Merry } tok_type_e;
1067ef270ab1SKenneth D. Merry 
1068ef270ab1SKenneth D. Merry /**
1069ef270ab1SKenneth D. Merry  * @brief Declare token sub-types
1070ef270ab1SKenneth D. Merry  */
1071ef270ab1SKenneth D. Merry typedef enum {
1072ef270ab1SKenneth D. Merry 	TOK_SUB_EQ = 100,
1073ef270ab1SKenneth D. Merry 	TOK_SUB_CQ,
1074ef270ab1SKenneth D. Merry 	TOK_SUB_RQ,
1075ef270ab1SKenneth D. Merry 	TOK_SUB_MQ,
1076ef270ab1SKenneth D. Merry 	TOK_SUB_WQ,
1077ef270ab1SKenneth D. Merry 	TOK_SUB_LEN,
1078ef270ab1SKenneth D. Merry 	TOK_SUB_CLASS,
1079ef270ab1SKenneth D. Merry 	TOK_SUB_ULP,
1080ef270ab1SKenneth D. Merry 	TOK_SUB_FILTER,
1081ef270ab1SKenneth D. Merry } tok_subtype_e;
1082ef270ab1SKenneth D. Merry 
1083ef270ab1SKenneth D. Merry /**
1084ef270ab1SKenneth D. Merry  * @brief convert queue subtype to QTOP entry
1085ef270ab1SKenneth D. Merry  *
1086ef270ab1SKenneth D. Merry  * @param q queue subtype
1087ef270ab1SKenneth D. Merry  *
1088ef270ab1SKenneth D. Merry  * @return QTOP entry or 0
1089ef270ab1SKenneth D. Merry  */
1090ef270ab1SKenneth D. Merry static ocs_hw_qtop_entry_e
subtype2qtop(tok_subtype_e q)1091ef270ab1SKenneth D. Merry subtype2qtop(tok_subtype_e q)
1092ef270ab1SKenneth D. Merry {
1093ef270ab1SKenneth D. Merry 	switch(q) {
1094ef270ab1SKenneth D. Merry 	case TOK_SUB_EQ:	return QTOP_EQ;
1095ef270ab1SKenneth D. Merry 	case TOK_SUB_CQ:	return QTOP_CQ;
1096ef270ab1SKenneth D. Merry 	case TOK_SUB_RQ:	return QTOP_RQ;
1097ef270ab1SKenneth D. Merry 	case TOK_SUB_MQ:	return QTOP_MQ;
1098ef270ab1SKenneth D. Merry 	case TOK_SUB_WQ:	return QTOP_WQ;
1099ef270ab1SKenneth D. Merry 	default:
1100ef270ab1SKenneth D. Merry 		break;
1101ef270ab1SKenneth D. Merry 	}
1102ef270ab1SKenneth D. Merry 	return 0;
1103ef270ab1SKenneth D. Merry }
1104ef270ab1SKenneth D. Merry 
1105ef270ab1SKenneth D. Merry /**
1106ef270ab1SKenneth D. Merry  * @brief Declare token object
1107ef270ab1SKenneth D. Merry  */
1108ef270ab1SKenneth D. Merry typedef struct {
1109ef270ab1SKenneth D. Merry 	tok_type_e type;
1110ef270ab1SKenneth D. Merry 	tok_subtype_e subtype;
1111ef270ab1SKenneth D. Merry 	char string[TOKEN_LEN];
1112ef270ab1SKenneth D. Merry } tok_t;
1113ef270ab1SKenneth D. Merry 
1114ef270ab1SKenneth D. Merry /**
1115ef270ab1SKenneth D. Merry  * @brief Declare token array object
1116ef270ab1SKenneth D. Merry  */
1117ef270ab1SKenneth D. Merry typedef struct {
1118ef270ab1SKenneth D. Merry 	tok_t *tokens;			/* Pointer to array of tokens */
1119ef270ab1SKenneth D. Merry 	uint32_t alloc_count;		/* Number of tokens in the array */
1120ef270ab1SKenneth D. Merry 	uint32_t inuse_count;		/* Number of tokens posted to array */
1121ef270ab1SKenneth D. Merry 	uint32_t iter_idx;		/* Iterator index */
1122ef270ab1SKenneth D. Merry } tokarray_t;
1123ef270ab1SKenneth D. Merry 
1124ef270ab1SKenneth D. Merry /**
1125ef270ab1SKenneth D. Merry  * @brief Declare token match structure
1126ef270ab1SKenneth D. Merry  */
1127ef270ab1SKenneth D. Merry typedef struct {
1128ef270ab1SKenneth D. Merry 	char *s;
1129ef270ab1SKenneth D. Merry 	tok_type_e type;
1130ef270ab1SKenneth D. Merry 	tok_subtype_e subtype;
1131ef270ab1SKenneth D. Merry } tokmatch_t;
1132ef270ab1SKenneth D. Merry 
1133ef270ab1SKenneth D. Merry /**
1134ef270ab1SKenneth D. Merry  * @brief test if character is ID start character
1135ef270ab1SKenneth D. Merry  *
1136ef270ab1SKenneth D. Merry  * @param c character to test
1137ef270ab1SKenneth D. Merry  *
1138ef270ab1SKenneth D. Merry  * @return TRUE if character is an ID start character
1139ef270ab1SKenneth D. Merry  */
1140ef270ab1SKenneth D. Merry static int32_t
idstart(int c)1141ef270ab1SKenneth D. Merry idstart(int c)
1142ef270ab1SKenneth D. Merry {
1143ef270ab1SKenneth D. Merry 	return	isalpha(c) || (c == '_') || (c == '$');
1144ef270ab1SKenneth D. Merry }
1145ef270ab1SKenneth D. Merry 
1146ef270ab1SKenneth D. Merry /**
1147ef270ab1SKenneth D. Merry  * @brief test if character is an ID character
1148ef270ab1SKenneth D. Merry  *
1149ef270ab1SKenneth D. Merry  * @param c character to test
1150ef270ab1SKenneth D. Merry  *
1151ef270ab1SKenneth D. Merry  * @return TRUE if character is an ID character
1152ef270ab1SKenneth D. Merry  */
1153ef270ab1SKenneth D. Merry static int32_t
idchar(int c)1154ef270ab1SKenneth D. Merry idchar(int c)
1155ef270ab1SKenneth D. Merry {
1156ef270ab1SKenneth D. Merry 	return idstart(c) || ocs_isdigit(c);
1157ef270ab1SKenneth D. Merry }
1158ef270ab1SKenneth D. Merry 
1159ef270ab1SKenneth D. Merry /**
1160ef270ab1SKenneth D. Merry  * @brief Declare single character matches
1161ef270ab1SKenneth D. Merry  */
1162ef270ab1SKenneth D. Merry static tokmatch_t cmatches[] = {
1163ef270ab1SKenneth D. Merry 	{"(", TOK_LPAREN},
1164ef270ab1SKenneth D. Merry 	{")", TOK_RPAREN},
1165ef270ab1SKenneth D. Merry 	{":", TOK_COLON},
1166ef270ab1SKenneth D. Merry 	{"=", TOK_EQUALS},
1167ef270ab1SKenneth D. Merry };
1168ef270ab1SKenneth D. Merry 
1169ef270ab1SKenneth D. Merry /**
1170ef270ab1SKenneth D. Merry  * @brief Declare identifier match strings
1171ef270ab1SKenneth D. Merry  */
1172ef270ab1SKenneth D. Merry static tokmatch_t smatches[] = {
1173ef270ab1SKenneth D. Merry 	{"eq", TOK_QUEUE, TOK_SUB_EQ},
1174ef270ab1SKenneth D. Merry 	{"cq", TOK_QUEUE, TOK_SUB_CQ},
1175ef270ab1SKenneth D. Merry 	{"rq", TOK_QUEUE, TOK_SUB_RQ},
1176ef270ab1SKenneth D. Merry 	{"mq", TOK_QUEUE, TOK_SUB_MQ},
1177ef270ab1SKenneth D. Merry 	{"wq", TOK_QUEUE, TOK_SUB_WQ},
1178ef270ab1SKenneth D. Merry 	{"len", TOK_ATTR_NAME, TOK_SUB_LEN},
1179ef270ab1SKenneth D. Merry 	{"class", TOK_ATTR_NAME, TOK_SUB_CLASS},
1180ef270ab1SKenneth D. Merry 	{"ulp", TOK_ATTR_NAME, TOK_SUB_ULP},
1181ef270ab1SKenneth D. Merry 	{"filter", TOK_ATTR_NAME, TOK_SUB_FILTER},
1182ef270ab1SKenneth D. Merry };
1183ef270ab1SKenneth D. Merry 
1184ef270ab1SKenneth D. Merry /**
1185ef270ab1SKenneth D. Merry  * @brief Scan string and return next token
1186ef270ab1SKenneth D. Merry  *
1187ef270ab1SKenneth D. Merry  * The string is scanned and the next token is returned
1188ef270ab1SKenneth D. Merry  *
1189ef270ab1SKenneth D. Merry  * @param s input string to scan
1190ef270ab1SKenneth D. Merry  * @param tok pointer to place scanned token
1191ef270ab1SKenneth D. Merry  *
1192ef270ab1SKenneth D. Merry  * @return pointer to input string following scanned token, or NULL
1193ef270ab1SKenneth D. Merry  */
1194ef270ab1SKenneth D. Merry static const char *
tokenize(const char * s,tok_t * tok)1195ef270ab1SKenneth D. Merry tokenize(const char *s, tok_t *tok)
1196ef270ab1SKenneth D. Merry {
1197ef270ab1SKenneth D. Merry 	uint32_t i;
1198ef270ab1SKenneth D. Merry 
1199ef270ab1SKenneth D. Merry 	memset(tok, 0, sizeof(*tok));
1200ef270ab1SKenneth D. Merry 
1201ef270ab1SKenneth D. Merry 	/* Skip over whitespace */
1202ef270ab1SKenneth D. Merry 	while (*s && ocs_isspace(*s)) {
1203ef270ab1SKenneth D. Merry 		s++;
1204ef270ab1SKenneth D. Merry 	}
1205ef270ab1SKenneth D. Merry 
1206ef270ab1SKenneth D. Merry 	/* Return if nothing left in this string */
1207ef270ab1SKenneth D. Merry 	if (*s == 0) {
1208ef270ab1SKenneth D. Merry 		return NULL;
1209ef270ab1SKenneth D. Merry 	}
1210ef270ab1SKenneth D. Merry 
1211ef270ab1SKenneth D. Merry 	/* Look for single character matches */
1212ef270ab1SKenneth D. Merry 	for (i = 0; i < ARRAY_SIZE(cmatches); i++) {
1213ef270ab1SKenneth D. Merry 		if (cmatches[i].s[0] == *s) {
1214ef270ab1SKenneth D. Merry 			tok->type = cmatches[i].type;
1215ef270ab1SKenneth D. Merry 			tok->subtype = cmatches[i].subtype;
1216ef270ab1SKenneth D. Merry 			tok->string[0] = *s++;
1217ef270ab1SKenneth D. Merry 			return s;
1218ef270ab1SKenneth D. Merry 		}
1219ef270ab1SKenneth D. Merry 	}
1220ef270ab1SKenneth D. Merry 
1221ef270ab1SKenneth D. Merry 	/* Scan for a hex number or decimal */
1222ef270ab1SKenneth D. Merry 	if ((s[0] == '0') && ((s[1] == 'x') || (s[1] == 'X'))) {
1223ef270ab1SKenneth D. Merry 		char *p = tok->string;
1224ef270ab1SKenneth D. Merry 
1225ef270ab1SKenneth D. Merry 		tok->type = TOK_NUMBER;
1226ef270ab1SKenneth D. Merry 
1227ef270ab1SKenneth D. Merry 		*p++ = *s++;
1228ef270ab1SKenneth D. Merry 		*p++ = *s++;
1229ef270ab1SKenneth D. Merry 		while ((*s == '.') || ocs_isxdigit(*s)) {
1230ef270ab1SKenneth D. Merry 			if ((p - tok->string) < (int32_t)sizeof(tok->string)) {
1231ef270ab1SKenneth D. Merry 				*p++ = *s;
1232ef270ab1SKenneth D. Merry 			}
1233ef270ab1SKenneth D. Merry 			if (*s == ',') {
1234ef270ab1SKenneth D. Merry 				tok->type = TOK_NUMBER_LIST;
1235ef270ab1SKenneth D. Merry 			}
1236ef270ab1SKenneth D. Merry 			s++;
1237ef270ab1SKenneth D. Merry 		}
1238ef270ab1SKenneth D. Merry 		*p = 0;
1239ef270ab1SKenneth D. Merry 		return s;
1240ef270ab1SKenneth D. Merry 	} else if (ocs_isdigit(*s)) {
1241ef270ab1SKenneth D. Merry 		char *p = tok->string;
1242ef270ab1SKenneth D. Merry 
1243ef270ab1SKenneth D. Merry 		tok->type = TOK_NUMBER;
1244ef270ab1SKenneth D. Merry 		while ((*s == ',') || ocs_isdigit(*s)) {
1245ef270ab1SKenneth D. Merry 			if ((p - tok->string) < (int32_t)sizeof(tok->string)) {
1246ef270ab1SKenneth D. Merry 				*p++ = *s;
1247ef270ab1SKenneth D. Merry 			}
1248ef270ab1SKenneth D. Merry 			if (*s == ',') {
1249ef270ab1SKenneth D. Merry 				tok->type = TOK_NUMBER_LIST;
1250ef270ab1SKenneth D. Merry 			}
1251ef270ab1SKenneth D. Merry 			s++;
1252ef270ab1SKenneth D. Merry 		}
1253ef270ab1SKenneth D. Merry 		*p = 0;
1254ef270ab1SKenneth D. Merry 		return s;
1255ef270ab1SKenneth D. Merry 	}
1256ef270ab1SKenneth D. Merry 
1257ef270ab1SKenneth D. Merry 	/* Scan for an ID */
1258ef270ab1SKenneth D. Merry 	if (idstart(*s)) {
1259ef270ab1SKenneth D. Merry 		char *p = tok->string;
1260ef270ab1SKenneth D. Merry 
1261ef270ab1SKenneth D. Merry 		for (*p++ = *s++; idchar(*s); s++) {
1262ef270ab1SKenneth D. Merry 			if ((p - tok->string) < TOKEN_LEN) {
1263ef270ab1SKenneth D. Merry 				*p++ = *s;
1264ef270ab1SKenneth D. Merry 			}
1265ef270ab1SKenneth D. Merry 		}
1266ef270ab1SKenneth D. Merry 
1267ef270ab1SKenneth D. Merry 		/* See if this is a $ number value */
1268ef270ab1SKenneth D. Merry 		if (tok->string[0] == '$') {
1269ef270ab1SKenneth D. Merry 			tok->type = TOK_NUMBER_VALUE;
1270ef270ab1SKenneth D. Merry 		} else {
1271ef270ab1SKenneth D. Merry 			/* Look for a string match */
1272ef270ab1SKenneth D. Merry 			for (i = 0; i < ARRAY_SIZE(smatches); i++) {
1273ef270ab1SKenneth D. Merry 				if (strcmp(smatches[i].s, tok->string) == 0) {
1274ef270ab1SKenneth D. Merry 					tok->type = smatches[i].type;
1275ef270ab1SKenneth D. Merry 					tok->subtype = smatches[i].subtype;
1276ef270ab1SKenneth D. Merry 					return s;
1277ef270ab1SKenneth D. Merry 				}
1278ef270ab1SKenneth D. Merry 			}
1279ef270ab1SKenneth D. Merry 		}
1280ef270ab1SKenneth D. Merry 	}
1281ef270ab1SKenneth D. Merry 	return s;
1282ef270ab1SKenneth D. Merry }
1283ef270ab1SKenneth D. Merry 
1284ef270ab1SKenneth D. Merry /**
1285ef270ab1SKenneth D. Merry  * @brief convert token type to string
1286ef270ab1SKenneth D. Merry  *
1287ef270ab1SKenneth D. Merry  * @param type token type
1288ef270ab1SKenneth D. Merry  *
1289ef270ab1SKenneth D. Merry  * @return string, or "unknown"
1290ef270ab1SKenneth D. Merry  */
1291ef270ab1SKenneth D. Merry static const char *
token_type2s(tok_type_e type)1292ef270ab1SKenneth D. Merry token_type2s(tok_type_e type)
1293ef270ab1SKenneth D. Merry {
1294ef270ab1SKenneth D. Merry 	switch(type) {
1295ef270ab1SKenneth D. Merry 	#define P(x)	case x: return #x;
1296ef270ab1SKenneth D. Merry 	P(TOK_LPAREN)
1297ef270ab1SKenneth D. Merry 	P(TOK_RPAREN)
1298ef270ab1SKenneth D. Merry 	P(TOK_COLON)
1299ef270ab1SKenneth D. Merry 	P(TOK_EQUALS)
1300ef270ab1SKenneth D. Merry 	P(TOK_QUEUE)
1301ef270ab1SKenneth D. Merry 	P(TOK_ATTR_NAME)
1302ef270ab1SKenneth D. Merry 	P(TOK_NUMBER)
1303ef270ab1SKenneth D. Merry 	P(TOK_NUMBER_VALUE)
1304ef270ab1SKenneth D. Merry 	P(TOK_NUMBER_LIST)
1305ef270ab1SKenneth D. Merry 	#undef P
1306ef270ab1SKenneth D. Merry 	}
1307ef270ab1SKenneth D. Merry 	return "unknown";
1308ef270ab1SKenneth D. Merry }
1309ef270ab1SKenneth D. Merry 
1310ef270ab1SKenneth D. Merry /**
1311ef270ab1SKenneth D. Merry  * @brief convert token sub-type to string
1312ef270ab1SKenneth D. Merry  *
1313ef270ab1SKenneth D. Merry  * @param subtype token sub-type
1314ef270ab1SKenneth D. Merry  *
1315ef270ab1SKenneth D. Merry  * @return string, or "unknown"
1316ef270ab1SKenneth D. Merry  */
1317ef270ab1SKenneth D. Merry static const char *
token_subtype2s(tok_subtype_e subtype)1318ef270ab1SKenneth D. Merry token_subtype2s(tok_subtype_e subtype)
1319ef270ab1SKenneth D. Merry {
1320ef270ab1SKenneth D. Merry 	switch(subtype) {
1321ef270ab1SKenneth D. Merry 	#define P(x)	case x: return #x;
1322ef270ab1SKenneth D. Merry 	P(TOK_SUB_EQ)
1323ef270ab1SKenneth D. Merry 	P(TOK_SUB_CQ)
1324ef270ab1SKenneth D. Merry 	P(TOK_SUB_RQ)
1325ef270ab1SKenneth D. Merry 	P(TOK_SUB_MQ)
1326ef270ab1SKenneth D. Merry 	P(TOK_SUB_WQ)
1327ef270ab1SKenneth D. Merry 	P(TOK_SUB_LEN)
1328ef270ab1SKenneth D. Merry 	P(TOK_SUB_CLASS)
1329ef270ab1SKenneth D. Merry 	P(TOK_SUB_ULP)
1330ef270ab1SKenneth D. Merry 	P(TOK_SUB_FILTER)
1331ef270ab1SKenneth D. Merry 	#undef P
1332ef270ab1SKenneth D. Merry 	}
1333ef270ab1SKenneth D. Merry 	return "";
1334ef270ab1SKenneth D. Merry }
1335ef270ab1SKenneth D. Merry 
1336ef270ab1SKenneth D. Merry /**
1337ef270ab1SKenneth D. Merry  * @brief Generate syntax error message
1338ef270ab1SKenneth D. Merry  *
1339ef270ab1SKenneth D. Merry  * A syntax error message is found, the input tokens are dumped up to and including
1340ef270ab1SKenneth D. Merry  * the token that failed as indicated by the current iterator index.
1341ef270ab1SKenneth D. Merry  *
1342ef270ab1SKenneth D. Merry  * @param hw pointer to HW object
1343ef270ab1SKenneth D. Merry  * @param tokarray pointer to token array object
1344ef270ab1SKenneth D. Merry  *
1345ef270ab1SKenneth D. Merry  * @return none
1346ef270ab1SKenneth D. Merry  */
1347ef270ab1SKenneth D. Merry static void
tok_syntax(ocs_hw_t * hw,tokarray_t * tokarray)1348ef270ab1SKenneth D. Merry tok_syntax(ocs_hw_t *hw, tokarray_t *tokarray)
1349ef270ab1SKenneth D. Merry {
1350ef270ab1SKenneth D. Merry 	uint32_t i;
1351ef270ab1SKenneth D. Merry 	tok_t *tok;
1352ef270ab1SKenneth D. Merry 
1353ef270ab1SKenneth D. Merry 	ocs_log_test(hw->os, "Syntax error:\n");
1354ef270ab1SKenneth D. Merry 
1355ef270ab1SKenneth D. Merry 	for (i = 0, tok = tokarray->tokens; (i <= tokarray->inuse_count); i++, tok++) {
1356ef270ab1SKenneth D. Merry 		ocs_log_test(hw->os, "%s [%2d]    %-16s %-16s %s\n", (i == tokarray->iter_idx) ? ">>>" : "   ", i,
1357ef270ab1SKenneth D. Merry 			token_type2s(tok->type), token_subtype2s(tok->subtype), tok->string);
1358ef270ab1SKenneth D. Merry 	}
1359ef270ab1SKenneth D. Merry }
1360ef270ab1SKenneth D. Merry 
1361ef270ab1SKenneth D. Merry /**
1362ef270ab1SKenneth D. Merry  * @brief parse a number
1363ef270ab1SKenneth D. Merry  *
1364ef270ab1SKenneth D. Merry  * Parses tokens of type TOK_NUMBER and TOK_NUMBER_VALUE, returning a numeric value
1365ef270ab1SKenneth D. Merry  *
1366ef270ab1SKenneth D. Merry  * @param hw pointer to HW object
1367ef270ab1SKenneth D. Merry  * @param qtop pointer to QTOP object
1368ef270ab1SKenneth D. Merry  * @param tok pointer to token to parse
1369ef270ab1SKenneth D. Merry  *
1370ef270ab1SKenneth D. Merry  * @return numeric value
1371ef270ab1SKenneth D. Merry  */
1372ef270ab1SKenneth D. Merry static uint32_t
tok_getnumber(ocs_hw_t * hw,ocs_hw_qtop_t * qtop,tok_t * tok)1373ef270ab1SKenneth D. Merry tok_getnumber(ocs_hw_t *hw, ocs_hw_qtop_t *qtop, tok_t *tok)
1374ef270ab1SKenneth D. Merry {
1375ef270ab1SKenneth D. Merry 	uint32_t rval = 0;
1376ef270ab1SKenneth D. Merry 	uint32_t num_cpus = ocs_get_num_cpus();
1377ef270ab1SKenneth D. Merry 
1378ef270ab1SKenneth D. Merry 	switch(tok->type) {
1379ef270ab1SKenneth D. Merry 	case TOK_NUMBER_VALUE:
1380ef270ab1SKenneth D. Merry 		if (ocs_strcmp(tok->string, "$ncpu") == 0) {
1381ef270ab1SKenneth D. Merry 			rval = num_cpus;
1382ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(tok->string, "$ncpu1") == 0) {
1383ef270ab1SKenneth D. Merry 			rval = num_cpus - 1;
1384ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(tok->string, "$nwq") == 0) {
1385ef270ab1SKenneth D. Merry 			if (hw != NULL) {
1386ef270ab1SKenneth D. Merry 				rval = hw->config.n_wq;
1387ef270ab1SKenneth D. Merry 			}
1388ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(tok->string, "$maxmrq") == 0) {
1389ef270ab1SKenneth D. Merry 			rval = MIN(num_cpus, OCS_HW_MAX_MRQS);
1390ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(tok->string, "$nulp") == 0) {
1391ef270ab1SKenneth D. Merry 			rval = hw->ulp_max - hw->ulp_start + 1;
1392ef270ab1SKenneth D. Merry 		} else if ((qtop->rptcount_idx > 0) && ocs_strcmp(tok->string, "$rpt0") == 0) {
1393ef270ab1SKenneth D. Merry 			rval = qtop->rptcount[qtop->rptcount_idx-1];
1394ef270ab1SKenneth D. Merry 		} else if ((qtop->rptcount_idx > 1) && ocs_strcmp(tok->string, "$rpt1") == 0) {
1395ef270ab1SKenneth D. Merry 			rval = qtop->rptcount[qtop->rptcount_idx-2];
1396ef270ab1SKenneth D. Merry 		} else if ((qtop->rptcount_idx > 2) && ocs_strcmp(tok->string, "$rpt2") == 0) {
1397ef270ab1SKenneth D. Merry 			rval = qtop->rptcount[qtop->rptcount_idx-3];
1398ef270ab1SKenneth D. Merry 		} else if ((qtop->rptcount_idx > 3) && ocs_strcmp(tok->string, "$rpt3") == 0) {
1399ef270ab1SKenneth D. Merry 			rval = qtop->rptcount[qtop->rptcount_idx-4];
1400ef270ab1SKenneth D. Merry 		} else {
1401ef270ab1SKenneth D. Merry 			rval = ocs_strtoul(tok->string, 0, 0);
1402ef270ab1SKenneth D. Merry 		}
1403ef270ab1SKenneth D. Merry 		break;
1404ef270ab1SKenneth D. Merry 	case TOK_NUMBER:
1405ef270ab1SKenneth D. Merry 		rval = ocs_strtoul(tok->string, 0, 0);
1406ef270ab1SKenneth D. Merry 		break;
1407ef270ab1SKenneth D. Merry 	default:
1408ef270ab1SKenneth D. Merry 		break;
1409ef270ab1SKenneth D. Merry 	}
1410ef270ab1SKenneth D. Merry 	return rval;
1411ef270ab1SKenneth D. Merry }
1412ef270ab1SKenneth D. Merry 
1413ef270ab1SKenneth D. Merry /**
1414ef270ab1SKenneth D. Merry  * @brief parse an array of tokens
1415ef270ab1SKenneth D. Merry  *
1416ef270ab1SKenneth D. Merry  * The tokens are semantically parsed, to generate QTOP entries.
1417ef270ab1SKenneth D. Merry  *
1418ef270ab1SKenneth D. Merry  * @param hw pointer to HW object
1419ef270ab1SKenneth D. Merry  * @param tokarray array array of tokens
1420ef270ab1SKenneth D. Merry  * @param qtop ouptut QTOP object
1421ef270ab1SKenneth D. Merry  *
1422ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
1423ef270ab1SKenneth D. Merry  */
1424ef270ab1SKenneth D. Merry static int32_t
parse_topology(ocs_hw_t * hw,tokarray_t * tokarray,ocs_hw_qtop_t * qtop)1425ef270ab1SKenneth D. Merry parse_topology(ocs_hw_t *hw, tokarray_t *tokarray, ocs_hw_qtop_t *qtop)
1426ef270ab1SKenneth D. Merry {
1427ef270ab1SKenneth D. Merry 	ocs_hw_qtop_entry_t *qt = qtop->entries + qtop->inuse_count;
1428ef270ab1SKenneth D. Merry 	tok_t *tok;
1429ef270ab1SKenneth D. Merry 
1430ef270ab1SKenneth D. Merry 	for (; (tokarray->iter_idx < tokarray->inuse_count) &&
1431ef270ab1SKenneth D. Merry 	     ((tok = &tokarray->tokens[tokarray->iter_idx]) != NULL); ) {
1432ef270ab1SKenneth D. Merry 		if (qtop->inuse_count >= qtop->alloc_count) {
1433ef270ab1SKenneth D. Merry 			return -1;
1434ef270ab1SKenneth D. Merry 		}
1435ef270ab1SKenneth D. Merry 
1436ef270ab1SKenneth D. Merry 		qt = qtop->entries + qtop->inuse_count;
1437ef270ab1SKenneth D. Merry 
1438ef270ab1SKenneth D. Merry 		switch (tok[0].type)
1439ef270ab1SKenneth D. Merry 		{
1440ef270ab1SKenneth D. Merry 		case TOK_QUEUE:
1441ef270ab1SKenneth D. Merry 			qt->entry = subtype2qtop(tok[0].subtype);
1442ef270ab1SKenneth D. Merry 			qt->set_default = FALSE;
1443ef270ab1SKenneth D. Merry 			qt->len = 0;
1444ef270ab1SKenneth D. Merry 			qt->class = 0;
1445ef270ab1SKenneth D. Merry 			qtop->inuse_count++;
1446ef270ab1SKenneth D. Merry 
1447ef270ab1SKenneth D. Merry 			tokarray->iter_idx++;		/* Advance current token index */
1448ef270ab1SKenneth D. Merry 
1449ef270ab1SKenneth D. Merry 			/* Parse for queue attributes, possibly multiple instances */
1450ef270ab1SKenneth D. Merry 			while ((tokarray->iter_idx + 4) <= tokarray->inuse_count) {
1451ef270ab1SKenneth D. Merry 				tok = &tokarray->tokens[tokarray->iter_idx];
1452ef270ab1SKenneth D. Merry 				if(	(tok[0].type == TOK_COLON) &&
1453ef270ab1SKenneth D. Merry 					(tok[1].type == TOK_ATTR_NAME) &&
1454ef270ab1SKenneth D. Merry 					(tok[2].type == TOK_EQUALS) &&
1455ef270ab1SKenneth D. Merry 					((tok[3].type == TOK_NUMBER) ||
1456ef270ab1SKenneth D. Merry 					 (tok[3].type == TOK_NUMBER_VALUE) ||
1457ef270ab1SKenneth D. Merry 					 (tok[3].type == TOK_NUMBER_LIST))) {
1458ef270ab1SKenneth D. Merry 					switch (tok[1].subtype) {
1459ef270ab1SKenneth D. Merry 					case TOK_SUB_LEN:
1460ef270ab1SKenneth D. Merry 						qt->len = tok_getnumber(hw, qtop, &tok[3]);
1461ef270ab1SKenneth D. Merry 						break;
1462ef270ab1SKenneth D. Merry 
1463ef270ab1SKenneth D. Merry 					case TOK_SUB_CLASS:
1464ef270ab1SKenneth D. Merry 						qt->class = tok_getnumber(hw, qtop, &tok[3]);
1465ef270ab1SKenneth D. Merry 						break;
1466ef270ab1SKenneth D. Merry 
1467ef270ab1SKenneth D. Merry 					case TOK_SUB_ULP:
1468ef270ab1SKenneth D. Merry 						qt->ulp = tok_getnumber(hw, qtop, &tok[3]);
1469ef270ab1SKenneth D. Merry 						break;
1470ef270ab1SKenneth D. Merry 
1471ef270ab1SKenneth D. Merry 					case TOK_SUB_FILTER:
1472ef270ab1SKenneth D. Merry 						if (tok[3].type == TOK_NUMBER_LIST) {
1473ef270ab1SKenneth D. Merry 							uint32_t mask = 0;
1474ef270ab1SKenneth D. Merry 							char *p = tok[3].string;
1475ef270ab1SKenneth D. Merry 
1476ef270ab1SKenneth D. Merry 							while ((p != NULL) && *p) {
1477ef270ab1SKenneth D. Merry 								uint32_t v;
1478ef270ab1SKenneth D. Merry 
1479ef270ab1SKenneth D. Merry 								v = ocs_strtoul(p, 0, 0);
1480ef270ab1SKenneth D. Merry 								if (v < 32) {
1481ef270ab1SKenneth D. Merry 									mask |= (1U << v);
1482ef270ab1SKenneth D. Merry 								}
1483ef270ab1SKenneth D. Merry 
1484ef270ab1SKenneth D. Merry 								p = ocs_strchr(p, ',');
1485ef270ab1SKenneth D. Merry 								if (p != NULL) {
1486ef270ab1SKenneth D. Merry 									p++;
1487ef270ab1SKenneth D. Merry 								}
1488ef270ab1SKenneth D. Merry 							}
1489ef270ab1SKenneth D. Merry 							qt->filter_mask = mask;
1490ef270ab1SKenneth D. Merry 						} else {
1491ef270ab1SKenneth D. Merry 							qt->filter_mask = (1U << tok_getnumber(hw, qtop, &tok[3]));
1492ef270ab1SKenneth D. Merry 						}
1493ef270ab1SKenneth D. Merry 						break;
1494ef270ab1SKenneth D. Merry 					default:
1495ef270ab1SKenneth D. Merry 						break;
1496ef270ab1SKenneth D. Merry 					}
1497ef270ab1SKenneth D. Merry 					/* Advance current token index */
1498ef270ab1SKenneth D. Merry 					tokarray->iter_idx += 4;
1499ef270ab1SKenneth D. Merry 				} else {
1500ef270ab1SKenneth D. Merry 					break;
1501ef270ab1SKenneth D. Merry 				}
1502ef270ab1SKenneth D. Merry 			}
1503ef270ab1SKenneth D. Merry 			qtop->entry_counts[qt->entry]++;
1504ef270ab1SKenneth D. Merry 			break;
1505ef270ab1SKenneth D. Merry 
1506ef270ab1SKenneth D. Merry 		case TOK_ATTR_NAME:
1507ef270ab1SKenneth D. Merry 			if (	((tokarray->iter_idx + 5) <= tokarray->inuse_count) &&
1508ef270ab1SKenneth D. Merry 				(tok[1].type == TOK_COLON) &&
1509ef270ab1SKenneth D. Merry 				(tok[2].type == TOK_QUEUE) &&
1510ef270ab1SKenneth D. Merry 				(tok[3].type == TOK_EQUALS) &&
1511ef270ab1SKenneth D. Merry 				((tok[4].type == TOK_NUMBER) || (tok[4].type == TOK_NUMBER_VALUE))) {
1512ef270ab1SKenneth D. Merry 				qt->entry = subtype2qtop(tok[2].subtype);
1513ef270ab1SKenneth D. Merry 				qt->set_default = TRUE;
1514ef270ab1SKenneth D. Merry 				switch(tok[0].subtype) {
1515ef270ab1SKenneth D. Merry 				case TOK_SUB_LEN:
1516ef270ab1SKenneth D. Merry 					qt->len = tok_getnumber(hw, qtop, &tok[4]);
1517ef270ab1SKenneth D. Merry 					break;
1518ef270ab1SKenneth D. Merry 				case TOK_SUB_CLASS:
1519ef270ab1SKenneth D. Merry 					qt->class = tok_getnumber(hw, qtop, &tok[4]);
1520ef270ab1SKenneth D. Merry 					break;
1521ef270ab1SKenneth D. Merry 				case TOK_SUB_ULP:
1522ef270ab1SKenneth D. Merry 					qt->ulp = tok_getnumber(hw, qtop, &tok[4]);
1523ef270ab1SKenneth D. Merry 					break;
1524ef270ab1SKenneth D. Merry 				default:
1525ef270ab1SKenneth D. Merry 					break;
1526ef270ab1SKenneth D. Merry 				}
1527ef270ab1SKenneth D. Merry 				qtop->inuse_count++;
1528ef270ab1SKenneth D. Merry 				tokarray->iter_idx += 5;
1529ef270ab1SKenneth D. Merry 			} else {
1530ef270ab1SKenneth D. Merry 				tok_syntax(hw, tokarray);
1531ef270ab1SKenneth D. Merry 				return -1;
1532ef270ab1SKenneth D. Merry 			}
1533ef270ab1SKenneth D. Merry 			break;
1534ef270ab1SKenneth D. Merry 
1535ef270ab1SKenneth D. Merry 		case TOK_NUMBER:
1536ef270ab1SKenneth D. Merry 		case TOK_NUMBER_VALUE: {
1537ef270ab1SKenneth D. Merry 			uint32_t rpt_count = 1;
1538ef270ab1SKenneth D. Merry 			uint32_t i;
1539ef270ab1SKenneth D. Merry 
1540ef270ab1SKenneth D. Merry 			rpt_count = tok_getnumber(hw, qtop, tok);
1541ef270ab1SKenneth D. Merry 
1542ef270ab1SKenneth D. Merry 			if (tok[1].type == TOK_LPAREN) {
1543ef270ab1SKenneth D. Merry 				uint32_t iter_idx_save;
1544ef270ab1SKenneth D. Merry 
1545ef270ab1SKenneth D. Merry 				tokarray->iter_idx += 2;
1546ef270ab1SKenneth D. Merry 
1547ef270ab1SKenneth D. Merry 				/* save token array iteration index */
1548ef270ab1SKenneth D. Merry 				iter_idx_save = tokarray->iter_idx;
1549ef270ab1SKenneth D. Merry 
1550ef270ab1SKenneth D. Merry 				for (i = 0; i < rpt_count; i++) {
1551ef270ab1SKenneth D. Merry 					uint32_t rptcount_idx = qtop->rptcount_idx;
1552ef270ab1SKenneth D. Merry 
1553ef270ab1SKenneth D. Merry 					if (qtop->rptcount_idx < ARRAY_SIZE(qtop->rptcount)) {
1554ef270ab1SKenneth D. Merry 						qtop->rptcount[qtop->rptcount_idx++] = i;
1555ef270ab1SKenneth D. Merry 					}
1556ef270ab1SKenneth D. Merry 
1557ef270ab1SKenneth D. Merry 					/* restore token array iteration index */
1558ef270ab1SKenneth D. Merry 					tokarray->iter_idx = iter_idx_save;
1559ef270ab1SKenneth D. Merry 
1560ef270ab1SKenneth D. Merry 					/* parse, append to qtop */
1561ef270ab1SKenneth D. Merry 					parse_topology(hw, tokarray, qtop);
1562ef270ab1SKenneth D. Merry 
1563ef270ab1SKenneth D. Merry 					qtop->rptcount_idx = rptcount_idx;
1564ef270ab1SKenneth D. Merry 				}
1565ef270ab1SKenneth D. Merry 			}
1566ef270ab1SKenneth D. Merry 			break;
1567ef270ab1SKenneth D. Merry 		}
1568ef270ab1SKenneth D. Merry 
1569ef270ab1SKenneth D. Merry 		case TOK_RPAREN:
1570ef270ab1SKenneth D. Merry 			tokarray->iter_idx++;
1571ef270ab1SKenneth D. Merry 			return 0;
1572ef270ab1SKenneth D. Merry 
1573ef270ab1SKenneth D. Merry 		default:
1574ef270ab1SKenneth D. Merry 			tok_syntax(hw, tokarray);
1575ef270ab1SKenneth D. Merry 			return -1;
1576ef270ab1SKenneth D. Merry 		}
1577ef270ab1SKenneth D. Merry 	}
1578ef270ab1SKenneth D. Merry 	return 0;
1579ef270ab1SKenneth D. Merry }
1580ef270ab1SKenneth D. Merry 
1581ef270ab1SKenneth D. Merry /**
1582ef270ab1SKenneth D. Merry  * @brief Parse queue topology string
1583ef270ab1SKenneth D. Merry  *
1584ef270ab1SKenneth D. Merry  * The queue topology object is allocated, and filled with the results of parsing the
1585ef270ab1SKenneth D. Merry  * passed in queue topology string
1586ef270ab1SKenneth D. Merry  *
1587ef270ab1SKenneth D. Merry  * @param hw pointer to HW object
1588ef270ab1SKenneth D. Merry  * @param qtop_string input queue topology string
1589ef270ab1SKenneth D. Merry  *
1590ef270ab1SKenneth D. Merry  * @return pointer to allocated QTOP object, or NULL if there was an error
1591ef270ab1SKenneth D. Merry  */
1592ef270ab1SKenneth D. Merry ocs_hw_qtop_t *
ocs_hw_qtop_parse(ocs_hw_t * hw,const char * qtop_string)1593ef270ab1SKenneth D. Merry ocs_hw_qtop_parse(ocs_hw_t *hw, const char *qtop_string)
1594ef270ab1SKenneth D. Merry {
1595ef270ab1SKenneth D. Merry 	ocs_hw_qtop_t *qtop;
1596ef270ab1SKenneth D. Merry 	tokarray_t tokarray;
1597ef270ab1SKenneth D. Merry 	const char *s;
1598ef270ab1SKenneth D. Merry #if HW_QTOP_DEBUG
1599ef270ab1SKenneth D. Merry 	uint32_t i;
1600ef270ab1SKenneth D. Merry 	ocs_hw_qtop_entry_t *qt;
1601ef270ab1SKenneth D. Merry #endif
1602ef270ab1SKenneth D. Merry 
1603ef270ab1SKenneth D. Merry 	ocs_log_debug(hw->os, "queue topology: %s\n", qtop_string);
1604ef270ab1SKenneth D. Merry 
1605ef270ab1SKenneth D. Merry 	/* Allocate a token array */
1606ef270ab1SKenneth D. Merry 	tokarray.tokens = ocs_malloc(hw->os, MAX_TOKENS * sizeof(*tokarray.tokens), OCS_M_ZERO | OCS_M_NOWAIT);
1607ef270ab1SKenneth D. Merry 	if (tokarray.tokens == NULL) {
1608ef270ab1SKenneth D. Merry 		return NULL;
1609ef270ab1SKenneth D. Merry 	}
1610ef270ab1SKenneth D. Merry 	tokarray.alloc_count = MAX_TOKENS;
1611ef270ab1SKenneth D. Merry 	tokarray.inuse_count = 0;
1612ef270ab1SKenneth D. Merry 	tokarray.iter_idx = 0;
1613ef270ab1SKenneth D. Merry 
1614ef270ab1SKenneth D. Merry 	/* Parse the tokens */
1615ef270ab1SKenneth D. Merry 	for (s = qtop_string; (tokarray.inuse_count < tokarray.alloc_count) &&
1616ef270ab1SKenneth D. Merry 	     ((s = tokenize(s, &tokarray.tokens[tokarray.inuse_count]))) != NULL; ) {
1617aeb665b5SEd Maste 		tokarray.inuse_count++;
1618ef270ab1SKenneth D. Merry 	}
1619ef270ab1SKenneth D. Merry 
1620ef270ab1SKenneth D. Merry 	/* Allocate a queue topology structure */
1621ef270ab1SKenneth D. Merry 	qtop = ocs_malloc(hw->os, sizeof(*qtop), OCS_M_ZERO | OCS_M_NOWAIT);
1622ef270ab1SKenneth D. Merry 	if (qtop == NULL) {
1623ef270ab1SKenneth D. Merry 		ocs_free(hw->os, tokarray.tokens, MAX_TOKENS * sizeof(*tokarray.tokens));
1624ef270ab1SKenneth D. Merry 		ocs_log_err(hw->os, "malloc qtop failed\n");
1625ef270ab1SKenneth D. Merry 		return NULL;
1626ef270ab1SKenneth D. Merry 	}
1627ef270ab1SKenneth D. Merry 	qtop->os = hw->os;
1628ef270ab1SKenneth D. Merry 
1629ef270ab1SKenneth D. Merry 	/* Allocate queue topology entries */
1630ef270ab1SKenneth D. Merry 	qtop->entries = ocs_malloc(hw->os, OCS_HW_MAX_QTOP_ENTRIES*sizeof(*qtop->entries), OCS_M_ZERO | OCS_M_NOWAIT);
1631ef270ab1SKenneth D. Merry 	if (qtop->entries == NULL) {
1632ef270ab1SKenneth D. Merry 		ocs_log_err(hw->os, "malloc qtop entries failed\n");
1633ef270ab1SKenneth D. Merry 		ocs_free(hw->os, qtop, sizeof(*qtop));
1634ef270ab1SKenneth D. Merry 		ocs_free(hw->os, tokarray.tokens, MAX_TOKENS * sizeof(*tokarray.tokens));
1635ef270ab1SKenneth D. Merry 		return NULL;
1636ef270ab1SKenneth D. Merry 	}
1637ef270ab1SKenneth D. Merry 	qtop->alloc_count = OCS_HW_MAX_QTOP_ENTRIES;
1638ef270ab1SKenneth D. Merry 	qtop->inuse_count = 0;
1639ef270ab1SKenneth D. Merry 
1640ef270ab1SKenneth D. Merry 	/* Parse the tokens */
1641ef270ab1SKenneth D. Merry 	parse_topology(hw, &tokarray, qtop);
1642ef270ab1SKenneth D. Merry #if HW_QTOP_DEBUG
1643ef270ab1SKenneth D. Merry 	for (i = 0, qt = qtop->entries; i < qtop->inuse_count; i++, qt++) {
1644ef270ab1SKenneth D. Merry 		ocs_log_debug(hw->os, "entry %s set_df %d len %4d class %d ulp %d\n", qtopentry2s(qt->entry), qt->set_default, qt->len,
1645ef270ab1SKenneth D. Merry 		       qt->class, qt->ulp);
1646ef270ab1SKenneth D. Merry 	}
1647ef270ab1SKenneth D. Merry #endif
1648ef270ab1SKenneth D. Merry 
1649ef270ab1SKenneth D. Merry 	/* Free the tokens array */
1650ef270ab1SKenneth D. Merry 	ocs_free(hw->os, tokarray.tokens, MAX_TOKENS * sizeof(*tokarray.tokens));
1651ef270ab1SKenneth D. Merry 
1652ef270ab1SKenneth D. Merry 	return qtop;
1653ef270ab1SKenneth D. Merry }
1654ef270ab1SKenneth D. Merry 
1655ef270ab1SKenneth D. Merry /**
1656ef270ab1SKenneth D. Merry  * @brief free queue topology object
1657ef270ab1SKenneth D. Merry  *
1658ef270ab1SKenneth D. Merry  * @param qtop pointer to QTOP object
1659ef270ab1SKenneth D. Merry  *
1660ef270ab1SKenneth D. Merry  * @return none
1661ef270ab1SKenneth D. Merry  */
1662ef270ab1SKenneth D. Merry void
ocs_hw_qtop_free(ocs_hw_qtop_t * qtop)1663ef270ab1SKenneth D. Merry ocs_hw_qtop_free(ocs_hw_qtop_t *qtop)
1664ef270ab1SKenneth D. Merry {
1665ef270ab1SKenneth D. Merry 	if (qtop != NULL) {
1666ef270ab1SKenneth D. Merry 		if (qtop->entries != NULL) {
1667ef270ab1SKenneth D. Merry 			ocs_free(qtop->os, qtop->entries, qtop->alloc_count*sizeof(*qtop->entries));
1668ef270ab1SKenneth D. Merry 		}
1669ef270ab1SKenneth D. Merry 		ocs_free(qtop->os, qtop, sizeof(*qtop));
1670ef270ab1SKenneth D. Merry 	}
1671ef270ab1SKenneth D. Merry }
1672ef270ab1SKenneth D. Merry 
1673ef270ab1SKenneth D. Merry /* Uncomment this to turn on RQ debug */
1674ef270ab1SKenneth D. Merry // #define ENABLE_DEBUG_RQBUF
1675ef270ab1SKenneth D. Merry 
1676ef270ab1SKenneth D. Merry static int32_t ocs_hw_rqpair_find(ocs_hw_t *hw, uint16_t rq_id);
1677ef270ab1SKenneth D. Merry static ocs_hw_sequence_t * ocs_hw_rqpair_get(ocs_hw_t *hw, uint16_t rqindex, uint16_t bufindex);
1678ef270ab1SKenneth D. Merry static int32_t ocs_hw_rqpair_put(ocs_hw_t *hw, ocs_hw_sequence_t *seq);
1679ef270ab1SKenneth D. Merry static ocs_hw_rtn_e ocs_hw_rqpair_auto_xfer_rdy_buffer_sequence_reset(ocs_hw_t *hw, ocs_hw_sequence_t *seq);
1680ef270ab1SKenneth D. Merry 
1681ef270ab1SKenneth D. Merry /**
1682ef270ab1SKenneth D. Merry  * @brief Process receive queue completions for RQ Pair mode.
1683ef270ab1SKenneth D. Merry  *
1684ef270ab1SKenneth D. Merry  * @par Description
1685ef270ab1SKenneth D. Merry  * RQ completions are processed. In RQ pair mode, a single header and single payload
1686ef270ab1SKenneth D. Merry  * buffer are received, and passed to the function that has registered for unsolicited
1687ef270ab1SKenneth D. Merry  * callbacks.
1688ef270ab1SKenneth D. Merry  *
1689ef270ab1SKenneth D. Merry  * @param hw Hardware context.
1690ef270ab1SKenneth D. Merry  * @param cq Pointer to HW completion queue.
1691ef270ab1SKenneth D. Merry  * @param cqe Completion queue entry.
1692ef270ab1SKenneth D. Merry  *
1693ef270ab1SKenneth D. Merry  * @return Returns 0 for success, or a negative error code value for failure.
1694ef270ab1SKenneth D. Merry  */
1695ef270ab1SKenneth D. Merry 
1696ef270ab1SKenneth D. Merry int32_t
ocs_hw_rqpair_process_rq(ocs_hw_t * hw,hw_cq_t * cq,uint8_t * cqe)1697ef270ab1SKenneth D. Merry ocs_hw_rqpair_process_rq(ocs_hw_t *hw, hw_cq_t *cq, uint8_t *cqe)
1698ef270ab1SKenneth D. Merry {
1699ef270ab1SKenneth D. Merry 	uint16_t rq_id;
1700ef270ab1SKenneth D. Merry 	uint32_t index;
1701ef270ab1SKenneth D. Merry 	int32_t rqindex;
1702ef270ab1SKenneth D. Merry 	int32_t	 rq_status;
1703ef270ab1SKenneth D. Merry 	uint32_t h_len;
1704ef270ab1SKenneth D. Merry 	uint32_t p_len;
1705ef270ab1SKenneth D. Merry 	ocs_hw_sequence_t *seq;
1706ef270ab1SKenneth D. Merry 
1707ef270ab1SKenneth D. Merry 	rq_status = sli_fc_rqe_rqid_and_index(&hw->sli, cqe, &rq_id, &index);
1708ef270ab1SKenneth D. Merry 	if (0 != rq_status) {
1709ef270ab1SKenneth D. Merry 		switch (rq_status) {
1710ef270ab1SKenneth D. Merry 		case SLI4_FC_ASYNC_RQ_BUF_LEN_EXCEEDED:
1711ef270ab1SKenneth D. Merry 		case SLI4_FC_ASYNC_RQ_DMA_FAILURE:
1712ef270ab1SKenneth D. Merry 			/* just get RQ buffer then return to chip */
1713ef270ab1SKenneth D. Merry 			rqindex = ocs_hw_rqpair_find(hw, rq_id);
1714ef270ab1SKenneth D. Merry 			if (rqindex < 0) {
1715ef270ab1SKenneth D. Merry 				ocs_log_test(hw->os, "status=%#x: rq_id lookup failed for id=%#x\n",
1716ef270ab1SKenneth D. Merry 					     rq_status, rq_id);
1717ef270ab1SKenneth D. Merry 				break;
1718ef270ab1SKenneth D. Merry 			}
1719ef270ab1SKenneth D. Merry 
1720ef270ab1SKenneth D. Merry 			/* get RQ buffer */
1721ef270ab1SKenneth D. Merry 			seq = ocs_hw_rqpair_get(hw, rqindex, index);
1722ef270ab1SKenneth D. Merry 
1723ef270ab1SKenneth D. Merry 			/* return to chip */
1724ef270ab1SKenneth D. Merry 			if (ocs_hw_rqpair_sequence_free(hw, seq)) {
1725ef270ab1SKenneth D. Merry 				ocs_log_test(hw->os, "status=%#x, failed to return buffers to RQ\n",
1726ef270ab1SKenneth D. Merry 					     rq_status);
1727ef270ab1SKenneth D. Merry 				break;
1728ef270ab1SKenneth D. Merry 			}
1729ef270ab1SKenneth D. Merry 			break;
1730ef270ab1SKenneth D. Merry 		case SLI4_FC_ASYNC_RQ_INSUFF_BUF_NEEDED:
1731ef270ab1SKenneth D. Merry 		case SLI4_FC_ASYNC_RQ_INSUFF_BUF_FRM_DISC:
1732ef270ab1SKenneth D. Merry 			/* since RQ buffers were not consumed, cannot return them to chip */
1733ef270ab1SKenneth D. Merry 			/* fall through */
1734ef270ab1SKenneth D. Merry 			ocs_log_debug(hw->os, "Warning: RCQE status=%#x, \n", rq_status);
1735ef270ab1SKenneth D. Merry 		default:
1736ef270ab1SKenneth D. Merry 			break;
1737ef270ab1SKenneth D. Merry 		}
1738ef270ab1SKenneth D. Merry 		return -1;
1739ef270ab1SKenneth D. Merry 	}
1740ef270ab1SKenneth D. Merry 
1741ef270ab1SKenneth D. Merry 	rqindex = ocs_hw_rqpair_find(hw, rq_id);
1742ef270ab1SKenneth D. Merry 	if (rqindex < 0) {
1743ef270ab1SKenneth D. Merry 		ocs_log_test(hw->os, "Error: rq_id lookup failed for id=%#x\n", rq_id);
1744ef270ab1SKenneth D. Merry 		return -1;
1745ef270ab1SKenneth D. Merry 	}
1746ef270ab1SKenneth D. Merry 
1747ef270ab1SKenneth D. Merry 	OCS_STAT({ hw_rq_t *rq = hw->hw_rq[hw->hw_rq_lookup[rqindex]]; rq->use_count++; rq->hdr_use_count++;
1748ef270ab1SKenneth D. Merry 		 rq->payload_use_count++;})
1749ef270ab1SKenneth D. Merry 
1750ef270ab1SKenneth D. Merry 	seq = ocs_hw_rqpair_get(hw, rqindex, index);
1751ef270ab1SKenneth D. Merry 	ocs_hw_assert(seq != NULL);
1752ef270ab1SKenneth D. Merry 
1753ef270ab1SKenneth D. Merry 	seq->hw = hw;
1754ef270ab1SKenneth D. Merry 	seq->auto_xrdy = 0;
1755ef270ab1SKenneth D. Merry 	seq->out_of_xris = 0;
1756ef270ab1SKenneth D. Merry 	seq->xri = 0;
1757ef270ab1SKenneth D. Merry 	seq->hio = NULL;
1758ef270ab1SKenneth D. Merry 
1759ef270ab1SKenneth D. Merry 	sli_fc_rqe_length(&hw->sli, cqe, &h_len, &p_len);
1760ef270ab1SKenneth D. Merry 	seq->header->dma.len = h_len;
1761ef270ab1SKenneth D. Merry 	seq->payload->dma.len = p_len;
1762ef270ab1SKenneth D. Merry 	seq->fcfi = sli_fc_rqe_fcfi(&hw->sli, cqe);
1763ef270ab1SKenneth D. Merry 	seq->hw_priv = cq->eq;
1764ef270ab1SKenneth D. Merry 
1765ef270ab1SKenneth D. Merry 	/* bounce enabled, single RQ, we snoop the ox_id to choose the cpuidx */
1766ef270ab1SKenneth D. Merry 	if (hw->config.bounce) {
1767ef270ab1SKenneth D. Merry 		fc_header_t *hdr = seq->header->dma.virt;
1768ef270ab1SKenneth D. Merry 		uint32_t s_id = fc_be24toh(hdr->s_id);
1769ef270ab1SKenneth D. Merry 		uint32_t d_id = fc_be24toh(hdr->d_id);
1770ef270ab1SKenneth D. Merry 		uint32_t ox_id =  ocs_be16toh(hdr->ox_id);
1771ef270ab1SKenneth D. Merry 		if (hw->callback.bounce != NULL) {
1772ef270ab1SKenneth D. Merry 			(*hw->callback.bounce)(ocs_hw_unsol_process_bounce, seq, s_id, d_id, ox_id);
1773ef270ab1SKenneth D. Merry 		}
1774ef270ab1SKenneth D. Merry 	} else {
1775ef270ab1SKenneth D. Merry 		hw->callback.unsolicited(hw->args.unsolicited, seq);
1776ef270ab1SKenneth D. Merry 	}
1777ef270ab1SKenneth D. Merry 
1778ef270ab1SKenneth D. Merry 	return 0;
1779ef270ab1SKenneth D. Merry }
1780ef270ab1SKenneth D. Merry 
1781ef270ab1SKenneth D. Merry /**
1782ef270ab1SKenneth D. Merry  * @brief Process receive queue completions for RQ Pair mode - Auto xfer rdy
1783ef270ab1SKenneth D. Merry  *
1784ef270ab1SKenneth D. Merry  * @par Description
1785ef270ab1SKenneth D. Merry  * RQ completions are processed. In RQ pair mode, a single header and single payload
1786ef270ab1SKenneth D. Merry  * buffer are received, and passed to the function that has registered for unsolicited
1787ef270ab1SKenneth D. Merry  * callbacks.
1788ef270ab1SKenneth D. Merry  *
1789ef270ab1SKenneth D. Merry  * @param hw Hardware context.
1790ef270ab1SKenneth D. Merry  * @param cq Pointer to HW completion queue.
1791ef270ab1SKenneth D. Merry  * @param cqe Completion queue entry.
1792ef270ab1SKenneth D. Merry  *
1793ef270ab1SKenneth D. Merry  * @return Returns 0 for success, or a negative error code value for failure.
1794ef270ab1SKenneth D. Merry  */
1795ef270ab1SKenneth D. Merry 
1796ef270ab1SKenneth D. Merry int32_t
ocs_hw_rqpair_process_auto_xfr_rdy_cmd(ocs_hw_t * hw,hw_cq_t * cq,uint8_t * cqe)1797ef270ab1SKenneth D. Merry ocs_hw_rqpair_process_auto_xfr_rdy_cmd(ocs_hw_t *hw, hw_cq_t *cq, uint8_t *cqe)
1798ef270ab1SKenneth D. Merry {
1799ef270ab1SKenneth D. Merry 	/* Seems silly to call a SLI function to decode - use the structure directly for performance */
1800ef270ab1SKenneth D. Merry 	sli4_fc_optimized_write_cmd_cqe_t *opt_wr = (sli4_fc_optimized_write_cmd_cqe_t*)cqe;
1801ef270ab1SKenneth D. Merry 	uint16_t rq_id;
1802ef270ab1SKenneth D. Merry 	uint32_t index;
1803ef270ab1SKenneth D. Merry 	int32_t rqindex;
1804ef270ab1SKenneth D. Merry 	int32_t	 rq_status;
1805ef270ab1SKenneth D. Merry 	uint32_t h_len;
1806ef270ab1SKenneth D. Merry 	uint32_t p_len;
1807ef270ab1SKenneth D. Merry 	ocs_hw_sequence_t *seq;
1808ef270ab1SKenneth D. Merry 	uint8_t axr_lock_taken = 0;
1809ef270ab1SKenneth D. Merry #if defined(OCS_DISC_SPIN_DELAY)
1810ef270ab1SKenneth D. Merry 	uint32_t 	delay = 0;
1811ef270ab1SKenneth D. Merry 	char 		prop_buf[32];
1812ef270ab1SKenneth D. Merry #endif
1813ef270ab1SKenneth D. Merry 
1814ef270ab1SKenneth D. Merry 	rq_status = sli_fc_rqe_rqid_and_index(&hw->sli, cqe, &rq_id, &index);
1815ef270ab1SKenneth D. Merry 	if (0 != rq_status) {
1816ef270ab1SKenneth D. Merry 		switch (rq_status) {
1817ef270ab1SKenneth D. Merry 		case SLI4_FC_ASYNC_RQ_BUF_LEN_EXCEEDED:
1818ef270ab1SKenneth D. Merry 		case SLI4_FC_ASYNC_RQ_DMA_FAILURE:
1819ef270ab1SKenneth D. Merry 			/* just get RQ buffer then return to chip */
1820ef270ab1SKenneth D. Merry 			rqindex = ocs_hw_rqpair_find(hw, rq_id);
1821ef270ab1SKenneth D. Merry 			if (rqindex < 0) {
1822ef270ab1SKenneth D. Merry 				ocs_log_err(hw->os, "status=%#x: rq_id lookup failed for id=%#x\n",
1823ef270ab1SKenneth D. Merry 					    rq_status, rq_id);
1824ef270ab1SKenneth D. Merry 				break;
1825ef270ab1SKenneth D. Merry 			}
1826ef270ab1SKenneth D. Merry 
1827ef270ab1SKenneth D. Merry 			/* get RQ buffer */
1828ef270ab1SKenneth D. Merry 			seq = ocs_hw_rqpair_get(hw, rqindex, index);
1829ef270ab1SKenneth D. Merry 
1830ef270ab1SKenneth D. Merry 			/* return to chip */
1831ef270ab1SKenneth D. Merry 			if (ocs_hw_rqpair_sequence_free(hw, seq)) {
1832ef270ab1SKenneth D. Merry 				ocs_log_err(hw->os, "status=%#x, failed to return buffers to RQ\n",
1833ef270ab1SKenneth D. Merry 					    rq_status);
1834ef270ab1SKenneth D. Merry 				break;
1835ef270ab1SKenneth D. Merry 			}
1836ef270ab1SKenneth D. Merry 			break;
1837ef270ab1SKenneth D. Merry 		case SLI4_FC_ASYNC_RQ_INSUFF_BUF_NEEDED:
1838ef270ab1SKenneth D. Merry 		case SLI4_FC_ASYNC_RQ_INSUFF_BUF_FRM_DISC:
1839ef270ab1SKenneth D. Merry 			/* since RQ buffers were not consumed, cannot return them to chip */
1840ef270ab1SKenneth D. Merry 			ocs_log_debug(hw->os, "Warning: RCQE status=%#x, \n", rq_status);
1841ef270ab1SKenneth D. Merry 			/* fall through */
1842ef270ab1SKenneth D. Merry 		default:
1843ef270ab1SKenneth D. Merry 			break;
1844ef270ab1SKenneth D. Merry 		}
1845ef270ab1SKenneth D. Merry 		return -1;
1846ef270ab1SKenneth D. Merry 	}
1847ef270ab1SKenneth D. Merry 
1848ef270ab1SKenneth D. Merry 	rqindex = ocs_hw_rqpair_find(hw, rq_id);
1849ef270ab1SKenneth D. Merry 	if (rqindex < 0) {
1850ef270ab1SKenneth D. Merry 		ocs_log_err(hw->os, "Error: rq_id lookup failed for id=%#x\n", rq_id);
1851ef270ab1SKenneth D. Merry 		return -1;
1852ef270ab1SKenneth D. Merry 	}
1853ef270ab1SKenneth D. Merry 
1854ef270ab1SKenneth D. Merry 	OCS_STAT({ hw_rq_t *rq = hw->hw_rq[hw->hw_rq_lookup[rqindex]]; rq->use_count++; rq->hdr_use_count++;
1855ef270ab1SKenneth D. Merry 		 rq->payload_use_count++;})
1856ef270ab1SKenneth D. Merry 
1857ef270ab1SKenneth D. Merry 	seq = ocs_hw_rqpair_get(hw, rqindex, index);
1858ef270ab1SKenneth D. Merry 	ocs_hw_assert(seq != NULL);
1859ef270ab1SKenneth D. Merry 
1860ef270ab1SKenneth D. Merry 	seq->hw = hw;
1861ef270ab1SKenneth D. Merry 	seq->auto_xrdy = opt_wr->agxr;
1862ef270ab1SKenneth D. Merry 	seq->out_of_xris = opt_wr->oox;
1863ef270ab1SKenneth D. Merry 	seq->xri = opt_wr->xri;
1864ef270ab1SKenneth D. Merry 	seq->hio = NULL;
1865ef270ab1SKenneth D. Merry 
1866ef270ab1SKenneth D. Merry 	sli_fc_rqe_length(&hw->sli, cqe, &h_len, &p_len);
1867ef270ab1SKenneth D. Merry 	seq->header->dma.len = h_len;
1868ef270ab1SKenneth D. Merry 	seq->payload->dma.len = p_len;
1869ef270ab1SKenneth D. Merry 	seq->fcfi = sli_fc_rqe_fcfi(&hw->sli, cqe);
1870ef270ab1SKenneth D. Merry 	seq->hw_priv = cq->eq;
1871ef270ab1SKenneth D. Merry 
1872ef270ab1SKenneth D. Merry 	if (seq->auto_xrdy) {
1873ef270ab1SKenneth D. Merry 		fc_header_t *fc_hdr = seq->header->dma.virt;
1874ef270ab1SKenneth D. Merry 
1875ef270ab1SKenneth D. Merry 		seq->hio = ocs_hw_io_lookup(hw, seq->xri);
1876ef270ab1SKenneth D. Merry 		ocs_lock(&seq->hio->axr_lock);
1877ef270ab1SKenneth D. Merry 		axr_lock_taken = 1;
1878ef270ab1SKenneth D. Merry 
1879ef270ab1SKenneth D. Merry 		/* save the FCFI, src_id, dest_id and ox_id because we need it for the sequence object when the data comes. */
1880ef270ab1SKenneth D. Merry 		seq->hio->axr_buf->fcfi = seq->fcfi;
1881ef270ab1SKenneth D. Merry 		seq->hio->axr_buf->hdr.ox_id = fc_hdr->ox_id;
1882ef270ab1SKenneth D. Merry 		seq->hio->axr_buf->hdr.s_id = fc_hdr->s_id;
1883ef270ab1SKenneth D. Merry 		seq->hio->axr_buf->hdr.d_id = fc_hdr->d_id;
1884ef270ab1SKenneth D. Merry 		seq->hio->axr_buf->cmd_cqe = 1;
1885ef270ab1SKenneth D. Merry 
1886ef270ab1SKenneth D. Merry 		/*
1887ef270ab1SKenneth D. Merry 		 * Since auto xfer rdy is used for this IO, then clear the sequence
1888ef270ab1SKenneth D. Merry 		 * initiative bit in the header so that the upper layers wait for the
1889ef270ab1SKenneth D. Merry 		 * data. This should flow exactly like the first burst case.
1890ef270ab1SKenneth D. Merry 		 */
1891ef270ab1SKenneth D. Merry 		fc_hdr->f_ctl &= fc_htobe24(~FC_FCTL_SEQUENCE_INITIATIVE);
1892ef270ab1SKenneth D. Merry 
1893ef270ab1SKenneth D. Merry 		/* If AXR CMD CQE came before previous TRSP CQE of same XRI */
1894ef270ab1SKenneth D. Merry 		if (seq->hio->type == OCS_HW_IO_TARGET_RSP) {
1895ef270ab1SKenneth D. Merry 			seq->hio->axr_buf->call_axr_cmd = 1;
1896ef270ab1SKenneth D. Merry 			seq->hio->axr_buf->cmd_seq = seq;
1897ef270ab1SKenneth D. Merry 			goto exit_ocs_hw_rqpair_process_auto_xfr_rdy_cmd;
1898ef270ab1SKenneth D. Merry 		}
1899ef270ab1SKenneth D. Merry 	}
1900ef270ab1SKenneth D. Merry 
1901ef270ab1SKenneth D. Merry 	/* bounce enabled, single RQ, we snoop the ox_id to choose the cpuidx */
1902ef270ab1SKenneth D. Merry 	if (hw->config.bounce) {
1903ef270ab1SKenneth D. Merry 		fc_header_t *hdr = seq->header->dma.virt;
1904ef270ab1SKenneth D. Merry 		uint32_t s_id = fc_be24toh(hdr->s_id);
1905ef270ab1SKenneth D. Merry 		uint32_t d_id = fc_be24toh(hdr->d_id);
1906ef270ab1SKenneth D. Merry 		uint32_t ox_id =  ocs_be16toh(hdr->ox_id);
1907ef270ab1SKenneth D. Merry 		if (hw->callback.bounce != NULL) {
1908ef270ab1SKenneth D. Merry 			(*hw->callback.bounce)(ocs_hw_unsol_process_bounce, seq, s_id, d_id, ox_id);
1909ef270ab1SKenneth D. Merry 		}
1910ef270ab1SKenneth D. Merry 	} else {
1911ef270ab1SKenneth D. Merry 		hw->callback.unsolicited(hw->args.unsolicited, seq);
1912ef270ab1SKenneth D. Merry 	}
1913ef270ab1SKenneth D. Merry 
1914ef270ab1SKenneth D. Merry 	if (seq->auto_xrdy) {
1915ef270ab1SKenneth D. Merry 		/* If data cqe came before cmd cqe in out of order in case of AXR */
1916ef270ab1SKenneth D. Merry 		if(seq->hio->axr_buf->data_cqe == 1) {
1917ef270ab1SKenneth D. Merry #if defined(OCS_DISC_SPIN_DELAY)
1918ef270ab1SKenneth D. Merry 			if (ocs_get_property("disk_spin_delay", prop_buf, sizeof(prop_buf)) == 0) {
1919ef270ab1SKenneth D. Merry 				delay = ocs_strtoul(prop_buf, 0, 0);
1920ef270ab1SKenneth D. Merry 				ocs_udelay(delay);
1921ef270ab1SKenneth D. Merry 			}
1922ef270ab1SKenneth D. Merry #endif
1923ef270ab1SKenneth D. Merry 			/* bounce enabled, single RQ, we snoop the ox_id to choose the cpuidx */
1924ef270ab1SKenneth D. Merry 			if (hw->config.bounce) {
1925ef270ab1SKenneth D. Merry 				fc_header_t *hdr = seq->header->dma.virt;
1926ef270ab1SKenneth D. Merry 				uint32_t s_id = fc_be24toh(hdr->s_id);
1927ef270ab1SKenneth D. Merry 				uint32_t d_id = fc_be24toh(hdr->d_id);
1928ef270ab1SKenneth D. Merry 				uint32_t ox_id =  ocs_be16toh(hdr->ox_id);
1929ef270ab1SKenneth D. Merry 				if (hw->callback.bounce != NULL) {
1930ef270ab1SKenneth D. Merry 					(*hw->callback.bounce)(ocs_hw_unsol_process_bounce, &seq->hio->axr_buf->seq, s_id, d_id, ox_id);
1931ef270ab1SKenneth D. Merry 				}
1932ef270ab1SKenneth D. Merry 			} else {
1933ef270ab1SKenneth D. Merry 				hw->callback.unsolicited(hw->args.unsolicited, &seq->hio->axr_buf->seq);
1934ef270ab1SKenneth D. Merry 			}
1935ef270ab1SKenneth D. Merry 		}
1936ef270ab1SKenneth D. Merry 	}
1937ef270ab1SKenneth D. Merry 
1938ef270ab1SKenneth D. Merry exit_ocs_hw_rqpair_process_auto_xfr_rdy_cmd:
1939ef270ab1SKenneth D. Merry 	if(axr_lock_taken) {
1940ef270ab1SKenneth D. Merry 		ocs_unlock(&seq->hio->axr_lock);
1941ef270ab1SKenneth D. Merry 	}
1942ef270ab1SKenneth D. Merry 	return 0;
1943ef270ab1SKenneth D. Merry }
1944ef270ab1SKenneth D. Merry 
1945ef270ab1SKenneth D. Merry /**
1946ef270ab1SKenneth D. Merry  * @brief Process CQ completions for Auto xfer rdy data phases.
1947ef270ab1SKenneth D. Merry  *
1948ef270ab1SKenneth D. Merry  * @par Description
1949ef270ab1SKenneth D. Merry  * The data is DMA'd into the data buffer posted to the SGL prior to the XRI
1950ef270ab1SKenneth D. Merry  * being assigned to an IO. When the completion is received, All of the data
1951ef270ab1SKenneth D. Merry  * is in the single buffer.
1952ef270ab1SKenneth D. Merry  *
1953ef270ab1SKenneth D. Merry  * @param hw Hardware context.
1954ef270ab1SKenneth D. Merry  * @param cq Pointer to HW completion queue.
1955ef270ab1SKenneth D. Merry  * @param cqe Completion queue entry.
1956ef270ab1SKenneth D. Merry  *
1957ef270ab1SKenneth D. Merry  * @return Returns 0 for success, or a negative error code value for failure.
1958ef270ab1SKenneth D. Merry  */
1959ef270ab1SKenneth D. Merry 
1960ef270ab1SKenneth D. Merry int32_t
ocs_hw_rqpair_process_auto_xfr_rdy_data(ocs_hw_t * hw,hw_cq_t * cq,uint8_t * cqe)1961ef270ab1SKenneth D. Merry ocs_hw_rqpair_process_auto_xfr_rdy_data(ocs_hw_t *hw, hw_cq_t *cq, uint8_t *cqe)
1962ef270ab1SKenneth D. Merry {
1963ef270ab1SKenneth D. Merry 	/* Seems silly to call a SLI function to decode - use the structure directly for performance */
1964ef270ab1SKenneth D. Merry 	sli4_fc_optimized_write_data_cqe_t *opt_wr = (sli4_fc_optimized_write_data_cqe_t*)cqe;
1965ef270ab1SKenneth D. Merry 	ocs_hw_sequence_t *seq;
1966ef270ab1SKenneth D. Merry 	ocs_hw_io_t *io;
1967ef270ab1SKenneth D. Merry 	ocs_hw_auto_xfer_rdy_buffer_t *buf;
1968ef270ab1SKenneth D. Merry #if defined(OCS_DISC_SPIN_DELAY)
1969ef270ab1SKenneth D. Merry 	uint32_t 	delay = 0;
1970ef270ab1SKenneth D. Merry 	char 		prop_buf[32];
1971ef270ab1SKenneth D. Merry #endif
1972ef270ab1SKenneth D. Merry 	/* Look up the IO */
1973ef270ab1SKenneth D. Merry 	io = ocs_hw_io_lookup(hw, opt_wr->xri);
1974ef270ab1SKenneth D. Merry 	ocs_lock(&io->axr_lock);
1975ef270ab1SKenneth D. Merry 	buf = io->axr_buf;
1976ef270ab1SKenneth D. Merry 	buf->data_cqe = 1;
1977ef270ab1SKenneth D. Merry 	seq = &buf->seq;
1978ef270ab1SKenneth D. Merry 	seq->hw = hw;
1979ef270ab1SKenneth D. Merry 	seq->auto_xrdy = 1;
1980ef270ab1SKenneth D. Merry 	seq->out_of_xris = 0;
1981ef270ab1SKenneth D. Merry 	seq->xri = opt_wr->xri;
1982ef270ab1SKenneth D. Merry 	seq->hio = io;
1983ef270ab1SKenneth D. Merry 	seq->header = &buf->header;
1984ef270ab1SKenneth D. Merry 	seq->payload = &buf->payload;
1985ef270ab1SKenneth D. Merry 
1986ef270ab1SKenneth D. Merry 	seq->header->dma.len = sizeof(fc_header_t);
1987ef270ab1SKenneth D. Merry 	seq->payload->dma.len = opt_wr->total_data_placed;
1988ef270ab1SKenneth D. Merry 	seq->fcfi = buf->fcfi;
1989ef270ab1SKenneth D. Merry 	seq->hw_priv = cq->eq;
1990ef270ab1SKenneth D. Merry 
1991ef270ab1SKenneth D. Merry 	if (opt_wr->status == SLI4_FC_WCQE_STATUS_SUCCESS) {
1992ef270ab1SKenneth D. Merry 		seq->status = OCS_HW_UNSOL_SUCCESS;
1993ef270ab1SKenneth D. Merry 	} else if (opt_wr->status == SLI4_FC_WCQE_STATUS_REMOTE_STOP) {
1994ef270ab1SKenneth D. Merry 		seq->status = OCS_HW_UNSOL_ABTS_RCVD;
1995ef270ab1SKenneth D. Merry 	} else {
1996ef270ab1SKenneth D. Merry 		seq->status = OCS_HW_UNSOL_ERROR;
1997ef270ab1SKenneth D. Merry 	}
1998ef270ab1SKenneth D. Merry 
1999ef270ab1SKenneth D. Merry  	/* If AXR CMD CQE came before previous TRSP CQE of same XRI */
2000ef270ab1SKenneth D. Merry 	if(io->type == OCS_HW_IO_TARGET_RSP) {
2001ef270ab1SKenneth D. Merry 		io->axr_buf->call_axr_data = 1;
2002ef270ab1SKenneth D. Merry 		goto exit_ocs_hw_rqpair_process_auto_xfr_rdy_data;
2003ef270ab1SKenneth D. Merry 	}
2004ef270ab1SKenneth D. Merry 
2005ef270ab1SKenneth D. Merry 	if(!buf->cmd_cqe) {
2006ef270ab1SKenneth D. Merry 		/* if data cqe came before cmd cqe, return here, cmd cqe will handle */
2007ef270ab1SKenneth D. Merry 		goto exit_ocs_hw_rqpair_process_auto_xfr_rdy_data;
2008ef270ab1SKenneth D. Merry 	}
2009ef270ab1SKenneth D. Merry #if defined(OCS_DISC_SPIN_DELAY)
2010ef270ab1SKenneth D. Merry 	if (ocs_get_property("disk_spin_delay", prop_buf, sizeof(prop_buf)) == 0) {
2011ef270ab1SKenneth D. Merry 		delay = ocs_strtoul(prop_buf, 0, 0);
2012ef270ab1SKenneth D. Merry 		ocs_udelay(delay);
2013ef270ab1SKenneth D. Merry 	}
2014ef270ab1SKenneth D. Merry #endif
2015ef270ab1SKenneth D. Merry 
2016ef270ab1SKenneth D. Merry 	/* bounce enabled, single RQ, we snoop the ox_id to choose the cpuidx */
2017ef270ab1SKenneth D. Merry 	if (hw->config.bounce) {
2018ef270ab1SKenneth D. Merry 		fc_header_t *hdr = seq->header->dma.virt;
2019ef270ab1SKenneth D. Merry 		uint32_t s_id = fc_be24toh(hdr->s_id);
2020ef270ab1SKenneth D. Merry 		uint32_t d_id = fc_be24toh(hdr->d_id);
2021ef270ab1SKenneth D. Merry 		uint32_t ox_id =  ocs_be16toh(hdr->ox_id);
2022ef270ab1SKenneth D. Merry 		if (hw->callback.bounce != NULL) {
2023ef270ab1SKenneth D. Merry 			(*hw->callback.bounce)(ocs_hw_unsol_process_bounce, seq, s_id, d_id, ox_id);
2024ef270ab1SKenneth D. Merry 		}
2025ef270ab1SKenneth D. Merry 	} else {
2026ef270ab1SKenneth D. Merry 		hw->callback.unsolicited(hw->args.unsolicited, seq);
2027ef270ab1SKenneth D. Merry 	}
2028ef270ab1SKenneth D. Merry 
2029ef270ab1SKenneth D. Merry exit_ocs_hw_rqpair_process_auto_xfr_rdy_data:
2030ef270ab1SKenneth D. Merry 	ocs_unlock(&io->axr_lock);
2031ef270ab1SKenneth D. Merry 	return 0;
2032ef270ab1SKenneth D. Merry }
2033ef270ab1SKenneth D. Merry 
2034ef270ab1SKenneth D. Merry /**
2035ef270ab1SKenneth D. Merry  * @brief Return pointer to RQ buffer entry.
2036ef270ab1SKenneth D. Merry  *
2037ef270ab1SKenneth D. Merry  * @par Description
2038ef270ab1SKenneth D. Merry  * Returns a pointer to the RQ buffer entry given by @c rqindex and @c bufindex.
2039ef270ab1SKenneth D. Merry  *
2040ef270ab1SKenneth D. Merry  * @param hw Hardware context.
2041ef270ab1SKenneth D. Merry  * @param rqindex Index of the RQ that is being processed.
2042ef270ab1SKenneth D. Merry  * @param bufindex Index into the RQ that is being processed.
2043ef270ab1SKenneth D. Merry  *
2044ef270ab1SKenneth D. Merry  * @return Pointer to the sequence structure, or NULL otherwise.
2045ef270ab1SKenneth D. Merry  */
2046ef270ab1SKenneth D. Merry static ocs_hw_sequence_t *
ocs_hw_rqpair_get(ocs_hw_t * hw,uint16_t rqindex,uint16_t bufindex)2047ef270ab1SKenneth D. Merry ocs_hw_rqpair_get(ocs_hw_t *hw, uint16_t rqindex, uint16_t bufindex)
2048ef270ab1SKenneth D. Merry {
2049ef270ab1SKenneth D. Merry 	sli4_queue_t *rq_hdr = &hw->rq[rqindex];
2050ef270ab1SKenneth D. Merry 	sli4_queue_t *rq_payload = &hw->rq[rqindex+1];
2051ef270ab1SKenneth D. Merry 	ocs_hw_sequence_t *seq = NULL;
2052ef270ab1SKenneth D. Merry 	hw_rq_t *rq = hw->hw_rq[hw->hw_rq_lookup[rqindex]];
2053ef270ab1SKenneth D. Merry 
2054ef270ab1SKenneth D. Merry #if defined(ENABLE_DEBUG_RQBUF)
2055ef270ab1SKenneth D. Merry 	uint64_t rqbuf_debug_value = 0xdead0000 | ((rq->id & 0xf) << 12) | (bufindex & 0xfff);
2056ef270ab1SKenneth D. Merry #endif
2057ef270ab1SKenneth D. Merry 
2058ef270ab1SKenneth D. Merry 	if (bufindex >= rq_hdr->length) {
2059ef270ab1SKenneth D. Merry 		ocs_log_err(hw->os, "RQ index %d bufindex %d exceed ring length %d for id %d\n",
2060ef270ab1SKenneth D. Merry 			    rqindex, bufindex, rq_hdr->length, rq_hdr->id);
2061ef270ab1SKenneth D. Merry 		return NULL;
2062ef270ab1SKenneth D. Merry 	}
2063ef270ab1SKenneth D. Merry 
2064ef270ab1SKenneth D. Merry 	sli_queue_lock(rq_hdr);
2065ef270ab1SKenneth D. Merry 	sli_queue_lock(rq_payload);
2066ef270ab1SKenneth D. Merry 
2067ef270ab1SKenneth D. Merry #if defined(ENABLE_DEBUG_RQBUF)
2068ef270ab1SKenneth D. Merry 	/* Put a debug value into the rq, to track which entries are still valid */
2069ef270ab1SKenneth D. Merry 	_sli_queue_poke(&hw->sli, rq_hdr, bufindex, (uint8_t *)&rqbuf_debug_value);
2070ef270ab1SKenneth D. Merry 	_sli_queue_poke(&hw->sli, rq_payload, bufindex, (uint8_t *)&rqbuf_debug_value);
2071ef270ab1SKenneth D. Merry #endif
2072ef270ab1SKenneth D. Merry 
2073ef270ab1SKenneth D. Merry 	seq = rq->rq_tracker[bufindex];
2074ef270ab1SKenneth D. Merry 	rq->rq_tracker[bufindex] = NULL;
2075ef270ab1SKenneth D. Merry 
2076ef270ab1SKenneth D. Merry 	if (seq == NULL ) {
2077ef270ab1SKenneth D. Merry 		ocs_log_err(hw->os, "RQ buffer NULL, rqindex %d, bufindex %d, current q index = %d\n",
2078ef270ab1SKenneth D. Merry 			    rqindex, bufindex, rq_hdr->index);
2079ef270ab1SKenneth D. Merry 	}
2080ef270ab1SKenneth D. Merry 
2081ef270ab1SKenneth D. Merry 	sli_queue_unlock(rq_payload);
2082ef270ab1SKenneth D. Merry 	sli_queue_unlock(rq_hdr);
2083ef270ab1SKenneth D. Merry 	return seq;
2084ef270ab1SKenneth D. Merry }
2085ef270ab1SKenneth D. Merry 
2086ef270ab1SKenneth D. Merry /**
2087ef270ab1SKenneth D. Merry  * @brief Posts an RQ buffer to a queue and update the verification structures
2088ef270ab1SKenneth D. Merry  *
2089ef270ab1SKenneth D. Merry  * @param hw		hardware context
2090ef270ab1SKenneth D. Merry  * @param seq Pointer to sequence object.
2091ef270ab1SKenneth D. Merry  *
2092ef270ab1SKenneth D. Merry  * @return Returns 0 on success, or a non-zero value otherwise.
2093ef270ab1SKenneth D. Merry  */
2094ef270ab1SKenneth D. Merry static int32_t
ocs_hw_rqpair_put(ocs_hw_t * hw,ocs_hw_sequence_t * seq)2095ef270ab1SKenneth D. Merry ocs_hw_rqpair_put(ocs_hw_t *hw, ocs_hw_sequence_t *seq)
2096ef270ab1SKenneth D. Merry {
2097ef270ab1SKenneth D. Merry 	sli4_queue_t *rq_hdr = &hw->rq[seq->header->rqindex];
2098ef270ab1SKenneth D. Merry 	sli4_queue_t *rq_payload = &hw->rq[seq->payload->rqindex];
2099ef270ab1SKenneth D. Merry 	uint32_t hw_rq_index = hw->hw_rq_lookup[seq->header->rqindex];
2100ef270ab1SKenneth D. Merry 	hw_rq_t *rq = hw->hw_rq[hw_rq_index];
2101ef270ab1SKenneth D. Merry 	uint32_t     phys_hdr[2];
2102ef270ab1SKenneth D. Merry 	uint32_t     phys_payload[2];
2103ef270ab1SKenneth D. Merry 	int32_t      qindex_hdr;
2104ef270ab1SKenneth D. Merry 	int32_t      qindex_payload;
2105ef270ab1SKenneth D. Merry 
2106ef270ab1SKenneth D. Merry 	/* Update the RQ verification lookup tables */
2107ef270ab1SKenneth D. Merry 	phys_hdr[0] = ocs_addr32_hi(seq->header->dma.phys);
2108ef270ab1SKenneth D. Merry 	phys_hdr[1] = ocs_addr32_lo(seq->header->dma.phys);
2109ef270ab1SKenneth D. Merry 	phys_payload[0] = ocs_addr32_hi(seq->payload->dma.phys);
2110ef270ab1SKenneth D. Merry 	phys_payload[1] = ocs_addr32_lo(seq->payload->dma.phys);
2111ef270ab1SKenneth D. Merry 
2112ef270ab1SKenneth D. Merry 	sli_queue_lock(rq_hdr);
2113ef270ab1SKenneth D. Merry 	sli_queue_lock(rq_payload);
2114ef270ab1SKenneth D. Merry 
2115ef270ab1SKenneth D. Merry 	/*
2116ef270ab1SKenneth D. Merry 	 * Note: The header must be posted last for buffer pair mode because
2117ef270ab1SKenneth D. Merry 	 *       posting on the header queue posts the payload queue as well.
2118ef270ab1SKenneth D. Merry 	 *       We do not ring the payload queue independently in RQ pair mode.
2119ef270ab1SKenneth D. Merry 	 */
2120ef270ab1SKenneth D. Merry 	qindex_payload = _sli_queue_write(&hw->sli, rq_payload, (void *)phys_payload);
2121ef270ab1SKenneth D. Merry 	qindex_hdr = _sli_queue_write(&hw->sli, rq_hdr, (void *)phys_hdr);
2122ef270ab1SKenneth D. Merry 	if (qindex_hdr < 0 ||
2123ef270ab1SKenneth D. Merry 	    qindex_payload < 0) {
2124ef270ab1SKenneth D. Merry 		ocs_log_err(hw->os, "RQ_ID=%#x write failed\n", rq_hdr->id);
2125ef270ab1SKenneth D. Merry 		sli_queue_unlock(rq_payload);
2126ef270ab1SKenneth D. Merry 		sli_queue_unlock(rq_hdr);
2127ef270ab1SKenneth D. Merry 		return OCS_HW_RTN_ERROR;
2128ef270ab1SKenneth D. Merry 	}
2129ef270ab1SKenneth D. Merry 
2130ef270ab1SKenneth D. Merry 	/* ensure the indexes are the same */
2131ef270ab1SKenneth D. Merry 	ocs_hw_assert(qindex_hdr == qindex_payload);
2132ef270ab1SKenneth D. Merry 
2133ef270ab1SKenneth D. Merry 	/* Update the lookup table */
2134ef270ab1SKenneth D. Merry 	if (rq->rq_tracker[qindex_hdr] == NULL) {
2135ef270ab1SKenneth D. Merry 		rq->rq_tracker[qindex_hdr] = seq;
2136ef270ab1SKenneth D. Merry 	} else {
2137ef270ab1SKenneth D. Merry 		ocs_log_test(hw->os, "expected rq_tracker[%d][%d] buffer to be NULL\n",
2138ef270ab1SKenneth D. Merry 			     hw_rq_index, qindex_hdr);
2139ef270ab1SKenneth D. Merry 	}
2140ef270ab1SKenneth D. Merry 
2141ef270ab1SKenneth D. Merry 	sli_queue_unlock(rq_payload);
2142ef270ab1SKenneth D. Merry 	sli_queue_unlock(rq_hdr);
2143ef270ab1SKenneth D. Merry 	return OCS_HW_RTN_SUCCESS;
2144ef270ab1SKenneth D. Merry }
2145ef270ab1SKenneth D. Merry 
2146ef270ab1SKenneth D. Merry /**
2147ef270ab1SKenneth D. Merry  * @brief Return RQ buffers (while in RQ pair mode).
2148ef270ab1SKenneth D. Merry  *
2149ef270ab1SKenneth D. Merry  * @par Description
2150ef270ab1SKenneth D. Merry  * The header and payload buffers are returned to the Receive Queue.
2151ef270ab1SKenneth D. Merry  *
2152ef270ab1SKenneth D. Merry  * @param hw Hardware context.
2153ef270ab1SKenneth D. Merry  * @param seq Header/payload sequence buffers.
2154ef270ab1SKenneth D. Merry  *
2155ef270ab1SKenneth D. Merry  * @return Returns OCS_HW_RTN_SUCCESS on success, or an error code value on failure.
2156ef270ab1SKenneth D. Merry  */
2157ef270ab1SKenneth D. Merry 
2158ef270ab1SKenneth D. Merry ocs_hw_rtn_e
ocs_hw_rqpair_sequence_free(ocs_hw_t * hw,ocs_hw_sequence_t * seq)2159ef270ab1SKenneth D. Merry ocs_hw_rqpair_sequence_free(ocs_hw_t *hw, ocs_hw_sequence_t *seq)
2160ef270ab1SKenneth D. Merry {
2161ef270ab1SKenneth D. Merry 	ocs_hw_rtn_e   rc = OCS_HW_RTN_SUCCESS;
2162ef270ab1SKenneth D. Merry 
2163ef270ab1SKenneth D. Merry 	/* Check for auto xfer rdy dummy buffers and call the proper release function. */
2164ef270ab1SKenneth D. Merry 	if (seq->header->rqindex == OCS_HW_RQ_INDEX_DUMMY_HDR) {
2165ef270ab1SKenneth D. Merry 		return ocs_hw_rqpair_auto_xfer_rdy_buffer_sequence_reset(hw, seq);
2166ef270ab1SKenneth D. Merry 	}
2167ef270ab1SKenneth D. Merry 
2168ef270ab1SKenneth D. Merry 	/*
2169ef270ab1SKenneth D. Merry 	 * Post the data buffer first. Because in RQ pair mode, ringing the
2170ef270ab1SKenneth D. Merry 	 * doorbell of the header ring will post the data buffer as well.
2171ef270ab1SKenneth D. Merry 	 */
2172ef270ab1SKenneth D. Merry 	if (ocs_hw_rqpair_put(hw, seq)) {
2173ef270ab1SKenneth D. Merry 		ocs_log_err(hw->os, "error writing buffers\n");
2174ef270ab1SKenneth D. Merry 		return OCS_HW_RTN_ERROR;
2175ef270ab1SKenneth D. Merry 	}
2176ef270ab1SKenneth D. Merry 
2177ef270ab1SKenneth D. Merry 	return rc;
2178ef270ab1SKenneth D. Merry }
2179ef270ab1SKenneth D. Merry 
2180ef270ab1SKenneth D. Merry /**
2181ef270ab1SKenneth D. Merry  * @brief Find the RQ index of RQ_ID.
2182ef270ab1SKenneth D. Merry  *
2183ef270ab1SKenneth D. Merry  * @param hw Hardware context.
2184ef270ab1SKenneth D. Merry  * @param rq_id RQ ID to find.
2185ef270ab1SKenneth D. Merry  *
2186ef270ab1SKenneth D. Merry  * @return Returns the RQ index, or -1 if not found
2187ef270ab1SKenneth D. Merry  */
2188ef270ab1SKenneth D. Merry static inline int32_t
ocs_hw_rqpair_find(ocs_hw_t * hw,uint16_t rq_id)2189ef270ab1SKenneth D. Merry ocs_hw_rqpair_find(ocs_hw_t *hw, uint16_t rq_id)
2190ef270ab1SKenneth D. Merry {
2191ef270ab1SKenneth D. Merry 	return ocs_hw_queue_hash_find(hw->rq_hash, rq_id);
2192ef270ab1SKenneth D. Merry }
2193ef270ab1SKenneth D. Merry 
2194ef270ab1SKenneth D. Merry /**
2195ef270ab1SKenneth D. Merry  * @ingroup devInitShutdown
2196ef270ab1SKenneth D. Merry  * @brief Allocate auto xfer rdy buffers.
2197ef270ab1SKenneth D. Merry  *
2198ef270ab1SKenneth D. Merry  * @par Description
2199ef270ab1SKenneth D. Merry  * Allocates the auto xfer rdy buffers and places them on the free list.
2200ef270ab1SKenneth D. Merry  *
2201ef270ab1SKenneth D. Merry  * @param hw Hardware context allocated by the caller.
2202ef270ab1SKenneth D. Merry  * @param num_buffers Number of buffers to allocate.
2203ef270ab1SKenneth D. Merry  *
2204ef270ab1SKenneth D. Merry  * @return Returns 0 on success, or a non-zero value on failure.
2205ef270ab1SKenneth D. Merry  */
2206ef270ab1SKenneth D. Merry ocs_hw_rtn_e
ocs_hw_rqpair_auto_xfer_rdy_buffer_alloc(ocs_hw_t * hw,uint32_t num_buffers)2207ef270ab1SKenneth D. Merry ocs_hw_rqpair_auto_xfer_rdy_buffer_alloc(ocs_hw_t *hw, uint32_t num_buffers)
2208ef270ab1SKenneth D. Merry {
2209ef270ab1SKenneth D. Merry 	ocs_hw_auto_xfer_rdy_buffer_t *buf;
2210ef270ab1SKenneth D. Merry 	uint32_t i;
2211ef270ab1SKenneth D. Merry 
2212ef270ab1SKenneth D. Merry 	hw->auto_xfer_rdy_buf_pool = ocs_pool_alloc(hw->os, sizeof(ocs_hw_auto_xfer_rdy_buffer_t), num_buffers, FALSE);
2213ef270ab1SKenneth D. Merry 	if (hw->auto_xfer_rdy_buf_pool == NULL) {
2214ef270ab1SKenneth D. Merry 		ocs_log_err(hw->os, "Failure to allocate auto xfer ready buffer pool\n");
2215ef270ab1SKenneth D. Merry 		return OCS_HW_RTN_NO_MEMORY;
2216ef270ab1SKenneth D. Merry 	}
2217ef270ab1SKenneth D. Merry 
2218ef270ab1SKenneth D. Merry 	for (i = 0; i < num_buffers; i++) {
2219ef270ab1SKenneth D. Merry 		/* allocate the wrapper object */
2220ef270ab1SKenneth D. Merry 		buf = ocs_pool_get_instance(hw->auto_xfer_rdy_buf_pool, i);
2221ef270ab1SKenneth D. Merry 		ocs_hw_assert(buf != NULL);
2222ef270ab1SKenneth D. Merry 
2223ef270ab1SKenneth D. Merry 		/* allocate the auto xfer ready buffer */
2224ef270ab1SKenneth D. Merry 		if (ocs_dma_alloc(hw->os, &buf->payload.dma, hw->config.auto_xfer_rdy_size, OCS_MIN_DMA_ALIGNMENT)) {
2225ef270ab1SKenneth D. Merry 			ocs_log_err(hw->os, "DMA allocation failed\n");
2226ef270ab1SKenneth D. Merry 			ocs_free(hw->os, buf, sizeof(*buf));
2227ef270ab1SKenneth D. Merry 			return OCS_HW_RTN_NO_MEMORY;
2228ef270ab1SKenneth D. Merry 		}
2229ef270ab1SKenneth D. Merry 
2230ef270ab1SKenneth D. Merry 		/* build a fake data header in big endian */
2231ef270ab1SKenneth D. Merry 		buf->hdr.info = FC_RCTL_INFO_SOL_DATA;
2232ef270ab1SKenneth D. Merry 		buf->hdr.r_ctl = FC_RCTL_FC4_DATA;
2233ef270ab1SKenneth D. Merry 		buf->hdr.type = FC_TYPE_FCP;
2234ef270ab1SKenneth D. Merry 		buf->hdr.f_ctl = fc_htobe24(FC_FCTL_EXCHANGE_RESPONDER |
2235ef270ab1SKenneth D. Merry 					    FC_FCTL_FIRST_SEQUENCE |
2236ef270ab1SKenneth D. Merry 					    FC_FCTL_LAST_SEQUENCE |
2237ef270ab1SKenneth D. Merry 					    FC_FCTL_END_SEQUENCE |
2238ef270ab1SKenneth D. Merry 					    FC_FCTL_SEQUENCE_INITIATIVE);
2239ef270ab1SKenneth D. Merry 
2240ef270ab1SKenneth D. Merry 		/* build the fake header DMA object */
2241ef270ab1SKenneth D. Merry 		buf->header.rqindex = OCS_HW_RQ_INDEX_DUMMY_HDR;
2242ef270ab1SKenneth D. Merry 		buf->header.dma.virt = &buf->hdr;
2243ef270ab1SKenneth D. Merry 		buf->header.dma.alloc = buf;
2244ef270ab1SKenneth D. Merry 		buf->header.dma.size = sizeof(buf->hdr);
2245ef270ab1SKenneth D. Merry 		buf->header.dma.len = sizeof(buf->hdr);
2246ef270ab1SKenneth D. Merry 
2247ef270ab1SKenneth D. Merry 		buf->payload.rqindex = OCS_HW_RQ_INDEX_DUMMY_DATA;
2248ef270ab1SKenneth D. Merry 	}
2249ef270ab1SKenneth D. Merry 	return OCS_HW_RTN_SUCCESS;
2250ef270ab1SKenneth D. Merry }
2251ef270ab1SKenneth D. Merry 
2252ef270ab1SKenneth D. Merry /**
2253ef270ab1SKenneth D. Merry  * @ingroup devInitShutdown
2254ef270ab1SKenneth D. Merry  * @brief Post Auto xfer rdy buffers to the XRIs posted with DNRX.
2255ef270ab1SKenneth D. Merry  *
2256ef270ab1SKenneth D. Merry  * @par Description
2257ef270ab1SKenneth D. Merry  * When new buffers are freed, check existing XRIs waiting for buffers.
2258ef270ab1SKenneth D. Merry  *
2259ef270ab1SKenneth D. Merry  * @param hw Hardware context allocated by the caller.
2260ef270ab1SKenneth D. Merry  */
2261ef270ab1SKenneth D. Merry static void
ocs_hw_rqpair_auto_xfer_rdy_dnrx_check(ocs_hw_t * hw)2262ef270ab1SKenneth D. Merry ocs_hw_rqpair_auto_xfer_rdy_dnrx_check(ocs_hw_t *hw)
2263ef270ab1SKenneth D. Merry {
2264ef270ab1SKenneth D. Merry 	ocs_hw_io_t *io;
2265ef270ab1SKenneth D. Merry 	int32_t rc;
2266ef270ab1SKenneth D. Merry 
2267ef270ab1SKenneth D. Merry 	ocs_lock(&hw->io_lock);
2268ef270ab1SKenneth D. Merry 
2269ef270ab1SKenneth D. Merry 	while (!ocs_list_empty(&hw->io_port_dnrx)) {
2270ef270ab1SKenneth D. Merry 		io = ocs_list_remove_head(&hw->io_port_dnrx);
2271ef270ab1SKenneth D. Merry 		rc = ocs_hw_reque_xri(hw, io);
2272ef270ab1SKenneth D. Merry 		if(rc) {
2273ef270ab1SKenneth D. Merry 			break;
2274ef270ab1SKenneth D. Merry 		}
2275ef270ab1SKenneth D. Merry 	}
2276ef270ab1SKenneth D. Merry 
2277ef270ab1SKenneth D. Merry 	ocs_unlock(&hw->io_lock);
2278ef270ab1SKenneth D. Merry }
2279ef270ab1SKenneth D. Merry 
2280ef270ab1SKenneth D. Merry /**
2281ef270ab1SKenneth D. Merry  * @brief Called when the POST_SGL_PAGE command completes.
2282ef270ab1SKenneth D. Merry  *
2283ef270ab1SKenneth D. Merry  * @par Description
2284ef270ab1SKenneth D. Merry  * Free the mailbox command buffer.
2285ef270ab1SKenneth D. Merry  *
2286ef270ab1SKenneth D. Merry  * @param hw Hardware context.
2287ef270ab1SKenneth D. Merry  * @param status Status field from the mbox completion.
2288ef270ab1SKenneth D. Merry  * @param mqe Mailbox response structure.
2289ef270ab1SKenneth D. Merry  * @param arg Pointer to a callback function that signals the caller that the command is done.
2290ef270ab1SKenneth D. Merry  *
2291ef270ab1SKenneth D. Merry  * @return Returns 0.
2292ef270ab1SKenneth D. Merry  */
2293ef270ab1SKenneth D. Merry static int32_t
ocs_hw_rqpair_auto_xfer_rdy_move_to_port_cb(ocs_hw_t * hw,int32_t status,uint8_t * mqe,void * arg)2294ef270ab1SKenneth D. Merry ocs_hw_rqpair_auto_xfer_rdy_move_to_port_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void  *arg)
2295ef270ab1SKenneth D. Merry {
2296ef270ab1SKenneth D. Merry 	if (status != 0) {
2297ef270ab1SKenneth D. Merry 		ocs_log_debug(hw->os, "Status 0x%x\n", status);
2298ef270ab1SKenneth D. Merry 	}
2299ef270ab1SKenneth D. Merry 
2300ef270ab1SKenneth D. Merry 	ocs_free(hw->os, mqe, SLI4_BMBX_SIZE);
2301ef270ab1SKenneth D. Merry 	return 0;
2302ef270ab1SKenneth D. Merry }
2303ef270ab1SKenneth D. Merry 
2304ef270ab1SKenneth D. Merry /**
2305ef270ab1SKenneth D. Merry  * @brief Prepares an XRI to move to the chip.
2306ef270ab1SKenneth D. Merry  *
2307ef270ab1SKenneth D. Merry  * @par Description
2308ef270ab1SKenneth D. Merry  * Puts the data SGL into the SGL list for the IO object and possibly registers
2309ef270ab1SKenneth D. Merry  * an SGL list for the XRI. Since both the POST_XRI and POST_SGL_PAGES commands are
2310ef270ab1SKenneth D. Merry  * mailbox commands, we don't need to wait for completion before preceding.
2311ef270ab1SKenneth D. Merry  *
2312ef270ab1SKenneth D. Merry  * @param hw Hardware context allocated by the caller.
2313ef270ab1SKenneth D. Merry  * @param io Pointer to the IO object.
2314ef270ab1SKenneth D. Merry  *
2315ef270ab1SKenneth D. Merry  * @return Returns OCS_HW_RTN_SUCCESS for success, or an error code value for failure.
2316ef270ab1SKenneth D. Merry  */
2317ef270ab1SKenneth D. Merry ocs_hw_rtn_e
ocs_hw_rqpair_auto_xfer_rdy_move_to_port(ocs_hw_t * hw,ocs_hw_io_t * io)2318ef270ab1SKenneth D. Merry ocs_hw_rqpair_auto_xfer_rdy_move_to_port(ocs_hw_t *hw, ocs_hw_io_t *io)
2319ef270ab1SKenneth D. Merry {
2320ef270ab1SKenneth D. Merry 	/* We only need to preregister the SGL if it has not yet been done. */
2321ef270ab1SKenneth D. Merry 	if (!sli_get_sgl_preregister(&hw->sli)) {
2322ef270ab1SKenneth D. Merry 		uint8_t	*post_sgl;
2323ef270ab1SKenneth D. Merry 		ocs_dma_t *psgls = &io->def_sgl;
2324ef270ab1SKenneth D. Merry 		ocs_dma_t **sgls = &psgls;
2325ef270ab1SKenneth D. Merry 
2326ef270ab1SKenneth D. Merry 		/* non-local buffer required for mailbox queue */
2327ef270ab1SKenneth D. Merry 		post_sgl = ocs_malloc(hw->os, SLI4_BMBX_SIZE, OCS_M_NOWAIT);
2328ef270ab1SKenneth D. Merry 		if (post_sgl == NULL) {
2329ef270ab1SKenneth D. Merry 			ocs_log_err(hw->os, "no buffer for command\n");
2330ef270ab1SKenneth D. Merry 			return OCS_HW_RTN_NO_MEMORY;
2331ef270ab1SKenneth D. Merry 		}
2332ef270ab1SKenneth D. Merry 		if (sli_cmd_fcoe_post_sgl_pages(&hw->sli, post_sgl, SLI4_BMBX_SIZE,
2333ef270ab1SKenneth D. Merry 						io->indicator, 1, sgls, NULL, NULL)) {
2334ef270ab1SKenneth D. Merry 			if (ocs_hw_command(hw, post_sgl, OCS_CMD_NOWAIT,
2335ef270ab1SKenneth D. Merry 					    ocs_hw_rqpair_auto_xfer_rdy_move_to_port_cb, NULL)) {
2336ef270ab1SKenneth D. Merry 				ocs_free(hw->os, post_sgl, SLI4_BMBX_SIZE);
2337ef270ab1SKenneth D. Merry 				ocs_log_err(hw->os, "SGL post failed\n");
2338ef270ab1SKenneth D. Merry 				return OCS_HW_RTN_ERROR;
2339ef270ab1SKenneth D. Merry 			}
2340ef270ab1SKenneth D. Merry 		}
2341ef270ab1SKenneth D. Merry 	}
2342ef270ab1SKenneth D. Merry 
2343ef270ab1SKenneth D. Merry 	ocs_lock(&hw->io_lock);
2344ef270ab1SKenneth D. Merry 	if (ocs_hw_rqpair_auto_xfer_rdy_buffer_post(hw, io, 0) != 0) { /* DNRX set - no buffer */
2345ef270ab1SKenneth D. Merry 		ocs_unlock(&hw->io_lock);
2346ef270ab1SKenneth D. Merry 		return OCS_HW_RTN_ERROR;
2347ef270ab1SKenneth D. Merry 	}
2348ef270ab1SKenneth D. Merry 	ocs_unlock(&hw->io_lock);
2349ef270ab1SKenneth D. Merry 	return OCS_HW_RTN_SUCCESS;
2350ef270ab1SKenneth D. Merry }
2351ef270ab1SKenneth D. Merry 
2352ef270ab1SKenneth D. Merry /**
2353ef270ab1SKenneth D. Merry  * @brief Prepares an XRI to move back to the host.
2354ef270ab1SKenneth D. Merry  *
2355ef270ab1SKenneth D. Merry  * @par Description
2356ef270ab1SKenneth D. Merry  * Releases any attached buffer back to the pool.
2357ef270ab1SKenneth D. Merry  *
2358ef270ab1SKenneth D. Merry  * @param hw Hardware context allocated by the caller.
2359ef270ab1SKenneth D. Merry  * @param io Pointer to the IO object.
2360ef270ab1SKenneth D. Merry  */
2361ef270ab1SKenneth D. Merry void
ocs_hw_rqpair_auto_xfer_rdy_move_to_host(ocs_hw_t * hw,ocs_hw_io_t * io)2362ef270ab1SKenneth D. Merry ocs_hw_rqpair_auto_xfer_rdy_move_to_host(ocs_hw_t *hw, ocs_hw_io_t *io)
2363ef270ab1SKenneth D. Merry {
2364ef270ab1SKenneth D. Merry 	if (io->axr_buf != NULL) {
2365ef270ab1SKenneth D. Merry 		ocs_lock(&hw->io_lock);
2366ef270ab1SKenneth D. Merry 			/* check  list and remove if there */
2367ef270ab1SKenneth D. Merry 			if (ocs_list_on_list(&io->dnrx_link)) {
2368ef270ab1SKenneth D. Merry 				ocs_list_remove(&hw->io_port_dnrx, io);
2369ef270ab1SKenneth D. Merry 				io->auto_xfer_rdy_dnrx = 0;
2370ef270ab1SKenneth D. Merry 
2371ef270ab1SKenneth D. Merry 				/* release the count for waiting for a buffer */
2372ef270ab1SKenneth D. Merry 				ocs_hw_io_free(hw, io);
2373ef270ab1SKenneth D. Merry 			}
2374ef270ab1SKenneth D. Merry 
2375ef270ab1SKenneth D. Merry 			ocs_pool_put(hw->auto_xfer_rdy_buf_pool, io->axr_buf);
2376ef270ab1SKenneth D. Merry 			io->axr_buf = NULL;
2377ef270ab1SKenneth D. Merry 		ocs_unlock(&hw->io_lock);
2378ef270ab1SKenneth D. Merry 
2379ef270ab1SKenneth D. Merry 		ocs_hw_rqpair_auto_xfer_rdy_dnrx_check(hw);
2380ef270ab1SKenneth D. Merry 	}
2381ef270ab1SKenneth D. Merry 	return;
2382ef270ab1SKenneth D. Merry }
2383ef270ab1SKenneth D. Merry 
2384ef270ab1SKenneth D. Merry /**
2385ef270ab1SKenneth D. Merry  * @brief Posts an auto xfer rdy buffer to an IO.
2386ef270ab1SKenneth D. Merry  *
2387ef270ab1SKenneth D. Merry  * @par Description
2388ef270ab1SKenneth D. Merry  * Puts the data SGL into the SGL list for the IO object
2389ef270ab1SKenneth D. Merry  * @n @name
2390ef270ab1SKenneth D. Merry  * @b Note: io_lock must be held.
2391ef270ab1SKenneth D. Merry  *
2392ef270ab1SKenneth D. Merry  * @param hw Hardware context allocated by the caller.
2393ef270ab1SKenneth D. Merry  * @param io Pointer to the IO object.
2394ef270ab1SKenneth D. Merry  *
2395ef270ab1SKenneth D. Merry  * @return Returns the value of DNRX bit in the TRSP and ABORT WQEs.
2396ef270ab1SKenneth D. Merry  */
2397ef270ab1SKenneth D. Merry uint8_t
ocs_hw_rqpair_auto_xfer_rdy_buffer_post(ocs_hw_t * hw,ocs_hw_io_t * io,int reuse_buf)2398ef270ab1SKenneth D. Merry ocs_hw_rqpair_auto_xfer_rdy_buffer_post(ocs_hw_t *hw, ocs_hw_io_t *io, int reuse_buf)
2399ef270ab1SKenneth D. Merry {
2400ef270ab1SKenneth D. Merry 	ocs_hw_auto_xfer_rdy_buffer_t *buf;
2401ef270ab1SKenneth D. Merry 	sli4_sge_t	*data;
2402ef270ab1SKenneth D. Merry 
2403ef270ab1SKenneth D. Merry 	if(!reuse_buf) {
2404ef270ab1SKenneth D. Merry 		buf = ocs_pool_get(hw->auto_xfer_rdy_buf_pool);
2405ef270ab1SKenneth D. Merry 		io->axr_buf = buf;
2406ef270ab1SKenneth D. Merry 	}
2407ef270ab1SKenneth D. Merry 
2408ef270ab1SKenneth D. Merry 	data = io->def_sgl.virt;
2409ef270ab1SKenneth D. Merry 	data[0].sge_type = SLI4_SGE_TYPE_SKIP;
2410ef270ab1SKenneth D. Merry 	data[0].last = 0;
2411ef270ab1SKenneth D. Merry 
2412ef270ab1SKenneth D. Merry 	/*
2413ef270ab1SKenneth D. Merry 	 * Note: if we are doing DIF assists, then the SGE[1] must contain the
2414ef270ab1SKenneth D. Merry 	 * DI_SEED SGE. The host is responsible for programming:
2415ef270ab1SKenneth D. Merry 	 *   SGE Type (Word 2, bits 30:27)
2416ef270ab1SKenneth D. Merry 	 *   Replacement App Tag (Word 2 bits 15:0)
2417ef270ab1SKenneth D. Merry 	 *   App Tag (Word 3 bits 15:0)
2418ef270ab1SKenneth D. Merry 	 *   New Ref Tag (Word 3 bit 23)
2419ef270ab1SKenneth D. Merry 	 *   Metadata Enable (Word 3 bit 20)
2420ef270ab1SKenneth D. Merry 	 *   Auto-Increment RefTag (Word 3 bit 19)
2421ef270ab1SKenneth D. Merry 	 *   Block Size (Word 3 bits 18:16)
2422ef270ab1SKenneth D. Merry 	 * The following fields are managed by the SLI Port:
2423ef270ab1SKenneth D. Merry 	 *    Ref Tag Compare (Word 0)
2424ef270ab1SKenneth D. Merry 	 *    Replacement Ref Tag (Word 1) - In not the LBA
2425ef270ab1SKenneth D. Merry 	 *    NA (Word 2 bit 25)
2426ef270ab1SKenneth D. Merry 	 *    Opcode RX (Word 3 bits 27:24)
2427ef270ab1SKenneth D. Merry 	 *    Checksum Enable (Word 3 bit 22)
2428ef270ab1SKenneth D. Merry 	 *    RefTag Enable (Word 3 bit 21)
2429ef270ab1SKenneth D. Merry 	 *
2430ef270ab1SKenneth D. Merry 	 * The first two SGLs are cleared by ocs_hw_io_init_sges(), so assume eveything is cleared.
2431ef270ab1SKenneth D. Merry 	 */
2432ef270ab1SKenneth D. Merry 	if (hw->config.auto_xfer_rdy_p_type) {
2433ef270ab1SKenneth D. Merry 		sli4_diseed_sge_t *diseed = (sli4_diseed_sge_t*)&data[1];
2434ef270ab1SKenneth D. Merry 
2435ef270ab1SKenneth D. Merry 		diseed->sge_type = SLI4_SGE_TYPE_DISEED;
2436ef270ab1SKenneth D. Merry 		diseed->repl_app_tag = hw->config.auto_xfer_rdy_app_tag_value;
2437ef270ab1SKenneth D. Merry 		diseed->app_tag_cmp = hw->config.auto_xfer_rdy_app_tag_value;
2438ef270ab1SKenneth D. Merry 		diseed->check_app_tag = hw->config.auto_xfer_rdy_app_tag_valid;
2439ef270ab1SKenneth D. Merry 		diseed->auto_incr_ref_tag = TRUE; /* Always the LBA */
2440ef270ab1SKenneth D. Merry 		diseed->dif_blk_size = hw->config.auto_xfer_rdy_blk_size_chip;
2441ef270ab1SKenneth D. Merry 	} else {
2442ef270ab1SKenneth D. Merry 		data[1].sge_type = SLI4_SGE_TYPE_SKIP;
2443ef270ab1SKenneth D. Merry 		data[1].last = 0;
2444ef270ab1SKenneth D. Merry 	}
2445ef270ab1SKenneth D. Merry 
2446ef270ab1SKenneth D. Merry 	data[2].sge_type = SLI4_SGE_TYPE_DATA;
2447ef270ab1SKenneth D. Merry 	data[2].buffer_address_high = ocs_addr32_hi(io->axr_buf->payload.dma.phys);
2448ef270ab1SKenneth D. Merry 	data[2].buffer_address_low  = ocs_addr32_lo(io->axr_buf->payload.dma.phys);
2449ef270ab1SKenneth D. Merry 	data[2].buffer_length = io->axr_buf->payload.dma.size;
2450ef270ab1SKenneth D. Merry 	data[2].last = TRUE;
2451ef270ab1SKenneth D. Merry 	data[3].sge_type = SLI4_SGE_TYPE_SKIP;
2452ef270ab1SKenneth D. Merry 
2453ef270ab1SKenneth D. Merry 	return 0;
2454ef270ab1SKenneth D. Merry }
2455ef270ab1SKenneth D. Merry 
2456ef270ab1SKenneth D. Merry /**
2457ef270ab1SKenneth D. Merry  * @brief Return auto xfer ready buffers (while in RQ pair mode).
2458ef270ab1SKenneth D. Merry  *
2459ef270ab1SKenneth D. Merry  * @par Description
2460ef270ab1SKenneth D. Merry  * The header and payload buffers are returned to the auto xfer rdy pool.
2461ef270ab1SKenneth D. Merry  *
2462ef270ab1SKenneth D. Merry  * @param hw Hardware context.
2463ef270ab1SKenneth D. Merry  * @param seq Header/payload sequence buffers.
2464ef270ab1SKenneth D. Merry  *
2465ef270ab1SKenneth D. Merry  * @return Returns OCS_HW_RTN_SUCCESS for success, an error code value for failure.
2466ef270ab1SKenneth D. Merry  */
2467ef270ab1SKenneth D. Merry 
2468ef270ab1SKenneth D. Merry static ocs_hw_rtn_e
ocs_hw_rqpair_auto_xfer_rdy_buffer_sequence_reset(ocs_hw_t * hw,ocs_hw_sequence_t * seq)2469ef270ab1SKenneth D. Merry ocs_hw_rqpair_auto_xfer_rdy_buffer_sequence_reset(ocs_hw_t *hw, ocs_hw_sequence_t *seq)
2470ef270ab1SKenneth D. Merry {
2471ef270ab1SKenneth D. Merry 	ocs_hw_auto_xfer_rdy_buffer_t *buf = seq->header->dma.alloc;
2472ef270ab1SKenneth D. Merry 
2473ef270ab1SKenneth D. Merry 	buf->data_cqe = 0;
2474ef270ab1SKenneth D. Merry 	buf->cmd_cqe = 0;
2475ef270ab1SKenneth D. Merry 	buf->fcfi = 0;
2476ef270ab1SKenneth D. Merry 	buf->call_axr_cmd = 0;
2477ef270ab1SKenneth D. Merry 	buf->call_axr_data = 0;
2478ef270ab1SKenneth D. Merry 
2479ef270ab1SKenneth D. Merry 	/* build a fake data header in big endian */
2480ef270ab1SKenneth D. Merry 	buf->hdr.info = FC_RCTL_INFO_SOL_DATA;
2481ef270ab1SKenneth D. Merry 	buf->hdr.r_ctl = FC_RCTL_FC4_DATA;
2482ef270ab1SKenneth D. Merry 	buf->hdr.type = FC_TYPE_FCP;
2483ef270ab1SKenneth D. Merry 	buf->hdr.f_ctl = fc_htobe24(FC_FCTL_EXCHANGE_RESPONDER |
2484ef270ab1SKenneth D. Merry 					FC_FCTL_FIRST_SEQUENCE |
2485ef270ab1SKenneth D. Merry 					FC_FCTL_LAST_SEQUENCE |
2486ef270ab1SKenneth D. Merry 					FC_FCTL_END_SEQUENCE |
2487ef270ab1SKenneth D. Merry 					FC_FCTL_SEQUENCE_INITIATIVE);
2488ef270ab1SKenneth D. Merry 
2489ef270ab1SKenneth D. Merry 	/* build the fake header DMA object */
2490ef270ab1SKenneth D. Merry 	buf->header.rqindex = OCS_HW_RQ_INDEX_DUMMY_HDR;
2491ef270ab1SKenneth D. Merry 	buf->header.dma.virt = &buf->hdr;
2492ef270ab1SKenneth D. Merry 	buf->header.dma.alloc = buf;
2493ef270ab1SKenneth D. Merry 	buf->header.dma.size = sizeof(buf->hdr);
2494ef270ab1SKenneth D. Merry 	buf->header.dma.len = sizeof(buf->hdr);
2495ef270ab1SKenneth D. Merry 	buf->payload.rqindex = OCS_HW_RQ_INDEX_DUMMY_DATA;
2496ef270ab1SKenneth D. Merry 
2497ef270ab1SKenneth D. Merry 	ocs_hw_rqpair_auto_xfer_rdy_dnrx_check(hw);
2498ef270ab1SKenneth D. Merry 
2499ef270ab1SKenneth D. Merry 	return OCS_HW_RTN_SUCCESS;
2500ef270ab1SKenneth D. Merry }
2501ef270ab1SKenneth D. Merry 
2502ef270ab1SKenneth D. Merry /**
2503ef270ab1SKenneth D. Merry  * @ingroup devInitShutdown
2504ef270ab1SKenneth D. Merry  * @brief Free auto xfer rdy buffers.
2505ef270ab1SKenneth D. Merry  *
2506ef270ab1SKenneth D. Merry  * @par Description
2507ef270ab1SKenneth D. Merry  * Frees the auto xfer rdy buffers.
2508ef270ab1SKenneth D. Merry  *
2509ef270ab1SKenneth D. Merry  * @param hw Hardware context allocated by the caller.
2510ef270ab1SKenneth D. Merry  *
2511ef270ab1SKenneth D. Merry  * @return Returns 0 on success, or a non-zero value on failure.
2512ef270ab1SKenneth D. Merry  */
2513ef270ab1SKenneth D. Merry static void
ocs_hw_rqpair_auto_xfer_rdy_buffer_free(ocs_hw_t * hw)2514ef270ab1SKenneth D. Merry ocs_hw_rqpair_auto_xfer_rdy_buffer_free(ocs_hw_t *hw)
2515ef270ab1SKenneth D. Merry {
2516ef270ab1SKenneth D. Merry 	ocs_hw_auto_xfer_rdy_buffer_t *buf;
2517ef270ab1SKenneth D. Merry 	uint32_t i;
2518ef270ab1SKenneth D. Merry 
2519ef270ab1SKenneth D. Merry 	if (hw->auto_xfer_rdy_buf_pool != NULL) {
2520ef270ab1SKenneth D. Merry 		ocs_lock(&hw->io_lock);
2521ef270ab1SKenneth D. Merry 			for (i = 0; i < ocs_pool_get_count(hw->auto_xfer_rdy_buf_pool); i++) {
2522ef270ab1SKenneth D. Merry 				buf = ocs_pool_get_instance(hw->auto_xfer_rdy_buf_pool, i);
2523ef270ab1SKenneth D. Merry 				if (buf != NULL) {
2524ef270ab1SKenneth D. Merry 					ocs_dma_free(hw->os, &buf->payload.dma);
2525ef270ab1SKenneth D. Merry 				}
2526ef270ab1SKenneth D. Merry 			}
2527ef270ab1SKenneth D. Merry 		ocs_unlock(&hw->io_lock);
2528ef270ab1SKenneth D. Merry 
2529ef270ab1SKenneth D. Merry 		ocs_pool_free(hw->auto_xfer_rdy_buf_pool);
2530ef270ab1SKenneth D. Merry 		hw->auto_xfer_rdy_buf_pool = NULL;
2531ef270ab1SKenneth D. Merry 	}
2532ef270ab1SKenneth D. Merry }
2533ef270ab1SKenneth D. Merry 
2534ef270ab1SKenneth D. Merry /**
2535ef270ab1SKenneth D. Merry  * @ingroup devInitShutdown
2536ef270ab1SKenneth D. Merry  * @brief Configure the rq_pair function from ocs_hw_init().
2537ef270ab1SKenneth D. Merry  *
2538ef270ab1SKenneth D. Merry  * @par Description
2539ef270ab1SKenneth D. Merry  * Allocates the buffers to auto xfer rdy and posts initial XRIs for this feature.
2540ef270ab1SKenneth D. Merry  *
2541ef270ab1SKenneth D. Merry  * @param hw Hardware context allocated by the caller.
2542ef270ab1SKenneth D. Merry  *
2543ef270ab1SKenneth D. Merry  * @return Returns 0 on success, or a non-zero value on failure.
2544ef270ab1SKenneth D. Merry  */
2545ef270ab1SKenneth D. Merry ocs_hw_rtn_e
ocs_hw_rqpair_init(ocs_hw_t * hw)2546ef270ab1SKenneth D. Merry ocs_hw_rqpair_init(ocs_hw_t *hw)
2547ef270ab1SKenneth D. Merry {
2548ef270ab1SKenneth D. Merry 	ocs_hw_rtn_e	rc;
2549ef270ab1SKenneth D. Merry 	uint32_t xris_posted;
2550ef270ab1SKenneth D. Merry 
2551ef270ab1SKenneth D. Merry 	ocs_log_debug(hw->os, "RQ Pair mode\n");
2552ef270ab1SKenneth D. Merry 
2553ef270ab1SKenneth D. Merry 	/*
2554ef270ab1SKenneth D. Merry 	 * If we get this far, the auto XFR_RDY feature was enabled successfully, otherwise ocs_hw_init() would
2555ef270ab1SKenneth D. Merry 	 * return with an error. So allocate the buffers based on the initial XRI pool required to support this
2556ef270ab1SKenneth D. Merry 	 * feature.
2557ef270ab1SKenneth D. Merry 	 */
2558ef270ab1SKenneth D. Merry 	if (sli_get_auto_xfer_rdy_capable(&hw->sli) &&
2559ef270ab1SKenneth D. Merry 	    hw->config.auto_xfer_rdy_size > 0) {
2560ef270ab1SKenneth D. Merry 		if (hw->auto_xfer_rdy_buf_pool == NULL) {
2561ef270ab1SKenneth D. Merry 			/*
2562ef270ab1SKenneth D. Merry 			 * Allocate one more buffer than XRIs so that when all the XRIs are in use, we still have
2563ef270ab1SKenneth D. Merry 			 * one to post back for the case where the response phase is started in the context of
2564ef270ab1SKenneth D. Merry 			 * the data completion.
2565ef270ab1SKenneth D. Merry 			 */
2566ef270ab1SKenneth D. Merry 			rc = ocs_hw_rqpair_auto_xfer_rdy_buffer_alloc(hw, hw->config.auto_xfer_rdy_xri_cnt + 1);
2567ef270ab1SKenneth D. Merry 			if (rc != OCS_HW_RTN_SUCCESS) {
2568ef270ab1SKenneth D. Merry 				return rc;
2569ef270ab1SKenneth D. Merry 			}
2570ef270ab1SKenneth D. Merry 		} else {
2571ef270ab1SKenneth D. Merry 			ocs_pool_reset(hw->auto_xfer_rdy_buf_pool);
2572ef270ab1SKenneth D. Merry 		}
2573ef270ab1SKenneth D. Merry 
2574ef270ab1SKenneth D. Merry 		/* Post the auto XFR_RDY XRIs */
2575ef270ab1SKenneth D. Merry 		xris_posted = ocs_hw_xri_move_to_port_owned(hw, hw->config.auto_xfer_rdy_xri_cnt);
2576ef270ab1SKenneth D. Merry 		if (xris_posted != hw->config.auto_xfer_rdy_xri_cnt) {
2577ef270ab1SKenneth D. Merry 			ocs_log_err(hw->os, "post_xri failed, only posted %d XRIs\n", xris_posted);
2578ef270ab1SKenneth D. Merry 			return OCS_HW_RTN_ERROR;
2579ef270ab1SKenneth D. Merry 		}
2580ef270ab1SKenneth D. Merry 	}
2581ef270ab1SKenneth D. Merry 
2582ef270ab1SKenneth D. Merry 	return 0;
2583ef270ab1SKenneth D. Merry }
2584ef270ab1SKenneth D. Merry 
2585ef270ab1SKenneth D. Merry /**
2586ef270ab1SKenneth D. Merry  * @ingroup devInitShutdown
2587ef270ab1SKenneth D. Merry  * @brief Tear down the rq_pair function from ocs_hw_teardown().
2588ef270ab1SKenneth D. Merry  *
2589ef270ab1SKenneth D. Merry  * @par Description
2590ef270ab1SKenneth D. Merry  * Frees the buffers to auto xfer rdy.
2591ef270ab1SKenneth D. Merry  *
2592ef270ab1SKenneth D. Merry  * @param hw Hardware context allocated by the caller.
2593ef270ab1SKenneth D. Merry  */
2594ef270ab1SKenneth D. Merry void
ocs_hw_rqpair_teardown(ocs_hw_t * hw)2595ef270ab1SKenneth D. Merry ocs_hw_rqpair_teardown(ocs_hw_t *hw)
2596ef270ab1SKenneth D. Merry {
2597ef270ab1SKenneth D. Merry 	/* We need to free any auto xfer ready buffers */
2598ef270ab1SKenneth D. Merry 	ocs_hw_rqpair_auto_xfer_rdy_buffer_free(hw);
2599ef270ab1SKenneth D. Merry }
2600