xref: /freebsd/sys/dev/ocs_fc/ocs_utils.c (revision ef270ab1)
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  * $FreeBSD$
32ef270ab1SKenneth D. Merry  */
33ef270ab1SKenneth D. Merry 
34ef270ab1SKenneth D. Merry /**
35ef270ab1SKenneth D. Merry  * @file
36ef270ab1SKenneth D. Merry  *
37ef270ab1SKenneth D. Merry  */
38ef270ab1SKenneth D. Merry 
39ef270ab1SKenneth D. Merry #include "ocs.h"
40ef270ab1SKenneth D. Merry #include "ocs_os.h"
41ef270ab1SKenneth D. Merry 
42ef270ab1SKenneth D. Merry #define DEFAULT_SLAB_LEN		(64*1024)
43ef270ab1SKenneth D. Merry 
44ef270ab1SKenneth D. Merry struct ocs_array_s {
45ef270ab1SKenneth D. Merry 	ocs_os_handle_t os;
46ef270ab1SKenneth D. Merry 
47ef270ab1SKenneth D. Merry 	uint32_t size;
48ef270ab1SKenneth D. Merry 	uint32_t count;
49ef270ab1SKenneth D. Merry 
50ef270ab1SKenneth D. Merry 	uint32_t n_rows;
51ef270ab1SKenneth D. Merry 	uint32_t elems_per_row;
52ef270ab1SKenneth D. Merry 	uint32_t bytes_per_row;
53ef270ab1SKenneth D. Merry 
54ef270ab1SKenneth D. Merry 	void **array_rows;
55ef270ab1SKenneth D. Merry 	uint32_t array_rows_len;
56ef270ab1SKenneth D. Merry };
57ef270ab1SKenneth D. Merry 
58ef270ab1SKenneth D. Merry static uint32_t slab_len = DEFAULT_SLAB_LEN;
59ef270ab1SKenneth D. Merry 
60ef270ab1SKenneth D. Merry /**
61ef270ab1SKenneth D. Merry  * @brief Set array slab allocation length
62ef270ab1SKenneth D. Merry  *
63ef270ab1SKenneth D. Merry  * The slab length is the maximum allocation length that the array uses.
64ef270ab1SKenneth D. Merry  * The default 64k slab length may be overridden using this function.
65ef270ab1SKenneth D. Merry  *
66ef270ab1SKenneth D. Merry  * @param len new slab length.
67ef270ab1SKenneth D. Merry  *
68ef270ab1SKenneth D. Merry  * @return none
69ef270ab1SKenneth D. Merry  */
70ef270ab1SKenneth D. Merry void
71ef270ab1SKenneth D. Merry ocs_array_set_slablen(uint32_t len)
72ef270ab1SKenneth D. Merry {
73ef270ab1SKenneth D. Merry 	slab_len = len;
74ef270ab1SKenneth D. Merry }
75ef270ab1SKenneth D. Merry 
76ef270ab1SKenneth D. Merry /**
77ef270ab1SKenneth D. Merry  * @brief Allocate an array object
78ef270ab1SKenneth D. Merry  *
79ef270ab1SKenneth D. Merry  * An array object of size and number of elements is allocated
80ef270ab1SKenneth D. Merry  *
81ef270ab1SKenneth D. Merry  * @param os OS handle
82ef270ab1SKenneth D. Merry  * @param size size of array elements in bytes
83ef270ab1SKenneth D. Merry  * @param count number of elements in array
84ef270ab1SKenneth D. Merry  *
85ef270ab1SKenneth D. Merry  * @return pointer to array object or NULL
86ef270ab1SKenneth D. Merry  */
87ef270ab1SKenneth D. Merry ocs_array_t *
88ef270ab1SKenneth D. Merry ocs_array_alloc(ocs_os_handle_t os, uint32_t size, uint32_t count)
89ef270ab1SKenneth D. Merry {
90ef270ab1SKenneth D. Merry 	ocs_array_t *array = NULL;
91ef270ab1SKenneth D. Merry 	uint32_t i;
92ef270ab1SKenneth D. Merry 
93ef270ab1SKenneth D. Merry 	/* Fail if the item size exceeds slab_len - caller should increase slab_size,
94ef270ab1SKenneth D. Merry 	 * or not use this API.
95ef270ab1SKenneth D. Merry 	 */
96ef270ab1SKenneth D. Merry 	if (size > slab_len) {
97ef270ab1SKenneth D. Merry 		ocs_log_err(NULL, "Error: size exceeds slab length\n");
98ef270ab1SKenneth D. Merry 		return NULL;
99ef270ab1SKenneth D. Merry 	}
100ef270ab1SKenneth D. Merry 
101ef270ab1SKenneth D. Merry 	array = ocs_malloc(os, sizeof(*array), OCS_M_ZERO | OCS_M_NOWAIT);
102ef270ab1SKenneth D. Merry 	if (array == NULL) {
103ef270ab1SKenneth D. Merry 		return NULL;
104ef270ab1SKenneth D. Merry 	}
105ef270ab1SKenneth D. Merry 
106ef270ab1SKenneth D. Merry 	array->os = os;
107ef270ab1SKenneth D. Merry 	array->size = size;
108ef270ab1SKenneth D. Merry 	array->count = count;
109ef270ab1SKenneth D. Merry 	array->elems_per_row = slab_len / size;
110ef270ab1SKenneth D. Merry 	array->n_rows = (count + array->elems_per_row - 1) / array->elems_per_row;
111ef270ab1SKenneth D. Merry 	array->bytes_per_row = array->elems_per_row * array->size;
112ef270ab1SKenneth D. Merry 
113ef270ab1SKenneth D. Merry 	array->array_rows_len = array->n_rows * sizeof(*array->array_rows);
114ef270ab1SKenneth D. Merry 	array->array_rows = ocs_malloc(os, array->array_rows_len, OCS_M_ZERO | OCS_M_NOWAIT);
115ef270ab1SKenneth D. Merry 	if (array->array_rows == NULL) {
116ef270ab1SKenneth D. Merry 		ocs_array_free(array);
117ef270ab1SKenneth D. Merry 		return NULL;
118ef270ab1SKenneth D. Merry 	}
119ef270ab1SKenneth D. Merry 	for (i = 0; i < array->n_rows; i++) {
120ef270ab1SKenneth D. Merry 		array->array_rows[i] = ocs_malloc(os, array->bytes_per_row, OCS_M_ZERO | OCS_M_NOWAIT);
121ef270ab1SKenneth D. Merry 		if (array->array_rows[i] == NULL) {
122ef270ab1SKenneth D. Merry 			ocs_array_free(array);
123ef270ab1SKenneth D. Merry 			return NULL;
124ef270ab1SKenneth D. Merry 		}
125ef270ab1SKenneth D. Merry 	}
126ef270ab1SKenneth D. Merry 
127ef270ab1SKenneth D. Merry 	return array;
128ef270ab1SKenneth D. Merry }
129ef270ab1SKenneth D. Merry 
130ef270ab1SKenneth D. Merry /**
131ef270ab1SKenneth D. Merry  * @brief Free an array object
132ef270ab1SKenneth D. Merry  *
133ef270ab1SKenneth D. Merry  * Frees a prevously allocated array object
134ef270ab1SKenneth D. Merry  *
135ef270ab1SKenneth D. Merry  * @param array pointer to array object
136ef270ab1SKenneth D. Merry  *
137ef270ab1SKenneth D. Merry  * @return none
138ef270ab1SKenneth D. Merry  */
139ef270ab1SKenneth D. Merry void
140ef270ab1SKenneth D. Merry ocs_array_free(ocs_array_t *array)
141ef270ab1SKenneth D. Merry {
142ef270ab1SKenneth D. Merry 	uint32_t i;
143ef270ab1SKenneth D. Merry 
144ef270ab1SKenneth D. Merry 	if (array != NULL) {
145ef270ab1SKenneth D. Merry 		if (array->array_rows != NULL) {
146ef270ab1SKenneth D. Merry 			for (i = 0; i < array->n_rows; i++) {
147ef270ab1SKenneth D. Merry 				if (array->array_rows[i] != NULL) {
148ef270ab1SKenneth D. Merry 					ocs_free(array->os, array->array_rows[i], array->bytes_per_row);
149ef270ab1SKenneth D. Merry 				}
150ef270ab1SKenneth D. Merry 			}
151ef270ab1SKenneth D. Merry 			ocs_free(array->os, array->array_rows, array->array_rows_len);
152ef270ab1SKenneth D. Merry 		}
153ef270ab1SKenneth D. Merry 		ocs_free(array->os, array, sizeof(*array));
154ef270ab1SKenneth D. Merry 	}
155ef270ab1SKenneth D. Merry }
156ef270ab1SKenneth D. Merry 
157ef270ab1SKenneth D. Merry /**
158ef270ab1SKenneth D. Merry  * @brief Return reference to an element of an array object
159ef270ab1SKenneth D. Merry  *
160ef270ab1SKenneth D. Merry  * Return the address of an array element given an index
161ef270ab1SKenneth D. Merry  *
162ef270ab1SKenneth D. Merry  * @param array pointer to array object
163ef270ab1SKenneth D. Merry  * @param idx array element index
164ef270ab1SKenneth D. Merry  *
165ef270ab1SKenneth D. Merry  * @return rointer to array element, or NULL if index out of range
166ef270ab1SKenneth D. Merry  */
167ef270ab1SKenneth D. Merry void *ocs_array_get(ocs_array_t *array, uint32_t idx)
168ef270ab1SKenneth D. Merry {
169ef270ab1SKenneth D. Merry 	void *entry = NULL;
170ef270ab1SKenneth D. Merry 
171ef270ab1SKenneth D. Merry 	if (idx < array->count) {
172ef270ab1SKenneth D. Merry 		uint32_t row = idx / array->elems_per_row;
173ef270ab1SKenneth D. Merry 		uint32_t offset = idx % array->elems_per_row;
174ef270ab1SKenneth D. Merry 		entry = ((uint8_t*)array->array_rows[row]) + (offset * array->size);
175ef270ab1SKenneth D. Merry 	}
176ef270ab1SKenneth D. Merry 	return entry;
177ef270ab1SKenneth D. Merry }
178ef270ab1SKenneth D. Merry 
179ef270ab1SKenneth D. Merry /**
180ef270ab1SKenneth D. Merry  * @brief Return number of elements in an array
181ef270ab1SKenneth D. Merry  *
182ef270ab1SKenneth D. Merry  * Return the number of elements in an array
183ef270ab1SKenneth D. Merry  *
184ef270ab1SKenneth D. Merry  * @param array pointer to array object
185ef270ab1SKenneth D. Merry  *
186ef270ab1SKenneth D. Merry  * @return returns count of elements in an array
187ef270ab1SKenneth D. Merry  */
188ef270ab1SKenneth D. Merry uint32_t
189ef270ab1SKenneth D. Merry ocs_array_get_count(ocs_array_t *array)
190ef270ab1SKenneth D. Merry {
191ef270ab1SKenneth D. Merry 	return array->count;
192ef270ab1SKenneth D. Merry }
193ef270ab1SKenneth D. Merry 
194ef270ab1SKenneth D. Merry /**
195ef270ab1SKenneth D. Merry  * @brief Return size of array elements in bytes
196ef270ab1SKenneth D. Merry  *
197ef270ab1SKenneth D. Merry  * Returns the size in bytes of each array element
198ef270ab1SKenneth D. Merry  *
199ef270ab1SKenneth D. Merry  * @param array pointer to array object
200ef270ab1SKenneth D. Merry  *
201ef270ab1SKenneth D. Merry  * @return size of array element
202ef270ab1SKenneth D. Merry  */
203ef270ab1SKenneth D. Merry uint32_t
204ef270ab1SKenneth D. Merry ocs_array_get_size(ocs_array_t *array)
205ef270ab1SKenneth D. Merry {
206ef270ab1SKenneth D. Merry 	return array->size;
207ef270ab1SKenneth D. Merry }
208ef270ab1SKenneth D. Merry 
209ef270ab1SKenneth D. Merry /**
210ef270ab1SKenneth D. Merry  * @brief Void pointer array structure
211ef270ab1SKenneth D. Merry  *
212ef270ab1SKenneth D. Merry  * This structure describes an object consisting of an array of void
213ef270ab1SKenneth D. Merry  * pointers.   The object is allocated with a maximum array size, entries
214ef270ab1SKenneth D. Merry  * are then added to the array with while maintaining an entry count.   A set of
215ef270ab1SKenneth D. Merry  * iterator APIs are included to allow facilitate cycling through the array
216ef270ab1SKenneth D. Merry  * entries in a circular fashion.
217ef270ab1SKenneth D. Merry  *
218ef270ab1SKenneth D. Merry  */
219ef270ab1SKenneth D. Merry struct ocs_varray_s {
220ef270ab1SKenneth D. Merry 	ocs_os_handle_t os;
221ef270ab1SKenneth D. Merry 	uint32_t array_count;			/*>> maximum entry count in array */
222ef270ab1SKenneth D. Merry 	void **array;				/*>> pointer to allocated array memory */
223ef270ab1SKenneth D. Merry 	uint32_t entry_count;			/*>> number of entries added to the array */
224ef270ab1SKenneth D. Merry 	uint32_t next_index;			/*>> iterator next index */
225ef270ab1SKenneth D. Merry 	ocs_lock_t lock;			/*>> iterator lock */
226ef270ab1SKenneth D. Merry };
227ef270ab1SKenneth D. Merry 
228ef270ab1SKenneth D. Merry /**
229ef270ab1SKenneth D. Merry  * @brief Allocate a void pointer array
230ef270ab1SKenneth D. Merry  *
231ef270ab1SKenneth D. Merry  * A void pointer array of given length is allocated.
232ef270ab1SKenneth D. Merry  *
233ef270ab1SKenneth D. Merry  * @param os OS handle
234ef270ab1SKenneth D. Merry  * @param array_count Array size
235ef270ab1SKenneth D. Merry  *
236ef270ab1SKenneth D. Merry  * @return returns a pointer to the ocs_varray_t object, other NULL on error
237ef270ab1SKenneth D. Merry  */
238ef270ab1SKenneth D. Merry ocs_varray_t *
239ef270ab1SKenneth D. Merry ocs_varray_alloc(ocs_os_handle_t os, uint32_t array_count)
240ef270ab1SKenneth D. Merry {
241ef270ab1SKenneth D. Merry 	ocs_varray_t *va;
242ef270ab1SKenneth D. Merry 
243ef270ab1SKenneth D. Merry 	va = ocs_malloc(os, sizeof(*va), OCS_M_ZERO | OCS_M_NOWAIT);
244ef270ab1SKenneth D. Merry 	if (va != NULL) {
245ef270ab1SKenneth D. Merry 		va->os = os;
246ef270ab1SKenneth D. Merry 		va->array_count = array_count;
247ef270ab1SKenneth D. Merry 		va->array = ocs_malloc(os, sizeof(*va->array) * va->array_count, OCS_M_ZERO | OCS_M_NOWAIT);
248ef270ab1SKenneth D. Merry 		if (va->array != NULL) {
249ef270ab1SKenneth D. Merry 			va->next_index = 0;
250ef270ab1SKenneth D. Merry 			ocs_lock_init(os, &va->lock, "varray:%p", va);
251ef270ab1SKenneth D. Merry 		} else {
252ef270ab1SKenneth D. Merry 			ocs_free(os, va, sizeof(*va));
253ef270ab1SKenneth D. Merry 			va = NULL;
254ef270ab1SKenneth D. Merry 		}
255ef270ab1SKenneth D. Merry 	}
256ef270ab1SKenneth D. Merry 	return va;
257ef270ab1SKenneth D. Merry }
258ef270ab1SKenneth D. Merry 
259ef270ab1SKenneth D. Merry /**
260ef270ab1SKenneth D. Merry  * @brief Free a void pointer array
261ef270ab1SKenneth D. Merry  *
262ef270ab1SKenneth D. Merry  * The void pointer array object is free'd
263ef270ab1SKenneth D. Merry  *
264ef270ab1SKenneth D. Merry  * @param va Pointer to void pointer array
265ef270ab1SKenneth D. Merry  *
266ef270ab1SKenneth D. Merry  * @return none
267ef270ab1SKenneth D. Merry  */
268ef270ab1SKenneth D. Merry void
269ef270ab1SKenneth D. Merry ocs_varray_free(ocs_varray_t *va)
270ef270ab1SKenneth D. Merry {
271ef270ab1SKenneth D. Merry 	if (va != NULL) {
272ef270ab1SKenneth D. Merry 		ocs_lock_free(&va->lock);
273ef270ab1SKenneth D. Merry 		if (va->array != NULL) {
274ef270ab1SKenneth D. Merry 			ocs_free(va->os, va->array, sizeof(*va->array) * va->array_count);
275ef270ab1SKenneth D. Merry 		}
276ef270ab1SKenneth D. Merry 		ocs_free(va->os, va, sizeof(*va));
277ef270ab1SKenneth D. Merry 	}
278ef270ab1SKenneth D. Merry }
279ef270ab1SKenneth D. Merry 
280ef270ab1SKenneth D. Merry /**
281ef270ab1SKenneth D. Merry  * @brief Add an entry to a void pointer array
282ef270ab1SKenneth D. Merry  *
283ef270ab1SKenneth D. Merry  * An entry is added to the void pointer array
284ef270ab1SKenneth D. Merry  *
285ef270ab1SKenneth D. Merry  * @param va Pointer to void pointer array
286ef270ab1SKenneth D. Merry  * @param entry Pointer to entry to add
287ef270ab1SKenneth D. Merry  *
288ef270ab1SKenneth D. Merry  * @return returns 0 if entry was added, -1 if there is no more space in the array
289ef270ab1SKenneth D. Merry  */
290ef270ab1SKenneth D. Merry int32_t
291ef270ab1SKenneth D. Merry ocs_varray_add(ocs_varray_t *va, void *entry)
292ef270ab1SKenneth D. Merry {
293ef270ab1SKenneth D. Merry 	uint32_t rc = -1;
294ef270ab1SKenneth D. Merry 
295ef270ab1SKenneth D. Merry 	ocs_lock(&va->lock);
296ef270ab1SKenneth D. Merry 		if (va->entry_count < va->array_count) {
297ef270ab1SKenneth D. Merry 			va->array[va->entry_count++] = entry;
298ef270ab1SKenneth D. Merry 			rc = 0;
299ef270ab1SKenneth D. Merry 		}
300ef270ab1SKenneth D. Merry 	ocs_unlock(&va->lock);
301ef270ab1SKenneth D. Merry 
302ef270ab1SKenneth D. Merry 	return rc;
303ef270ab1SKenneth D. Merry }
304ef270ab1SKenneth D. Merry 
305ef270ab1SKenneth D. Merry /**
306ef270ab1SKenneth D. Merry  * @brief Reset the void pointer array iterator
307ef270ab1SKenneth D. Merry  *
308ef270ab1SKenneth D. Merry  * The next index value of the void pointer array iterator is cleared.
309ef270ab1SKenneth D. Merry  *
310ef270ab1SKenneth D. Merry  * @param va Pointer to void pointer array
311ef270ab1SKenneth D. Merry  *
312ef270ab1SKenneth D. Merry  * @return none
313ef270ab1SKenneth D. Merry  */
314ef270ab1SKenneth D. Merry void
315ef270ab1SKenneth D. Merry ocs_varray_iter_reset(ocs_varray_t *va)
316ef270ab1SKenneth D. Merry {
317ef270ab1SKenneth D. Merry 	ocs_lock(&va->lock);
318ef270ab1SKenneth D. Merry 		va->next_index = 0;
319ef270ab1SKenneth D. Merry 	ocs_unlock(&va->lock);
320ef270ab1SKenneth D. Merry }
321ef270ab1SKenneth D. Merry 
322ef270ab1SKenneth D. Merry /**
323ef270ab1SKenneth D. Merry  * @brief Return next entry from a void pointer array
324ef270ab1SKenneth D. Merry  *
325ef270ab1SKenneth D. Merry  * The next entry in the void pointer array is returned.
326ef270ab1SKenneth D. Merry  *
327ef270ab1SKenneth D. Merry  * @param va Pointer to void point array
328ef270ab1SKenneth D. Merry  *
329ef270ab1SKenneth D. Merry  * Note: takes the void pointer array lock
330ef270ab1SKenneth D. Merry  *
331ef270ab1SKenneth D. Merry  * @return returns next void pointer entry
332ef270ab1SKenneth D. Merry  */
333ef270ab1SKenneth D. Merry void *
334ef270ab1SKenneth D. Merry ocs_varray_iter_next(ocs_varray_t *va)
335ef270ab1SKenneth D. Merry {
336ef270ab1SKenneth D. Merry 	void *rval = NULL;
337ef270ab1SKenneth D. Merry 
338ef270ab1SKenneth D. Merry 	if (va != NULL) {
339ef270ab1SKenneth D. Merry 		ocs_lock(&va->lock);
340ef270ab1SKenneth D. Merry 			rval = _ocs_varray_iter_next(va);
341ef270ab1SKenneth D. Merry 		ocs_unlock(&va->lock);
342ef270ab1SKenneth D. Merry 	}
343ef270ab1SKenneth D. Merry 	return rval;
344ef270ab1SKenneth D. Merry }
345ef270ab1SKenneth D. Merry 
346ef270ab1SKenneth D. Merry /**
347ef270ab1SKenneth D. Merry  * @brief Return next entry from a void pointer array
348ef270ab1SKenneth D. Merry  *
349ef270ab1SKenneth D. Merry  * The next entry in the void pointer array is returned.
350ef270ab1SKenneth D. Merry  *
351ef270ab1SKenneth D. Merry  * @param va Pointer to void point array
352ef270ab1SKenneth D. Merry  *
353ef270ab1SKenneth D. Merry  * Note: doesn't take the void pointer array lock
354ef270ab1SKenneth D. Merry  *
355ef270ab1SKenneth D. Merry  * @return returns next void pointer entry
356ef270ab1SKenneth D. Merry  */
357ef270ab1SKenneth D. Merry void *
358ef270ab1SKenneth D. Merry _ocs_varray_iter_next(ocs_varray_t *va)
359ef270ab1SKenneth D. Merry {
360ef270ab1SKenneth D. Merry 	void *rval;
361ef270ab1SKenneth D. Merry 
362ef270ab1SKenneth D. Merry 	rval = va->array[va->next_index];
363ef270ab1SKenneth D. Merry 	if (++va->next_index >= va->entry_count) {
364ef270ab1SKenneth D. Merry 		va->next_index = 0;
365ef270ab1SKenneth D. Merry 	}
366ef270ab1SKenneth D. Merry 	return rval;
367ef270ab1SKenneth D. Merry }
368ef270ab1SKenneth D. Merry 
369ef270ab1SKenneth D. Merry /**
370ef270ab1SKenneth D. Merry  * @brief Take void pointer array lock
371ef270ab1SKenneth D. Merry  *
372ef270ab1SKenneth D. Merry  * Takes the lock for the given void pointer array
373ef270ab1SKenneth D. Merry  *
374ef270ab1SKenneth D. Merry  * @param va Pointer to void pointer array
375ef270ab1SKenneth D. Merry  *
376ef270ab1SKenneth D. Merry  * @return none
377ef270ab1SKenneth D. Merry  */
378ef270ab1SKenneth D. Merry void
379ef270ab1SKenneth D. Merry ocs_varray_lock(ocs_varray_t *va)
380ef270ab1SKenneth D. Merry {
381ef270ab1SKenneth D. Merry 	ocs_lock(&va->lock);
382ef270ab1SKenneth D. Merry }
383ef270ab1SKenneth D. Merry 
384ef270ab1SKenneth D. Merry /**
385ef270ab1SKenneth D. Merry  * @brief Release void pointer array lock
386ef270ab1SKenneth D. Merry  *
387ef270ab1SKenneth D. Merry  * Releases the lock for the given void pointer array
388ef270ab1SKenneth D. Merry  *
389ef270ab1SKenneth D. Merry  * @param va Pointer to void pointer array
390ef270ab1SKenneth D. Merry  *
391ef270ab1SKenneth D. Merry  * @return none
392ef270ab1SKenneth D. Merry  */
393ef270ab1SKenneth D. Merry void
394ef270ab1SKenneth D. Merry ocs_varray_unlock(ocs_varray_t *va)
395ef270ab1SKenneth D. Merry {
396ef270ab1SKenneth D. Merry 	ocs_unlock(&va->lock);
397ef270ab1SKenneth D. Merry }
398ef270ab1SKenneth D. Merry 
399ef270ab1SKenneth D. Merry /**
400ef270ab1SKenneth D. Merry  * @brief Return entry count for a void pointer array
401ef270ab1SKenneth D. Merry  *
402ef270ab1SKenneth D. Merry  * The entry count for a void pointer array is returned
403ef270ab1SKenneth D. Merry  *
404ef270ab1SKenneth D. Merry  * @param va Pointer to void pointer array
405ef270ab1SKenneth D. Merry  *
406ef270ab1SKenneth D. Merry  * @return returns entry count
407ef270ab1SKenneth D. Merry  */
408ef270ab1SKenneth D. Merry uint32_t
409ef270ab1SKenneth D. Merry ocs_varray_get_count(ocs_varray_t *va)
410ef270ab1SKenneth D. Merry {
411ef270ab1SKenneth D. Merry 	uint32_t rc;
412ef270ab1SKenneth D. Merry 
413ef270ab1SKenneth D. Merry 	ocs_lock(&va->lock);
414ef270ab1SKenneth D. Merry 		rc = va->entry_count;
415ef270ab1SKenneth D. Merry 	ocs_unlock(&va->lock);
416ef270ab1SKenneth D. Merry 	return rc;
417ef270ab1SKenneth D. Merry }
418ef270ab1SKenneth D. Merry 
419ef270ab1SKenneth D. Merry 
420ef270ab1SKenneth D. Merry struct ocs_cbuf_s {
421ef270ab1SKenneth D. Merry 	ocs_os_handle_t os;		/*<< OS handle */
422ef270ab1SKenneth D. Merry 	uint32_t entry_count;		/*<< entry count */
423ef270ab1SKenneth D. Merry 	void **array;			/*<< pointer to array of cbuf pointers */
424ef270ab1SKenneth D. Merry 	uint32_t pidx;			/*<< producer index */
425ef270ab1SKenneth D. Merry 	uint32_t cidx;			/*<< consumer index */
426ef270ab1SKenneth D. Merry 	ocs_lock_t cbuf_plock;		/*<< idx lock */
427ef270ab1SKenneth D. Merry 	ocs_lock_t cbuf_clock;		/*<< idx lock */
428ef270ab1SKenneth D. Merry 	ocs_sem_t cbuf_psem;		/*<< cbuf producer counting semaphore */
429ef270ab1SKenneth D. Merry 	ocs_sem_t cbuf_csem;		/*<< cbuf consumer counting semaphore */
430ef270ab1SKenneth D. Merry };
431ef270ab1SKenneth D. Merry 
432ef270ab1SKenneth D. Merry /**
433ef270ab1SKenneth D. Merry  * @brief Initialize a circular buffer queue
434ef270ab1SKenneth D. Merry  *
435ef270ab1SKenneth D. Merry  * A circular buffer with producer/consumer API is allocated
436ef270ab1SKenneth D. Merry  *
437ef270ab1SKenneth D. Merry  * @param os OS handle
438ef270ab1SKenneth D. Merry  * @param entry_count count of entries
439ef270ab1SKenneth D. Merry  *
440ef270ab1SKenneth D. Merry  * @return returns pointer to circular buffer, or NULL
441ef270ab1SKenneth D. Merry  */
442ef270ab1SKenneth D. Merry ocs_cbuf_t*
443ef270ab1SKenneth D. Merry ocs_cbuf_alloc(ocs_os_handle_t os, uint32_t entry_count)
444ef270ab1SKenneth D. Merry {
445ef270ab1SKenneth D. Merry 	ocs_cbuf_t *cbuf;
446ef270ab1SKenneth D. Merry 
447ef270ab1SKenneth D. Merry 	cbuf = ocs_malloc(os, sizeof(*cbuf), OCS_M_NOWAIT | OCS_M_ZERO);
448ef270ab1SKenneth D. Merry 	if (cbuf == NULL) {
449ef270ab1SKenneth D. Merry 		return NULL;
450ef270ab1SKenneth D. Merry 	}
451ef270ab1SKenneth D. Merry 
452ef270ab1SKenneth D. Merry 	cbuf->os = os;
453ef270ab1SKenneth D. Merry 	cbuf->entry_count = entry_count;
454ef270ab1SKenneth D. Merry 	cbuf->pidx = 0;
455ef270ab1SKenneth D. Merry 	cbuf->cidx = 0;
456ef270ab1SKenneth D. Merry 
457ef270ab1SKenneth D. Merry 	ocs_lock_init(NULL, &cbuf->cbuf_clock, "cbuf_c:%p", cbuf);
458ef270ab1SKenneth D. Merry 	ocs_lock_init(NULL, &cbuf->cbuf_plock, "cbuf_p:%p", cbuf);
459ef270ab1SKenneth D. Merry 	ocs_sem_init(&cbuf->cbuf_csem, 0, "cbuf:%p", cbuf);
460ef270ab1SKenneth D. Merry 	ocs_sem_init(&cbuf->cbuf_psem, cbuf->entry_count, "cbuf:%p", cbuf);
461ef270ab1SKenneth D. Merry 
462ef270ab1SKenneth D. Merry 	cbuf->array = ocs_malloc(os, entry_count * sizeof(*cbuf->array), OCS_M_NOWAIT | OCS_M_ZERO);
463ef270ab1SKenneth D. Merry 	if (cbuf->array == NULL) {
464ef270ab1SKenneth D. Merry 		ocs_cbuf_free(cbuf);
465ef270ab1SKenneth D. Merry 		return NULL;
466ef270ab1SKenneth D. Merry 	}
467ef270ab1SKenneth D. Merry 
468ef270ab1SKenneth D. Merry 	return cbuf;
469ef270ab1SKenneth D. Merry }
470ef270ab1SKenneth D. Merry 
471ef270ab1SKenneth D. Merry /**
472ef270ab1SKenneth D. Merry  * @brief Free a circular buffer
473ef270ab1SKenneth D. Merry  *
474ef270ab1SKenneth D. Merry  * The memory resources of a circular buffer are free'd
475ef270ab1SKenneth D. Merry  *
476ef270ab1SKenneth D. Merry  * @param cbuf pointer to circular buffer
477ef270ab1SKenneth D. Merry  *
478ef270ab1SKenneth D. Merry  * @return none
479ef270ab1SKenneth D. Merry  */
480ef270ab1SKenneth D. Merry void
481ef270ab1SKenneth D. Merry ocs_cbuf_free(ocs_cbuf_t *cbuf)
482ef270ab1SKenneth D. Merry {
483ef270ab1SKenneth D. Merry 	if (cbuf != NULL) {
484ef270ab1SKenneth D. Merry 		if (cbuf->array != NULL) {
485ef270ab1SKenneth D. Merry 			ocs_free(cbuf->os, cbuf->array, sizeof(*cbuf->array) * cbuf->entry_count);
486ef270ab1SKenneth D. Merry 		}
487ef270ab1SKenneth D. Merry 		ocs_lock_free(&cbuf->cbuf_clock);
488ef270ab1SKenneth D. Merry 		ocs_lock_free(&cbuf->cbuf_plock);
489ef270ab1SKenneth D. Merry 		ocs_free(cbuf->os, cbuf, sizeof(*cbuf));
490ef270ab1SKenneth D. Merry 	}
491ef270ab1SKenneth D. Merry }
492ef270ab1SKenneth D. Merry 
493ef270ab1SKenneth D. Merry /**
494ef270ab1SKenneth D. Merry  * @brief Get pointer to buffer
495ef270ab1SKenneth D. Merry  *
496ef270ab1SKenneth D. Merry  * Wait for a buffer to become available, and return a pointer to the buffer.
497ef270ab1SKenneth D. Merry  *
498ef270ab1SKenneth D. Merry  * @param cbuf pointer to circular buffer
499ef270ab1SKenneth D. Merry  * @param timeout_usec timeout in microseconds
500ef270ab1SKenneth D. Merry  *
501ef270ab1SKenneth D. Merry  * @return pointer to buffer, or NULL if timeout
502ef270ab1SKenneth D. Merry  */
503ef270ab1SKenneth D. Merry void*
504ef270ab1SKenneth D. Merry ocs_cbuf_get(ocs_cbuf_t *cbuf, int32_t timeout_usec)
505ef270ab1SKenneth D. Merry {
506ef270ab1SKenneth D. Merry 	void *ret = NULL;
507ef270ab1SKenneth D. Merry 
508ef270ab1SKenneth D. Merry 	if (likely(ocs_sem_p(&cbuf->cbuf_csem, timeout_usec) == 0)) {
509ef270ab1SKenneth D. Merry 		ocs_lock(&cbuf->cbuf_clock);
510ef270ab1SKenneth D. Merry 			ret = cbuf->array[cbuf->cidx];
511ef270ab1SKenneth D. Merry 			if (unlikely(++cbuf->cidx >= cbuf->entry_count)) {
512ef270ab1SKenneth D. Merry 				cbuf->cidx = 0;
513ef270ab1SKenneth D. Merry 			}
514ef270ab1SKenneth D. Merry 		ocs_unlock(&cbuf->cbuf_clock);
515ef270ab1SKenneth D. Merry 		ocs_sem_v(&cbuf->cbuf_psem);
516ef270ab1SKenneth D. Merry 	}
517ef270ab1SKenneth D. Merry 	return ret;
518ef270ab1SKenneth D. Merry }
519ef270ab1SKenneth D. Merry 
520ef270ab1SKenneth D. Merry /**
521ef270ab1SKenneth D. Merry  * @brief write a buffer
522ef270ab1SKenneth D. Merry  *
523ef270ab1SKenneth D. Merry  * The buffer is written to the circular buffer.
524ef270ab1SKenneth D. Merry  *
525ef270ab1SKenneth D. Merry  * @param cbuf pointer to circular buffer
526ef270ab1SKenneth D. Merry  * @param elem pointer to entry
527ef270ab1SKenneth D. Merry  *
528ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
529ef270ab1SKenneth D. Merry  */
530ef270ab1SKenneth D. Merry int32_t
531ef270ab1SKenneth D. Merry ocs_cbuf_put(ocs_cbuf_t *cbuf, void *elem)
532ef270ab1SKenneth D. Merry {
533ef270ab1SKenneth D. Merry 	int32_t rc = 0;
534ef270ab1SKenneth D. Merry 
535ef270ab1SKenneth D. Merry 	if (likely(ocs_sem_p(&cbuf->cbuf_psem, -1) == 0)) {
536ef270ab1SKenneth D. Merry 		ocs_lock(&cbuf->cbuf_plock);
537ef270ab1SKenneth D. Merry 			cbuf->array[cbuf->pidx] = elem;
538ef270ab1SKenneth D. Merry 			if (unlikely(++cbuf->pidx >= cbuf->entry_count)) {
539ef270ab1SKenneth D. Merry 				cbuf->pidx = 0;
540ef270ab1SKenneth D. Merry 			}
541ef270ab1SKenneth D. Merry 		ocs_unlock(&cbuf->cbuf_plock);
542ef270ab1SKenneth D. Merry 		ocs_sem_v(&cbuf->cbuf_csem);
543ef270ab1SKenneth D. Merry 	} else {
544ef270ab1SKenneth D. Merry 		rc = -1;
545ef270ab1SKenneth D. Merry 	}
546ef270ab1SKenneth D. Merry 	return rc;
547ef270ab1SKenneth D. Merry }
548ef270ab1SKenneth D. Merry 
549ef270ab1SKenneth D. Merry /**
550ef270ab1SKenneth D. Merry  * @brief Prime a circular buffer data
551ef270ab1SKenneth D. Merry  *
552ef270ab1SKenneth D. Merry  * Post array buffers to a circular buffer
553ef270ab1SKenneth D. Merry  *
554ef270ab1SKenneth D. Merry  * @param cbuf pointer to circular buffer
555ef270ab1SKenneth D. Merry  * @param array pointer to buffer array
556ef270ab1SKenneth D. Merry  *
557ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
558ef270ab1SKenneth D. Merry  */
559ef270ab1SKenneth D. Merry int32_t
560ef270ab1SKenneth D. Merry ocs_cbuf_prime(ocs_cbuf_t *cbuf, ocs_array_t *array)
561ef270ab1SKenneth D. Merry {
562ef270ab1SKenneth D. Merry 	uint32_t i;
563ef270ab1SKenneth D. Merry 	uint32_t count = MIN(ocs_array_get_count(array), cbuf->entry_count);
564ef270ab1SKenneth D. Merry 
565ef270ab1SKenneth D. Merry 	for (i = 0; i < count; i++) {
566ef270ab1SKenneth D. Merry 		ocs_cbuf_put(cbuf, ocs_array_get(array, i));
567ef270ab1SKenneth D. Merry 	}
568ef270ab1SKenneth D. Merry 	return 0;
569ef270ab1SKenneth D. Merry }
570ef270ab1SKenneth D. Merry 
571ef270ab1SKenneth D. Merry /**
572ef270ab1SKenneth D. Merry  * @brief Generate driver dump start of file information
573ef270ab1SKenneth D. Merry  *
574ef270ab1SKenneth D. Merry  * The start of file information is added to 'textbuf'
575ef270ab1SKenneth D. Merry  *
576ef270ab1SKenneth D. Merry  * @param textbuf pointer to driver dump text buffer
577ef270ab1SKenneth D. Merry  *
578ef270ab1SKenneth D. Merry  * @return none
579ef270ab1SKenneth D. Merry  */
580ef270ab1SKenneth D. Merry 
581ef270ab1SKenneth D. Merry void
582ef270ab1SKenneth D. Merry ocs_ddump_startfile(ocs_textbuf_t *textbuf)
583ef270ab1SKenneth D. Merry {
584ef270ab1SKenneth D. Merry 	ocs_textbuf_printf(textbuf, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n");
585ef270ab1SKenneth D. Merry }
586ef270ab1SKenneth D. Merry 
587ef270ab1SKenneth D. Merry /**
588ef270ab1SKenneth D. Merry  * @brief Generate driver dump end of file information
589ef270ab1SKenneth D. Merry  *
590ef270ab1SKenneth D. Merry  * The end of file information is added to 'textbuf'
591ef270ab1SKenneth D. Merry  *
592ef270ab1SKenneth D. Merry  * @param textbuf pointer to driver dump text buffer
593ef270ab1SKenneth D. Merry  *
594ef270ab1SKenneth D. Merry  * @return none
595ef270ab1SKenneth D. Merry  */
596ef270ab1SKenneth D. Merry 
597ef270ab1SKenneth D. Merry void
598ef270ab1SKenneth D. Merry ocs_ddump_endfile(ocs_textbuf_t *textbuf)
599ef270ab1SKenneth D. Merry {
600ef270ab1SKenneth D. Merry }
601ef270ab1SKenneth D. Merry 
602ef270ab1SKenneth D. Merry /**
603ef270ab1SKenneth D. Merry  * @brief Generate driver dump section start data
604ef270ab1SKenneth D. Merry  *
605ef270ab1SKenneth D. Merry  * The driver section start information is added to textbuf
606ef270ab1SKenneth D. Merry  *
607ef270ab1SKenneth D. Merry  * @param textbuf pointer to text buffer
608ef270ab1SKenneth D. Merry  * @param name name of section
609ef270ab1SKenneth D. Merry  * @param instance instance number of this section
610ef270ab1SKenneth D. Merry  *
611ef270ab1SKenneth D. Merry  * @return none
612ef270ab1SKenneth D. Merry  */
613ef270ab1SKenneth D. Merry 
614ef270ab1SKenneth D. Merry void
615ef270ab1SKenneth D. Merry ocs_ddump_section(ocs_textbuf_t *textbuf, const char *name, uint32_t instance)
616ef270ab1SKenneth D. Merry {
617ef270ab1SKenneth D. Merry 	ocs_textbuf_printf(textbuf, "<%s type=\"section\" instance=\"%d\">\n", name, instance);
618ef270ab1SKenneth D. Merry }
619ef270ab1SKenneth D. Merry 
620ef270ab1SKenneth D. Merry /**
621ef270ab1SKenneth D. Merry  * @brief Generate driver dump section end data
622ef270ab1SKenneth D. Merry  *
623ef270ab1SKenneth D. Merry  * The driver section end information is added to textbuf
624ef270ab1SKenneth D. Merry  *
625ef270ab1SKenneth D. Merry  * @param textbuf pointer to text buffer
626ef270ab1SKenneth D. Merry  * @param name name of section
627ef270ab1SKenneth D. Merry  * @param instance instance number of this section
628ef270ab1SKenneth D. Merry  *
629ef270ab1SKenneth D. Merry  * @return none
630ef270ab1SKenneth D. Merry  */
631ef270ab1SKenneth D. Merry 
632ef270ab1SKenneth D. Merry void
633ef270ab1SKenneth D. Merry ocs_ddump_endsection(ocs_textbuf_t *textbuf, const char *name, uint32_t instance)
634ef270ab1SKenneth D. Merry {
635ef270ab1SKenneth D. Merry 	ocs_textbuf_printf(textbuf, "</%s>\n", name);
636ef270ab1SKenneth D. Merry }
637ef270ab1SKenneth D. Merry 
638ef270ab1SKenneth D. Merry /**
639ef270ab1SKenneth D. Merry  * @brief Generate driver dump data for a given value
640ef270ab1SKenneth D. Merry  *
641ef270ab1SKenneth D. Merry  * A value is added to textbuf
642ef270ab1SKenneth D. Merry  *
643ef270ab1SKenneth D. Merry  * @param textbuf pointer to text buffer
644ef270ab1SKenneth D. Merry  * @param name name of variable
645ef270ab1SKenneth D. Merry  * @param fmt snprintf format specifier
646ef270ab1SKenneth D. Merry  *
647ef270ab1SKenneth D. Merry  * @return none
648ef270ab1SKenneth D. Merry  */
649ef270ab1SKenneth D. Merry 
650ef270ab1SKenneth D. Merry void
651ef270ab1SKenneth D. Merry ocs_ddump_value(ocs_textbuf_t *textbuf, const char *name, const char *fmt, ...)
652ef270ab1SKenneth D. Merry {
653ef270ab1SKenneth D. Merry 	va_list ap;
654ef270ab1SKenneth D. Merry 	char valuebuf[64];
655ef270ab1SKenneth D. Merry 
656ef270ab1SKenneth D. Merry 	va_start(ap, fmt);
657ef270ab1SKenneth D. Merry 	vsnprintf(valuebuf, sizeof(valuebuf), fmt, ap);
658ef270ab1SKenneth D. Merry 	va_end(ap);
659ef270ab1SKenneth D. Merry 
660ef270ab1SKenneth D. Merry 	ocs_textbuf_printf(textbuf, "<%s>%s</%s>\n", name, valuebuf, name);
661ef270ab1SKenneth D. Merry }
662ef270ab1SKenneth D. Merry 
663ef270ab1SKenneth D. Merry 
664ef270ab1SKenneth D. Merry /**
665ef270ab1SKenneth D. Merry  * @brief Generate driver dump data for an arbitrary buffer of DWORDS
666ef270ab1SKenneth D. Merry  *
667ef270ab1SKenneth D. Merry  * A status value is added to textbuf
668ef270ab1SKenneth D. Merry  *
669ef270ab1SKenneth D. Merry  * @param textbuf pointer to text buffer
670ef270ab1SKenneth D. Merry  * @param name name of status variable
671ef270ab1SKenneth D. Merry  * @param instance instance number of this section
672ef270ab1SKenneth D. Merry  * @param buffer buffer to print
673ef270ab1SKenneth D. Merry  * @param size size of buffer in bytes
674ef270ab1SKenneth D. Merry  *
675ef270ab1SKenneth D. Merry  * @return none
676ef270ab1SKenneth D. Merry  */
677ef270ab1SKenneth D. Merry 
678ef270ab1SKenneth D. Merry void
679ef270ab1SKenneth D. Merry ocs_ddump_buffer(ocs_textbuf_t *textbuf, const char *name, uint32_t instance, void *buffer, uint32_t size)
680ef270ab1SKenneth D. Merry {
681ef270ab1SKenneth D. Merry 	uint32_t *dword;
682ef270ab1SKenneth D. Merry 	uint32_t i;
683ef270ab1SKenneth D. Merry 	uint32_t count;
684ef270ab1SKenneth D. Merry 
685ef270ab1SKenneth D. Merry 	count = size / sizeof(uint32_t);
686ef270ab1SKenneth D. Merry 
687ef270ab1SKenneth D. Merry 	if (count == 0) {
688ef270ab1SKenneth D. Merry 		return;
689ef270ab1SKenneth D. Merry 	}
690ef270ab1SKenneth D. Merry 
691ef270ab1SKenneth D. Merry 	ocs_textbuf_printf(textbuf, "<%s type=\"buffer\" instance=\"%d\">\n", name, instance);
692ef270ab1SKenneth D. Merry 
693ef270ab1SKenneth D. Merry 	dword = buffer;
694ef270ab1SKenneth D. Merry 	for (i = 0; i < count; i++) {
695ef270ab1SKenneth D. Merry #define OCS_NEWLINE_MOD	8
696ef270ab1SKenneth D. Merry 		ocs_textbuf_printf(textbuf, "%08x ", *dword++);
697ef270ab1SKenneth D. Merry 		if ((i % OCS_NEWLINE_MOD) == (OCS_NEWLINE_MOD - 1)) {
698ef270ab1SKenneth D. Merry 			ocs_textbuf_printf(textbuf, "\n");
699ef270ab1SKenneth D. Merry 		}
700ef270ab1SKenneth D. Merry 	}
701ef270ab1SKenneth D. Merry 
702ef270ab1SKenneth D. Merry 	ocs_textbuf_printf(textbuf, "</%s>\n", name);
703ef270ab1SKenneth D. Merry }
704ef270ab1SKenneth D. Merry 
705ef270ab1SKenneth D. Merry /**
706ef270ab1SKenneth D. Merry  * @brief Generate driver dump for queue
707ef270ab1SKenneth D. Merry  *
708ef270ab1SKenneth D. Merry  * Add queue elements to text buffer
709ef270ab1SKenneth D. Merry  *
710ef270ab1SKenneth D. Merry  * @param textbuf pointer to driver dump text buffer
711ef270ab1SKenneth D. Merry  * @param q_addr address of start of queue
712ef270ab1SKenneth D. Merry  * @param size size of each queue entry
713ef270ab1SKenneth D. Merry  * @param length number of queue entries in the queue
714ef270ab1SKenneth D. Merry  * @param index current index of queue
715ef270ab1SKenneth D. Merry  * @param qentries number of most recent queue entries to dump
716ef270ab1SKenneth D. Merry  *
717ef270ab1SKenneth D. Merry  * @return none
718ef270ab1SKenneth D. Merry  */
719ef270ab1SKenneth D. Merry 
720ef270ab1SKenneth D. Merry void
721ef270ab1SKenneth D. Merry ocs_ddump_queue_entries(ocs_textbuf_t *textbuf, void *q_addr, uint32_t size,
722ef270ab1SKenneth D. Merry 			uint32_t length, int32_t index, uint32_t qentries)
723ef270ab1SKenneth D. Merry {
724ef270ab1SKenneth D. Merry 	uint32_t i;
725ef270ab1SKenneth D. Merry 	uint32_t j;
726ef270ab1SKenneth D. Merry 	uint8_t *entry;
727ef270ab1SKenneth D. Merry 	uint32_t *dword;
728ef270ab1SKenneth D. Merry 	uint32_t entry_count = 0;
729ef270ab1SKenneth D. Merry 	uint32_t entry_words = size / sizeof(uint32_t);
730ef270ab1SKenneth D. Merry 
731ef270ab1SKenneth D. Merry 	if ((qentries == (uint32_t)-1) || (qentries > length)) {
732ef270ab1SKenneth D. Merry 		/* if qentries is -1 or larger than queue size, dump entire queue */
733ef270ab1SKenneth D. Merry 		entry_count = length;
734ef270ab1SKenneth D. Merry 		index = 0;
735ef270ab1SKenneth D. Merry 	} else {
736ef270ab1SKenneth D. Merry 		entry_count = qentries;
737ef270ab1SKenneth D. Merry 
738ef270ab1SKenneth D. Merry 		index -= (qentries - 1);
739ef270ab1SKenneth D. Merry 		if (index < 0) {
740ef270ab1SKenneth D. Merry 			index += length;
741ef270ab1SKenneth D. Merry 		}
742ef270ab1SKenneth D. Merry 
743ef270ab1SKenneth D. Merry 	}
744ef270ab1SKenneth D. Merry #define OCS_NEWLINE_MOD	8
745ef270ab1SKenneth D. Merry 	ocs_textbuf_printf(textbuf, "<qentries>\n");
746ef270ab1SKenneth D. Merry 	for (i = 0; i < entry_count; i++){
747ef270ab1SKenneth D. Merry 		entry = q_addr;
748ef270ab1SKenneth D. Merry 		entry += index * size;
749ef270ab1SKenneth D. Merry 		dword = (uint32_t *)entry;
750ef270ab1SKenneth D. Merry 
751ef270ab1SKenneth D. Merry 		ocs_textbuf_printf(textbuf, "[%04x] ", index);
752ef270ab1SKenneth D. Merry 		for (j = 0; j < entry_words; j++) {
753ef270ab1SKenneth D. Merry 			ocs_textbuf_printf(textbuf, "%08x ", *dword++);
754ef270ab1SKenneth D. Merry 			if (((j+1) == entry_words) ||
755ef270ab1SKenneth D. Merry 			    ((j % OCS_NEWLINE_MOD) == (OCS_NEWLINE_MOD - 1))) {
756ef270ab1SKenneth D. Merry 				ocs_textbuf_printf(textbuf, "\n");
757ef270ab1SKenneth D. Merry 				if ((j+1) < entry_words) {
758ef270ab1SKenneth D. Merry 					ocs_textbuf_printf(textbuf, "       ");
759ef270ab1SKenneth D. Merry 				}
760ef270ab1SKenneth D. Merry 			}
761ef270ab1SKenneth D. Merry 		}
762ef270ab1SKenneth D. Merry 
763ef270ab1SKenneth D. Merry 		index++;
764ef270ab1SKenneth D. Merry 		if ((uint32_t)index >= length) {
765ef270ab1SKenneth D. Merry 			index = 0;
766ef270ab1SKenneth D. Merry 		}
767ef270ab1SKenneth D. Merry 	}
768ef270ab1SKenneth D. Merry 	ocs_textbuf_printf(textbuf, "</qentries>\n");
769ef270ab1SKenneth D. Merry }
770ef270ab1SKenneth D. Merry 
771ef270ab1SKenneth D. Merry 
772ef270ab1SKenneth D. Merry #define OCS_DEBUG_ENABLE(x)	(x ? ~0 : 0)
773ef270ab1SKenneth D. Merry 
774ef270ab1SKenneth D. Merry #define OCS_DEBUG_MASK \
775ef270ab1SKenneth D. Merry 	(OCS_DEBUG_ENABLE(1)	& OCS_DEBUG_ALWAYS)  | \
776ef270ab1SKenneth D. Merry 	(OCS_DEBUG_ENABLE(0)	& OCS_DEBUG_ENABLE_MQ_DUMP) | \
777ef270ab1SKenneth D. Merry 	(OCS_DEBUG_ENABLE(0)	& OCS_DEBUG_ENABLE_CQ_DUMP) | \
778ef270ab1SKenneth D. Merry 	(OCS_DEBUG_ENABLE(0)	& OCS_DEBUG_ENABLE_WQ_DUMP) | \
779ef270ab1SKenneth D. Merry 	(OCS_DEBUG_ENABLE(0)	& OCS_DEBUG_ENABLE_EQ_DUMP) | \
780ef270ab1SKenneth D. Merry 	(OCS_DEBUG_ENABLE(0)	& OCS_DEBUG_ENABLE_SPARAM_DUMP)
781ef270ab1SKenneth D. Merry 
782ef270ab1SKenneth D. Merry static uint32_t ocs_debug_mask = OCS_DEBUG_MASK;
783ef270ab1SKenneth D. Merry 
784ef270ab1SKenneth D. Merry static int
785ef270ab1SKenneth D. Merry _isprint(int c) {
786ef270ab1SKenneth D. Merry 	return ((c > 32) && (c < 127));
787ef270ab1SKenneth D. Merry }
788ef270ab1SKenneth D. Merry 
789ef270ab1SKenneth D. Merry /**
790ef270ab1SKenneth D. Merry  * @ingroup debug
791ef270ab1SKenneth D. Merry  * @brief enable debug options
792ef270ab1SKenneth D. Merry  *
793ef270ab1SKenneth D. Merry  * Enables debug options by or-ing in <b>mask</b> into the currently enabled
794ef270ab1SKenneth D. Merry  * debug mask.
795ef270ab1SKenneth D. Merry  *
796ef270ab1SKenneth D. Merry  * @param mask mask bits to enable
797ef270ab1SKenneth D. Merry  *
798ef270ab1SKenneth D. Merry  * @return none
799ef270ab1SKenneth D. Merry  */
800ef270ab1SKenneth D. Merry 
801ef270ab1SKenneth D. Merry void ocs_debug_enable(uint32_t mask) {
802ef270ab1SKenneth D. Merry 	ocs_debug_mask |= mask;
803ef270ab1SKenneth D. Merry }
804ef270ab1SKenneth D. Merry 
805ef270ab1SKenneth D. Merry /**
806ef270ab1SKenneth D. Merry  * @ingroup debug
807ef270ab1SKenneth D. Merry  * @brief disable debug options
808ef270ab1SKenneth D. Merry  *
809ef270ab1SKenneth D. Merry  * Disables debug options by clearing bits in <b>mask</b> into the currently enabled
810ef270ab1SKenneth D. Merry  * debug mask.
811ef270ab1SKenneth D. Merry  *
812ef270ab1SKenneth D. Merry  * @param mask mask bits to enable
813ef270ab1SKenneth D. Merry  *
814ef270ab1SKenneth D. Merry  * @return none
815ef270ab1SKenneth D. Merry  */
816ef270ab1SKenneth D. Merry 
817ef270ab1SKenneth D. Merry void ocs_debug_disable(uint32_t mask) {
818ef270ab1SKenneth D. Merry 	ocs_debug_mask &= ~mask;
819ef270ab1SKenneth D. Merry }
820ef270ab1SKenneth D. Merry 
821ef270ab1SKenneth D. Merry /**
822ef270ab1SKenneth D. Merry  * @ingroup debug
823ef270ab1SKenneth D. Merry  * @brief return true if debug bits are enabled
824ef270ab1SKenneth D. Merry  *
825ef270ab1SKenneth D. Merry  * Returns true if the request debug bits are set.
826ef270ab1SKenneth D. Merry  *
827ef270ab1SKenneth D. Merry  * @param mask debug bit mask
828ef270ab1SKenneth D. Merry  *
829ef270ab1SKenneth D. Merry  * @return true if corresponding bits are set
830ef270ab1SKenneth D. Merry  *
831ef270ab1SKenneth D. Merry  * @note Passing in a mask value of zero always returns true
832ef270ab1SKenneth D. Merry  */
833ef270ab1SKenneth D. Merry 
834ef270ab1SKenneth D. Merry int ocs_debug_is_enabled(uint32_t mask) {
835ef270ab1SKenneth D. Merry 	return (ocs_debug_mask & mask) == mask;
836ef270ab1SKenneth D. Merry }
837ef270ab1SKenneth D. Merry 
838ef270ab1SKenneth D. Merry 
839ef270ab1SKenneth D. Merry /**
840ef270ab1SKenneth D. Merry  * @ingroup debug
841ef270ab1SKenneth D. Merry  * @brief Dump 32 bit hex/ascii data
842ef270ab1SKenneth D. Merry  *
843ef270ab1SKenneth D. Merry  * Dumps using ocs_log a buffer of data as 32 bit hex and ascii
844ef270ab1SKenneth D. Merry  *
845ef270ab1SKenneth D. Merry  * @param mask debug enable bits
846ef270ab1SKenneth D. Merry  * @param os os handle
847ef270ab1SKenneth D. Merry  * @param label text label for the display (may be NULL)
848ef270ab1SKenneth D. Merry  * @param buf pointer to data buffer
849ef270ab1SKenneth D. Merry  * @param buf_length length of data buffer
850ef270ab1SKenneth D. Merry  *
851ef270ab1SKenneth D. Merry  * @return none
852ef270ab1SKenneth D. Merry  *
853ef270ab1SKenneth D. Merry  */
854ef270ab1SKenneth D. Merry 
855ef270ab1SKenneth D. Merry void
856ef270ab1SKenneth D. Merry ocs_dump32(uint32_t mask, ocs_os_handle_t os, const char *label, void *buf, uint32_t buf_length)
857ef270ab1SKenneth D. Merry {
858ef270ab1SKenneth D. Merry 	uint32_t word_count = buf_length / sizeof(uint32_t);
859ef270ab1SKenneth D. Merry 	uint32_t i;
860ef270ab1SKenneth D. Merry 	uint32_t columns = 8;
861ef270ab1SKenneth D. Merry 	uint32_t n;
862ef270ab1SKenneth D. Merry 	uint32_t *wbuf;
863ef270ab1SKenneth D. Merry 	char *cbuf;
864ef270ab1SKenneth D. Merry 	uint32_t addr = 0;
865ef270ab1SKenneth D. Merry 	char linebuf[200];
866ef270ab1SKenneth D. Merry 	char *pbuf = linebuf;
867ef270ab1SKenneth D. Merry 
868ef270ab1SKenneth D. Merry 	if (!ocs_debug_is_enabled(mask))
869ef270ab1SKenneth D. Merry 		return;
870ef270ab1SKenneth D. Merry 
871ef270ab1SKenneth D. Merry 	if (label)
872ef270ab1SKenneth D. Merry 		ocs_log_debug(os, "%s\n", label);
873ef270ab1SKenneth D. Merry 
874ef270ab1SKenneth D. Merry 	wbuf = buf;
875ef270ab1SKenneth D. Merry 	while (word_count > 0) {
876ef270ab1SKenneth D. Merry 		pbuf = linebuf;
877ef270ab1SKenneth D. Merry 		pbuf += ocs_snprintf(pbuf, sizeof(linebuf) - (pbuf-linebuf), "%08X:  ", addr);
878ef270ab1SKenneth D. Merry 
879ef270ab1SKenneth D. Merry 		n = word_count;
880ef270ab1SKenneth D. Merry 		if (n > columns)
881ef270ab1SKenneth D. Merry 			n = columns;
882ef270ab1SKenneth D. Merry 
883ef270ab1SKenneth D. Merry 		for (i = 0; i < n; i ++)
884ef270ab1SKenneth D. Merry 			pbuf += ocs_snprintf(pbuf, sizeof(linebuf) - (pbuf-linebuf), "%08X ", wbuf[i]);
885ef270ab1SKenneth D. Merry 
886ef270ab1SKenneth D. Merry 		for (; i < columns; i ++)
887ef270ab1SKenneth D. Merry 			pbuf += ocs_snprintf(pbuf, sizeof(linebuf) - (pbuf-linebuf), "%8s ", "");
888ef270ab1SKenneth D. Merry 
889ef270ab1SKenneth D. Merry 		pbuf += ocs_snprintf(pbuf, sizeof(linebuf) - (pbuf-linebuf), "    ");
890ef270ab1SKenneth D. Merry 		cbuf = (char*)wbuf;
891ef270ab1SKenneth D. Merry 		for (i = 0; i < n*sizeof(uint32_t); i ++)
892ef270ab1SKenneth D. Merry 			pbuf += ocs_snprintf(pbuf, sizeof(linebuf) - (pbuf-linebuf), "%c", _isprint(cbuf[i]) ? cbuf[i] : '.');
893ef270ab1SKenneth D. Merry 		pbuf += ocs_snprintf(pbuf, sizeof(linebuf) - (pbuf-linebuf), "\n");
894ef270ab1SKenneth D. Merry 
895ef270ab1SKenneth D. Merry 		ocs_log_debug(os, "%s", linebuf);
896ef270ab1SKenneth D. Merry 
897ef270ab1SKenneth D. Merry 		wbuf += n;
898ef270ab1SKenneth D. Merry 		word_count -= n;
899ef270ab1SKenneth D. Merry 		addr += n*sizeof(uint32_t);
900ef270ab1SKenneth D. Merry 	}
901ef270ab1SKenneth D. Merry }
902ef270ab1SKenneth D. Merry 
903ef270ab1SKenneth D. Merry 
904ef270ab1SKenneth D. Merry #if defined(OCS_DEBUG_QUEUE_HISTORY)
905ef270ab1SKenneth D. Merry 
906ef270ab1SKenneth D. Merry /* each bit corresponds to word to capture */
907ef270ab1SKenneth D. Merry #define OCS_Q_HIST_WQE_WORD_MASK_DEFAULT	(BIT(4) | BIT(6) | BIT(7) | BIT(9) | BIT(12))
908ef270ab1SKenneth D. Merry #define OCS_Q_HIST_TRECV_CONT_WQE_WORD_MASK	(BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(9) | BIT(12))
909ef270ab1SKenneth D. Merry #define OCS_Q_HIST_IWRITE_WQE_WORD_MASK		(BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(9))
910ef270ab1SKenneth D. Merry #define OCS_Q_HIST_IREAD_WQE_WORD_MASK		(BIT(4) | BIT(6) | BIT(7) | BIT(9))
911ef270ab1SKenneth D. Merry #define OCS_Q_HIST_ABORT_WQE_WORD_MASK		(BIT(3) | BIT(7) | BIT(8) | BIT(9))
912ef270ab1SKenneth D. Merry #define OCS_Q_HIST_WCQE_WORD_MASK		(BIT(0) | BIT(3))
913ef270ab1SKenneth D. Merry #define OCS_Q_HIST_WCQE_WORD_MASK_ERR		(BIT(0) | BIT(1) | BIT(2) | BIT(3))
914ef270ab1SKenneth D. Merry #define OCS_Q_HIST_CQXABT_WORD_MASK		(BIT(0) | BIT(1) | BIT(2) | BIT(3))
915ef270ab1SKenneth D. Merry 
916ef270ab1SKenneth D. Merry /* if set, will provide extra queue information in each entry */
917ef270ab1SKenneth D. Merry #define OCS_Q_HIST_ENABLE_Q_INFO	0
918ef270ab1SKenneth D. Merry uint8_t ocs_queue_history_q_info_enabled(void)
919ef270ab1SKenneth D. Merry {
920ef270ab1SKenneth D. Merry 	return OCS_Q_HIST_ENABLE_Q_INFO;
921ef270ab1SKenneth D. Merry }
922ef270ab1SKenneth D. Merry 
923ef270ab1SKenneth D. Merry /* if set, will provide timestamps in each entry */
924ef270ab1SKenneth D. Merry #define OCS_Q_HIST_ENABLE_TIMESTAMPS	0
925ef270ab1SKenneth D. Merry uint8_t ocs_queue_history_timestamp_enabled(void)
926ef270ab1SKenneth D. Merry {
927ef270ab1SKenneth D. Merry 	return OCS_Q_HIST_ENABLE_TIMESTAMPS;
928ef270ab1SKenneth D. Merry }
929ef270ab1SKenneth D. Merry 
930ef270ab1SKenneth D. Merry /* Add WQEs and masks to override default WQE mask */
931ef270ab1SKenneth D. Merry ocs_q_hist_wqe_mask_t ocs_q_hist_wqe_masks[] = {
932ef270ab1SKenneth D. Merry 	/* WQE command   Word mask */
933ef270ab1SKenneth D. Merry 	{SLI4_WQE_ABORT, OCS_Q_HIST_ABORT_WQE_WORD_MASK},
934ef270ab1SKenneth D. Merry 	{SLI4_WQE_FCP_IREAD64, OCS_Q_HIST_IREAD_WQE_WORD_MASK},
935ef270ab1SKenneth D. Merry 	{SLI4_WQE_FCP_IWRITE64, OCS_Q_HIST_IWRITE_WQE_WORD_MASK},
936ef270ab1SKenneth D. Merry 	{SLI4_WQE_FCP_CONT_TRECEIVE64, OCS_Q_HIST_TRECV_CONT_WQE_WORD_MASK},
937ef270ab1SKenneth D. Merry };
938ef270ab1SKenneth D. Merry 
939ef270ab1SKenneth D. Merry /* CQE masks */
940ef270ab1SKenneth D. Merry ocs_q_hist_cqe_mask_t ocs_q_hist_cqe_masks[] = {
941ef270ab1SKenneth D. Merry 	/* CQE type     Q_hist_type		mask (success) 	mask (non-success) */
942ef270ab1SKenneth D. Merry 	{SLI_QENTRY_WQ, OCS_Q_HIST_TYPE_CWQE, 	OCS_Q_HIST_WCQE_WORD_MASK, OCS_Q_HIST_WCQE_WORD_MASK_ERR},
943ef270ab1SKenneth D. Merry 	{SLI_QENTRY_XABT, OCS_Q_HIST_TYPE_CXABT, OCS_Q_HIST_CQXABT_WORD_MASK, OCS_Q_HIST_WCQE_WORD_MASK},
944ef270ab1SKenneth D. Merry };
945ef270ab1SKenneth D. Merry 
946ef270ab1SKenneth D. Merry static uint32_t ocs_q_hist_get_wqe_mask(sli4_generic_wqe_t *wqe)
947ef270ab1SKenneth D. Merry {
948ef270ab1SKenneth D. Merry 	uint32_t i;
949ef270ab1SKenneth D. Merry 	for (i = 0; i < ARRAY_SIZE(ocs_q_hist_wqe_masks); i++) {
950ef270ab1SKenneth D. Merry 		if (ocs_q_hist_wqe_masks[i].command == wqe->command) {
951ef270ab1SKenneth D. Merry 			return ocs_q_hist_wqe_masks[i].mask;
952ef270ab1SKenneth D. Merry 		}
953ef270ab1SKenneth D. Merry 	}
954ef270ab1SKenneth D. Merry 	/* return default WQE mask */
955ef270ab1SKenneth D. Merry 	return OCS_Q_HIST_WQE_WORD_MASK_DEFAULT;
956ef270ab1SKenneth D. Merry }
957ef270ab1SKenneth D. Merry 
958ef270ab1SKenneth D. Merry /**
959ef270ab1SKenneth D. Merry  * @ingroup debug
960ef270ab1SKenneth D. Merry  * @brief Initialize resources for queue history
961ef270ab1SKenneth D. Merry  *
962ef270ab1SKenneth D. Merry  * @param os os handle
963ef270ab1SKenneth D. Merry  * @param q_hist Pointer to the queue history object.
964ef270ab1SKenneth D. Merry  *
965ef270ab1SKenneth D. Merry  * @return none
966ef270ab1SKenneth D. Merry  */
967ef270ab1SKenneth D. Merry void
968ef270ab1SKenneth D. Merry ocs_queue_history_init(ocs_t *ocs, ocs_hw_q_hist_t *q_hist)
969ef270ab1SKenneth D. Merry {
970ef270ab1SKenneth D. Merry 	q_hist->ocs = ocs;
971ef270ab1SKenneth D. Merry 	if (q_hist->q_hist != NULL) {
972ef270ab1SKenneth D. Merry 		/* Setup is already done */
973ef270ab1SKenneth D. Merry 		ocs_log_debug(ocs, "q_hist not NULL, skipping init\n");
974ef270ab1SKenneth D. Merry 		return;
975ef270ab1SKenneth D. Merry 	}
976ef270ab1SKenneth D. Merry 
977ef270ab1SKenneth D. Merry 	q_hist->q_hist = ocs_malloc(ocs, sizeof(*q_hist->q_hist)*OCS_Q_HIST_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
978ef270ab1SKenneth D. Merry 
979ef270ab1SKenneth D. Merry 	if (q_hist->q_hist == NULL) {
980ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "Could not allocate queue history buffer\n");
981ef270ab1SKenneth D. Merry 	} else {
982ef270ab1SKenneth D. Merry 		ocs_lock_init(ocs, &q_hist->q_hist_lock, "queue history lock[%d]", ocs_instance(ocs));
983ef270ab1SKenneth D. Merry 	}
984ef270ab1SKenneth D. Merry 
985ef270ab1SKenneth D. Merry 	q_hist->q_hist_index = 0;
986ef270ab1SKenneth D. Merry }
987ef270ab1SKenneth D. Merry 
988ef270ab1SKenneth D. Merry /**
989ef270ab1SKenneth D. Merry  * @ingroup debug
990ef270ab1SKenneth D. Merry  * @brief Free resources for queue history
991ef270ab1SKenneth D. Merry  *
992ef270ab1SKenneth D. Merry  * @param q_hist Pointer to the queue history object.
993ef270ab1SKenneth D. Merry  *
994ef270ab1SKenneth D. Merry  * @return none
995ef270ab1SKenneth D. Merry  */
996ef270ab1SKenneth D. Merry void
997ef270ab1SKenneth D. Merry ocs_queue_history_free(ocs_hw_q_hist_t *q_hist)
998ef270ab1SKenneth D. Merry {
999ef270ab1SKenneth D. Merry 	ocs_t *ocs = q_hist->ocs;
1000ef270ab1SKenneth D. Merry 
1001ef270ab1SKenneth D. Merry 	if (q_hist->q_hist != NULL) {
1002ef270ab1SKenneth D. Merry 		ocs_free(ocs, q_hist->q_hist, sizeof(*q_hist->q_hist)*OCS_Q_HIST_SIZE);
1003ef270ab1SKenneth D. Merry 		ocs_lock_free(&q_hist->q_hist_lock);
1004ef270ab1SKenneth D. Merry 		q_hist->q_hist = NULL;
1005ef270ab1SKenneth D. Merry 	}
1006ef270ab1SKenneth D. Merry }
1007ef270ab1SKenneth D. Merry 
1008ef270ab1SKenneth D. Merry static void
1009ef270ab1SKenneth D. Merry ocs_queue_history_add_q_info(ocs_hw_q_hist_t *q_hist, uint32_t qid, uint32_t qindex)
1010ef270ab1SKenneth D. Merry {
1011ef270ab1SKenneth D. Merry 	if (ocs_queue_history_q_info_enabled()) {
1012ef270ab1SKenneth D. Merry 		/* write qid, index */
1013ef270ab1SKenneth D. Merry 		q_hist->q_hist[q_hist->q_hist_index] = (qid << 16) | qindex;
1014ef270ab1SKenneth D. Merry 		q_hist->q_hist_index++;
1015ef270ab1SKenneth D. Merry 		q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
1016ef270ab1SKenneth D. Merry 	}
1017ef270ab1SKenneth D. Merry }
1018ef270ab1SKenneth D. Merry 
1019ef270ab1SKenneth D. Merry static void
1020ef270ab1SKenneth D. Merry ocs_queue_history_add_timestamp(ocs_hw_q_hist_t *q_hist)
1021ef270ab1SKenneth D. Merry {
1022ef270ab1SKenneth D. Merry 	if (ocs_queue_history_timestamp_enabled()) {
1023ef270ab1SKenneth D. Merry 		/* write tsc */
1024ef270ab1SKenneth D. Merry 		uint64_t tsc_value;
1025ef270ab1SKenneth D. Merry 		tsc_value = get_cyclecount();
1026ef270ab1SKenneth D. Merry 		q_hist->q_hist[q_hist->q_hist_index] = ((tsc_value >> 32 ) & 0xFFFFFFFF);
1027ef270ab1SKenneth D. Merry 		q_hist->q_hist_index++;
1028ef270ab1SKenneth D. Merry 		q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
1029ef270ab1SKenneth D. Merry 		q_hist->q_hist[q_hist->q_hist_index] = (tsc_value & 0xFFFFFFFF);
1030ef270ab1SKenneth D. Merry 		q_hist->q_hist_index++;
1031ef270ab1SKenneth D. Merry 		q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
1032ef270ab1SKenneth D. Merry 	}
1033ef270ab1SKenneth D. Merry }
1034ef270ab1SKenneth D. Merry 
1035ef270ab1SKenneth D. Merry /**
1036ef270ab1SKenneth D. Merry  * @ingroup debug
1037ef270ab1SKenneth D. Merry  * @brief Log work queue entry (WQE) into history array
1038ef270ab1SKenneth D. Merry  *
1039ef270ab1SKenneth D. Merry  * @param q_hist Pointer to the queue history object.
1040ef270ab1SKenneth D. Merry  * @param entryw Work queue entry in words
1041ef270ab1SKenneth D. Merry  * @param qid Queue ID
1042ef270ab1SKenneth D. Merry  * @param qindex Queue index
1043ef270ab1SKenneth D. Merry  *
1044ef270ab1SKenneth D. Merry  * @return none
1045ef270ab1SKenneth D. Merry  */
1046ef270ab1SKenneth D. Merry void
1047ef270ab1SKenneth D. Merry ocs_queue_history_wq(ocs_hw_q_hist_t *q_hist, uint32_t *entryw, uint32_t qid, uint32_t qindex)
1048ef270ab1SKenneth D. Merry {
1049ef270ab1SKenneth D. Merry 	int i;
1050ef270ab1SKenneth D. Merry 	ocs_q_hist_ftr_t ftr;
1051ef270ab1SKenneth D. Merry 	uint32_t wqe_word_mask = ocs_q_hist_get_wqe_mask((sli4_generic_wqe_t *)entryw);
1052ef270ab1SKenneth D. Merry 
1053ef270ab1SKenneth D. Merry 	if (q_hist->q_hist == NULL) {
1054ef270ab1SKenneth D. Merry 		/* Can't save anything */
1055ef270ab1SKenneth D. Merry 		return;
1056ef270ab1SKenneth D. Merry 	}
1057ef270ab1SKenneth D. Merry 
1058ef270ab1SKenneth D. Merry 	ftr.word = 0;
1059ef270ab1SKenneth D. Merry 	ftr.s.type = OCS_Q_HIST_TYPE_WQE;
1060ef270ab1SKenneth D. Merry 	ocs_lock(&q_hist->q_hist_lock);
1061ef270ab1SKenneth D. Merry 		/* Capture words in reverse order since we'll be interpretting them LIFO */
1062ef270ab1SKenneth D. Merry 		for (i = ((sizeof(wqe_word_mask)*8) - 1); i >= 0; i--){
1063ef270ab1SKenneth D. Merry 			if ((wqe_word_mask >> i) & 1) {
1064ef270ab1SKenneth D. Merry 				q_hist->q_hist[q_hist->q_hist_index] = entryw[i];
1065ef270ab1SKenneth D. Merry 				q_hist->q_hist_index++;
1066ef270ab1SKenneth D. Merry 				q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
1067ef270ab1SKenneth D. Merry 			}
1068ef270ab1SKenneth D. Merry 		}
1069ef270ab1SKenneth D. Merry 
1070ef270ab1SKenneth D. Merry 		ocs_queue_history_add_q_info(q_hist, qid, qindex);
1071ef270ab1SKenneth D. Merry 		ocs_queue_history_add_timestamp(q_hist);
1072ef270ab1SKenneth D. Merry 
1073ef270ab1SKenneth D. Merry 		/* write footer */
1074ef270ab1SKenneth D. Merry 		if (wqe_word_mask) {
1075ef270ab1SKenneth D. Merry 			ftr.s.mask = wqe_word_mask;
1076ef270ab1SKenneth D. Merry 			q_hist->q_hist[q_hist->q_hist_index] = ftr.word;
1077ef270ab1SKenneth D. Merry 			q_hist->q_hist_index++;
1078ef270ab1SKenneth D. Merry 			q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
1079ef270ab1SKenneth D. Merry 		}
1080ef270ab1SKenneth D. Merry 
1081ef270ab1SKenneth D. Merry 	ocs_unlock(&q_hist->q_hist_lock);
1082ef270ab1SKenneth D. Merry }
1083ef270ab1SKenneth D. Merry 
1084ef270ab1SKenneth D. Merry /**
1085ef270ab1SKenneth D. Merry  * @ingroup debug
1086ef270ab1SKenneth D. Merry  * @brief Log misc words
1087ef270ab1SKenneth D. Merry  *
1088ef270ab1SKenneth D. Merry  * @param q_hist Pointer to the queue history object.
1089ef270ab1SKenneth D. Merry  * @param entryw array of words
1090ef270ab1SKenneth D. Merry  * @param num_words number of words in entryw
1091ef270ab1SKenneth D. Merry  *
1092ef270ab1SKenneth D. Merry  * @return none
1093ef270ab1SKenneth D. Merry  */
1094ef270ab1SKenneth D. Merry void
1095ef270ab1SKenneth D. Merry ocs_queue_history_misc(ocs_hw_q_hist_t *q_hist, uint32_t *entryw, uint32_t num_words)
1096ef270ab1SKenneth D. Merry {
1097ef270ab1SKenneth D. Merry 	int i;
1098ef270ab1SKenneth D. Merry 	ocs_q_hist_ftr_t ftr;
1099ef270ab1SKenneth D. Merry 	uint32_t mask = 0;
1100ef270ab1SKenneth D. Merry 
1101ef270ab1SKenneth D. Merry 	if (q_hist->q_hist == NULL) {
1102ef270ab1SKenneth D. Merry 		/* Can't save anything */
1103ef270ab1SKenneth D. Merry 		return;
1104ef270ab1SKenneth D. Merry 	}
1105ef270ab1SKenneth D. Merry 
1106ef270ab1SKenneth D. Merry 	ftr.word = 0;
1107ef270ab1SKenneth D. Merry 	ftr.s.type = OCS_Q_HIST_TYPE_MISC;
1108ef270ab1SKenneth D. Merry 	ocs_lock(&q_hist->q_hist_lock);
1109ef270ab1SKenneth D. Merry 		/* Capture words in reverse order since we'll be interpretting them LIFO */
1110ef270ab1SKenneth D. Merry 		for (i = num_words-1; i >= 0; i--) {
1111ef270ab1SKenneth D. Merry 			q_hist->q_hist[q_hist->q_hist_index] = entryw[i];
1112ef270ab1SKenneth D. Merry 			q_hist->q_hist_index++;
1113ef270ab1SKenneth D. Merry 			q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
1114ef270ab1SKenneth D. Merry 			mask |= BIT(i);
1115ef270ab1SKenneth D. Merry 		}
1116ef270ab1SKenneth D. Merry 
1117ef270ab1SKenneth D. Merry 		ocs_queue_history_add_timestamp(q_hist);
1118ef270ab1SKenneth D. Merry 
1119ef270ab1SKenneth D. Merry 		/* write footer */
1120ef270ab1SKenneth D. Merry 		if (num_words) {
1121ef270ab1SKenneth D. Merry 			ftr.s.mask = mask;
1122ef270ab1SKenneth D. Merry 			q_hist->q_hist[q_hist->q_hist_index] = ftr.word;
1123ef270ab1SKenneth D. Merry 			q_hist->q_hist_index++;
1124ef270ab1SKenneth D. Merry 			q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
1125ef270ab1SKenneth D. Merry 		}
1126ef270ab1SKenneth D. Merry 
1127ef270ab1SKenneth D. Merry 	ocs_unlock(&q_hist->q_hist_lock);
1128ef270ab1SKenneth D. Merry }
1129ef270ab1SKenneth D. Merry 
1130ef270ab1SKenneth D. Merry /**
1131ef270ab1SKenneth D. Merry  * @ingroup debug
1132ef270ab1SKenneth D. Merry  * @brief Log work queue completion (CQE) entry into history
1133ef270ab1SKenneth D. Merry  *        array
1134ef270ab1SKenneth D. Merry  *
1135ef270ab1SKenneth D. Merry  * @param q_hist Pointer to the queue history object.
1136ef270ab1SKenneth D. Merry  * @param ctype Type of completion entry
1137ef270ab1SKenneth D. Merry  * @param entryw Completion queue entry in words
1138ef270ab1SKenneth D. Merry  * @param status Completion queue status
1139ef270ab1SKenneth D. Merry  * @param qid Queue ID
1140ef270ab1SKenneth D. Merry  * @param qindex Queue index
1141ef270ab1SKenneth D. Merry  *
1142ef270ab1SKenneth D. Merry  * @return none
1143ef270ab1SKenneth D. Merry  */
1144ef270ab1SKenneth D. Merry void
1145ef270ab1SKenneth D. Merry ocs_queue_history_cqe(ocs_hw_q_hist_t *q_hist, uint8_t ctype, uint32_t *entryw, uint8_t status, uint32_t qid, uint32_t qindex)
1146ef270ab1SKenneth D. Merry {
1147ef270ab1SKenneth D. Merry 	int i;
1148ef270ab1SKenneth D. Merry 	unsigned j;
1149ef270ab1SKenneth D. Merry 	uint32_t cqe_word_mask = 0;
1150ef270ab1SKenneth D. Merry 	ocs_q_hist_ftr_t ftr;
1151ef270ab1SKenneth D. Merry 
1152ef270ab1SKenneth D. Merry 	if (q_hist->q_hist == NULL) {
1153ef270ab1SKenneth D. Merry 		/* Can't save anything */
1154ef270ab1SKenneth D. Merry 		return;
1155ef270ab1SKenneth D. Merry 	}
1156ef270ab1SKenneth D. Merry 
1157ef270ab1SKenneth D. Merry 	ftr.word = 0;
1158ef270ab1SKenneth D. Merry 	for (j = 0; j < ARRAY_SIZE(ocs_q_hist_cqe_masks); j++) {
1159ef270ab1SKenneth D. Merry 		if (ocs_q_hist_cqe_masks[j].ctype == ctype) {
1160ef270ab1SKenneth D. Merry 			ftr.s.type = ocs_q_hist_cqe_masks[j].type;
1161ef270ab1SKenneth D. Merry 			if (status != 0) {
1162ef270ab1SKenneth D. Merry 				cqe_word_mask = ocs_q_hist_cqe_masks[j].mask_err;
1163ef270ab1SKenneth D. Merry 			} else {
1164ef270ab1SKenneth D. Merry 				cqe_word_mask = ocs_q_hist_cqe_masks[j].mask;
1165ef270ab1SKenneth D. Merry 			}
1166ef270ab1SKenneth D. Merry 		}
1167ef270ab1SKenneth D. Merry 	}
1168ef270ab1SKenneth D. Merry 	ocs_lock(&q_hist->q_hist_lock);
1169ef270ab1SKenneth D. Merry 		/* Capture words in reverse order since we'll be interpretting them LIFO */
1170ef270ab1SKenneth D. Merry 		for (i = ((sizeof(cqe_word_mask)*8) - 1); i >= 0; i--){
1171ef270ab1SKenneth D. Merry 			if ((cqe_word_mask >> i) & 1) {
1172ef270ab1SKenneth D. Merry 				q_hist->q_hist[q_hist->q_hist_index] = entryw[i];
1173ef270ab1SKenneth D. Merry 				q_hist->q_hist_index++;
1174ef270ab1SKenneth D. Merry 				q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
1175ef270ab1SKenneth D. Merry 			}
1176ef270ab1SKenneth D. Merry 		}
1177ef270ab1SKenneth D. Merry 		ocs_queue_history_add_q_info(q_hist, qid, qindex);
1178ef270ab1SKenneth D. Merry 		ocs_queue_history_add_timestamp(q_hist);
1179ef270ab1SKenneth D. Merry 
1180ef270ab1SKenneth D. Merry 		/* write footer */
1181ef270ab1SKenneth D. Merry 		if (cqe_word_mask) {
1182ef270ab1SKenneth D. Merry 			ftr.s.mask = cqe_word_mask;
1183ef270ab1SKenneth D. Merry 			q_hist->q_hist[q_hist->q_hist_index] = ftr.word;
1184ef270ab1SKenneth D. Merry 			q_hist->q_hist_index++;
1185ef270ab1SKenneth D. Merry 			q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
1186ef270ab1SKenneth D. Merry 		}
1187ef270ab1SKenneth D. Merry 
1188ef270ab1SKenneth D. Merry 	ocs_unlock(&q_hist->q_hist_lock);
1189ef270ab1SKenneth D. Merry }
1190ef270ab1SKenneth D. Merry 
1191ef270ab1SKenneth D. Merry /**
1192ef270ab1SKenneth D. Merry  * @brief Get previous index
1193ef270ab1SKenneth D. Merry  *
1194ef270ab1SKenneth D. Merry  * @param index Index from which previous index is derived.
1195ef270ab1SKenneth D. Merry  */
1196ef270ab1SKenneth D. Merry uint32_t
1197ef270ab1SKenneth D. Merry ocs_queue_history_prev_index(uint32_t index)
1198ef270ab1SKenneth D. Merry {
1199ef270ab1SKenneth D. Merry 	if (index == 0) {
1200ef270ab1SKenneth D. Merry 		return OCS_Q_HIST_SIZE - 1;
1201ef270ab1SKenneth D. Merry 	} else {
1202ef270ab1SKenneth D. Merry 		return index - 1;
1203ef270ab1SKenneth D. Merry 	}
1204ef270ab1SKenneth D. Merry }
1205ef270ab1SKenneth D. Merry 
1206ef270ab1SKenneth D. Merry #endif /* OCS_DEBUG_QUEUE_HISTORY */
1207ef270ab1SKenneth D. Merry 
1208ef270ab1SKenneth D. Merry /**
1209ef270ab1SKenneth D. Merry  * @brief Display service parameters
1210ef270ab1SKenneth D. Merry  *
1211ef270ab1SKenneth D. Merry  * <description>
1212ef270ab1SKenneth D. Merry  *
1213ef270ab1SKenneth D. Merry  * @param prelabel leading display label
1214ef270ab1SKenneth D. Merry  * @param reqlabel display label
1215ef270ab1SKenneth D. Merry  * @param dest destination 0=ocs_log, 1=textbuf
1216ef270ab1SKenneth D. Merry  * @param textbuf text buffer destination (if dest==1)
1217ef270ab1SKenneth D. Merry  * @param sparams pointer to service parameter
1218ef270ab1SKenneth D. Merry  *
1219ef270ab1SKenneth D. Merry  * @return none
1220ef270ab1SKenneth D. Merry  */
1221ef270ab1SKenneth D. Merry 
1222ef270ab1SKenneth D. Merry void
1223ef270ab1SKenneth D. Merry ocs_display_sparams(const char *prelabel, const char *reqlabel, int dest, void *textbuf, void *sparams)
1224ef270ab1SKenneth D. Merry {
1225ef270ab1SKenneth D. Merry 	char label[64];
1226ef270ab1SKenneth D. Merry 
1227ef270ab1SKenneth D. Merry 	if (sparams == NULL) {
1228ef270ab1SKenneth D. Merry 		return;
1229ef270ab1SKenneth D. Merry 	}
1230ef270ab1SKenneth D. Merry 
1231ef270ab1SKenneth D. Merry 	switch(dest) {
1232ef270ab1SKenneth D. Merry 	case 0:
1233ef270ab1SKenneth D. Merry 		if (prelabel != NULL) {
1234ef270ab1SKenneth D. Merry 			ocs_snprintf(label, sizeof(label), "[%s] sparam: %s", prelabel, reqlabel);
1235ef270ab1SKenneth D. Merry 		} else {
1236ef270ab1SKenneth D. Merry 			ocs_snprintf(label, sizeof(label), "sparam: %s", reqlabel);
1237ef270ab1SKenneth D. Merry 		}
1238ef270ab1SKenneth D. Merry 
1239ef270ab1SKenneth D. Merry 		ocs_dump32(OCS_DEBUG_ENABLE_SPARAM_DUMP, NULL, label, sparams, sizeof(fc_plogi_payload_t));
1240ef270ab1SKenneth D. Merry 		break;
1241ef270ab1SKenneth D. Merry 	case 1:
1242ef270ab1SKenneth D. Merry 		ocs_ddump_buffer((ocs_textbuf_t*) textbuf, reqlabel, 0, sparams, sizeof(fc_plogi_payload_t));
1243ef270ab1SKenneth D. Merry 		break;
1244ef270ab1SKenneth D. Merry 	}
1245ef270ab1SKenneth D. Merry }
1246ef270ab1SKenneth D. Merry 
1247ef270ab1SKenneth D. Merry /**
1248ef270ab1SKenneth D. Merry  * @brief Calculate the T10 PI CRC guard value for a block.
1249ef270ab1SKenneth D. Merry  *
1250ef270ab1SKenneth D. Merry  * @param buffer Pointer to the data buffer.
1251ef270ab1SKenneth D. Merry  * @param size Number of bytes.
1252ef270ab1SKenneth D. Merry  * @param crc Previously-calculated CRC, or 0 for a new block.
1253ef270ab1SKenneth D. Merry  *
1254ef270ab1SKenneth D. Merry  * @return Returns the calculated CRC, which may be passed back in for partial blocks.
1255ef270ab1SKenneth D. Merry  *
1256ef270ab1SKenneth D. Merry  */
1257ef270ab1SKenneth D. Merry 
1258ef270ab1SKenneth D. Merry uint16_t
1259ef270ab1SKenneth D. Merry ocs_scsi_dif_calc_crc(const uint8_t *buffer, uint32_t size, uint16_t crc)
1260ef270ab1SKenneth D. Merry {
1261ef270ab1SKenneth D. Merry 	return t10crc16(buffer, size, crc);
1262ef270ab1SKenneth D. Merry }
1263ef270ab1SKenneth D. Merry 
1264ef270ab1SKenneth D. Merry /**
1265ef270ab1SKenneth D. Merry  * @brief Calculate the IP-checksum guard value for a block.
1266ef270ab1SKenneth D. Merry  *
1267ef270ab1SKenneth D. Merry  * @param addrlen array of address length pairs
1268ef270ab1SKenneth D. Merry  * @param addrlen_count number of entries in the addrlen[] array
1269ef270ab1SKenneth D. Merry  *
1270ef270ab1SKenneth D. Merry  * Algorithm:
1271ef270ab1SKenneth D. Merry  *    Sum all all the 16-byte words in the block
1272ef270ab1SKenneth D. Merry  *    Add in the "carry", which is everything in excess of 16-bits
1273ef270ab1SKenneth D. Merry  *    Flip all the bits
1274ef270ab1SKenneth D. Merry  *
1275ef270ab1SKenneth D. Merry  * @return Returns the calculated checksum
1276ef270ab1SKenneth D. Merry  */
1277ef270ab1SKenneth D. Merry 
1278ef270ab1SKenneth D. Merry uint16_t
1279ef270ab1SKenneth D. Merry ocs_scsi_dif_calc_checksum(ocs_scsi_vaddr_len_t addrlen[], uint32_t addrlen_count)
1280ef270ab1SKenneth D. Merry {
1281ef270ab1SKenneth D. Merry 	uint32_t i, j;
1282ef270ab1SKenneth D. Merry 	uint16_t checksum;
1283ef270ab1SKenneth D. Merry 	uint32_t intermediate; /* Use an intermediate to hold more than 16 bits during calculations */
1284ef270ab1SKenneth D. Merry 	uint32_t count;
1285ef270ab1SKenneth D. Merry 	uint16_t *buffer;
1286ef270ab1SKenneth D. Merry 
1287ef270ab1SKenneth D. Merry 	intermediate = 0;
1288ef270ab1SKenneth D. Merry 	for (j = 0; j < addrlen_count; j++) {
1289ef270ab1SKenneth D. Merry 		buffer = addrlen[j].vaddr;
1290ef270ab1SKenneth D. Merry 		count = addrlen[j].length / 2;
1291ef270ab1SKenneth D. Merry 		for (i=0; i < count; i++) {
1292ef270ab1SKenneth D. Merry 			intermediate += buffer[i];
1293ef270ab1SKenneth D. Merry 		}
1294ef270ab1SKenneth D. Merry 	}
1295ef270ab1SKenneth D. Merry 
1296ef270ab1SKenneth D. Merry 	/* Carry is everything over 16 bits */
1297ef270ab1SKenneth D. Merry 	intermediate += ((intermediate & 0xffff0000) >> 16);
1298ef270ab1SKenneth D. Merry 
1299ef270ab1SKenneth D. Merry 	/* Flip all the bits */
1300ef270ab1SKenneth D. Merry 	intermediate = ~intermediate;
1301ef270ab1SKenneth D. Merry 
1302ef270ab1SKenneth D. Merry 	checksum = intermediate;
1303ef270ab1SKenneth D. Merry 
1304ef270ab1SKenneth D. Merry 	return checksum;
1305ef270ab1SKenneth D. Merry }
1306ef270ab1SKenneth D. Merry 
1307ef270ab1SKenneth D. Merry /**
1308ef270ab1SKenneth D. Merry  * @brief Return blocksize given SCSI API DIF block size
1309ef270ab1SKenneth D. Merry  *
1310ef270ab1SKenneth D. Merry  * Given the DIF block size enumerated value, return the block size value. (e.g.
1311ef270ab1SKenneth D. Merry  * OCS_SCSI_DIF_BLK_SIZE_512 returns 512)
1312ef270ab1SKenneth D. Merry  *
1313ef270ab1SKenneth D. Merry  * @param dif_info Pointer to SCSI API DIF info block
1314ef270ab1SKenneth D. Merry  *
1315ef270ab1SKenneth D. Merry  * @return returns block size, or 0 if SCSI API DIF blocksize is invalid
1316ef270ab1SKenneth D. Merry  */
1317ef270ab1SKenneth D. Merry 
1318ef270ab1SKenneth D. Merry uint32_t
1319ef270ab1SKenneth D. Merry ocs_scsi_dif_blocksize(ocs_scsi_dif_info_t *dif_info)
1320ef270ab1SKenneth D. Merry {
1321ef270ab1SKenneth D. Merry 	uint32_t blocksize = 0;
1322ef270ab1SKenneth D. Merry 
1323ef270ab1SKenneth D. Merry 	switch(dif_info->blk_size) {
1324ef270ab1SKenneth D. Merry 	case OCS_SCSI_DIF_BK_SIZE_512:	blocksize = 512; break;
1325ef270ab1SKenneth D. Merry 	case OCS_SCSI_DIF_BK_SIZE_1024:	blocksize = 1024; break;
1326ef270ab1SKenneth D. Merry 	case OCS_SCSI_DIF_BK_SIZE_2048:	blocksize = 2048; break;
1327ef270ab1SKenneth D. Merry 	case OCS_SCSI_DIF_BK_SIZE_4096:	blocksize = 4096; break;
1328ef270ab1SKenneth D. Merry 	case OCS_SCSI_DIF_BK_SIZE_520:	blocksize = 520; break;
1329ef270ab1SKenneth D. Merry 	case OCS_SCSI_DIF_BK_SIZE_4104:	blocksize = 4104; break;
1330ef270ab1SKenneth D. Merry 	default:
1331ef270ab1SKenneth D. Merry 		break;
1332ef270ab1SKenneth D. Merry 	}
1333ef270ab1SKenneth D. Merry 
1334ef270ab1SKenneth D. Merry 	return blocksize;
1335ef270ab1SKenneth D. Merry }
1336ef270ab1SKenneth D. Merry 
1337ef270ab1SKenneth D. Merry /**
1338ef270ab1SKenneth D. Merry  * @brief Set SCSI API DIF blocksize
1339ef270ab1SKenneth D. Merry  *
1340ef270ab1SKenneth D. Merry  * Given a blocksize value (512, 1024, etc.), set the SCSI API DIF blocksize
1341ef270ab1SKenneth D. Merry  * in the DIF info block
1342ef270ab1SKenneth D. Merry  *
1343ef270ab1SKenneth D. Merry  * @param dif_info Pointer to the SCSI API DIF info block
1344ef270ab1SKenneth D. Merry  * @param blocksize Block size
1345ef270ab1SKenneth D. Merry  *
1346ef270ab1SKenneth D. Merry  * @return returns 0 for success, a negative error code value for failure.
1347ef270ab1SKenneth D. Merry  */
1348ef270ab1SKenneth D. Merry 
1349ef270ab1SKenneth D. Merry int32_t
1350ef270ab1SKenneth D. Merry ocs_scsi_dif_set_blocksize(ocs_scsi_dif_info_t *dif_info, uint32_t blocksize)
1351ef270ab1SKenneth D. Merry {
1352ef270ab1SKenneth D. Merry 	int32_t rc = 0;
1353ef270ab1SKenneth D. Merry 
1354ef270ab1SKenneth D. Merry 	switch(blocksize) {
1355ef270ab1SKenneth D. Merry 	case 512:	dif_info->blk_size = OCS_SCSI_DIF_BK_SIZE_512; break;
1356ef270ab1SKenneth D. Merry 	case 1024:	dif_info->blk_size = OCS_SCSI_DIF_BK_SIZE_1024; break;
1357ef270ab1SKenneth D. Merry 	case 2048:	dif_info->blk_size = OCS_SCSI_DIF_BK_SIZE_2048; break;
1358ef270ab1SKenneth D. Merry 	case 4096:	dif_info->blk_size = OCS_SCSI_DIF_BK_SIZE_4096; break;
1359ef270ab1SKenneth D. Merry 	case 520:	dif_info->blk_size = OCS_SCSI_DIF_BK_SIZE_520; break;
1360ef270ab1SKenneth D. Merry 	case 4104:	dif_info->blk_size = OCS_SCSI_DIF_BK_SIZE_4104; break;
1361ef270ab1SKenneth D. Merry 	default:
1362ef270ab1SKenneth D. Merry 		rc = -1;
1363ef270ab1SKenneth D. Merry 		break;
1364ef270ab1SKenneth D. Merry 	}
1365ef270ab1SKenneth D. Merry 	return rc;
1366ef270ab1SKenneth D. Merry 
1367ef270ab1SKenneth D. Merry }
1368ef270ab1SKenneth D. Merry 
1369ef270ab1SKenneth D. Merry /**
1370ef270ab1SKenneth D. Merry  * @brief Return memory block size given SCSI DIF API
1371ef270ab1SKenneth D. Merry  *
1372ef270ab1SKenneth D. Merry  * The blocksize in memory for the DIF transfer is returned, given the SCSI DIF info
1373ef270ab1SKenneth D. Merry  * block and the direction of transfer.
1374ef270ab1SKenneth D. Merry  *
1375ef270ab1SKenneth D. Merry  * @param dif_info Pointer to DIF info block
1376ef270ab1SKenneth D. Merry  * @param wiretomem Transfer direction, 1 is wire to memory, 0 is memory to wire
1377ef270ab1SKenneth D. Merry  *
1378ef270ab1SKenneth D. Merry  * @return Memory blocksize, or negative error value
1379ef270ab1SKenneth D. Merry  *
1380ef270ab1SKenneth D. Merry  * WARNING: the order of initialization of the adj[] arrays MUST match the declarations
1381ef270ab1SKenneth D. Merry  * of OCS_SCSI_DIF_OPER_*
1382ef270ab1SKenneth D. Merry  */
1383ef270ab1SKenneth D. Merry 
1384ef270ab1SKenneth D. Merry int32_t
1385ef270ab1SKenneth D. Merry ocs_scsi_dif_mem_blocksize(ocs_scsi_dif_info_t *dif_info, int wiretomem)
1386ef270ab1SKenneth D. Merry {
1387ef270ab1SKenneth D. Merry 	uint32_t blocksize;
1388ef270ab1SKenneth D. Merry 	uint8_t wiretomem_adj[] = {
1389ef270ab1SKenneth D. Merry 		0,		/* OCS_SCSI_DIF_OPER_DISABLED, */
1390ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CRC, */
1391ef270ab1SKenneth D. Merry 		0,		/* OCS_SCSI_DIF_OPER_IN_CRC_OUT_NODIF, */
1392ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CHKSUM, */
1393ef270ab1SKenneth D. Merry 		0,		/* OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_NODIF, */
1394ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_SCSI_DIF_OPER_IN_CRC_OUT_CRC, */
1395ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CHKSUM, */
1396ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_SCSI_DIF_OPER_IN_CRC_OUT_CHKSUM, */
1397ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CRC, */
1398ef270ab1SKenneth D. Merry 		DIF_SIZE};	/* OCS_SCSI_DIF_OPER_IN_RAW_OUT_RAW, */
1399ef270ab1SKenneth D. Merry 	uint8_t memtowire_adj[] = {
1400ef270ab1SKenneth D. Merry 		0,		/* OCS_SCSI_DIF_OPER_DISABLED, */
1401ef270ab1SKenneth D. Merry 		0,		/* OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CRC, */
1402ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_SCSI_DIF_OPER_IN_CRC_OUT_NODIF, */
1403ef270ab1SKenneth D. Merry 		0,		/* OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CHKSUM, */
1404ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_NODIF, */
1405ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_SCSI_DIF_OPER_IN_CRC_OUT_CRC, */
1406ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CHKSUM, */
1407ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_SCSI_DIF_OPER_IN_CRC_OUT_CHKSUM, */
1408ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CRC, */
1409ef270ab1SKenneth D. Merry 		DIF_SIZE};	/* OCS_SCSI_DIF_OPER_IN_RAW_OUT_RAW, */
1410ef270ab1SKenneth D. Merry 
1411ef270ab1SKenneth D. Merry 	blocksize = ocs_scsi_dif_blocksize(dif_info);
1412ef270ab1SKenneth D. Merry 	if (blocksize == 0) {
1413ef270ab1SKenneth D. Merry 		return -1;
1414ef270ab1SKenneth D. Merry 	}
1415ef270ab1SKenneth D. Merry 
1416ef270ab1SKenneth D. Merry 	if (wiretomem) {
1417ef270ab1SKenneth D. Merry 		ocs_assert(dif_info->dif_oper < ARRAY_SIZE(wiretomem_adj), 0);
1418ef270ab1SKenneth D. Merry 		blocksize += wiretomem_adj[dif_info->dif_oper];
1419ef270ab1SKenneth D. Merry 	} else {	/* mem to wire */
1420ef270ab1SKenneth D. Merry 		ocs_assert(dif_info->dif_oper < ARRAY_SIZE(memtowire_adj), 0);
1421ef270ab1SKenneth D. Merry 		blocksize += memtowire_adj[dif_info->dif_oper];
1422ef270ab1SKenneth D. Merry 	}
1423ef270ab1SKenneth D. Merry 	return blocksize;
1424ef270ab1SKenneth D. Merry }
1425ef270ab1SKenneth D. Merry 
1426ef270ab1SKenneth D. Merry /**
1427ef270ab1SKenneth D. Merry  * @brief Return wire block size given SCSI DIF API
1428ef270ab1SKenneth D. Merry  *
1429ef270ab1SKenneth D. Merry  * The blocksize on the wire for the DIF transfer is returned, given the SCSI DIF info
1430ef270ab1SKenneth D. Merry  * block and the direction of transfer.
1431ef270ab1SKenneth D. Merry  *
1432ef270ab1SKenneth D. Merry  * @param dif_info Pointer to DIF info block
1433ef270ab1SKenneth D. Merry  * @param wiretomem Transfer direction, 1 is wire to memory, 0 is memory to wire
1434ef270ab1SKenneth D. Merry  *
1435ef270ab1SKenneth D. Merry  * @return Wire blocksize or negative error value
1436ef270ab1SKenneth D. Merry  *
1437ef270ab1SKenneth D. Merry  * WARNING: the order of initialization of the adj[] arrays MUST match the declarations
1438ef270ab1SKenneth D. Merry  * of OCS_SCSI_DIF_OPER_*
1439ef270ab1SKenneth D. Merry  */
1440ef270ab1SKenneth D. Merry 
1441ef270ab1SKenneth D. Merry int32_t
1442ef270ab1SKenneth D. Merry ocs_scsi_dif_wire_blocksize(ocs_scsi_dif_info_t *dif_info, int wiretomem)
1443ef270ab1SKenneth D. Merry {
1444ef270ab1SKenneth D. Merry 	uint32_t blocksize;
1445ef270ab1SKenneth D. Merry 	uint8_t wiretomem_adj[] = {
1446ef270ab1SKenneth D. Merry 		0,		/* OCS_SCSI_DIF_OPER_DISABLED, */
1447ef270ab1SKenneth D. Merry 		0,		/* OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CRC, */
1448ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_SCSI_DIF_OPER_IN_CRC_OUT_NODIF, */
1449ef270ab1SKenneth D. Merry 		0,		/* OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CHKSUM, */
1450ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_NODIF, */
1451ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_SCSI_DIF_OPER_IN_CRC_OUT_CRC, */
1452ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CHKSUM, */
1453ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_SCSI_DIF_OPER_IN_CRC_OUT_CHKSUM, */
1454ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CRC, */
1455ef270ab1SKenneth D. Merry 		DIF_SIZE};	/* OCS_SCSI_DIF_OPER_IN_RAW_OUT_RAW, */
1456ef270ab1SKenneth D. Merry 	uint8_t memtowire_adj[] = {
1457ef270ab1SKenneth D. Merry 		0,		/* OCS_SCSI_DIF_OPER_DISABLED, */
1458ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CRC, */
1459ef270ab1SKenneth D. Merry 		0,		/* OCS_SCSI_DIF_OPER_IN_CRC_OUT_NODIF, */
1460ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CHKSUM, */
1461ef270ab1SKenneth D. Merry 		0,		/* OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_NODIF, */
1462ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_SCSI_DIF_OPER_IN_CRC_OUT_CRC, */
1463ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CHKSUM, */
1464ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_SCSI_DIF_OPER_IN_CRC_OUT_CHKSUM, */
1465ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CRC, */
1466ef270ab1SKenneth D. Merry 		DIF_SIZE};	/* OCS_SCSI_DIF_OPER_IN_RAW_OUT_RAW, */
1467ef270ab1SKenneth D. Merry 
1468ef270ab1SKenneth D. Merry 
1469ef270ab1SKenneth D. Merry 	blocksize = ocs_scsi_dif_blocksize(dif_info);
1470ef270ab1SKenneth D. Merry 	if (blocksize == 0) {
1471ef270ab1SKenneth D. Merry 		return -1;
1472ef270ab1SKenneth D. Merry 	}
1473ef270ab1SKenneth D. Merry 
1474ef270ab1SKenneth D. Merry 	if (wiretomem) {
1475ef270ab1SKenneth D. Merry 		ocs_assert(dif_info->dif_oper < ARRAY_SIZE(wiretomem_adj), 0);
1476ef270ab1SKenneth D. Merry 		blocksize += wiretomem_adj[dif_info->dif_oper];
1477ef270ab1SKenneth D. Merry 	} else {	/* mem to wire */
1478ef270ab1SKenneth D. Merry 		ocs_assert(dif_info->dif_oper < ARRAY_SIZE(memtowire_adj), 0);
1479ef270ab1SKenneth D. Merry 		blocksize += memtowire_adj[dif_info->dif_oper];
1480ef270ab1SKenneth D. Merry 	}
1481ef270ab1SKenneth D. Merry 
1482ef270ab1SKenneth D. Merry 	return blocksize;
1483ef270ab1SKenneth D. Merry }
1484ef270ab1SKenneth D. Merry /**
1485ef270ab1SKenneth D. Merry  * @brief Return blocksize given HW API DIF block size
1486ef270ab1SKenneth D. Merry  *
1487ef270ab1SKenneth D. Merry  * Given the DIF block size enumerated value, return the block size value. (e.g.
1488ef270ab1SKenneth D. Merry  * OCS_SCSI_DIF_BLK_SIZE_512 returns 512)
1489ef270ab1SKenneth D. Merry  *
1490ef270ab1SKenneth D. Merry  * @param dif_info Pointer to HW API DIF info block
1491ef270ab1SKenneth D. Merry  *
1492ef270ab1SKenneth D. Merry  * @return returns block size, or 0 if HW API DIF blocksize is invalid
1493ef270ab1SKenneth D. Merry  */
1494ef270ab1SKenneth D. Merry 
1495ef270ab1SKenneth D. Merry uint32_t
1496ef270ab1SKenneth D. Merry ocs_hw_dif_blocksize(ocs_hw_dif_info_t *dif_info)
1497ef270ab1SKenneth D. Merry {
1498ef270ab1SKenneth D. Merry 	uint32_t blocksize = 0;
1499ef270ab1SKenneth D. Merry 
1500ef270ab1SKenneth D. Merry 	switch(dif_info->blk_size) {
1501ef270ab1SKenneth D. Merry 	case OCS_HW_DIF_BK_SIZE_512:	blocksize = 512; break;
1502ef270ab1SKenneth D. Merry 	case OCS_HW_DIF_BK_SIZE_1024:	blocksize = 1024; break;
1503ef270ab1SKenneth D. Merry 	case OCS_HW_DIF_BK_SIZE_2048:	blocksize = 2048; break;
1504ef270ab1SKenneth D. Merry 	case OCS_HW_DIF_BK_SIZE_4096:	blocksize = 4096; break;
1505ef270ab1SKenneth D. Merry 	case OCS_HW_DIF_BK_SIZE_520:	blocksize = 520; break;
1506ef270ab1SKenneth D. Merry 	case OCS_HW_DIF_BK_SIZE_4104:	blocksize = 4104; break;
1507ef270ab1SKenneth D. Merry 	default:
1508ef270ab1SKenneth D. Merry 		break;
1509ef270ab1SKenneth D. Merry 	}
1510ef270ab1SKenneth D. Merry 
1511ef270ab1SKenneth D. Merry 	return blocksize;
1512ef270ab1SKenneth D. Merry }
1513ef270ab1SKenneth D. Merry 
1514ef270ab1SKenneth D. Merry /**
1515ef270ab1SKenneth D. Merry  * @brief Return memory block size given HW DIF API
1516ef270ab1SKenneth D. Merry  *
1517ef270ab1SKenneth D. Merry  * The blocksize in memory for the DIF transfer is returned, given the HW DIF info
1518ef270ab1SKenneth D. Merry  * block and the direction of transfer.
1519ef270ab1SKenneth D. Merry  *
1520ef270ab1SKenneth D. Merry  * @param dif_info Pointer to DIF info block
1521ef270ab1SKenneth D. Merry  * @param wiretomem Transfer direction, 1 is wire to memory, 0 is memory to wire
1522ef270ab1SKenneth D. Merry  *
1523ef270ab1SKenneth D. Merry  * @return Memory blocksize, or negative error value
1524ef270ab1SKenneth D. Merry  *
1525ef270ab1SKenneth D. Merry  * WARNING: the order of initialization of the adj[] arrays MUST match the declarations
1526ef270ab1SKenneth D. Merry  * of OCS_HW_DIF_OPER_*
1527ef270ab1SKenneth D. Merry  */
1528ef270ab1SKenneth D. Merry 
1529ef270ab1SKenneth D. Merry int32_t
1530ef270ab1SKenneth D. Merry ocs_hw_dif_mem_blocksize(ocs_hw_dif_info_t *dif_info, int wiretomem)
1531ef270ab1SKenneth D. Merry {
1532ef270ab1SKenneth D. Merry 	uint32_t blocksize;
1533ef270ab1SKenneth D. Merry 	uint8_t wiretomem_adj[] = {
1534ef270ab1SKenneth D. Merry 		0,		/* OCS_HW_DIF_OPER_DISABLED, */
1535ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_HW_DIF_OPER_IN_NODIF_OUT_CRC, */
1536ef270ab1SKenneth D. Merry 		0,		/* OCS_HW_DIF_OPER_IN_CRC_OUT_NODIF, */
1537ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_HW_DIF_OPER_IN_NODIF_OUT_CHKSUM, */
1538ef270ab1SKenneth D. Merry 		0,		/* OCS_HW_DIF_OPER_IN_CHKSUM_OUT_NODIF, */
1539ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_HW_DIF_OPER_IN_CRC_OUT_CRC, */
1540ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_HW_DIF_OPER_IN_CHKSUM_OUT_CHKSUM, */
1541ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_HW_DIF_OPER_IN_CRC_OUT_CHKSUM, */
1542ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_HW_DIF_OPER_IN_CHKSUM_OUT_CRC, */
1543ef270ab1SKenneth D. Merry 		DIF_SIZE};	/* OCS_HW_DIF_OPER_IN_RAW_OUT_RAW, */
1544ef270ab1SKenneth D. Merry 	uint8_t memtowire_adj[] = {
1545ef270ab1SKenneth D. Merry 		0,		/* OCS_HW_DIF_OPER_DISABLED, */
1546ef270ab1SKenneth D. Merry 		0,		/* OCS_HW_DIF_OPER_IN_NODIF_OUT_CRC, */
1547ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_HW_DIF_OPER_IN_CRC_OUT_NODIF, */
1548ef270ab1SKenneth D. Merry 		0,		/* OCS_HW_DIF_OPER_IN_NODIF_OUT_CHKSUM, */
1549ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_HW_DIF_OPER_IN_CHKSUM_OUT_NODIF, */
1550ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_HW_DIF_OPER_IN_CRC_OUT_CRC, */
1551ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_HW_DIF_OPER_IN_CHKSUM_OUT_CHKSUM, */
1552ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_HW_DIF_OPER_IN_CRC_OUT_CHKSUM, */
1553ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_HW_DIF_OPER_IN_CHKSUM_OUT_CRC, */
1554ef270ab1SKenneth D. Merry 		DIF_SIZE};	/* OCS_HW_DIF_OPER_IN_RAW_OUT_RAW, */
1555ef270ab1SKenneth D. Merry 
1556ef270ab1SKenneth D. Merry 	blocksize = ocs_hw_dif_blocksize(dif_info);
1557ef270ab1SKenneth D. Merry 	if (blocksize == 0) {
1558ef270ab1SKenneth D. Merry 		return -1;
1559ef270ab1SKenneth D. Merry 	}
1560ef270ab1SKenneth D. Merry 
1561ef270ab1SKenneth D. Merry 	if (wiretomem) {
1562ef270ab1SKenneth D. Merry 		ocs_assert(dif_info->dif_oper < ARRAY_SIZE(wiretomem_adj), 0);
1563ef270ab1SKenneth D. Merry 		blocksize += wiretomem_adj[dif_info->dif_oper];
1564ef270ab1SKenneth D. Merry 	} else {	/* mem to wire */
1565ef270ab1SKenneth D. Merry 		ocs_assert(dif_info->dif_oper < ARRAY_SIZE(memtowire_adj), 0);
1566ef270ab1SKenneth D. Merry 		blocksize += memtowire_adj[dif_info->dif_oper];
1567ef270ab1SKenneth D. Merry 	}
1568ef270ab1SKenneth D. Merry 	return blocksize;
1569ef270ab1SKenneth D. Merry }
1570ef270ab1SKenneth D. Merry 
1571ef270ab1SKenneth D. Merry /**
1572ef270ab1SKenneth D. Merry  * @brief Return wire block size given HW DIF API
1573ef270ab1SKenneth D. Merry  *
1574ef270ab1SKenneth D. Merry  * The blocksize on the wire for the DIF transfer is returned, given the HW DIF info
1575ef270ab1SKenneth D. Merry  * block and the direction of transfer.
1576ef270ab1SKenneth D. Merry  *
1577ef270ab1SKenneth D. Merry  * @param dif_info Pointer to DIF info block
1578ef270ab1SKenneth D. Merry  * @param wiretomem Transfer direction, 1 is wire to memory, 0 is memory to wire
1579ef270ab1SKenneth D. Merry  *
1580ef270ab1SKenneth D. Merry  * @return Wire blocksize or negative error value
1581ef270ab1SKenneth D. Merry  *
1582ef270ab1SKenneth D. Merry  * WARNING: the order of initialization of the adj[] arrays MUST match the declarations
1583ef270ab1SKenneth D. Merry  * of OCS_HW_DIF_OPER_*
1584ef270ab1SKenneth D. Merry  */
1585ef270ab1SKenneth D. Merry 
1586ef270ab1SKenneth D. Merry int32_t
1587ef270ab1SKenneth D. Merry ocs_hw_dif_wire_blocksize(ocs_hw_dif_info_t *dif_info, int wiretomem)
1588ef270ab1SKenneth D. Merry {
1589ef270ab1SKenneth D. Merry 	uint32_t blocksize;
1590ef270ab1SKenneth D. Merry 	uint8_t wiretomem_adj[] = {
1591ef270ab1SKenneth D. Merry 		0,		/* OCS_HW_DIF_OPER_DISABLED, */
1592ef270ab1SKenneth D. Merry 		0,		/* OCS_HW_DIF_OPER_IN_NODIF_OUT_CRC, */
1593ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_HW_DIF_OPER_IN_CRC_OUT_NODIF, */
1594ef270ab1SKenneth D. Merry 		0,		/* OCS_HW_DIF_OPER_IN_NODIF_OUT_CHKSUM, */
1595ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_HW_DIF_OPER_IN_CHKSUM_OUT_NODIF, */
1596ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_HW_DIF_OPER_IN_CRC_OUT_CRC, */
1597ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_HW_DIF_OPER_IN_CHKSUM_OUT_CHKSUM, */
1598ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_HW_DIF_OPER_IN_CRC_OUT_CHKSUM, */
1599ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_HW_DIF_OPER_IN_CHKSUM_OUT_CRC, */
1600ef270ab1SKenneth D. Merry 		DIF_SIZE};	/* OCS_HW_DIF_OPER_IN_RAW_OUT_RAW, */
1601ef270ab1SKenneth D. Merry 	uint8_t memtowire_adj[] = {
1602ef270ab1SKenneth D. Merry 		0,		/* OCS_HW_DIF_OPER_DISABLED, */
1603ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_HW_DIF_OPER_IN_NODIF_OUT_CRC, */
1604ef270ab1SKenneth D. Merry 		0,		/* OCS_HW_DIF_OPER_IN_CRC_OUT_NODIF, */
1605ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_HW_DIF_OPER_IN_NODIF_OUT_CHKSUM, */
1606ef270ab1SKenneth D. Merry 		0,		/* OCS_HW_DIF_OPER_IN_CHKSUM_OUT_NODIF, */
1607ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_HW_DIF_OPER_IN_CRC_OUT_CRC, */
1608ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_HW_DIF_OPER_IN_CHKSUM_OUT_CHKSUM, */
1609ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_HW_DIF_OPER_IN_CRC_OUT_CHKSUM, */
1610ef270ab1SKenneth D. Merry 		DIF_SIZE,	/* OCS_HW_DIF_OPER_IN_CHKSUM_OUT_CRC, */
1611ef270ab1SKenneth D. Merry 		DIF_SIZE};	/* OCS_HW_DIF_OPER_IN_RAW_OUT_RAW, */
1612ef270ab1SKenneth D. Merry 
1613ef270ab1SKenneth D. Merry 
1614ef270ab1SKenneth D. Merry 	blocksize = ocs_hw_dif_blocksize(dif_info);
1615ef270ab1SKenneth D. Merry 	if (blocksize == 0) {
1616ef270ab1SKenneth D. Merry 		return -1;
1617ef270ab1SKenneth D. Merry 	}
1618ef270ab1SKenneth D. Merry 
1619ef270ab1SKenneth D. Merry 	if (wiretomem) {
1620ef270ab1SKenneth D. Merry 		ocs_assert(dif_info->dif_oper < ARRAY_SIZE(wiretomem_adj), 0);
1621ef270ab1SKenneth D. Merry 		blocksize += wiretomem_adj[dif_info->dif_oper];
1622ef270ab1SKenneth D. Merry 	} else {	/* mem to wire */
1623ef270ab1SKenneth D. Merry 		ocs_assert(dif_info->dif_oper < ARRAY_SIZE(memtowire_adj), 0);
1624ef270ab1SKenneth D. Merry 		blocksize += memtowire_adj[dif_info->dif_oper];
1625ef270ab1SKenneth D. Merry 	}
1626ef270ab1SKenneth D. Merry 
1627ef270ab1SKenneth D. Merry 	return blocksize;
1628ef270ab1SKenneth D. Merry }
1629ef270ab1SKenneth D. Merry 
1630ef270ab1SKenneth D. Merry static int32_t ocs_segment_remaining(ocs_textbuf_segment_t *segment);
1631ef270ab1SKenneth D. Merry static ocs_textbuf_segment_t *ocs_textbuf_segment_alloc(ocs_textbuf_t *textbuf);
1632ef270ab1SKenneth D. Merry static void ocs_textbuf_segment_free(ocs_t *ocs, ocs_textbuf_segment_t *segment);
1633ef270ab1SKenneth D. Merry static ocs_textbuf_segment_t *ocs_textbuf_get_segment(ocs_textbuf_t *textbuf, uint32_t idx);
1634ef270ab1SKenneth D. Merry 
1635ef270ab1SKenneth D. Merry uint8_t *
1636ef270ab1SKenneth D. Merry ocs_textbuf_get_buffer(ocs_textbuf_t *textbuf)
1637ef270ab1SKenneth D. Merry {
1638ef270ab1SKenneth D. Merry 	return ocs_textbuf_ext_get_buffer(textbuf, 0);
1639ef270ab1SKenneth D. Merry }
1640ef270ab1SKenneth D. Merry 
1641ef270ab1SKenneth D. Merry int32_t
1642ef270ab1SKenneth D. Merry ocs_textbuf_get_length(ocs_textbuf_t *textbuf)
1643ef270ab1SKenneth D. Merry {
1644ef270ab1SKenneth D. Merry 	return ocs_textbuf_ext_get_length(textbuf, 0);
1645ef270ab1SKenneth D. Merry }
1646ef270ab1SKenneth D. Merry 
1647ef270ab1SKenneth D. Merry int32_t
1648ef270ab1SKenneth D. Merry ocs_textbuf_get_written(ocs_textbuf_t *textbuf)
1649ef270ab1SKenneth D. Merry {
1650ef270ab1SKenneth D. Merry 	uint32_t idx;
1651ef270ab1SKenneth D. Merry 	int32_t n;
1652ef270ab1SKenneth D. Merry 	int32_t total = 0;
1653ef270ab1SKenneth D. Merry 
1654ef270ab1SKenneth D. Merry 	for (idx = 0; (n = ocs_textbuf_ext_get_written(textbuf, idx)) >= 0; idx++) {
1655ef270ab1SKenneth D. Merry 		total += n;
1656ef270ab1SKenneth D. Merry 	}
1657ef270ab1SKenneth D. Merry 	return total;
1658ef270ab1SKenneth D. Merry }
1659ef270ab1SKenneth D. Merry 
1660ef270ab1SKenneth D. Merry uint8_t *ocs_textbuf_ext_get_buffer(ocs_textbuf_t *textbuf, uint32_t idx)
1661ef270ab1SKenneth D. Merry {
1662ef270ab1SKenneth D. Merry 	ocs_textbuf_segment_t *segment = ocs_textbuf_get_segment(textbuf, idx);
1663ef270ab1SKenneth D. Merry 	if (segment == NULL) {
1664ef270ab1SKenneth D. Merry 		return NULL;
1665ef270ab1SKenneth D. Merry 	}
1666ef270ab1SKenneth D. Merry 	return segment->buffer;
1667ef270ab1SKenneth D. Merry }
1668ef270ab1SKenneth D. Merry 
1669ef270ab1SKenneth D. Merry int32_t ocs_textbuf_ext_get_length(ocs_textbuf_t *textbuf, uint32_t idx)
1670ef270ab1SKenneth D. Merry {
1671ef270ab1SKenneth D. Merry 	ocs_textbuf_segment_t *segment = ocs_textbuf_get_segment(textbuf, idx);
1672ef270ab1SKenneth D. Merry 	if (segment == NULL) {
1673ef270ab1SKenneth D. Merry 		return -1;
1674ef270ab1SKenneth D. Merry 	}
1675ef270ab1SKenneth D. Merry 	return segment->buffer_length;
1676ef270ab1SKenneth D. Merry }
1677ef270ab1SKenneth D. Merry 
1678ef270ab1SKenneth D. Merry int32_t ocs_textbuf_ext_get_written(ocs_textbuf_t *textbuf, uint32_t idx)
1679ef270ab1SKenneth D. Merry {
1680ef270ab1SKenneth D. Merry 	ocs_textbuf_segment_t *segment = ocs_textbuf_get_segment(textbuf, idx);
1681ef270ab1SKenneth D. Merry 	if (segment == NULL) {
1682ef270ab1SKenneth D. Merry 		return -1;
1683ef270ab1SKenneth D. Merry 	}
1684ef270ab1SKenneth D. Merry 	return segment->buffer_written;
1685ef270ab1SKenneth D. Merry }
1686ef270ab1SKenneth D. Merry 
1687ef270ab1SKenneth D. Merry uint32_t
1688ef270ab1SKenneth D. Merry ocs_textbuf_initialized(ocs_textbuf_t *textbuf)
1689ef270ab1SKenneth D. Merry {
1690ef270ab1SKenneth D. Merry 	return (textbuf->ocs != NULL);
1691ef270ab1SKenneth D. Merry }
1692ef270ab1SKenneth D. Merry 
1693ef270ab1SKenneth D. Merry int32_t
1694ef270ab1SKenneth D. Merry ocs_textbuf_alloc(ocs_t *ocs, ocs_textbuf_t *textbuf, uint32_t length)
1695ef270ab1SKenneth D. Merry {
1696ef270ab1SKenneth D. Merry 	ocs_memset(textbuf, 0, sizeof(*textbuf));
1697ef270ab1SKenneth D. Merry 
1698ef270ab1SKenneth D. Merry 	textbuf->ocs = ocs;
1699ef270ab1SKenneth D. Merry 	ocs_list_init(&textbuf->segment_list, ocs_textbuf_segment_t, link);
1700ef270ab1SKenneth D. Merry 
1701ef270ab1SKenneth D. Merry 	if (length > OCS_TEXTBUF_MAX_ALLOC_LEN) {
1702ef270ab1SKenneth D. Merry 		textbuf->allocation_length = OCS_TEXTBUF_MAX_ALLOC_LEN;
1703ef270ab1SKenneth D. Merry 	} else {
1704ef270ab1SKenneth D. Merry 		textbuf->allocation_length = length;
1705ef270ab1SKenneth D. Merry 	}
1706ef270ab1SKenneth D. Merry 
1707ef270ab1SKenneth D. Merry 	/* mark as extendable */
1708ef270ab1SKenneth D. Merry 	textbuf->extendable = TRUE;
1709ef270ab1SKenneth D. Merry 
1710ef270ab1SKenneth D. Merry 	/* save maximum allocation length */
1711ef270ab1SKenneth D. Merry 	textbuf->max_allocation_length = length;
1712ef270ab1SKenneth D. Merry 
1713ef270ab1SKenneth D. Merry 	/* Add first segment */
1714ef270ab1SKenneth D. Merry 	return (ocs_textbuf_segment_alloc(textbuf) == NULL) ? -1 : 0;
1715ef270ab1SKenneth D. Merry }
1716ef270ab1SKenneth D. Merry 
1717ef270ab1SKenneth D. Merry static ocs_textbuf_segment_t *
1718ef270ab1SKenneth D. Merry ocs_textbuf_segment_alloc(ocs_textbuf_t *textbuf)
1719ef270ab1SKenneth D. Merry {
1720ef270ab1SKenneth D. Merry 	ocs_textbuf_segment_t *segment = NULL;
1721ef270ab1SKenneth D. Merry 
1722ef270ab1SKenneth D. Merry 	if (textbuf->extendable) {
1723ef270ab1SKenneth D. Merry 		segment = ocs_malloc(textbuf->ocs, sizeof(*segment), OCS_M_ZERO | OCS_M_NOWAIT);
1724ef270ab1SKenneth D. Merry 		if (segment != NULL) {
1725ef270ab1SKenneth D. Merry 			segment->buffer = ocs_malloc(textbuf->ocs, textbuf->allocation_length, OCS_M_ZERO | OCS_M_NOWAIT);
1726ef270ab1SKenneth D. Merry 			if (segment->buffer != NULL) {
1727ef270ab1SKenneth D. Merry 				segment->buffer_length = textbuf->allocation_length;
1728ef270ab1SKenneth D. Merry 				segment->buffer_written = 0;
1729ef270ab1SKenneth D. Merry 				ocs_list_add_tail(&textbuf->segment_list, segment);
1730ef270ab1SKenneth D. Merry 				textbuf->total_allocation_length += textbuf->allocation_length;
1731ef270ab1SKenneth D. Merry 
1732ef270ab1SKenneth D. Merry 				/* If we've allocated our limit, then mark as not extendable */
1733ef270ab1SKenneth D. Merry 				if (textbuf->total_allocation_length >= textbuf->max_allocation_length) {
1734ef270ab1SKenneth D. Merry 					textbuf->extendable = 0;
1735ef270ab1SKenneth D. Merry 				}
1736ef270ab1SKenneth D. Merry 
1737ef270ab1SKenneth D. Merry 			} else {
1738ef270ab1SKenneth D. Merry 				ocs_textbuf_segment_free(textbuf->ocs, segment);
1739ef270ab1SKenneth D. Merry 				segment = NULL;
1740ef270ab1SKenneth D. Merry 			}
1741ef270ab1SKenneth D. Merry 		}
1742ef270ab1SKenneth D. Merry 	}
1743ef270ab1SKenneth D. Merry 	return segment;
1744ef270ab1SKenneth D. Merry }
1745ef270ab1SKenneth D. Merry 
1746ef270ab1SKenneth D. Merry static void
1747ef270ab1SKenneth D. Merry ocs_textbuf_segment_free(ocs_t *ocs, ocs_textbuf_segment_t *segment)
1748ef270ab1SKenneth D. Merry {
1749ef270ab1SKenneth D. Merry 	if (segment) {
1750ef270ab1SKenneth D. Merry 		if (segment->buffer && !segment->user_allocated) {
1751ef270ab1SKenneth D. Merry 			ocs_free(ocs, segment->buffer, segment->buffer_length);
1752ef270ab1SKenneth D. Merry 		}
1753ef270ab1SKenneth D. Merry 		ocs_free(ocs, segment, sizeof(*segment));
1754ef270ab1SKenneth D. Merry 	}
1755ef270ab1SKenneth D. Merry }
1756ef270ab1SKenneth D. Merry 
1757ef270ab1SKenneth D. Merry static ocs_textbuf_segment_t *
1758ef270ab1SKenneth D. Merry ocs_textbuf_get_segment(ocs_textbuf_t *textbuf, uint32_t idx)
1759ef270ab1SKenneth D. Merry {
1760ef270ab1SKenneth D. Merry 	uint32_t i;
1761ef270ab1SKenneth D. Merry 	ocs_textbuf_segment_t *segment;
1762ef270ab1SKenneth D. Merry 
1763ef270ab1SKenneth D. Merry 	if (ocs_textbuf_initialized(textbuf)) {
1764ef270ab1SKenneth D. Merry 		i = 0;
1765ef270ab1SKenneth D. Merry 		ocs_list_foreach(&textbuf->segment_list, segment) {
1766ef270ab1SKenneth D. Merry 			if (i == idx) {
1767ef270ab1SKenneth D. Merry 				return segment;
1768ef270ab1SKenneth D. Merry 			}
1769ef270ab1SKenneth D. Merry 			i++;
1770ef270ab1SKenneth D. Merry 		}
1771ef270ab1SKenneth D. Merry 	}
1772ef270ab1SKenneth D. Merry 	return NULL;
1773ef270ab1SKenneth D. Merry }
1774ef270ab1SKenneth D. Merry 
1775ef270ab1SKenneth D. Merry int32_t
1776ef270ab1SKenneth D. Merry ocs_textbuf_init(ocs_t *ocs, ocs_textbuf_t *textbuf, void *buffer, uint32_t length)
1777ef270ab1SKenneth D. Merry {
1778ef270ab1SKenneth D. Merry 	int32_t rc = -1;
1779ef270ab1SKenneth D. Merry 	ocs_textbuf_segment_t *segment;
1780ef270ab1SKenneth D. Merry 
1781ef270ab1SKenneth D. Merry 	ocs_memset(textbuf, 0, sizeof(*textbuf));
1782ef270ab1SKenneth D. Merry 
1783ef270ab1SKenneth D. Merry 	textbuf->ocs = ocs;
1784ef270ab1SKenneth D. Merry 	ocs_list_init(&textbuf->segment_list, ocs_textbuf_segment_t, link);
1785ef270ab1SKenneth D. Merry 	segment = ocs_malloc(ocs, sizeof(*segment), OCS_M_ZERO | OCS_M_NOWAIT);
1786ef270ab1SKenneth D. Merry 	if (segment) {
1787ef270ab1SKenneth D. Merry 		segment->buffer = buffer;
1788ef270ab1SKenneth D. Merry 		segment->buffer_length = length;
1789ef270ab1SKenneth D. Merry 		segment->buffer_written = 0;
1790ef270ab1SKenneth D. Merry 		segment->user_allocated = 1;
1791ef270ab1SKenneth D. Merry 		ocs_list_add_tail(&textbuf->segment_list, segment);
1792ef270ab1SKenneth D. Merry 		rc = 0;
1793ef270ab1SKenneth D. Merry 	}
1794ef270ab1SKenneth D. Merry 
1795ef270ab1SKenneth D. Merry 	return rc;
1796ef270ab1SKenneth D. Merry }
1797ef270ab1SKenneth D. Merry 
1798ef270ab1SKenneth D. Merry void
1799ef270ab1SKenneth D. Merry ocs_textbuf_free(ocs_t *ocs, ocs_textbuf_t *textbuf)
1800ef270ab1SKenneth D. Merry {
1801ef270ab1SKenneth D. Merry 	ocs_textbuf_segment_t *segment;
1802ef270ab1SKenneth D. Merry 	ocs_textbuf_segment_t *n;
1803ef270ab1SKenneth D. Merry 
1804ef270ab1SKenneth D. Merry 	if (ocs_textbuf_initialized(textbuf)) {
1805ef270ab1SKenneth D. Merry 		ocs_list_foreach_safe(&textbuf->segment_list, segment, n) {
1806ef270ab1SKenneth D. Merry 			ocs_list_remove(&textbuf->segment_list, segment);
1807ef270ab1SKenneth D. Merry 			ocs_textbuf_segment_free(ocs, segment);
1808ef270ab1SKenneth D. Merry 		}
1809ef270ab1SKenneth D. Merry 
1810ef270ab1SKenneth D. Merry 		ocs_memset(textbuf, 0, sizeof(*textbuf));
1811ef270ab1SKenneth D. Merry 	}
1812ef270ab1SKenneth D. Merry }
1813ef270ab1SKenneth D. Merry 
1814ef270ab1SKenneth D. Merry void
1815ef270ab1SKenneth D. Merry ocs_textbuf_printf(ocs_textbuf_t *textbuf, const char *fmt, ...)
1816ef270ab1SKenneth D. Merry {
1817ef270ab1SKenneth D. Merry 	va_list ap;
1818ef270ab1SKenneth D. Merry 
1819ef270ab1SKenneth D. Merry 	if (ocs_textbuf_initialized(textbuf)) {
1820ef270ab1SKenneth D. Merry 		va_start(ap, fmt);
1821ef270ab1SKenneth D. Merry 		ocs_textbuf_vprintf(textbuf, fmt, ap);
1822ef270ab1SKenneth D. Merry 		va_end(ap);
1823ef270ab1SKenneth D. Merry 	}
1824ef270ab1SKenneth D. Merry }
1825ef270ab1SKenneth D. Merry 
1826ef270ab1SKenneth D. Merry void
1827ef270ab1SKenneth D. Merry ocs_textbuf_vprintf(ocs_textbuf_t *textbuf, const char *fmt, va_list ap)
1828ef270ab1SKenneth D. Merry {
1829ef270ab1SKenneth D. Merry 	int avail;
1830ef270ab1SKenneth D. Merry 	int written;
1831ef270ab1SKenneth D. Merry 	ocs_textbuf_segment_t *segment;
1832ef270ab1SKenneth D. Merry 	va_list save_ap;
1833ef270ab1SKenneth D. Merry 
1834ef270ab1SKenneth D. Merry 	if (!ocs_textbuf_initialized(textbuf)) {
1835ef270ab1SKenneth D. Merry 		return;
1836ef270ab1SKenneth D. Merry 	}
1837ef270ab1SKenneth D. Merry 
1838ef270ab1SKenneth D. Merry 	va_copy(save_ap, ap);
1839ef270ab1SKenneth D. Merry 
1840ef270ab1SKenneth D. Merry 	/* fetch last segment */
1841ef270ab1SKenneth D. Merry 	segment = ocs_list_get_tail(&textbuf->segment_list);
1842ef270ab1SKenneth D. Merry 
1843ef270ab1SKenneth D. Merry 	avail = ocs_segment_remaining(segment);
1844ef270ab1SKenneth D. Merry 	if (avail == 0) {
1845ef270ab1SKenneth D. Merry 		if ((segment = ocs_textbuf_segment_alloc(textbuf)) == NULL) {
1846ef270ab1SKenneth D. Merry 			goto out;
1847ef270ab1SKenneth D. Merry 		}
1848ef270ab1SKenneth D. Merry 		avail = ocs_segment_remaining(segment);
1849ef270ab1SKenneth D. Merry 	}
1850ef270ab1SKenneth D. Merry 
1851ef270ab1SKenneth D. Merry 	written = ocs_vsnprintf(segment->buffer + segment->buffer_written, avail, fmt, ap);
1852ef270ab1SKenneth D. Merry 
1853ef270ab1SKenneth D. Merry 	/* See if data was truncated */
1854ef270ab1SKenneth D. Merry 	if (written >= avail) {
1855ef270ab1SKenneth D. Merry 
1856ef270ab1SKenneth D. Merry 		written = avail;
1857ef270ab1SKenneth D. Merry 
1858ef270ab1SKenneth D. Merry 		if (textbuf->extendable) {
1859ef270ab1SKenneth D. Merry 
1860ef270ab1SKenneth D. Merry 			/* revert the partially written data */
1861ef270ab1SKenneth D. Merry 			*(segment->buffer + segment->buffer_written) = 0;
1862ef270ab1SKenneth D. Merry 
1863ef270ab1SKenneth D. Merry 			/* Allocate a new segment */
1864ef270ab1SKenneth D. Merry 			if ((segment = ocs_textbuf_segment_alloc(textbuf)) == NULL) {
1865ef270ab1SKenneth D. Merry 				ocs_log_err(textbuf->ocs, "alloc segment failed\n");
1866ef270ab1SKenneth D. Merry 				goto out;
1867ef270ab1SKenneth D. Merry 			}
1868ef270ab1SKenneth D. Merry 			avail = ocs_segment_remaining(segment);
1869ef270ab1SKenneth D. Merry 
1870ef270ab1SKenneth D. Merry 			/* Retry the write */
1871ef270ab1SKenneth D. Merry 			written = ocs_vsnprintf(segment->buffer + segment->buffer_written, avail, fmt, save_ap);
1872ef270ab1SKenneth D. Merry 		}
1873ef270ab1SKenneth D. Merry 	}
1874ef270ab1SKenneth D. Merry 	segment->buffer_written += written;
1875ef270ab1SKenneth D. Merry 
1876ef270ab1SKenneth D. Merry out:
1877ef270ab1SKenneth D. Merry 	va_end(save_ap);
1878ef270ab1SKenneth D. Merry }
1879ef270ab1SKenneth D. Merry 
1880ef270ab1SKenneth D. Merry void
1881ef270ab1SKenneth D. Merry ocs_textbuf_putc(ocs_textbuf_t *textbuf, uint8_t c)
1882ef270ab1SKenneth D. Merry {
1883ef270ab1SKenneth D. Merry 	ocs_textbuf_segment_t *segment;
1884ef270ab1SKenneth D. Merry 
1885ef270ab1SKenneth D. Merry 	if (ocs_textbuf_initialized(textbuf)) {
1886ef270ab1SKenneth D. Merry 		segment = ocs_list_get_tail(&textbuf->segment_list);
1887ef270ab1SKenneth D. Merry 
1888ef270ab1SKenneth D. Merry 		if (ocs_segment_remaining(segment)) {
1889ef270ab1SKenneth D. Merry 			*(segment->buffer + segment->buffer_written++) = c;
1890ef270ab1SKenneth D. Merry 		}
1891ef270ab1SKenneth D. Merry 		if (ocs_segment_remaining(segment) == 0) {
1892ef270ab1SKenneth D. Merry 			ocs_textbuf_segment_alloc(textbuf);
1893ef270ab1SKenneth D. Merry 		}
1894ef270ab1SKenneth D. Merry 	}
1895ef270ab1SKenneth D. Merry }
1896ef270ab1SKenneth D. Merry 
1897ef270ab1SKenneth D. Merry void
1898ef270ab1SKenneth D. Merry ocs_textbuf_puts(ocs_textbuf_t *textbuf, char *s)
1899ef270ab1SKenneth D. Merry {
1900ef270ab1SKenneth D. Merry 	if (ocs_textbuf_initialized(textbuf)) {
1901ef270ab1SKenneth D. Merry 		while(*s) {
1902ef270ab1SKenneth D. Merry 			ocs_textbuf_putc(textbuf, *s++);
1903ef270ab1SKenneth D. Merry 		}
1904ef270ab1SKenneth D. Merry 	}
1905ef270ab1SKenneth D. Merry }
1906ef270ab1SKenneth D. Merry 
1907ef270ab1SKenneth D. Merry void
1908ef270ab1SKenneth D. Merry ocs_textbuf_buffer(ocs_textbuf_t *textbuf, uint8_t *buffer, uint32_t buffer_length)
1909ef270ab1SKenneth D. Merry {
1910ef270ab1SKenneth D. Merry 	char *s;
1911ef270ab1SKenneth D. Merry 
1912ef270ab1SKenneth D. Merry 	if (!ocs_textbuf_initialized(textbuf)) {
1913ef270ab1SKenneth D. Merry 		return;
1914ef270ab1SKenneth D. Merry 	}
1915ef270ab1SKenneth D. Merry 
1916ef270ab1SKenneth D. Merry 	s = (char*) buffer;
1917ef270ab1SKenneth D. Merry 	while(*s) {
1918ef270ab1SKenneth D. Merry 
1919ef270ab1SKenneth D. Merry 		/*
1920ef270ab1SKenneth D. Merry 		 * XML escapes
1921ef270ab1SKenneth D. Merry 		 *
1922ef270ab1SKenneth D. Merry 		 * "   &quot;
1923ef270ab1SKenneth D. Merry 		 * '   &apos;
1924ef270ab1SKenneth D. Merry 		 * <   &lt;
1925ef270ab1SKenneth D. Merry 		 * >   &gt;
1926ef270ab1SKenneth D. Merry 		 * &   &amp;
1927ef270ab1SKenneth D. Merry 		 */
1928ef270ab1SKenneth D. Merry 
1929ef270ab1SKenneth D. Merry 		switch(*s) {
1930ef270ab1SKenneth D. Merry 		case '"':	ocs_textbuf_puts(textbuf, "&quot;"); break;
1931ef270ab1SKenneth D. Merry 		case '\'':	ocs_textbuf_puts(textbuf, "&apos;"); break;
1932ef270ab1SKenneth D. Merry 		case '<':	ocs_textbuf_puts(textbuf, "&lt;"); break;
1933ef270ab1SKenneth D. Merry 		case '>':	ocs_textbuf_puts(textbuf, "&gt;"); break;
1934ef270ab1SKenneth D. Merry 		case '&':	ocs_textbuf_puts(textbuf, "&amp;"); break;
1935ef270ab1SKenneth D. Merry 		default:	ocs_textbuf_putc(textbuf, *s); break;
1936ef270ab1SKenneth D. Merry 		}
1937ef270ab1SKenneth D. Merry 		s++;
1938ef270ab1SKenneth D. Merry 	}
1939ef270ab1SKenneth D. Merry 
1940ef270ab1SKenneth D. Merry }
1941ef270ab1SKenneth D. Merry 
1942ef270ab1SKenneth D. Merry void
1943ef270ab1SKenneth D. Merry ocs_textbuf_copy(ocs_textbuf_t *textbuf, uint8_t *buffer, uint32_t buffer_length)
1944ef270ab1SKenneth D. Merry {
1945ef270ab1SKenneth D. Merry 	char *s;
1946ef270ab1SKenneth D. Merry 
1947ef270ab1SKenneth D. Merry 	if (!ocs_textbuf_initialized(textbuf)) {
1948ef270ab1SKenneth D. Merry 		return;
1949ef270ab1SKenneth D. Merry 	}
1950ef270ab1SKenneth D. Merry 
1951ef270ab1SKenneth D. Merry 	s = (char*) buffer;
1952ef270ab1SKenneth D. Merry 	while(*s) {
1953ef270ab1SKenneth D. Merry 		ocs_textbuf_putc(textbuf, *s++);
1954ef270ab1SKenneth D. Merry 	}
1955ef270ab1SKenneth D. Merry 
1956ef270ab1SKenneth D. Merry }
1957ef270ab1SKenneth D. Merry 
1958ef270ab1SKenneth D. Merry int32_t
1959ef270ab1SKenneth D. Merry ocs_textbuf_remaining(ocs_textbuf_t *textbuf)
1960ef270ab1SKenneth D. Merry {
1961ef270ab1SKenneth D. Merry 	if (ocs_textbuf_initialized(textbuf)) {
1962ef270ab1SKenneth D. Merry 		return ocs_segment_remaining(ocs_list_get_head(&textbuf->segment_list));
1963ef270ab1SKenneth D. Merry 	} else {
1964ef270ab1SKenneth D. Merry 		return 0;
1965ef270ab1SKenneth D. Merry 	}
1966ef270ab1SKenneth D. Merry }
1967ef270ab1SKenneth D. Merry 
1968ef270ab1SKenneth D. Merry static int32_t
1969ef270ab1SKenneth D. Merry ocs_segment_remaining(ocs_textbuf_segment_t *segment)
1970ef270ab1SKenneth D. Merry {
1971ef270ab1SKenneth D. Merry 	return segment->buffer_length - segment->buffer_written;
1972ef270ab1SKenneth D. Merry }
1973ef270ab1SKenneth D. Merry 
1974ef270ab1SKenneth D. Merry void
1975ef270ab1SKenneth D. Merry ocs_textbuf_reset(ocs_textbuf_t *textbuf)
1976ef270ab1SKenneth D. Merry {
1977ef270ab1SKenneth D. Merry 	uint32_t i = 0;
1978ef270ab1SKenneth D. Merry 	ocs_textbuf_segment_t *segment;
1979ef270ab1SKenneth D. Merry 	ocs_textbuf_segment_t *n;
1980ef270ab1SKenneth D. Merry 
1981ef270ab1SKenneth D. Merry 	if (ocs_textbuf_initialized(textbuf)) {
1982ef270ab1SKenneth D. Merry 		/* zero written on the first segment, free the rest */
1983ef270ab1SKenneth D. Merry 		ocs_list_foreach_safe(&textbuf->segment_list, segment, n) {
1984ef270ab1SKenneth D. Merry 			if (i++ == 0) {
1985ef270ab1SKenneth D. Merry 				segment->buffer_written = 0;
1986ef270ab1SKenneth D. Merry 			} else {
1987ef270ab1SKenneth D. Merry 				ocs_list_remove(&textbuf->segment_list, segment);
1988ef270ab1SKenneth D. Merry 				ocs_textbuf_segment_free(textbuf->ocs, segment);
1989ef270ab1SKenneth D. Merry 			}
1990ef270ab1SKenneth D. Merry 		}
1991ef270ab1SKenneth D. Merry 	}
1992ef270ab1SKenneth D. Merry }
1993ef270ab1SKenneth D. Merry 
1994ef270ab1SKenneth D. Merry /**
1995ef270ab1SKenneth D. Merry  * @brief Sparse Vector API.
1996ef270ab1SKenneth D. Merry  *
1997ef270ab1SKenneth D. Merry  * This is a trimmed down sparse vector implementation tuned to the problem of
1998ef270ab1SKenneth D. Merry  * 24-bit FC_IDs. In this case, the 24-bit index value is broken down in three
1999ef270ab1SKenneth D. Merry  * 8-bit values. These values are used to index up to three 256 element arrays.
2000ef270ab1SKenneth D. Merry  * Arrays are allocated, only when needed. @n @n
2001ef270ab1SKenneth D. Merry  * The lookup can complete in constant time (3 indexed array references). @n @n
2002ef270ab1SKenneth D. Merry  * A typical use case would be that the fabric/directory FC_IDs would cause two rows to be
2003ef270ab1SKenneth D. Merry  * allocated, and the fabric assigned remote nodes would cause two rows to be allocated, with
2004ef270ab1SKenneth D. Merry  * the root row always allocated. This gives five rows of 256 x sizeof(void*),
2005ef270ab1SKenneth D. Merry  * resulting in 10k.
2006ef270ab1SKenneth D. Merry  */
2007ef270ab1SKenneth D. Merry 
2008ef270ab1SKenneth D. Merry 
2009ef270ab1SKenneth D. Merry 
2010ef270ab1SKenneth D. Merry /**
2011ef270ab1SKenneth D. Merry  * @ingroup spv
2012ef270ab1SKenneth D. Merry  * @brief Allocate a new sparse vector row.
2013ef270ab1SKenneth D. Merry  *
2014ef270ab1SKenneth D. Merry  * @param os OS handle
2015ef270ab1SKenneth D. Merry  * @param rowcount Count of rows.
2016ef270ab1SKenneth D. Merry  *
2017ef270ab1SKenneth D. Merry  * @par Description
2018ef270ab1SKenneth D. Merry  * A new sparse vector row is allocated.
2019ef270ab1SKenneth D. Merry  *
2020ef270ab1SKenneth D. Merry  * @param rowcount Number of elements in a row.
2021ef270ab1SKenneth D. Merry  *
2022ef270ab1SKenneth D. Merry  * @return Returns the pointer to a row.
2023ef270ab1SKenneth D. Merry  */
2024ef270ab1SKenneth D. Merry static void
2025ef270ab1SKenneth D. Merry **spv_new_row(ocs_os_handle_t os, uint32_t rowcount)
2026ef270ab1SKenneth D. Merry {
2027ef270ab1SKenneth D. Merry 	return ocs_malloc(os, sizeof(void*) * rowcount, OCS_M_ZERO | OCS_M_NOWAIT);
2028ef270ab1SKenneth D. Merry }
2029ef270ab1SKenneth D. Merry 
2030ef270ab1SKenneth D. Merry 
2031ef270ab1SKenneth D. Merry 
2032ef270ab1SKenneth D. Merry /**
2033ef270ab1SKenneth D. Merry  * @ingroup spv
2034ef270ab1SKenneth D. Merry  * @brief Delete row recursively.
2035ef270ab1SKenneth D. Merry  *
2036ef270ab1SKenneth D. Merry  * @par Description
2037ef270ab1SKenneth D. Merry  * This function recursively deletes the rows in this sparse vector
2038ef270ab1SKenneth D. Merry  *
2039ef270ab1SKenneth D. Merry  * @param os OS handle
2040ef270ab1SKenneth D. Merry  * @param a Pointer to the row.
2041ef270ab1SKenneth D. Merry  * @param n Number of elements in the row.
2042ef270ab1SKenneth D. Merry  * @param depth Depth of deleting.
2043ef270ab1SKenneth D. Merry  *
2044ef270ab1SKenneth D. Merry  * @return None.
2045ef270ab1SKenneth D. Merry  */
2046ef270ab1SKenneth D. Merry static void
2047ef270ab1SKenneth D. Merry _spv_del(ocs_os_handle_t os, void **a, uint32_t n, uint32_t depth)
2048ef270ab1SKenneth D. Merry {
2049ef270ab1SKenneth D. Merry 	if (a) {
2050ef270ab1SKenneth D. Merry 		if (depth) {
2051ef270ab1SKenneth D. Merry 			uint32_t i;
2052ef270ab1SKenneth D. Merry 
2053ef270ab1SKenneth D. Merry 			for (i = 0; i < n; i ++) {
2054ef270ab1SKenneth D. Merry 				_spv_del(os, a[i], n, depth-1);
2055ef270ab1SKenneth D. Merry 			}
2056ef270ab1SKenneth D. Merry 
2057ef270ab1SKenneth D. Merry 			ocs_free(os, a, SPV_ROWLEN*sizeof(*a));
2058ef270ab1SKenneth D. Merry 		}
2059ef270ab1SKenneth D. Merry 	}
2060ef270ab1SKenneth D. Merry }
2061ef270ab1SKenneth D. Merry 
2062ef270ab1SKenneth D. Merry /**
2063ef270ab1SKenneth D. Merry  * @ingroup spv
2064ef270ab1SKenneth D. Merry  * @brief Delete a sparse vector.
2065ef270ab1SKenneth D. Merry  *
2066ef270ab1SKenneth D. Merry  * @par Description
2067ef270ab1SKenneth D. Merry  * The sparse vector is freed.
2068ef270ab1SKenneth D. Merry  *
2069ef270ab1SKenneth D. Merry  * @param spv Pointer to the sparse vector object.
2070ef270ab1SKenneth D. Merry  */
2071ef270ab1SKenneth D. Merry void
2072ef270ab1SKenneth D. Merry spv_del(sparse_vector_t spv)
2073ef270ab1SKenneth D. Merry {
2074ef270ab1SKenneth D. Merry 	if (spv) {
2075ef270ab1SKenneth D. Merry 		_spv_del(spv->os, spv->array, SPV_ROWLEN, SPV_DIM);
2076ef270ab1SKenneth D. Merry 		ocs_free(spv->os, spv, sizeof(*spv));
2077ef270ab1SKenneth D. Merry 	}
2078ef270ab1SKenneth D. Merry }
2079ef270ab1SKenneth D. Merry 
2080ef270ab1SKenneth D. Merry /**
2081ef270ab1SKenneth D. Merry  * @ingroup spv
2082ef270ab1SKenneth D. Merry  * @brief Instantiate a new sparse vector object.
2083ef270ab1SKenneth D. Merry  *
2084ef270ab1SKenneth D. Merry  * @par Description
2085ef270ab1SKenneth D. Merry  * A new sparse vector is allocated.
2086ef270ab1SKenneth D. Merry  *
2087ef270ab1SKenneth D. Merry  * @param os OS handle
2088ef270ab1SKenneth D. Merry  *
2089ef270ab1SKenneth D. Merry  * @return Returns the pointer to the sparse vector, or NULL.
2090ef270ab1SKenneth D. Merry  */
2091ef270ab1SKenneth D. Merry sparse_vector_t
2092ef270ab1SKenneth D. Merry spv_new(ocs_os_handle_t os)
2093ef270ab1SKenneth D. Merry {
2094ef270ab1SKenneth D. Merry 	sparse_vector_t spv;
2095ef270ab1SKenneth D. Merry 	uint32_t i;
2096ef270ab1SKenneth D. Merry 
2097ef270ab1SKenneth D. Merry 	spv = ocs_malloc(os, sizeof(*spv), OCS_M_ZERO | OCS_M_NOWAIT);
2098ef270ab1SKenneth D. Merry 	if (!spv) {
2099ef270ab1SKenneth D. Merry 		return NULL;
2100ef270ab1SKenneth D. Merry 	}
2101ef270ab1SKenneth D. Merry 
2102ef270ab1SKenneth D. Merry 	spv->os = os;
2103ef270ab1SKenneth D. Merry 	spv->max_idx = 1;
2104ef270ab1SKenneth D. Merry 	for (i = 0; i < SPV_DIM; i ++) {
2105ef270ab1SKenneth D. Merry 		spv->max_idx *= SPV_ROWLEN;
2106ef270ab1SKenneth D. Merry 	}
2107ef270ab1SKenneth D. Merry 
2108ef270ab1SKenneth D. Merry 	return spv;
2109ef270ab1SKenneth D. Merry }
2110ef270ab1SKenneth D. Merry 
2111ef270ab1SKenneth D. Merry /**
2112ef270ab1SKenneth D. Merry  * @ingroup spv
2113ef270ab1SKenneth D. Merry  * @brief Return the address of a cell.
2114ef270ab1SKenneth D. Merry  *
2115ef270ab1SKenneth D. Merry  * @par Description
2116ef270ab1SKenneth D. Merry  * Returns the address of a cell, allocates sparse rows as needed if the
2117ef270ab1SKenneth D. Merry  *         alloc_new_rows parameter is set.
2118ef270ab1SKenneth D. Merry  *
2119ef270ab1SKenneth D. Merry  * @param sv Pointer to the sparse vector.
2120ef270ab1SKenneth D. Merry  * @param idx Index of which to return the address.
2121ef270ab1SKenneth D. Merry  * @param alloc_new_rows If TRUE, then new rows may be allocated to set values,
2122ef270ab1SKenneth D. Merry  *                       Set to FALSE for retrieving values.
2123ef270ab1SKenneth D. Merry  *
2124ef270ab1SKenneth D. Merry  * @return Returns the pointer to the cell, or NULL.
2125ef270ab1SKenneth D. Merry  */
2126ef270ab1SKenneth D. Merry static void
2127ef270ab1SKenneth D. Merry *spv_new_cell(sparse_vector_t sv, uint32_t idx, uint8_t alloc_new_rows)
2128ef270ab1SKenneth D. Merry {
2129ef270ab1SKenneth D. Merry 	uint32_t a = (idx >> 16) & 0xff;
2130ef270ab1SKenneth D. Merry 	uint32_t b = (idx >>  8) & 0xff;
2131ef270ab1SKenneth D. Merry 	uint32_t c = (idx >>  0) & 0xff;
2132ef270ab1SKenneth D. Merry 	void **p;
2133ef270ab1SKenneth D. Merry 
2134ef270ab1SKenneth D. Merry 	if (idx >= sv->max_idx) {
2135ef270ab1SKenneth D. Merry 		return NULL;
2136ef270ab1SKenneth D. Merry 	}
2137ef270ab1SKenneth D. Merry 
2138ef270ab1SKenneth D. Merry 	if (sv->array == NULL) {
2139ef270ab1SKenneth D. Merry 		sv->array = (alloc_new_rows ? spv_new_row(sv->os, SPV_ROWLEN) : NULL);
2140ef270ab1SKenneth D. Merry 		if (sv->array == NULL) {
2141ef270ab1SKenneth D. Merry 			return NULL;
2142ef270ab1SKenneth D. Merry 		}
2143ef270ab1SKenneth D. Merry 	}
2144ef270ab1SKenneth D. Merry 	p = sv->array;
2145ef270ab1SKenneth D. Merry 	if (p[a] == NULL) {
2146ef270ab1SKenneth D. Merry 		p[a] = (alloc_new_rows ? spv_new_row(sv->os, SPV_ROWLEN) : NULL);
2147ef270ab1SKenneth D. Merry 		if (p[a] == NULL) {
2148ef270ab1SKenneth D. Merry 			return NULL;
2149ef270ab1SKenneth D. Merry 		}
2150ef270ab1SKenneth D. Merry 	}
2151ef270ab1SKenneth D. Merry 	p = p[a];
2152ef270ab1SKenneth D. Merry 	if (p[b] == NULL) {
2153ef270ab1SKenneth D. Merry 		p[b] = (alloc_new_rows ? spv_new_row(sv->os, SPV_ROWLEN) : NULL);
2154ef270ab1SKenneth D. Merry 		if (p[b] == NULL) {
2155ef270ab1SKenneth D. Merry 			return NULL;
2156ef270ab1SKenneth D. Merry 		}
2157ef270ab1SKenneth D. Merry 	}
2158ef270ab1SKenneth D. Merry 	p = p[b];
2159ef270ab1SKenneth D. Merry 
2160ef270ab1SKenneth D. Merry 	return &p[c];
2161ef270ab1SKenneth D. Merry }
2162ef270ab1SKenneth D. Merry 
2163ef270ab1SKenneth D. Merry /**
2164ef270ab1SKenneth D. Merry  * @ingroup spv
2165ef270ab1SKenneth D. Merry  * @brief Set the sparse vector cell value.
2166ef270ab1SKenneth D. Merry  *
2167ef270ab1SKenneth D. Merry  * @par Description
2168ef270ab1SKenneth D. Merry  * Sets the sparse vector at @c idx to @c value.
2169ef270ab1SKenneth D. Merry  *
2170ef270ab1SKenneth D. Merry  * @param sv Pointer to the sparse vector.
2171ef270ab1SKenneth D. Merry  * @param idx Index of which to store.
2172ef270ab1SKenneth D. Merry  * @param value Value to store.
2173ef270ab1SKenneth D. Merry  *
2174ef270ab1SKenneth D. Merry  * @return None.
2175ef270ab1SKenneth D. Merry  */
2176ef270ab1SKenneth D. Merry void
2177ef270ab1SKenneth D. Merry spv_set(sparse_vector_t sv, uint32_t idx, void *value)
2178ef270ab1SKenneth D. Merry {
2179ef270ab1SKenneth D. Merry 	void **ref = spv_new_cell(sv, idx, TRUE);
2180ef270ab1SKenneth D. Merry 	if (ref) {
2181ef270ab1SKenneth D. Merry 		*ref = value;
2182ef270ab1SKenneth D. Merry 	}
2183ef270ab1SKenneth D. Merry }
2184ef270ab1SKenneth D. Merry 
2185ef270ab1SKenneth D. Merry /**
2186ef270ab1SKenneth D. Merry  * @ingroup spv
2187ef270ab1SKenneth D. Merry  * @brief Return the sparse vector cell value.
2188ef270ab1SKenneth D. Merry  *
2189ef270ab1SKenneth D. Merry  * @par Description
2190ef270ab1SKenneth D. Merry  * Returns the value at @c idx.
2191ef270ab1SKenneth D. Merry  *
2192ef270ab1SKenneth D. Merry  * @param sv Pointer to the sparse vector.
2193ef270ab1SKenneth D. Merry  * @param idx Index of which to return the value.
2194ef270ab1SKenneth D. Merry  *
2195ef270ab1SKenneth D. Merry  * @return Returns the cell value, or NULL.
2196ef270ab1SKenneth D. Merry  */
2197ef270ab1SKenneth D. Merry void
2198ef270ab1SKenneth D. Merry *spv_get(sparse_vector_t sv, uint32_t idx)
2199ef270ab1SKenneth D. Merry {
2200ef270ab1SKenneth D. Merry 	void **ref = spv_new_cell(sv, idx, FALSE);
2201ef270ab1SKenneth D. Merry 	if (ref) {
2202ef270ab1SKenneth D. Merry 		return *ref;
2203ef270ab1SKenneth D. Merry 	}
2204ef270ab1SKenneth D. Merry 	return NULL;
2205ef270ab1SKenneth D. Merry }
2206ef270ab1SKenneth D. Merry 
2207ef270ab1SKenneth D. Merry /*****************************************************************/
2208ef270ab1SKenneth D. Merry /*                                                               */
2209ef270ab1SKenneth D. Merry /* CRC LOOKUP TABLE                                              */
2210ef270ab1SKenneth D. Merry /* ================                                              */
2211ef270ab1SKenneth D. Merry /* The following CRC lookup table was generated automagically    */
2212ef270ab1SKenneth D. Merry /* by the Rocksoft^tm Model CRC Algorithm Table Generation       */
2213ef270ab1SKenneth D. Merry /* Program V1.0 using the following model parameters:            */
2214ef270ab1SKenneth D. Merry /*                                                               */
2215ef270ab1SKenneth D. Merry /*    Width   : 2 bytes.                                         */
2216ef270ab1SKenneth D. Merry /*    Poly    : 0x8BB7                                           */
2217ef270ab1SKenneth D. Merry /*    Reverse : FALSE.                                           */
2218ef270ab1SKenneth D. Merry /*                                                               */
2219ef270ab1SKenneth D. Merry /* For more information on the Rocksoft^tm Model CRC Algorithm,  */
2220ef270ab1SKenneth D. Merry /* see the document titled "A Painless Guide to CRC Error        */
2221ef270ab1SKenneth D. Merry /* Detection Algorithms" by Ross Williams                        */
2222ef270ab1SKenneth D. Merry /* (ross@guest.adelaide.edu.au.). This document is likely to be  */
2223ef270ab1SKenneth D. Merry /* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft".        */
2224ef270ab1SKenneth D. Merry /*                                                               */
2225ef270ab1SKenneth D. Merry /*****************************************************************/
2226ef270ab1SKenneth D. Merry /*
2227ef270ab1SKenneth D. Merry  * Emulex Inc, changes:
2228ef270ab1SKenneth D. Merry  * - minor syntax changes for successful compilation with contemporary
2229ef270ab1SKenneth D. Merry  *   C compilers, and OCS SDK API
2230ef270ab1SKenneth D. Merry  * - crctable[] generated using Rocksoft public domain code
2231ef270ab1SKenneth D. Merry  *
2232ef270ab1SKenneth D. Merry  * Used in the Emulex SDK, the generated file crctable.out is cut and pasted into
2233ef270ab1SKenneth D. Merry  * applicable SDK sources.
2234ef270ab1SKenneth D. Merry  */
2235ef270ab1SKenneth D. Merry 
2236ef270ab1SKenneth D. Merry 
2237ef270ab1SKenneth D. Merry static unsigned short crctable[256] =
2238ef270ab1SKenneth D. Merry {
2239ef270ab1SKenneth D. Merry  0x0000, 0x8BB7, 0x9CD9, 0x176E, 0xB205, 0x39B2, 0x2EDC, 0xA56B,
2240ef270ab1SKenneth D. Merry  0xEFBD, 0x640A, 0x7364, 0xF8D3, 0x5DB8, 0xD60F, 0xC161, 0x4AD6,
2241ef270ab1SKenneth D. Merry  0x54CD, 0xDF7A, 0xC814, 0x43A3, 0xE6C8, 0x6D7F, 0x7A11, 0xF1A6,
2242ef270ab1SKenneth D. Merry  0xBB70, 0x30C7, 0x27A9, 0xAC1E, 0x0975, 0x82C2, 0x95AC, 0x1E1B,
2243ef270ab1SKenneth D. Merry  0xA99A, 0x222D, 0x3543, 0xBEF4, 0x1B9F, 0x9028, 0x8746, 0x0CF1,
2244ef270ab1SKenneth D. Merry  0x4627, 0xCD90, 0xDAFE, 0x5149, 0xF422, 0x7F95, 0x68FB, 0xE34C,
2245ef270ab1SKenneth D. Merry  0xFD57, 0x76E0, 0x618E, 0xEA39, 0x4F52, 0xC4E5, 0xD38B, 0x583C,
2246ef270ab1SKenneth D. Merry  0x12EA, 0x995D, 0x8E33, 0x0584, 0xA0EF, 0x2B58, 0x3C36, 0xB781,
2247ef270ab1SKenneth D. Merry  0xD883, 0x5334, 0x445A, 0xCFED, 0x6A86, 0xE131, 0xF65F, 0x7DE8,
2248ef270ab1SKenneth D. Merry  0x373E, 0xBC89, 0xABE7, 0x2050, 0x853B, 0x0E8C, 0x19E2, 0x9255,
2249ef270ab1SKenneth D. Merry  0x8C4E, 0x07F9, 0x1097, 0x9B20, 0x3E4B, 0xB5FC, 0xA292, 0x2925,
2250ef270ab1SKenneth D. Merry  0x63F3, 0xE844, 0xFF2A, 0x749D, 0xD1F6, 0x5A41, 0x4D2F, 0xC698,
2251ef270ab1SKenneth D. Merry  0x7119, 0xFAAE, 0xEDC0, 0x6677, 0xC31C, 0x48AB, 0x5FC5, 0xD472,
2252ef270ab1SKenneth D. Merry  0x9EA4, 0x1513, 0x027D, 0x89CA, 0x2CA1, 0xA716, 0xB078, 0x3BCF,
2253ef270ab1SKenneth D. Merry  0x25D4, 0xAE63, 0xB90D, 0x32BA, 0x97D1, 0x1C66, 0x0B08, 0x80BF,
2254ef270ab1SKenneth D. Merry  0xCA69, 0x41DE, 0x56B0, 0xDD07, 0x786C, 0xF3DB, 0xE4B5, 0x6F02,
2255ef270ab1SKenneth D. Merry  0x3AB1, 0xB106, 0xA668, 0x2DDF, 0x88B4, 0x0303, 0x146D, 0x9FDA,
2256ef270ab1SKenneth D. Merry  0xD50C, 0x5EBB, 0x49D5, 0xC262, 0x6709, 0xECBE, 0xFBD0, 0x7067,
2257ef270ab1SKenneth D. Merry  0x6E7C, 0xE5CB, 0xF2A5, 0x7912, 0xDC79, 0x57CE, 0x40A0, 0xCB17,
2258ef270ab1SKenneth D. Merry  0x81C1, 0x0A76, 0x1D18, 0x96AF, 0x33C4, 0xB873, 0xAF1D, 0x24AA,
2259ef270ab1SKenneth D. Merry  0x932B, 0x189C, 0x0FF2, 0x8445, 0x212E, 0xAA99, 0xBDF7, 0x3640,
2260ef270ab1SKenneth D. Merry  0x7C96, 0xF721, 0xE04F, 0x6BF8, 0xCE93, 0x4524, 0x524A, 0xD9FD,
2261ef270ab1SKenneth D. Merry  0xC7E6, 0x4C51, 0x5B3F, 0xD088, 0x75E3, 0xFE54, 0xE93A, 0x628D,
2262ef270ab1SKenneth D. Merry  0x285B, 0xA3EC, 0xB482, 0x3F35, 0x9A5E, 0x11E9, 0x0687, 0x8D30,
2263ef270ab1SKenneth D. Merry  0xE232, 0x6985, 0x7EEB, 0xF55C, 0x5037, 0xDB80, 0xCCEE, 0x4759,
2264ef270ab1SKenneth D. Merry  0x0D8F, 0x8638, 0x9156, 0x1AE1, 0xBF8A, 0x343D, 0x2353, 0xA8E4,
2265ef270ab1SKenneth D. Merry  0xB6FF, 0x3D48, 0x2A26, 0xA191, 0x04FA, 0x8F4D, 0x9823, 0x1394,
2266ef270ab1SKenneth D. Merry  0x5942, 0xD2F5, 0xC59B, 0x4E2C, 0xEB47, 0x60F0, 0x779E, 0xFC29,
2267ef270ab1SKenneth D. Merry  0x4BA8, 0xC01F, 0xD771, 0x5CC6, 0xF9AD, 0x721A, 0x6574, 0xEEC3,
2268ef270ab1SKenneth D. Merry  0xA415, 0x2FA2, 0x38CC, 0xB37B, 0x1610, 0x9DA7, 0x8AC9, 0x017E,
2269ef270ab1SKenneth D. Merry  0x1F65, 0x94D2, 0x83BC, 0x080B, 0xAD60, 0x26D7, 0x31B9, 0xBA0E,
2270ef270ab1SKenneth D. Merry  0xF0D8, 0x7B6F, 0x6C01, 0xE7B6, 0x42DD, 0xC96A, 0xDE04, 0x55B3
2271ef270ab1SKenneth D. Merry };
2272ef270ab1SKenneth D. Merry 
2273ef270ab1SKenneth D. Merry /*****************************************************************/
2274ef270ab1SKenneth D. Merry /*                   End of CRC Lookup Table                     */
2275ef270ab1SKenneth D. Merry /*****************************************************************/
2276ef270ab1SKenneth D. Merry 
2277ef270ab1SKenneth D. Merry /**
2278ef270ab1SKenneth D. Merry  * @brief Calculate the T10 PI CRC guard value for a block.
2279ef270ab1SKenneth D. Merry  *
2280ef270ab1SKenneth D. Merry  * Code based on Rocksoft's public domain CRC code, refer to
2281ef270ab1SKenneth D. Merry  * http://www.ross.net/crc/download/crc_v3.txt.  Minimally altered
2282ef270ab1SKenneth D. Merry  * to work with the ocs_dif API.
2283ef270ab1SKenneth D. Merry  *
2284ef270ab1SKenneth D. Merry  * @param blk_adr Pointer to the data buffer.
2285ef270ab1SKenneth D. Merry  * @param blk_len Number of bytes.
2286ef270ab1SKenneth D. Merry  * @param crc Previously-calculated CRC, or crcseed for a new block.
2287ef270ab1SKenneth D. Merry  *
2288ef270ab1SKenneth D. Merry  * @return Returns the calculated CRC, which may be passed back in for partial blocks.
2289ef270ab1SKenneth D. Merry  *
2290ef270ab1SKenneth D. Merry  */
2291ef270ab1SKenneth D. Merry 
2292ef270ab1SKenneth D. Merry unsigned short
2293ef270ab1SKenneth D. Merry t10crc16(const unsigned char *blk_adr, unsigned long blk_len, unsigned short crc)
2294ef270ab1SKenneth D. Merry {
2295ef270ab1SKenneth D. Merry 	if (blk_len > 0) {
2296ef270ab1SKenneth D. Merry 		while (blk_len--) {
2297ef270ab1SKenneth D. Merry 			crc = crctable[((crc>>8) ^ *blk_adr++) & 0xFFL] ^ (crc << 8);
2298ef270ab1SKenneth D. Merry 		}
2299ef270ab1SKenneth D. Merry 	}
2300ef270ab1SKenneth D. Merry 	return crc;
2301ef270ab1SKenneth D. Merry }
2302ef270ab1SKenneth D. Merry 
2303ef270ab1SKenneth D. Merry struct ocs_ramlog_s {
2304ef270ab1SKenneth D. Merry 	uint32_t initialized;
2305ef270ab1SKenneth D. Merry 	uint32_t textbuf_count;
2306ef270ab1SKenneth D. Merry 	uint32_t textbuf_base;
2307ef270ab1SKenneth D. Merry 	ocs_textbuf_t *textbufs;
2308ef270ab1SKenneth D. Merry 	uint32_t cur_textbuf_idx;
2309ef270ab1SKenneth D. Merry 	ocs_textbuf_t *cur_textbuf;
2310ef270ab1SKenneth D. Merry 	ocs_lock_t lock;
2311ef270ab1SKenneth D. Merry };
2312ef270ab1SKenneth D. Merry 
2313ef270ab1SKenneth D. Merry static uint32_t ocs_ramlog_next_idx(ocs_ramlog_t *ramlog, uint32_t idx);
2314ef270ab1SKenneth D. Merry 
2315ef270ab1SKenneth D. Merry /**
2316ef270ab1SKenneth D. Merry  * @brief Allocate a ramlog buffer.
2317ef270ab1SKenneth D. Merry  *
2318ef270ab1SKenneth D. Merry  * Initialize a RAM logging buffer with text buffers totalling buffer_len.
2319ef270ab1SKenneth D. Merry  *
2320ef270ab1SKenneth D. Merry  * @param ocs Pointer to driver structure.
2321ef270ab1SKenneth D. Merry  * @param buffer_len Total length of RAM log buffers.
2322ef270ab1SKenneth D. Merry  * @param buffer_count Number of text buffers to allocate (totalling buffer-len).
2323ef270ab1SKenneth D. Merry  *
2324ef270ab1SKenneth D. Merry  * @return Returns pointer to ocs_ramlog_t instance, or NULL.
2325ef270ab1SKenneth D. Merry  */
2326ef270ab1SKenneth D. Merry ocs_ramlog_t *
2327ef270ab1SKenneth D. Merry ocs_ramlog_init(ocs_t *ocs, uint32_t buffer_len, uint32_t buffer_count)
2328ef270ab1SKenneth D. Merry {
2329ef270ab1SKenneth D. Merry 	uint32_t i;
2330ef270ab1SKenneth D. Merry 	uint32_t rc;
2331ef270ab1SKenneth D. Merry 	ocs_ramlog_t *ramlog;
2332ef270ab1SKenneth D. Merry 
2333ef270ab1SKenneth D. Merry 	ramlog = ocs_malloc(ocs, sizeof(*ramlog), OCS_M_ZERO | OCS_M_NOWAIT);
2334ef270ab1SKenneth D. Merry 	if (ramlog == NULL) {
2335ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "ocs_malloc ramlog failed\n");
2336ef270ab1SKenneth D. Merry 		return NULL;
2337ef270ab1SKenneth D. Merry 	}
2338ef270ab1SKenneth D. Merry 
2339ef270ab1SKenneth D. Merry 	ramlog->textbuf_count = buffer_count;
2340ef270ab1SKenneth D. Merry 
2341ef270ab1SKenneth D. Merry 	ramlog->textbufs = ocs_malloc(ocs, sizeof(*ramlog->textbufs)*buffer_count, OCS_M_ZERO | OCS_M_NOWAIT);
2342ef270ab1SKenneth D. Merry 	if (ramlog->textbufs == NULL) {
2343ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "ocs_malloc textbufs failed\n");
2344ef270ab1SKenneth D. Merry 		ocs_ramlog_free(ocs, ramlog);
2345ef270ab1SKenneth D. Merry 		return NULL;
2346ef270ab1SKenneth D. Merry 	}
2347ef270ab1SKenneth D. Merry 
2348ef270ab1SKenneth D. Merry 	for (i = 0; i < buffer_count; i ++) {
2349ef270ab1SKenneth D. Merry 		rc = ocs_textbuf_alloc(ocs, &ramlog->textbufs[i], buffer_len);
2350ef270ab1SKenneth D. Merry 		if (rc) {
2351ef270ab1SKenneth D. Merry 			ocs_log_err(ocs, "ocs_textbuf_alloc failed\n");
2352ef270ab1SKenneth D. Merry 			ocs_ramlog_free(ocs, ramlog);
2353ef270ab1SKenneth D. Merry 			return NULL;
2354ef270ab1SKenneth D. Merry 		}
2355ef270ab1SKenneth D. Merry 	}
2356ef270ab1SKenneth D. Merry 
2357ef270ab1SKenneth D. Merry 	ramlog->cur_textbuf_idx = 0;
2358ef270ab1SKenneth D. Merry 	ramlog->textbuf_base = 1;
2359ef270ab1SKenneth D. Merry 	ramlog->cur_textbuf = &ramlog->textbufs[0];
2360ef270ab1SKenneth D. Merry 	ramlog->initialized = TRUE;
2361ef270ab1SKenneth D. Merry 	ocs_lock_init(ocs, &ramlog->lock, "ramlog_lock[%d]", ocs_instance(ocs));
2362ef270ab1SKenneth D. Merry 	return ramlog;
2363ef270ab1SKenneth D. Merry }
2364ef270ab1SKenneth D. Merry 
2365ef270ab1SKenneth D. Merry /**
2366ef270ab1SKenneth D. Merry  * @brief Free a ramlog buffer.
2367ef270ab1SKenneth D. Merry  *
2368ef270ab1SKenneth D. Merry  * A previously allocated RAM logging buffer is freed.
2369ef270ab1SKenneth D. Merry  *
2370ef270ab1SKenneth D. Merry  * @param ocs Pointer to driver structure.
2371ef270ab1SKenneth D. Merry  * @param ramlog Pointer to RAM logging buffer structure.
2372ef270ab1SKenneth D. Merry  *
2373ef270ab1SKenneth D. Merry  * @return None.
2374ef270ab1SKenneth D. Merry  */
2375ef270ab1SKenneth D. Merry 
2376ef270ab1SKenneth D. Merry void
2377ef270ab1SKenneth D. Merry ocs_ramlog_free(ocs_t *ocs, ocs_ramlog_t *ramlog)
2378ef270ab1SKenneth D. Merry {
2379ef270ab1SKenneth D. Merry 	uint32_t i;
2380ef270ab1SKenneth D. Merry 
2381ef270ab1SKenneth D. Merry 	if (ramlog != NULL) {
2382ef270ab1SKenneth D. Merry 		ocs_lock_free(&ramlog->lock);
2383ef270ab1SKenneth D. Merry 		if (ramlog->textbufs) {
2384ef270ab1SKenneth D. Merry 			for (i = 0; i < ramlog->textbuf_count; i ++) {
2385ef270ab1SKenneth D. Merry 				ocs_textbuf_free(ocs, &ramlog->textbufs[i]);
2386ef270ab1SKenneth D. Merry 			}
2387ef270ab1SKenneth D. Merry 
2388ef270ab1SKenneth D. Merry 			ocs_free(ocs, ramlog->textbufs, ramlog->textbuf_count*sizeof(*ramlog->textbufs));
2389ef270ab1SKenneth D. Merry 			ramlog->textbufs = NULL;
2390ef270ab1SKenneth D. Merry 		}
2391ef270ab1SKenneth D. Merry 		ocs_free(ocs, ramlog, sizeof(*ramlog));
2392ef270ab1SKenneth D. Merry 	}
2393ef270ab1SKenneth D. Merry }
2394ef270ab1SKenneth D. Merry 
2395ef270ab1SKenneth D. Merry /**
2396ef270ab1SKenneth D. Merry  * @brief Clear a ramlog buffer.
2397ef270ab1SKenneth D. Merry  *
2398ef270ab1SKenneth D. Merry  * The text in the start of day and/or recent ramlog text buffers is cleared.
2399ef270ab1SKenneth D. Merry  *
2400ef270ab1SKenneth D. Merry  * @param ocs Pointer to driver structure.
2401ef270ab1SKenneth D. Merry  * @param ramlog Pointer to RAM logging buffer structure.
2402ef270ab1SKenneth D. Merry  * @param clear_start_of_day Clear the start of day (driver init) portion of the ramlog.
2403ef270ab1SKenneth D. Merry  * @param clear_recent Clear the recent messages portion of the ramlog.
2404ef270ab1SKenneth D. Merry  *
2405ef270ab1SKenneth D. Merry  * @return None.
2406ef270ab1SKenneth D. Merry  */
2407ef270ab1SKenneth D. Merry 
2408ef270ab1SKenneth D. Merry void
2409ef270ab1SKenneth D. Merry ocs_ramlog_clear(ocs_t *ocs, ocs_ramlog_t *ramlog, int clear_start_of_day, int clear_recent)
2410ef270ab1SKenneth D. Merry {
2411ef270ab1SKenneth D. Merry 	uint32_t i;
2412ef270ab1SKenneth D. Merry 
2413ef270ab1SKenneth D. Merry 	if (clear_recent) {
2414ef270ab1SKenneth D. Merry 		for (i = ramlog->textbuf_base; i < ramlog->textbuf_count; i ++) {
2415ef270ab1SKenneth D. Merry 			ocs_textbuf_reset(&ramlog->textbufs[i]);
2416ef270ab1SKenneth D. Merry 		}
2417ef270ab1SKenneth D. Merry 		ramlog->cur_textbuf_idx = 1;
2418ef270ab1SKenneth D. Merry 	}
2419ef270ab1SKenneth D. Merry 	if (clear_start_of_day && ramlog->textbuf_base) {
2420ef270ab1SKenneth D. Merry 		ocs_textbuf_reset(&ramlog->textbufs[0]);
2421ef270ab1SKenneth D. Merry 		/* Set textbuf_base to 0, so that all buffers are available for
2422ef270ab1SKenneth D. Merry 		 * recent logs
2423ef270ab1SKenneth D. Merry 		 */
2424ef270ab1SKenneth D. Merry 		ramlog->textbuf_base = 0;
2425ef270ab1SKenneth D. Merry 	}
2426ef270ab1SKenneth D. Merry }
2427ef270ab1SKenneth D. Merry 
2428ef270ab1SKenneth D. Merry /**
2429ef270ab1SKenneth D. Merry  * @brief Append formatted printf data to a ramlog buffer.
2430ef270ab1SKenneth D. Merry  *
2431ef270ab1SKenneth D. Merry  * Formatted data is appended to a RAM logging buffer.
2432ef270ab1SKenneth D. Merry  *
2433ef270ab1SKenneth D. Merry  * @param os Pointer to driver structure.
2434ef270ab1SKenneth D. Merry  * @param fmt Pointer to printf style format specifier.
2435ef270ab1SKenneth D. Merry  *
2436ef270ab1SKenneth D. Merry  * @return Returns 0 on success, or a negative error code value on failure.
2437ef270ab1SKenneth D. Merry  */
2438ef270ab1SKenneth D. Merry 
2439ef270ab1SKenneth D. Merry int32_t
2440ef270ab1SKenneth D. Merry ocs_ramlog_printf(void *os, const char *fmt, ...)
2441ef270ab1SKenneth D. Merry {
2442ef270ab1SKenneth D. Merry 	ocs_t *ocs = os;
2443ef270ab1SKenneth D. Merry 	va_list ap;
2444ef270ab1SKenneth D. Merry 	int32_t res;
2445ef270ab1SKenneth D. Merry 
2446ef270ab1SKenneth D. Merry 	if (ocs == NULL || ocs->ramlog == NULL) {
2447ef270ab1SKenneth D. Merry 		return -1;
2448ef270ab1SKenneth D. Merry 	}
2449ef270ab1SKenneth D. Merry 
2450ef270ab1SKenneth D. Merry 	va_start(ap, fmt);
2451ef270ab1SKenneth D. Merry 	res = ocs_ramlog_vprintf(ocs->ramlog, fmt, ap);
2452ef270ab1SKenneth D. Merry 	va_end(ap);
2453ef270ab1SKenneth D. Merry 
2454ef270ab1SKenneth D. Merry 	return res;
2455ef270ab1SKenneth D. Merry }
2456ef270ab1SKenneth D. Merry 
2457ef270ab1SKenneth D. Merry /**
2458ef270ab1SKenneth D. Merry  * @brief Append formatted text to a ramlog using variable arguments.
2459ef270ab1SKenneth D. Merry  *
2460ef270ab1SKenneth D. Merry  * Formatted data is appended to the RAM logging buffer, using variable arguments.
2461ef270ab1SKenneth D. Merry  *
2462ef270ab1SKenneth D. Merry  * @param ramlog Pointer to RAM logging buffer.
2463ef270ab1SKenneth D. Merry  * @param fmt Pointer to printf style formatting string.
2464ef270ab1SKenneth D. Merry  * @param ap Variable argument pointer.
2465ef270ab1SKenneth D. Merry  *
2466ef270ab1SKenneth D. Merry  * @return Returns 0 on success, or a negative error code value on failure.
2467ef270ab1SKenneth D. Merry  */
2468ef270ab1SKenneth D. Merry 
2469ef270ab1SKenneth D. Merry int32_t
2470ef270ab1SKenneth D. Merry ocs_ramlog_vprintf(ocs_ramlog_t *ramlog, const char *fmt, va_list ap)
2471ef270ab1SKenneth D. Merry {
2472ef270ab1SKenneth D. Merry 	if (ramlog == NULL || !ramlog->initialized) {
2473ef270ab1SKenneth D. Merry 		return -1;
2474ef270ab1SKenneth D. Merry 	}
2475ef270ab1SKenneth D. Merry 
2476ef270ab1SKenneth D. Merry 	/* check the current text buffer, if it is almost full (less than 120 characaters), then
2477ef270ab1SKenneth D. Merry 	 * roll to the next one.
2478ef270ab1SKenneth D. Merry 	 */
2479ef270ab1SKenneth D. Merry 	ocs_lock(&ramlog->lock);
2480ef270ab1SKenneth D. Merry 	if (ocs_textbuf_remaining(ramlog->cur_textbuf) < 120) {
2481ef270ab1SKenneth D. Merry 		ramlog->cur_textbuf_idx = ocs_ramlog_next_idx(ramlog, ramlog->cur_textbuf_idx);
2482ef270ab1SKenneth D. Merry 		ramlog->cur_textbuf = &ramlog->textbufs[ramlog->cur_textbuf_idx];
2483ef270ab1SKenneth D. Merry 		ocs_textbuf_reset(ramlog->cur_textbuf);
2484ef270ab1SKenneth D. Merry 	}
2485ef270ab1SKenneth D. Merry 
2486ef270ab1SKenneth D. Merry 	ocs_textbuf_vprintf(ramlog->cur_textbuf, fmt, ap);
2487ef270ab1SKenneth D. Merry 	ocs_unlock(&ramlog->lock);
2488ef270ab1SKenneth D. Merry 
2489ef270ab1SKenneth D. Merry 	return 0;
2490ef270ab1SKenneth D. Merry }
2491ef270ab1SKenneth D. Merry 
2492ef270ab1SKenneth D. Merry /**
2493ef270ab1SKenneth D. Merry  * @brief Return next ramlog buffer index.
2494ef270ab1SKenneth D. Merry  *
2495ef270ab1SKenneth D. Merry  * Given a RAM logging buffer index, return the next index.
2496ef270ab1SKenneth D. Merry  *
2497ef270ab1SKenneth D. Merry  * @param ramlog Pointer to RAM logging buffer.
2498ef270ab1SKenneth D. Merry  * @param idx Index value.
2499ef270ab1SKenneth D. Merry  *
2500ef270ab1SKenneth D. Merry  * @return Returns next index value.
2501ef270ab1SKenneth D. Merry  */
2502ef270ab1SKenneth D. Merry 
2503ef270ab1SKenneth D. Merry static uint32_t
2504ef270ab1SKenneth D. Merry ocs_ramlog_next_idx(ocs_ramlog_t *ramlog, uint32_t idx)
2505ef270ab1SKenneth D. Merry {
2506ef270ab1SKenneth D. Merry 	idx = idx + 1;
2507ef270ab1SKenneth D. Merry 
2508ef270ab1SKenneth D. Merry 	if (idx >= ramlog->textbuf_count) {
2509ef270ab1SKenneth D. Merry 		idx = ramlog->textbuf_base;
2510ef270ab1SKenneth D. Merry 	}
2511ef270ab1SKenneth D. Merry 
2512ef270ab1SKenneth D. Merry 	return idx;
2513ef270ab1SKenneth D. Merry }
2514ef270ab1SKenneth D. Merry 
2515ef270ab1SKenneth D. Merry /**
2516ef270ab1SKenneth D. Merry  * @brief Perform ramlog buffer driver dump.
2517ef270ab1SKenneth D. Merry  *
2518ef270ab1SKenneth D. Merry  * The RAM logging buffer is appended to the driver dump data.
2519ef270ab1SKenneth D. Merry  *
2520ef270ab1SKenneth D. Merry  * @param textbuf Pointer to the driver dump text buffer.
2521ef270ab1SKenneth D. Merry  * @param ramlog Pointer to the RAM logging buffer.
2522ef270ab1SKenneth D. Merry  *
2523ef270ab1SKenneth D. Merry  * @return Returns 0 on success, or a negative error code value on failure.
2524ef270ab1SKenneth D. Merry  */
2525ef270ab1SKenneth D. Merry 
2526ef270ab1SKenneth D. Merry int32_t
2527ef270ab1SKenneth D. Merry ocs_ddump_ramlog(ocs_textbuf_t *textbuf, ocs_ramlog_t *ramlog)
2528ef270ab1SKenneth D. Merry {
2529ef270ab1SKenneth D. Merry 	uint32_t i;
2530ef270ab1SKenneth D. Merry 	ocs_textbuf_t *rltextbuf;
2531ef270ab1SKenneth D. Merry 	int idx;
2532ef270ab1SKenneth D. Merry 
2533ef270ab1SKenneth D. Merry 	if ((ramlog == NULL) || (ramlog->textbufs == NULL)) {
2534ef270ab1SKenneth D. Merry 		return -1;
2535ef270ab1SKenneth D. Merry 	}
2536ef270ab1SKenneth D. Merry 
2537ef270ab1SKenneth D. Merry 	ocs_ddump_section(textbuf, "driver-log", 0);
2538ef270ab1SKenneth D. Merry 
2539ef270ab1SKenneth D. Merry 	/* Dump the start of day buffer */
2540ef270ab1SKenneth D. Merry 	ocs_ddump_section(textbuf, "startofday", 0);
2541ef270ab1SKenneth D. Merry 	/* If textbuf_base is 0, then all buffers are used for recent */
2542ef270ab1SKenneth D. Merry 	if (ramlog->textbuf_base) {
2543ef270ab1SKenneth D. Merry 		rltextbuf = &ramlog->textbufs[0];
2544ef270ab1SKenneth D. Merry 		ocs_textbuf_buffer(textbuf, ocs_textbuf_get_buffer(rltextbuf), ocs_textbuf_get_written(rltextbuf));
2545ef270ab1SKenneth D. Merry 	}
2546ef270ab1SKenneth D. Merry 	ocs_ddump_endsection(textbuf, "startofday", 0);
2547ef270ab1SKenneth D. Merry 
2548ef270ab1SKenneth D. Merry 	/* Dump the most recent buffers */
2549ef270ab1SKenneth D. Merry 	ocs_ddump_section(textbuf, "recent", 0);
2550ef270ab1SKenneth D. Merry 
2551ef270ab1SKenneth D. Merry 	/* start with the next textbuf */
2552ef270ab1SKenneth D. Merry 	idx = ocs_ramlog_next_idx(ramlog, ramlog->textbuf_count);
2553ef270ab1SKenneth D. Merry 
2554ef270ab1SKenneth D. Merry 	for (i = ramlog->textbuf_base; i < ramlog->textbuf_count; i ++) {
2555ef270ab1SKenneth D. Merry 		rltextbuf = &ramlog->textbufs[idx];
2556ef270ab1SKenneth D. Merry 		ocs_textbuf_buffer(textbuf, ocs_textbuf_get_buffer(rltextbuf), ocs_textbuf_get_written(rltextbuf));
2557ef270ab1SKenneth D. Merry 		idx = ocs_ramlog_next_idx(ramlog, idx);
2558ef270ab1SKenneth D. Merry 	}
2559ef270ab1SKenneth D. Merry 	ocs_ddump_endsection(textbuf, "recent", 0);
2560ef270ab1SKenneth D. Merry 	ocs_ddump_endsection(textbuf, "driver-log", 0);
2561ef270ab1SKenneth D. Merry 
2562ef270ab1SKenneth D. Merry 	return 0;
2563ef270ab1SKenneth D. Merry }
2564ef270ab1SKenneth D. Merry 
2565ef270ab1SKenneth D. Merry struct ocs_pool_s {
2566ef270ab1SKenneth D. Merry 	ocs_os_handle_t os;
2567ef270ab1SKenneth D. Merry 	ocs_array_t *a;
2568ef270ab1SKenneth D. Merry 	ocs_list_t freelist;
2569ef270ab1SKenneth D. Merry 	uint32_t use_lock:1;
2570ef270ab1SKenneth D. Merry 	ocs_lock_t lock;
2571ef270ab1SKenneth D. Merry };
2572ef270ab1SKenneth D. Merry 
2573ef270ab1SKenneth D. Merry typedef struct {
2574ef270ab1SKenneth D. Merry 	ocs_list_link_t link;
2575ef270ab1SKenneth D. Merry } pool_hdr_t;
2576ef270ab1SKenneth D. Merry 
2577ef270ab1SKenneth D. Merry 
2578ef270ab1SKenneth D. Merry /**
2579ef270ab1SKenneth D. Merry  * @brief Allocate a memory pool.
2580ef270ab1SKenneth D. Merry  *
2581ef270ab1SKenneth D. Merry  * A memory pool of given size and item count is allocated.
2582ef270ab1SKenneth D. Merry  *
2583ef270ab1SKenneth D. Merry  * @param os OS handle.
2584ef270ab1SKenneth D. Merry  * @param size Size in bytes of item.
2585ef270ab1SKenneth D. Merry  * @param count Number of items in a memory pool.
2586ef270ab1SKenneth D. Merry  * @param use_lock TRUE to enable locking of pool.
2587ef270ab1SKenneth D. Merry  *
2588ef270ab1SKenneth D. Merry  * @return Returns pointer to allocated memory pool, or NULL.
2589ef270ab1SKenneth D. Merry  */
2590ef270ab1SKenneth D. Merry ocs_pool_t *
2591ef270ab1SKenneth D. Merry ocs_pool_alloc(ocs_os_handle_t os, uint32_t size, uint32_t count, uint32_t use_lock)
2592ef270ab1SKenneth D. Merry {
2593ef270ab1SKenneth D. Merry 	ocs_pool_t *pool;
2594ef270ab1SKenneth D. Merry 	uint32_t i;
2595ef270ab1SKenneth D. Merry 
2596ef270ab1SKenneth D. Merry 	pool = ocs_malloc(os, sizeof(*pool), OCS_M_ZERO | OCS_M_NOWAIT);
2597ef270ab1SKenneth D. Merry 	if (pool == NULL) {
2598ef270ab1SKenneth D. Merry 		return NULL;
2599ef270ab1SKenneth D. Merry 	}
2600ef270ab1SKenneth D. Merry 
2601ef270ab1SKenneth D. Merry 	pool->os = os;
2602ef270ab1SKenneth D. Merry 	pool->use_lock = use_lock;
2603ef270ab1SKenneth D. Merry 
2604ef270ab1SKenneth D. Merry 	/* Allocate an array where each array item is the size of a pool_hdr_t plus
2605ef270ab1SKenneth D. Merry 	 * the requested memory item size (size)
2606ef270ab1SKenneth D. Merry 	 */
2607ef270ab1SKenneth D. Merry 	pool->a = ocs_array_alloc(os, size + sizeof(pool_hdr_t), count);
2608ef270ab1SKenneth D. Merry 	if (pool->a == NULL) {
2609ef270ab1SKenneth D. Merry 		ocs_pool_free(pool);
2610ef270ab1SKenneth D. Merry 		return NULL;
2611ef270ab1SKenneth D. Merry 	}
2612ef270ab1SKenneth D. Merry 
2613ef270ab1SKenneth D. Merry 	ocs_list_init(&pool->freelist, pool_hdr_t, link);
2614ef270ab1SKenneth D. Merry 	for (i = 0; i < count; i++) {
2615ef270ab1SKenneth D. Merry 		ocs_list_add_tail(&pool->freelist, ocs_array_get(pool->a, i));
2616ef270ab1SKenneth D. Merry 	}
2617ef270ab1SKenneth D. Merry 
2618ef270ab1SKenneth D. Merry 	if (pool->use_lock) {
2619ef270ab1SKenneth D. Merry 		ocs_lock_init(os, &pool->lock, "ocs_pool:%p", pool);
2620ef270ab1SKenneth D. Merry 	}
2621ef270ab1SKenneth D. Merry 
2622ef270ab1SKenneth D. Merry 	return pool;
2623ef270ab1SKenneth D. Merry }
2624ef270ab1SKenneth D. Merry 
2625ef270ab1SKenneth D. Merry /**
2626ef270ab1SKenneth D. Merry  * @brief Reset a memory pool.
2627ef270ab1SKenneth D. Merry  *
2628ef270ab1SKenneth D. Merry  * Place all pool elements on the free list, and zero them.
2629ef270ab1SKenneth D. Merry  *
2630ef270ab1SKenneth D. Merry  * @param pool Pointer to the pool object.
2631ef270ab1SKenneth D. Merry  *
2632ef270ab1SKenneth D. Merry  * @return None.
2633ef270ab1SKenneth D. Merry  */
2634ef270ab1SKenneth D. Merry void
2635ef270ab1SKenneth D. Merry ocs_pool_reset(ocs_pool_t *pool)
2636ef270ab1SKenneth D. Merry {
2637ef270ab1SKenneth D. Merry 	uint32_t i;
2638ef270ab1SKenneth D. Merry 	uint32_t count = ocs_array_get_count(pool->a);
2639ef270ab1SKenneth D. Merry 	uint32_t size = ocs_array_get_size(pool->a);
2640ef270ab1SKenneth D. Merry 
2641ef270ab1SKenneth D. Merry 	if (pool->use_lock) {
2642ef270ab1SKenneth D. Merry 		ocs_lock(&pool->lock);
2643ef270ab1SKenneth D. Merry 	}
2644ef270ab1SKenneth D. Merry 
2645ef270ab1SKenneth D. Merry 	/*
2646ef270ab1SKenneth D. Merry 	 * Remove all the entries from the free list, otherwise we will
2647ef270ab1SKenneth D. Merry 	 * encountered linked list asserts when they are re-added.
2648ef270ab1SKenneth D. Merry 	 */
2649ef270ab1SKenneth D. Merry 	while (!ocs_list_empty(&pool->freelist)) {
2650ef270ab1SKenneth D. Merry 		ocs_list_remove_head(&pool->freelist);
2651ef270ab1SKenneth D. Merry 	}
2652ef270ab1SKenneth D. Merry 
2653ef270ab1SKenneth D. Merry 	/* Reset the free list */
2654ef270ab1SKenneth D. Merry 	ocs_list_init(&pool->freelist, pool_hdr_t, link);
2655ef270ab1SKenneth D. Merry 
2656ef270ab1SKenneth D. Merry 	/* Return all elements to the free list and zero the elements */
2657ef270ab1SKenneth D. Merry 	for (i = 0; i < count; i++) {
2658ef270ab1SKenneth D. Merry 		ocs_memset(ocs_pool_get_instance(pool, i), 0, size - sizeof(pool_hdr_t));
2659ef270ab1SKenneth D. Merry 		ocs_list_add_tail(&pool->freelist, ocs_array_get(pool->a, i));
2660ef270ab1SKenneth D. Merry 	}
2661ef270ab1SKenneth D. Merry 	if (pool->use_lock) {
2662ef270ab1SKenneth D. Merry 		ocs_unlock(&pool->lock);
2663ef270ab1SKenneth D. Merry 	}
2664ef270ab1SKenneth D. Merry 
2665ef270ab1SKenneth D. Merry }
2666ef270ab1SKenneth D. Merry 
2667ef270ab1SKenneth D. Merry /**
2668ef270ab1SKenneth D. Merry  * @brief Free a previously allocated memory pool.
2669ef270ab1SKenneth D. Merry  *
2670ef270ab1SKenneth D. Merry  * The memory pool is freed.
2671ef270ab1SKenneth D. Merry  *
2672ef270ab1SKenneth D. Merry  * @param pool Pointer to memory pool.
2673ef270ab1SKenneth D. Merry  *
2674ef270ab1SKenneth D. Merry  * @return None.
2675ef270ab1SKenneth D. Merry  */
2676ef270ab1SKenneth D. Merry void
2677ef270ab1SKenneth D. Merry ocs_pool_free(ocs_pool_t *pool)
2678ef270ab1SKenneth D. Merry {
2679ef270ab1SKenneth D. Merry 	if (pool != NULL) {
2680ef270ab1SKenneth D. Merry 		if (pool->a != NULL) {
2681ef270ab1SKenneth D. Merry 			ocs_array_free(pool->a);
2682ef270ab1SKenneth D. Merry 		}
2683ef270ab1SKenneth D. Merry 		if (pool->use_lock) {
2684ef270ab1SKenneth D. Merry 			ocs_lock_free(&pool->lock);
2685ef270ab1SKenneth D. Merry 		}
2686ef270ab1SKenneth D. Merry 		ocs_free(pool->os, pool, sizeof(*pool));
2687ef270ab1SKenneth D. Merry 	}
2688ef270ab1SKenneth D. Merry }
2689ef270ab1SKenneth D. Merry 
2690ef270ab1SKenneth D. Merry /**
2691ef270ab1SKenneth D. Merry  * @brief Allocate a memory pool item
2692ef270ab1SKenneth D. Merry  *
2693ef270ab1SKenneth D. Merry  * A memory pool item is taken from the free list and returned.
2694ef270ab1SKenneth D. Merry  *
2695ef270ab1SKenneth D. Merry  * @param pool Pointer to memory pool.
2696ef270ab1SKenneth D. Merry  *
2697ef270ab1SKenneth D. Merry  * @return Pointer to allocated item, otherwise NULL if there are no unallocated
2698ef270ab1SKenneth D. Merry  *	   items.
2699ef270ab1SKenneth D. Merry  */
2700ef270ab1SKenneth D. Merry void *
2701ef270ab1SKenneth D. Merry ocs_pool_get(ocs_pool_t *pool)
2702ef270ab1SKenneth D. Merry {
2703ef270ab1SKenneth D. Merry 	pool_hdr_t *h;
2704ef270ab1SKenneth D. Merry 	void *item = NULL;
2705ef270ab1SKenneth D. Merry 
2706ef270ab1SKenneth D. Merry 	if (pool->use_lock) {
2707ef270ab1SKenneth D. Merry 		ocs_lock(&pool->lock);
2708ef270ab1SKenneth D. Merry 	}
2709ef270ab1SKenneth D. Merry 
2710ef270ab1SKenneth D. Merry 	h = ocs_list_remove_head(&pool->freelist);
2711ef270ab1SKenneth D. Merry 
2712ef270ab1SKenneth D. Merry 	if (h != NULL) {
2713ef270ab1SKenneth D. Merry 		/* Return the array item address offset by the size of pool_hdr_t */
2714ef270ab1SKenneth D. Merry 		item = &h[1];
2715ef270ab1SKenneth D. Merry 	}
2716ef270ab1SKenneth D. Merry 
2717ef270ab1SKenneth D. Merry 	if (pool->use_lock) {
2718ef270ab1SKenneth D. Merry 		ocs_unlock(&pool->lock);
2719ef270ab1SKenneth D. Merry 	}
2720ef270ab1SKenneth D. Merry 	return item;
2721ef270ab1SKenneth D. Merry }
2722ef270ab1SKenneth D. Merry 
2723ef270ab1SKenneth D. Merry /**
2724ef270ab1SKenneth D. Merry  * @brief free memory pool item
2725ef270ab1SKenneth D. Merry  *
2726ef270ab1SKenneth D. Merry  * A memory pool item is freed.
2727ef270ab1SKenneth D. Merry  *
2728ef270ab1SKenneth D. Merry  * @param pool Pointer to memory pool.
2729ef270ab1SKenneth D. Merry  * @param item Pointer to item to free.
2730ef270ab1SKenneth D. Merry  *
2731ef270ab1SKenneth D. Merry  * @return None.
2732ef270ab1SKenneth D. Merry  */
2733ef270ab1SKenneth D. Merry void
2734ef270ab1SKenneth D. Merry ocs_pool_put(ocs_pool_t *pool, void *item)
2735ef270ab1SKenneth D. Merry {
2736ef270ab1SKenneth D. Merry 	pool_hdr_t *h;
2737ef270ab1SKenneth D. Merry 
2738ef270ab1SKenneth D. Merry 	if (pool->use_lock) {
2739ef270ab1SKenneth D. Merry 		ocs_lock(&pool->lock);
2740ef270ab1SKenneth D. Merry 	}
2741ef270ab1SKenneth D. Merry 
2742ef270ab1SKenneth D. Merry 	/* Fetch the address of the array item, which is the item address negatively offset
2743ef270ab1SKenneth D. Merry 	 * by size of pool_hdr_t (note the index of [-1]
2744ef270ab1SKenneth D. Merry 	 */
2745ef270ab1SKenneth D. Merry 	h = &((pool_hdr_t*)item)[-1];
2746ef270ab1SKenneth D. Merry 
2747ef270ab1SKenneth D. Merry 	ocs_list_add_tail(&pool->freelist, h);
2748ef270ab1SKenneth D. Merry 
2749ef270ab1SKenneth D. Merry 	if (pool->use_lock) {
2750ef270ab1SKenneth D. Merry 		ocs_unlock(&pool->lock);
2751ef270ab1SKenneth D. Merry 	}
2752ef270ab1SKenneth D. Merry 
2753ef270ab1SKenneth D. Merry }
2754ef270ab1SKenneth D. Merry 
2755ef270ab1SKenneth D. Merry /**
2756ef270ab1SKenneth D. Merry  * @brief Return memory pool item count.
2757ef270ab1SKenneth D. Merry  *
2758ef270ab1SKenneth D. Merry  * Returns the allocated number of items.
2759ef270ab1SKenneth D. Merry  *
2760ef270ab1SKenneth D. Merry  * @param pool Pointer to memory pool.
2761ef270ab1SKenneth D. Merry  *
2762ef270ab1SKenneth D. Merry  * @return Returns count of allocated items.
2763ef270ab1SKenneth D. Merry  */
2764ef270ab1SKenneth D. Merry uint32_t
2765ef270ab1SKenneth D. Merry ocs_pool_get_count(ocs_pool_t *pool)
2766ef270ab1SKenneth D. Merry {
2767ef270ab1SKenneth D. Merry 	uint32_t count;
2768ef270ab1SKenneth D. Merry 	if (pool->use_lock) {
2769ef270ab1SKenneth D. Merry 		ocs_lock(&pool->lock);
2770ef270ab1SKenneth D. Merry 	}
2771ef270ab1SKenneth D. Merry 	count = ocs_array_get_count(pool->a);
2772ef270ab1SKenneth D. Merry 	if (pool->use_lock) {
2773ef270ab1SKenneth D. Merry 		ocs_unlock(&pool->lock);
2774ef270ab1SKenneth D. Merry 	}
2775ef270ab1SKenneth D. Merry 	return count;
2776ef270ab1SKenneth D. Merry }
2777ef270ab1SKenneth D. Merry 
2778ef270ab1SKenneth D. Merry /**
2779ef270ab1SKenneth D. Merry  * @brief Return item given an index.
2780ef270ab1SKenneth D. Merry  *
2781ef270ab1SKenneth D. Merry  * A pointer to a memory pool item is returned given an index.
2782ef270ab1SKenneth D. Merry  *
2783ef270ab1SKenneth D. Merry  * @param pool Pointer to memory pool.
2784ef270ab1SKenneth D. Merry  * @param idx Index.
2785ef270ab1SKenneth D. Merry  *
2786ef270ab1SKenneth D. Merry  * @return Returns pointer to item, or NULL if index is invalid.
2787ef270ab1SKenneth D. Merry  */
2788ef270ab1SKenneth D. Merry void *
2789ef270ab1SKenneth D. Merry ocs_pool_get_instance(ocs_pool_t *pool, uint32_t idx)
2790ef270ab1SKenneth D. Merry {
2791ef270ab1SKenneth D. Merry 	pool_hdr_t *h = ocs_array_get(pool->a, idx);
2792ef270ab1SKenneth D. Merry 
2793ef270ab1SKenneth D. Merry 	if (h == NULL) {
2794ef270ab1SKenneth D. Merry 		return NULL;
2795ef270ab1SKenneth D. Merry 	}
2796ef270ab1SKenneth D. Merry 	return &h[1];
2797ef270ab1SKenneth D. Merry }
2798ef270ab1SKenneth D. Merry 
2799ef270ab1SKenneth D. Merry /**
2800ef270ab1SKenneth D. Merry  * @brief Return count of free objects in a pool.
2801ef270ab1SKenneth D. Merry  *
2802ef270ab1SKenneth D. Merry  * The number of objects on a pool's free list.
2803ef270ab1SKenneth D. Merry  *
2804ef270ab1SKenneth D. Merry  * @param pool Pointer to memory pool.
2805ef270ab1SKenneth D. Merry  *
2806ef270ab1SKenneth D. Merry  * @return Returns count of objects on free list.
2807ef270ab1SKenneth D. Merry  */
2808ef270ab1SKenneth D. Merry uint32_t
2809ef270ab1SKenneth D. Merry ocs_pool_get_freelist_count(ocs_pool_t *pool)
2810ef270ab1SKenneth D. Merry {
2811ef270ab1SKenneth D. Merry 	uint32_t count = 0;
2812ef270ab1SKenneth D. Merry 	void *item;
2813ef270ab1SKenneth D. Merry 
2814ef270ab1SKenneth D. Merry 	if (pool->use_lock) {
2815ef270ab1SKenneth D. Merry 		ocs_lock(&pool->lock);
2816ef270ab1SKenneth D. Merry 	}
2817ef270ab1SKenneth D. Merry 
2818ef270ab1SKenneth D. Merry 	ocs_list_foreach(&pool->freelist, item) {
2819ef270ab1SKenneth D. Merry 		count++;
2820ef270ab1SKenneth D. Merry 	}
2821ef270ab1SKenneth D. Merry 
2822ef270ab1SKenneth D. Merry 	if (pool->use_lock) {
2823ef270ab1SKenneth D. Merry 		ocs_unlock(&pool->lock);
2824ef270ab1SKenneth D. Merry 	}
2825ef270ab1SKenneth D. Merry 	return count;
2826ef270ab1SKenneth D. Merry }
2827