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