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 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 * 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 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 */ 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 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 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 * 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 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 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 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 * 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 * 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 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 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 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* 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 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* 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 1626 ocs_textbuf_get_buffer(ocs_textbuf_t *textbuf) 1627 { 1628 return ocs_textbuf_ext_get_buffer(textbuf, 0); 1629 } 1630 1631 int32_t 1632 ocs_textbuf_get_length(ocs_textbuf_t *textbuf) 1633 { 1634 return ocs_textbuf_ext_get_length(textbuf, 0); 1635 } 1636 1637 int32_t 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 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 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 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 1678 ocs_textbuf_initialized(ocs_textbuf_t *textbuf) 1679 { 1680 return (textbuf->ocs != NULL); 1681 } 1682 1683 int32_t 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 * 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 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 * 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 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 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 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 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 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 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 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 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 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 1956 ocs_segment_remaining(ocs_textbuf_segment_t *segment) 1957 { 1958 return segment->buffer_length - segment->buffer_written; 1959 } 1960 1961 void 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 * 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 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 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 * 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 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 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 * 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 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