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