The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ocs_fc/ocs_utils.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: a8c75e210295b524eb058c998ff7c74a


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.