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