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 * " "
1912 * ' '
1913 * < <
1914 * > >
1915 * & &
1916 */
1917
1918 switch(*s) {
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;
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
|