2 * Copyright (c) 2017 Broadcom. All rights reserved.
3 * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
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.
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.
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.
42 #define DEFAULT_SLAB_LEN (64*1024)
51 uint32_t elems_per_row;
52 uint32_t bytes_per_row;
55 uint32_t array_rows_len;
58 static uint32_t slab_len = DEFAULT_SLAB_LEN;
61 * @brief Set array slab allocation length
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.
66 * @param len new slab length.
71 ocs_array_set_slablen(uint32_t len)
77 * @brief Allocate an array object
79 * An array object of size and number of elements is allocated
82 * @param size size of array elements in bytes
83 * @param count number of elements in array
85 * @return pointer to array object or NULL
88 ocs_array_alloc(ocs_os_handle_t os, uint32_t size, uint32_t count)
90 ocs_array_t *array = NULL;
93 /* Fail if the item size exceeds slab_len - caller should increase slab_size,
94 * or not use this API.
96 if (size > slab_len) {
97 ocs_log_err(NULL, "Error: size exceeds slab length\n");
101 array = ocs_malloc(os, sizeof(*array), OCS_M_ZERO | OCS_M_NOWAIT);
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;
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);
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);
131 * @brief Free an array object
133 * Frees a prevously allocated array object
135 * @param array pointer to array object
140 ocs_array_free(ocs_array_t *array)
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);
151 ocs_free(array->os, array->array_rows, array->array_rows_len);
153 ocs_free(array->os, array, sizeof(*array));
158 * @brief Return reference to an element of an array object
160 * Return the address of an array element given an index
162 * @param array pointer to array object
163 * @param idx array element index
165 * @return rointer to array element, or NULL if index out of range
167 void *ocs_array_get(ocs_array_t *array, uint32_t idx)
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);
180 * @brief Return number of elements in an array
182 * Return the number of elements in an array
184 * @param array pointer to array object
186 * @return returns count of elements in an array
189 ocs_array_get_count(ocs_array_t *array)
195 * @brief Return size of array elements in bytes
197 * Returns the size in bytes of each array element
199 * @param array pointer to array object
201 * @return size of array element
204 ocs_array_get_size(ocs_array_t *array)
210 * @brief Void pointer array structure
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.
219 struct ocs_varray_s {
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 */
229 * @brief Allocate a void pointer array
231 * A void pointer array of given length is allocated.
233 * @param os OS handle
234 * @param array_count Array size
236 * @return returns a pointer to the ocs_varray_t object, other NULL on error
239 ocs_varray_alloc(ocs_os_handle_t os, uint32_t array_count)
243 va = ocs_malloc(os, sizeof(*va), OCS_M_ZERO | OCS_M_NOWAIT);
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) {
250 ocs_lock_init(os, &va->lock, "varray:%p", va);
252 ocs_free(os, va, sizeof(*va));
260 * @brief Free a void pointer array
262 * The void pointer array object is free'd
264 * @param va Pointer to void pointer array
269 ocs_varray_free(ocs_varray_t *va)
272 ocs_lock_free(&va->lock);
273 if (va->array != NULL) {
274 ocs_free(va->os, va->array, sizeof(*va->array) * va->array_count);
276 ocs_free(va->os, va, sizeof(*va));
281 * @brief Add an entry to a void pointer array
283 * An entry is added to the void pointer array
285 * @param va Pointer to void pointer array
286 * @param entry Pointer to entry to add
288 * @return returns 0 if entry was added, -1 if there is no more space in the array
291 ocs_varray_add(ocs_varray_t *va, void *entry)
296 if (va->entry_count < va->array_count) {
297 va->array[va->entry_count++] = entry;
300 ocs_unlock(&va->lock);
306 * @brief Reset the void pointer array iterator
308 * The next index value of the void pointer array iterator is cleared.
310 * @param va Pointer to void pointer array
315 ocs_varray_iter_reset(ocs_varray_t *va)
319 ocs_unlock(&va->lock);
323 * @brief Return next entry from a void pointer array
325 * The next entry in the void pointer array is returned.
327 * @param va Pointer to void point array
329 * Note: takes the void pointer array lock
331 * @return returns next void pointer entry
334 ocs_varray_iter_next(ocs_varray_t *va)
340 rval = _ocs_varray_iter_next(va);
341 ocs_unlock(&va->lock);
347 * @brief Return next entry from a void pointer array
349 * The next entry in the void pointer array is returned.
351 * @param va Pointer to void point array
353 * Note: doesn't take the void pointer array lock
355 * @return returns next void pointer entry
358 _ocs_varray_iter_next(ocs_varray_t *va)
362 rval = va->array[va->next_index];
363 if (++va->next_index >= va->entry_count) {
370 * @brief Take void pointer array lock
372 * Takes the lock for the given void pointer array
374 * @param va Pointer to void pointer array
379 ocs_varray_lock(ocs_varray_t *va)
385 * @brief Release void pointer array lock
387 * Releases the lock for the given void pointer array
389 * @param va Pointer to void pointer array
394 ocs_varray_unlock(ocs_varray_t *va)
396 ocs_unlock(&va->lock);
400 * @brief Return entry count for a void pointer array
402 * The entry count for a void pointer array is returned
404 * @param va Pointer to void pointer array
406 * @return returns entry count
409 ocs_varray_get_count(ocs_varray_t *va)
414 rc = va->entry_count;
415 ocs_unlock(&va->lock);
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 */
432 * @brief Initialize a circular buffer queue
434 * A circular buffer with producer/consumer API is allocated
436 * @param os OS handle
437 * @param entry_count count of entries
439 * @return returns pointer to circular buffer, or NULL
442 ocs_cbuf_alloc(ocs_os_handle_t os, uint32_t entry_count)
446 cbuf = ocs_malloc(os, sizeof(*cbuf), OCS_M_NOWAIT | OCS_M_ZERO);
452 cbuf->entry_count = entry_count;
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);
461 cbuf->array = ocs_malloc(os, entry_count * sizeof(*cbuf->array), OCS_M_NOWAIT | OCS_M_ZERO);
462 if (cbuf->array == NULL) {
471 * @brief Free a circular buffer
473 * The memory resources of a circular buffer are free'd
475 * @param cbuf pointer to circular buffer
480 ocs_cbuf_free(ocs_cbuf_t *cbuf)
483 if (cbuf->array != NULL) {
484 ocs_free(cbuf->os, cbuf->array, sizeof(*cbuf->array) * cbuf->entry_count);
486 ocs_lock_free(&cbuf->cbuf_clock);
487 ocs_lock_free(&cbuf->cbuf_plock);
488 ocs_free(cbuf->os, cbuf, sizeof(*cbuf));
493 * @brief Get pointer to buffer
495 * Wait for a buffer to become available, and return a pointer to the buffer.
497 * @param cbuf pointer to circular buffer
498 * @param timeout_usec timeout in microseconds
500 * @return pointer to buffer, or NULL if timeout
503 ocs_cbuf_get(ocs_cbuf_t *cbuf, int32_t timeout_usec)
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)) {
513 ocs_unlock(&cbuf->cbuf_clock);
514 ocs_sem_v(&cbuf->cbuf_psem);
520 * @brief write a buffer
522 * The buffer is written to the circular buffer.
524 * @param cbuf pointer to circular buffer
525 * @param elem pointer to entry
527 * @return returns 0 for success, a negative error code value for failure.
530 ocs_cbuf_put(ocs_cbuf_t *cbuf, void *elem)
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)) {
540 ocs_unlock(&cbuf->cbuf_plock);
541 ocs_sem_v(&cbuf->cbuf_csem);
549 * @brief Prime a circular buffer data
551 * Post array buffers to a circular buffer
553 * @param cbuf pointer to circular buffer
554 * @param array pointer to buffer array
556 * @return returns 0 for success, a negative error code value for failure.
559 ocs_cbuf_prime(ocs_cbuf_t *cbuf, ocs_array_t *array)
562 uint32_t count = MIN(ocs_array_get_count(array), cbuf->entry_count);
564 for (i = 0; i < count; i++) {
565 ocs_cbuf_put(cbuf, ocs_array_get(array, i));
571 * @brief Generate driver dump start of file information
573 * The start of file information is added to 'textbuf'
575 * @param textbuf pointer to driver dump text buffer
581 ocs_ddump_startfile(ocs_textbuf_t *textbuf)
583 ocs_textbuf_printf(textbuf, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n");
587 * @brief Generate driver dump end of file information
589 * The end of file information is added to 'textbuf'
591 * @param textbuf pointer to driver dump text buffer
597 ocs_ddump_endfile(ocs_textbuf_t *textbuf)
602 * @brief Generate driver dump section start data
604 * The driver section start information is added to textbuf
606 * @param textbuf pointer to text buffer
607 * @param name name of section
608 * @param instance instance number of this section
614 ocs_ddump_section(ocs_textbuf_t *textbuf, const char *name, uint32_t instance)
616 ocs_textbuf_printf(textbuf, "<%s type=\"section\" instance=\"%d\">\n", name, instance);
620 * @brief Generate driver dump section end data
622 * The driver section end information is added to textbuf
624 * @param textbuf pointer to text buffer
625 * @param name name of section
626 * @param instance instance number of this section
632 ocs_ddump_endsection(ocs_textbuf_t *textbuf, const char *name, uint32_t instance)
634 ocs_textbuf_printf(textbuf, "</%s>\n", name);
638 * @brief Generate driver dump data for a given value
640 * A value is added to textbuf
642 * @param textbuf pointer to text buffer
643 * @param name name of variable
644 * @param fmt snprintf format specifier
650 ocs_ddump_value(ocs_textbuf_t *textbuf, const char *name, const char *fmt, ...)
656 vsnprintf(valuebuf, sizeof(valuebuf), fmt, ap);
659 ocs_textbuf_printf(textbuf, "<%s>%s</%s>\n", name, valuebuf, name);
663 * @brief Generate driver dump data for an arbitrary buffer of DWORDS
665 * A status value is added to textbuf
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
677 ocs_ddump_buffer(ocs_textbuf_t *textbuf, const char *name, uint32_t instance, void *buffer, uint32_t size)
683 count = size / sizeof(uint32_t);
689 ocs_textbuf_printf(textbuf, "<%s type=\"buffer\" instance=\"%d\">\n", name, instance);
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");
700 ocs_textbuf_printf(textbuf, "</%s>\n", name);
704 * @brief Generate driver dump for queue
706 * Add queue elements to text buffer
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
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)
726 uint32_t entry_count = 0;
727 uint32_t entry_words = size / sizeof(uint32_t);
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;
734 entry_count = qentries;
736 index -= (qentries - 1);
741 #define OCS_NEWLINE_MOD 8
742 ocs_textbuf_printf(textbuf, "<qentries>\n");
743 for (i = 0; i < entry_count; i++){
745 entry += index * size;
746 dword = (uint32_t *)entry;
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, " ");
761 if ((uint32_t)index >= length) {
765 ocs_textbuf_printf(textbuf, "</qentries>\n");
768 #define OCS_DEBUG_ENABLE(x) (x ? ~0 : 0)
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)
778 static uint32_t ocs_debug_mask = OCS_DEBUG_MASK;
782 return ((c > 32) && (c < 127));
787 * @brief enable debug options
789 * Enables debug options by or-ing in <b>mask</b> into the currently enabled
792 * @param mask mask bits to enable
797 void ocs_debug_enable(uint32_t mask) {
798 ocs_debug_mask |= mask;
803 * @brief disable debug options
805 * Disables debug options by clearing bits in <b>mask</b> into the currently enabled
808 * @param mask mask bits to enable
813 void ocs_debug_disable(uint32_t mask) {
814 ocs_debug_mask &= ~mask;
819 * @brief return true if debug bits are enabled
821 * Returns true if the request debug bits are set.
823 * @param mask debug bit mask
825 * @return true if corresponding bits are set
827 * @note Passing in a mask value of zero always returns true
830 int ocs_debug_is_enabled(uint32_t mask) {
831 return (ocs_debug_mask & mask) == mask;
836 * @brief Dump 32 bit hex/ascii data
838 * Dumps using ocs_log a buffer of data as 32 bit hex and ascii
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
851 ocs_dump32(uint32_t mask, ocs_os_handle_t os, const char *label, void *buf, uint32_t buf_length)
853 uint32_t word_count = buf_length / sizeof(uint32_t);
855 uint32_t columns = 8;
861 char *pbuf = linebuf;
863 if (!ocs_debug_is_enabled(mask))
867 ocs_log_debug(os, "%s\n", label);
870 while (word_count > 0) {
872 pbuf += ocs_snprintf(pbuf, sizeof(linebuf) - (pbuf-linebuf), "%08X: ", addr);
878 for (i = 0; i < n; i ++)
879 pbuf += ocs_snprintf(pbuf, sizeof(linebuf) - (pbuf-linebuf), "%08X ", wbuf[i]);
881 for (; i < columns; i ++)
882 pbuf += ocs_snprintf(pbuf, sizeof(linebuf) - (pbuf-linebuf), "%8s ", "");
884 pbuf += ocs_snprintf(pbuf, sizeof(linebuf) - (pbuf-linebuf), " ");
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");
890 ocs_log_debug(os, "%s", linebuf);
894 addr += n*sizeof(uint32_t);
898 #if defined(OCS_DEBUG_QUEUE_HISTORY)
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))
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)
914 return OCS_Q_HIST_ENABLE_Q_INFO;
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)
921 return OCS_Q_HIST_ENABLE_TIMESTAMPS;
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},
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},
940 static uint32_t ocs_q_hist_get_wqe_mask(sli4_generic_wqe_t *wqe)
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;
948 /* return default WQE mask */
949 return OCS_Q_HIST_WQE_WORD_MASK_DEFAULT;
954 * @brief Initialize resources for queue history
956 * @param os os handle
957 * @param q_hist Pointer to the queue history object.
962 ocs_queue_history_init(ocs_t *ocs, ocs_hw_q_hist_t *q_hist)
965 if (q_hist->q_hist != NULL) {
966 /* Setup is already done */
967 ocs_log_debug(ocs, "q_hist not NULL, skipping init\n");
971 q_hist->q_hist = ocs_malloc(ocs, sizeof(*q_hist->q_hist)*OCS_Q_HIST_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
973 if (q_hist->q_hist == NULL) {
974 ocs_log_err(ocs, "Could not allocate queue history buffer\n");
976 ocs_lock_init(ocs, &q_hist->q_hist_lock, "queue history lock[%d]", ocs_instance(ocs));
979 q_hist->q_hist_index = 0;
984 * @brief Free resources for queue history
986 * @param q_hist Pointer to the queue history object.
991 ocs_queue_history_free(ocs_hw_q_hist_t *q_hist)
993 ocs_t *ocs = q_hist->ocs;
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;
1003 ocs_queue_history_add_q_info(ocs_hw_q_hist_t *q_hist, uint32_t qid, uint32_t qindex)
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;
1014 ocs_queue_history_add_timestamp(ocs_hw_q_hist_t *q_hist)
1016 if (ocs_queue_history_timestamp_enabled()) {
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;
1031 * @brief Log work queue entry (WQE) into history array
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
1041 ocs_queue_history_wq(ocs_hw_q_hist_t *q_hist, uint32_t *entryw, uint32_t qid, uint32_t qindex)
1044 ocs_q_hist_ftr_t ftr;
1045 uint32_t wqe_word_mask = ocs_q_hist_get_wqe_mask((sli4_generic_wqe_t *)entryw);
1047 if (q_hist->q_hist == NULL) {
1048 /* Can't save anything */
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;
1064 ocs_queue_history_add_q_info(q_hist, qid, qindex);
1065 ocs_queue_history_add_timestamp(q_hist);
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;
1075 ocs_unlock(&q_hist->q_hist_lock);
1080 * @brief Log misc words
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
1089 ocs_queue_history_misc(ocs_hw_q_hist_t *q_hist, uint32_t *entryw, uint32_t num_words)
1092 ocs_q_hist_ftr_t ftr;
1095 if (q_hist->q_hist == NULL) {
1096 /* Can't save anything */
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;
1111 ocs_queue_history_add_timestamp(q_hist);
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;
1121 ocs_unlock(&q_hist->q_hist_lock);
1126 * @brief Log work queue completion (CQE) entry into history
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
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)
1143 uint32_t cqe_word_mask = 0;
1144 ocs_q_hist_ftr_t ftr;
1146 if (q_hist->q_hist == NULL) {
1147 /* Can't save anything */
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;
1156 cqe_word_mask = ocs_q_hist_cqe_masks[j].mask_err;
1158 cqe_word_mask = ocs_q_hist_cqe_masks[j].mask;
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;
1171 ocs_queue_history_add_q_info(q_hist, qid, qindex);
1172 ocs_queue_history_add_timestamp(q_hist);
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;
1182 ocs_unlock(&q_hist->q_hist_lock);
1186 * @brief Get previous index
1188 * @param index Index from which previous index is derived.
1191 ocs_queue_history_prev_index(uint32_t index)
1194 return OCS_Q_HIST_SIZE - 1;
1200 #endif /* OCS_DEBUG_QUEUE_HISTORY */
1203 * @brief Display service parameters
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
1217 ocs_display_sparams(const char *prelabel, const char *reqlabel, int dest, void *textbuf, void *sparams)
1221 if (sparams == NULL) {
1227 if (prelabel != NULL) {
1228 ocs_snprintf(label, sizeof(label), "[%s] sparam: %s", prelabel, reqlabel);
1230 ocs_snprintf(label, sizeof(label), "sparam: %s", reqlabel);
1233 ocs_dump32(OCS_DEBUG_ENABLE_SPARAM_DUMP, NULL, label, sparams, sizeof(fc_plogi_payload_t));
1236 ocs_ddump_buffer((ocs_textbuf_t*) textbuf, reqlabel, 0, sparams, sizeof(fc_plogi_payload_t));
1242 * @brief Calculate the T10 PI CRC guard value for a block.
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.
1248 * @return Returns the calculated CRC, which may be passed back in for partial blocks.
1253 ocs_scsi_dif_calc_crc(const uint8_t *buffer, uint32_t size, uint16_t crc)
1255 return t10crc16(buffer, size, crc);
1259 * @brief Calculate the IP-checksum guard value for a block.
1261 * @param addrlen array of address length pairs
1262 * @param addrlen_count number of entries in the addrlen[] array
1265 * Sum all all the 16-byte words in the block
1266 * Add in the "carry", which is everything in excess of 16-bits
1269 * @return Returns the calculated checksum
1273 ocs_scsi_dif_calc_checksum(ocs_scsi_vaddr_len_t addrlen[], uint32_t addrlen_count)
1277 uint32_t intermediate; /* Use an intermediate to hold more than 16 bits during calculations */
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];
1290 /* Carry is everything over 16 bits */
1291 intermediate += ((intermediate & 0xffff0000) >> 16);
1293 /* Flip all the bits */
1294 intermediate = ~intermediate;
1296 checksum = intermediate;
1302 * @brief Return blocksize given SCSI API DIF block size
1304 * Given the DIF block size enumerated value, return the block size value. (e.g.
1305 * OCS_SCSI_DIF_BLK_SIZE_512 returns 512)
1307 * @param dif_info Pointer to SCSI API DIF info block
1309 * @return returns block size, or 0 if SCSI API DIF blocksize is invalid
1313 ocs_scsi_dif_blocksize(ocs_scsi_dif_info_t *dif_info)
1315 uint32_t blocksize = 0;
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;
1332 * @brief Set SCSI API DIF blocksize
1334 * Given a blocksize value (512, 1024, etc.), set the SCSI API DIF blocksize
1335 * in the DIF info block
1337 * @param dif_info Pointer to the SCSI API DIF info block
1338 * @param blocksize Block size
1340 * @return returns 0 for success, a negative error code value for failure.
1344 ocs_scsi_dif_set_blocksize(ocs_scsi_dif_info_t *dif_info, uint32_t 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;
1364 * @brief Return memory block size given SCSI DIF API
1366 * The blocksize in memory for the DIF transfer is returned, given the SCSI DIF info
1367 * block and the direction of transfer.
1369 * @param dif_info Pointer to DIF info block
1370 * @param wiretomem Transfer direction, 1 is wire to memory, 0 is memory to wire
1372 * @return Memory blocksize, or negative error value
1374 * WARNING: the order of initialization of the adj[] arrays MUST match the declarations
1375 * of OCS_SCSI_DIF_OPER_*
1379 ocs_scsi_dif_mem_blocksize(ocs_scsi_dif_info_t *dif_info, int wiretomem)
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, */
1405 blocksize = ocs_scsi_dif_blocksize(dif_info);
1406 if (blocksize == 0) {
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];
1421 * @brief Return wire block size given SCSI DIF API
1423 * The blocksize on the wire for the DIF transfer is returned, given the SCSI DIF info
1424 * block and the direction of transfer.
1426 * @param dif_info Pointer to DIF info block
1427 * @param wiretomem Transfer direction, 1 is wire to memory, 0 is memory to wire
1429 * @return Wire blocksize or negative error value
1431 * WARNING: the order of initialization of the adj[] arrays MUST match the declarations
1432 * of OCS_SCSI_DIF_OPER_*
1436 ocs_scsi_dif_wire_blocksize(ocs_scsi_dif_info_t *dif_info, int wiretomem)
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, */
1462 blocksize = ocs_scsi_dif_blocksize(dif_info);
1463 if (blocksize == 0) {
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];
1478 * @brief Return blocksize given HW API DIF block size
1480 * Given the DIF block size enumerated value, return the block size value. (e.g.
1481 * OCS_SCSI_DIF_BLK_SIZE_512 returns 512)
1483 * @param dif_info Pointer to HW API DIF info block
1485 * @return returns block size, or 0 if HW API DIF blocksize is invalid
1489 ocs_hw_dif_blocksize(ocs_hw_dif_info_t *dif_info)
1491 uint32_t blocksize = 0;
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;
1508 * @brief Return memory block size given HW DIF API
1510 * The blocksize in memory for the DIF transfer is returned, given the HW DIF info
1511 * block and the direction of transfer.
1513 * @param dif_info Pointer to DIF info block
1514 * @param wiretomem Transfer direction, 1 is wire to memory, 0 is memory to wire
1516 * @return Memory blocksize, or negative error value
1518 * WARNING: the order of initialization of the adj[] arrays MUST match the declarations
1519 * of OCS_HW_DIF_OPER_*
1523 ocs_hw_dif_mem_blocksize(ocs_hw_dif_info_t *dif_info, int wiretomem)
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, */
1549 blocksize = ocs_hw_dif_blocksize(dif_info);
1550 if (blocksize == 0) {
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];
1565 * @brief Return wire block size given HW DIF API
1567 * The blocksize on the wire for the DIF transfer is returned, given the HW DIF info
1568 * block and the direction of transfer.
1570 * @param dif_info Pointer to DIF info block
1571 * @param wiretomem Transfer direction, 1 is wire to memory, 0 is memory to wire
1573 * @return Wire blocksize or negative error value
1575 * WARNING: the order of initialization of the adj[] arrays MUST match the declarations
1576 * of OCS_HW_DIF_OPER_*
1580 ocs_hw_dif_wire_blocksize(ocs_hw_dif_info_t *dif_info, int wiretomem)
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, */
1606 blocksize = ocs_hw_dif_blocksize(dif_info);
1607 if (blocksize == 0) {
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];
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);
1628 ocs_textbuf_get_buffer(ocs_textbuf_t *textbuf)
1630 return ocs_textbuf_ext_get_buffer(textbuf, 0);
1634 ocs_textbuf_get_length(ocs_textbuf_t *textbuf)
1636 return ocs_textbuf_ext_get_length(textbuf, 0);
1640 ocs_textbuf_get_written(ocs_textbuf_t *textbuf)
1646 for (idx = 0; (n = ocs_textbuf_ext_get_written(textbuf, idx)) >= 0; idx++) {
1652 uint8_t *ocs_textbuf_ext_get_buffer(ocs_textbuf_t *textbuf, uint32_t idx)
1654 ocs_textbuf_segment_t *segment = ocs_textbuf_get_segment(textbuf, idx);
1655 if (segment == NULL) {
1658 return segment->buffer;
1661 int32_t ocs_textbuf_ext_get_length(ocs_textbuf_t *textbuf, uint32_t idx)
1663 ocs_textbuf_segment_t *segment = ocs_textbuf_get_segment(textbuf, idx);
1664 if (segment == NULL) {
1667 return segment->buffer_length;
1670 int32_t ocs_textbuf_ext_get_written(ocs_textbuf_t *textbuf, uint32_t idx)
1672 ocs_textbuf_segment_t *segment = ocs_textbuf_get_segment(textbuf, idx);
1673 if (segment == NULL) {
1676 return segment->buffer_written;
1680 ocs_textbuf_initialized(ocs_textbuf_t *textbuf)
1682 return (textbuf->ocs != NULL);
1686 ocs_textbuf_alloc(ocs_t *ocs, ocs_textbuf_t *textbuf, uint32_t length)
1688 ocs_memset(textbuf, 0, sizeof(*textbuf));
1691 ocs_list_init(&textbuf->segment_list, ocs_textbuf_segment_t, link);
1693 if (length > OCS_TEXTBUF_MAX_ALLOC_LEN) {
1694 textbuf->allocation_length = OCS_TEXTBUF_MAX_ALLOC_LEN;
1696 textbuf->allocation_length = length;
1699 /* mark as extendable */
1700 textbuf->extendable = TRUE;
1702 /* save maximum allocation length */
1703 textbuf->max_allocation_length = length;
1705 /* Add first segment */
1706 return (ocs_textbuf_segment_alloc(textbuf) == NULL) ? -1 : 0;
1709 static ocs_textbuf_segment_t *
1710 ocs_textbuf_segment_alloc(ocs_textbuf_t *textbuf)
1712 ocs_textbuf_segment_t *segment = NULL;
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;
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;
1730 ocs_textbuf_segment_free(textbuf->ocs, segment);
1739 ocs_textbuf_segment_free(ocs_t *ocs, ocs_textbuf_segment_t *segment)
1742 if (segment->buffer && !segment->user_allocated) {
1743 ocs_free(ocs, segment->buffer, segment->buffer_length);
1745 ocs_free(ocs, segment, sizeof(*segment));
1749 static ocs_textbuf_segment_t *
1750 ocs_textbuf_get_segment(ocs_textbuf_t *textbuf, uint32_t idx)
1753 ocs_textbuf_segment_t *segment;
1755 if (ocs_textbuf_initialized(textbuf)) {
1757 ocs_list_foreach(&textbuf->segment_list, segment) {
1768 ocs_textbuf_init(ocs_t *ocs, ocs_textbuf_t *textbuf, void *buffer, uint32_t length)
1771 ocs_textbuf_segment_t *segment;
1773 ocs_memset(textbuf, 0, sizeof(*textbuf));
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);
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);
1791 ocs_textbuf_free(ocs_t *ocs, ocs_textbuf_t *textbuf)
1793 ocs_textbuf_segment_t *segment;
1794 ocs_textbuf_segment_t *n;
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);
1802 ocs_memset(textbuf, 0, sizeof(*textbuf));
1807 ocs_textbuf_printf(ocs_textbuf_t *textbuf, const char *fmt, ...)
1811 if (ocs_textbuf_initialized(textbuf)) {
1813 ocs_textbuf_vprintf(textbuf, fmt, ap);
1819 ocs_textbuf_vprintf(ocs_textbuf_t *textbuf, const char *fmt, va_list ap)
1823 ocs_textbuf_segment_t *segment;
1826 if (!ocs_textbuf_initialized(textbuf)) {
1830 va_copy(save_ap, ap);
1832 /* fetch last segment */
1833 segment = ocs_list_get_tail(&textbuf->segment_list);
1835 avail = ocs_segment_remaining(segment);
1837 if ((segment = ocs_textbuf_segment_alloc(textbuf)) == NULL) {
1840 avail = ocs_segment_remaining(segment);
1843 written = ocs_vsnprintf(segment->buffer + segment->buffer_written, avail, fmt, ap);
1845 /* See if data was truncated */
1846 if (written >= avail) {
1849 if (textbuf->extendable) {
1850 /* revert the partially written data */
1851 *(segment->buffer + segment->buffer_written) = 0;
1853 /* Allocate a new segment */
1854 if ((segment = ocs_textbuf_segment_alloc(textbuf)) == NULL) {
1855 ocs_log_err(textbuf->ocs, "alloc segment failed\n");
1858 avail = ocs_segment_remaining(segment);
1860 /* Retry the write */
1861 written = ocs_vsnprintf(segment->buffer + segment->buffer_written, avail, fmt, save_ap);
1864 segment->buffer_written += written;
1871 ocs_textbuf_putc(ocs_textbuf_t *textbuf, uint8_t c)
1873 ocs_textbuf_segment_t *segment;
1875 if (ocs_textbuf_initialized(textbuf)) {
1876 segment = ocs_list_get_tail(&textbuf->segment_list);
1878 if (ocs_segment_remaining(segment)) {
1879 *(segment->buffer + segment->buffer_written++) = c;
1881 if (ocs_segment_remaining(segment) == 0) {
1882 ocs_textbuf_segment_alloc(textbuf);
1888 ocs_textbuf_puts(ocs_textbuf_t *textbuf, char *s)
1890 if (ocs_textbuf_initialized(textbuf)) {
1892 ocs_textbuf_putc(textbuf, *s++);
1898 ocs_textbuf_buffer(ocs_textbuf_t *textbuf, uint8_t *buffer, uint32_t buffer_length)
1902 if (!ocs_textbuf_initialized(textbuf)) {
1919 case '"': ocs_textbuf_puts(textbuf, """); break;
1920 case '\'': ocs_textbuf_puts(textbuf, "'"); break;
1921 case '<': ocs_textbuf_puts(textbuf, "<"); break;
1922 case '>': ocs_textbuf_puts(textbuf, ">"); break;
1923 case '&': ocs_textbuf_puts(textbuf, "&"); break;
1924 default: ocs_textbuf_putc(textbuf, *s); break;
1932 ocs_textbuf_copy(ocs_textbuf_t *textbuf, uint8_t *buffer, uint32_t buffer_length)
1936 if (!ocs_textbuf_initialized(textbuf)) {
1942 ocs_textbuf_putc(textbuf, *s++);
1948 ocs_textbuf_remaining(ocs_textbuf_t *textbuf)
1950 if (ocs_textbuf_initialized(textbuf)) {
1951 return ocs_segment_remaining(ocs_list_get_head(&textbuf->segment_list));
1958 ocs_segment_remaining(ocs_textbuf_segment_t *segment)
1960 return segment->buffer_length - segment->buffer_written;
1964 ocs_textbuf_reset(ocs_textbuf_t *textbuf)
1967 ocs_textbuf_segment_t *segment;
1968 ocs_textbuf_segment_t *n;
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) {
1974 segment->buffer_written = 0;
1976 ocs_list_remove(&textbuf->segment_list, segment);
1977 ocs_textbuf_segment_free(textbuf->ocs, segment);
1984 * @brief Sparse Vector API.
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*),
1999 * @brief Allocate a new sparse vector row.
2001 * @param os OS handle
2002 * @param rowcount Count of rows.
2005 * A new sparse vector row is allocated.
2007 * @param rowcount Number of elements in a row.
2009 * @return Returns the pointer to a row.
2012 **spv_new_row(ocs_os_handle_t os, uint32_t rowcount)
2014 return ocs_malloc(os, sizeof(void*) * rowcount, OCS_M_ZERO | OCS_M_NOWAIT);
2019 * @brief Delete row recursively.
2022 * This function recursively deletes the rows in this sparse vector
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.
2032 _spv_del(ocs_os_handle_t os, void **a, uint32_t n, uint32_t depth)
2038 for (i = 0; i < n; i ++) {
2039 _spv_del(os, a[i], n, depth-1);
2042 ocs_free(os, a, SPV_ROWLEN*sizeof(*a));
2049 * @brief Delete a sparse vector.
2052 * The sparse vector is freed.
2054 * @param spv Pointer to the sparse vector object.
2057 spv_del(sparse_vector_t spv)
2060 _spv_del(spv->os, spv->array, SPV_ROWLEN, SPV_DIM);
2061 ocs_free(spv->os, spv, sizeof(*spv));
2067 * @brief Instantiate a new sparse vector object.
2070 * A new sparse vector is allocated.
2072 * @param os OS handle
2074 * @return Returns the pointer to the sparse vector, or NULL.
2077 spv_new(ocs_os_handle_t os)
2079 sparse_vector_t spv;
2082 spv = ocs_malloc(os, sizeof(*spv), OCS_M_ZERO | OCS_M_NOWAIT);
2089 for (i = 0; i < SPV_DIM; i ++) {
2090 spv->max_idx *= SPV_ROWLEN;
2098 * @brief Return the address of a cell.
2101 * Returns the address of a cell, allocates sparse rows as needed if the
2102 * alloc_new_rows parameter is set.
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.
2109 * @return Returns the pointer to the cell, or NULL.
2112 *spv_new_cell(sparse_vector_t sv, uint32_t idx, uint8_t alloc_new_rows)
2114 uint32_t a = (idx >> 16) & 0xff;
2115 uint32_t b = (idx >> 8) & 0xff;
2116 uint32_t c = (idx >> 0) & 0xff;
2119 if (idx >= sv->max_idx) {
2123 if (sv->array == NULL) {
2124 sv->array = (alloc_new_rows ? spv_new_row(sv->os, SPV_ROWLEN) : NULL);
2125 if (sv->array == NULL) {
2131 p[a] = (alloc_new_rows ? spv_new_row(sv->os, SPV_ROWLEN) : NULL);
2138 p[b] = (alloc_new_rows ? spv_new_row(sv->os, SPV_ROWLEN) : NULL);
2150 * @brief Set the sparse vector cell value.
2153 * Sets the sparse vector at @c idx to @c value.
2155 * @param sv Pointer to the sparse vector.
2156 * @param idx Index of which to store.
2157 * @param value Value to store.
2162 spv_set(sparse_vector_t sv, uint32_t idx, void *value)
2164 void **ref = spv_new_cell(sv, idx, TRUE);
2172 * @brief Return the sparse vector cell value.
2175 * Returns the value at @c idx.
2177 * @param sv Pointer to the sparse vector.
2178 * @param idx Index of which to return the value.
2180 * @return Returns the cell value, or NULL.
2183 *spv_get(sparse_vector_t sv, uint32_t idx)
2185 void **ref = spv_new_cell(sv, idx, FALSE);
2192 /*****************************************************************/
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: */
2200 /* Width : 2 bytes. */
2202 /* Reverse : FALSE. */
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". */
2210 /*****************************************************************/
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
2217 * Used in the Emulex SDK, the generated file crctable.out is cut and pasted into
2218 * applicable SDK sources.
2221 static unsigned short crctable[256] =
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
2257 /*****************************************************************/
2258 /* End of CRC Lookup Table */
2259 /*****************************************************************/
2262 * @brief Calculate the T10 PI CRC guard value for a block.
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.
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.
2272 * @return Returns the calculated CRC, which may be passed back in for partial blocks.
2277 t10crc16(const unsigned char *blk_adr, unsigned long blk_len, unsigned short crc)
2281 crc = crctable[((crc>>8) ^ *blk_adr++) & 0xFFL] ^ (crc << 8);
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;
2297 static uint32_t ocs_ramlog_next_idx(ocs_ramlog_t *ramlog, uint32_t idx);
2300 * @brief Allocate a ramlog buffer.
2302 * Initialize a RAM logging buffer with text buffers totalling buffer_len.
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).
2308 * @return Returns pointer to ocs_ramlog_t instance, or NULL.
2311 ocs_ramlog_init(ocs_t *ocs, uint32_t buffer_len, uint32_t buffer_count)
2315 ocs_ramlog_t *ramlog;
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");
2323 ramlog->textbuf_count = buffer_count;
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);
2332 for (i = 0; i < buffer_count; i ++) {
2333 rc = ocs_textbuf_alloc(ocs, &ramlog->textbufs[i], buffer_len);
2335 ocs_log_err(ocs, "ocs_textbuf_alloc failed\n");
2336 ocs_ramlog_free(ocs, ramlog);
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));
2350 * @brief Free a ramlog buffer.
2352 * A previously allocated RAM logging buffer is freed.
2354 * @param ocs Pointer to driver structure.
2355 * @param ramlog Pointer to RAM logging buffer structure.
2361 ocs_ramlog_free(ocs_t *ocs, ocs_ramlog_t *ramlog)
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]);
2372 ocs_free(ocs, ramlog->textbufs, ramlog->textbuf_count*sizeof(*ramlog->textbufs));
2373 ramlog->textbufs = NULL;
2375 ocs_free(ocs, ramlog, sizeof(*ramlog));
2380 * @brief Clear a ramlog buffer.
2382 * The text in the start of day and/or recent ramlog text buffers is cleared.
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.
2393 ocs_ramlog_clear(ocs_t *ocs, ocs_ramlog_t *ramlog, int clear_start_of_day, int clear_recent)
2398 for (i = ramlog->textbuf_base; i < ramlog->textbuf_count; i ++) {
2399 ocs_textbuf_reset(&ramlog->textbufs[i]);
2401 ramlog->cur_textbuf_idx = 1;
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
2408 ramlog->textbuf_base = 0;
2413 * @brief Append formatted printf data to a ramlog buffer.
2415 * Formatted data is appended to a RAM logging buffer.
2417 * @param os Pointer to driver structure.
2418 * @param fmt Pointer to printf style format specifier.
2420 * @return Returns 0 on success, or a negative error code value on failure.
2424 ocs_ramlog_printf(void *os, const char *fmt, ...)
2430 if (ocs == NULL || ocs->ramlog == NULL) {
2435 res = ocs_ramlog_vprintf(ocs->ramlog, fmt, ap);
2442 * @brief Append formatted text to a ramlog using variable arguments.
2444 * Formatted data is appended to the RAM logging buffer, using variable arguments.
2446 * @param ramlog Pointer to RAM logging buffer.
2447 * @param fmt Pointer to printf style formatting string.
2448 * @param ap Variable argument pointer.
2450 * @return Returns 0 on success, or a negative error code value on failure.
2454 ocs_ramlog_vprintf(ocs_ramlog_t *ramlog, const char *fmt, va_list ap)
2456 if (ramlog == NULL || !ramlog->initialized) {
2460 /* check the current text buffer, if it is almost full (less than 120 characaters), then
2461 * roll to the next one.
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);
2470 ocs_textbuf_vprintf(ramlog->cur_textbuf, fmt, ap);
2471 ocs_unlock(&ramlog->lock);
2477 * @brief Return next ramlog buffer index.
2479 * Given a RAM logging buffer index, return the next index.
2481 * @param ramlog Pointer to RAM logging buffer.
2482 * @param idx Index value.
2484 * @return Returns next index value.
2488 ocs_ramlog_next_idx(ocs_ramlog_t *ramlog, uint32_t idx)
2492 if (idx >= ramlog->textbuf_count) {
2493 idx = ramlog->textbuf_base;
2500 * @brief Perform ramlog buffer driver dump.
2502 * The RAM logging buffer is appended to the driver dump data.
2504 * @param textbuf Pointer to the driver dump text buffer.
2505 * @param ramlog Pointer to the RAM logging buffer.
2507 * @return Returns 0 on success, or a negative error code value on failure.
2511 ocs_ddump_ramlog(ocs_textbuf_t *textbuf, ocs_ramlog_t *ramlog)
2514 ocs_textbuf_t *rltextbuf;
2517 if ((ramlog == NULL) || (ramlog->textbufs == NULL)) {
2521 ocs_ddump_section(textbuf, "driver-log", 0);
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));
2530 ocs_ddump_endsection(textbuf, "startofday", 0);
2532 /* Dump the most recent buffers */
2533 ocs_ddump_section(textbuf, "recent", 0);
2535 /* start with the next textbuf */
2536 idx = ocs_ramlog_next_idx(ramlog, ramlog->textbuf_count);
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);
2543 ocs_ddump_endsection(textbuf, "recent", 0);
2544 ocs_ddump_endsection(textbuf, "driver-log", 0);
2552 ocs_list_t freelist;
2553 uint32_t use_lock:1;
2558 ocs_list_link_t link;
2562 * @brief Allocate a memory pool.
2564 * A memory pool of given size and item count is allocated.
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.
2571 * @return Returns pointer to allocated memory pool, or NULL.
2574 ocs_pool_alloc(ocs_os_handle_t os, uint32_t size, uint32_t count, uint32_t use_lock)
2579 pool = ocs_malloc(os, sizeof(*pool), OCS_M_ZERO | OCS_M_NOWAIT);
2585 pool->use_lock = use_lock;
2587 /* Allocate an array where each array item is the size of a pool_hdr_t plus
2588 * the requested memory item size (size)
2590 pool->a = ocs_array_alloc(os, size + sizeof(pool_hdr_t), count);
2591 if (pool->a == NULL) {
2592 ocs_pool_free(pool);
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));
2601 if (pool->use_lock) {
2602 ocs_lock_init(os, &pool->lock, "ocs_pool:%p", pool);
2609 * @brief Reset a memory pool.
2611 * Place all pool elements on the free list, and zero them.
2613 * @param pool Pointer to the pool object.
2618 ocs_pool_reset(ocs_pool_t *pool)
2621 uint32_t count = ocs_array_get_count(pool->a);
2622 uint32_t size = ocs_array_get_size(pool->a);
2624 if (pool->use_lock) {
2625 ocs_lock(&pool->lock);
2629 * Remove all the entries from the free list, otherwise we will
2630 * encountered linked list asserts when they are re-added.
2632 while (!ocs_list_empty(&pool->freelist)) {
2633 ocs_list_remove_head(&pool->freelist);
2636 /* Reset the free list */
2637 ocs_list_init(&pool->freelist, pool_hdr_t, link);
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));
2644 if (pool->use_lock) {
2645 ocs_unlock(&pool->lock);
2651 * @brief Free a previously allocated memory pool.
2653 * The memory pool is freed.
2655 * @param pool Pointer to memory pool.
2660 ocs_pool_free(ocs_pool_t *pool)
2663 if (pool->a != NULL) {
2664 ocs_array_free(pool->a);
2666 if (pool->use_lock) {
2667 ocs_lock_free(&pool->lock);
2669 ocs_free(pool->os, pool, sizeof(*pool));
2674 * @brief Allocate a memory pool item
2676 * A memory pool item is taken from the free list and returned.
2678 * @param pool Pointer to memory pool.
2680 * @return Pointer to allocated item, otherwise NULL if there are no unallocated
2684 ocs_pool_get(ocs_pool_t *pool)
2689 if (pool->use_lock) {
2690 ocs_lock(&pool->lock);
2693 h = ocs_list_remove_head(&pool->freelist);
2696 /* Return the array item address offset by the size of pool_hdr_t */
2700 if (pool->use_lock) {
2701 ocs_unlock(&pool->lock);
2707 * @brief free memory pool item
2709 * A memory pool item is freed.
2711 * @param pool Pointer to memory pool.
2712 * @param item Pointer to item to free.
2717 ocs_pool_put(ocs_pool_t *pool, void *item)
2721 if (pool->use_lock) {
2722 ocs_lock(&pool->lock);
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]
2728 h = &((pool_hdr_t*)item)[-1];
2730 ocs_list_add_tail(&pool->freelist, h);
2732 if (pool->use_lock) {
2733 ocs_unlock(&pool->lock);
2739 * @brief Return memory pool item count.
2741 * Returns the allocated number of items.
2743 * @param pool Pointer to memory pool.
2745 * @return Returns count of allocated items.
2748 ocs_pool_get_count(ocs_pool_t *pool)
2751 if (pool->use_lock) {
2752 ocs_lock(&pool->lock);
2754 count = ocs_array_get_count(pool->a);
2755 if (pool->use_lock) {
2756 ocs_unlock(&pool->lock);
2762 * @brief Return item given an index.
2764 * A pointer to a memory pool item is returned given an index.
2766 * @param pool Pointer to memory pool.
2769 * @return Returns pointer to item, or NULL if index is invalid.
2772 ocs_pool_get_instance(ocs_pool_t *pool, uint32_t idx)
2774 pool_hdr_t *h = ocs_array_get(pool->a, idx);
2783 * @brief Return count of free objects in a pool.
2785 * The number of objects on a pool's free list.
2787 * @param pool Pointer to memory pool.
2789 * @return Returns count of objects on free list.
2792 ocs_pool_get_freelist_count(ocs_pool_t *pool)
2797 if (pool->use_lock) {
2798 ocs_lock(&pool->lock);
2801 ocs_list_foreach(&pool->freelist, item) {
2805 if (pool->use_lock) {
2806 ocs_unlock(&pool->lock);