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 } 2810