1 /*- 2 * Copyright (c) 2012-2016 Solarflare Communications Inc. 3 * All rights reserved. 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 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * The views and conclusions contained in the software and documentation are 27 * those of the authors and should not be interpreted as representing official 28 * policies, either expressed or implied, of the FreeBSD Project. 29 */ 30 31 #include <sys/cdefs.h> 32 #include "efx.h" 33 #include "efx_impl.h" 34 35 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 36 37 #if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM 38 39 #include "ef10_tlv_layout.h" 40 41 /* Cursor for TLV partition format */ 42 typedef struct tlv_cursor_s { 43 uint32_t *block; /* Base of data block */ 44 uint32_t *current; /* Cursor position */ 45 uint32_t *end; /* End tag position */ 46 uint32_t *limit; /* Last dword of data block */ 47 } tlv_cursor_t; 48 49 typedef struct nvram_partition_s { 50 uint16_t type; 51 uint8_t chip_select; 52 uint8_t flags; 53 /* 54 * The full length of the NVRAM partition. 55 * This is different from tlv_partition_header.total_length, 56 * which can be smaller. 57 */ 58 uint32_t length; 59 uint32_t erase_size; 60 uint32_t *data; 61 tlv_cursor_t tlv_cursor; 62 } nvram_partition_t; 63 64 static __checkReturn efx_rc_t 65 tlv_validate_state( 66 __inout tlv_cursor_t *cursor); 67 68 static void 69 tlv_init_block( 70 __out uint32_t *block) 71 { 72 *block = __CPU_TO_LE_32(TLV_TAG_END); 73 } 74 75 static uint32_t 76 tlv_tag( 77 __in tlv_cursor_t *cursor) 78 { 79 uint32_t dword, tag; 80 81 dword = cursor->current[0]; 82 tag = __LE_TO_CPU_32(dword); 83 84 return (tag); 85 } 86 87 static size_t 88 tlv_length( 89 __in tlv_cursor_t *cursor) 90 { 91 uint32_t dword, length; 92 93 if (tlv_tag(cursor) == TLV_TAG_END) 94 return (0); 95 96 dword = cursor->current[1]; 97 length = __LE_TO_CPU_32(dword); 98 99 return ((size_t)length); 100 } 101 102 static uint8_t * 103 tlv_value( 104 __in tlv_cursor_t *cursor) 105 { 106 if (tlv_tag(cursor) == TLV_TAG_END) 107 return (NULL); 108 109 return ((uint8_t *)(&cursor->current[2])); 110 } 111 112 static uint8_t * 113 tlv_item( 114 __in tlv_cursor_t *cursor) 115 { 116 if (tlv_tag(cursor) == TLV_TAG_END) 117 return (NULL); 118 119 return ((uint8_t *)cursor->current); 120 } 121 122 /* 123 * TLV item DWORD length is tag + length + value (rounded up to DWORD) 124 * equivalent to tlv_n_words_for_len in mc-comms tlv.c 125 */ 126 #define TLV_DWORD_COUNT(length) \ 127 (1 + 1 + (((length) + sizeof (uint32_t) - 1) / sizeof (uint32_t))) 128 129 static uint32_t * 130 tlv_next_item_ptr( 131 __in tlv_cursor_t *cursor) 132 { 133 uint32_t length; 134 135 length = tlv_length(cursor); 136 137 return (cursor->current + TLV_DWORD_COUNT(length)); 138 } 139 140 static __checkReturn efx_rc_t 141 tlv_advance( 142 __inout tlv_cursor_t *cursor) 143 { 144 efx_rc_t rc; 145 146 if ((rc = tlv_validate_state(cursor)) != 0) 147 goto fail1; 148 149 if (cursor->current == cursor->end) { 150 /* No more tags after END tag */ 151 cursor->current = NULL; 152 rc = ENOENT; 153 goto fail2; 154 } 155 156 /* Advance to next item and validate */ 157 cursor->current = tlv_next_item_ptr(cursor); 158 159 if ((rc = tlv_validate_state(cursor)) != 0) 160 goto fail3; 161 162 return (0); 163 164 fail3: 165 EFSYS_PROBE(fail3); 166 fail2: 167 EFSYS_PROBE(fail2); 168 fail1: 169 EFSYS_PROBE1(fail1, efx_rc_t, rc); 170 171 return (rc); 172 } 173 174 static efx_rc_t 175 tlv_rewind( 176 __in tlv_cursor_t *cursor) 177 { 178 efx_rc_t rc; 179 180 cursor->current = cursor->block; 181 182 if ((rc = tlv_validate_state(cursor)) != 0) 183 goto fail1; 184 185 return (0); 186 187 fail1: 188 EFSYS_PROBE1(fail1, efx_rc_t, rc); 189 190 return (rc); 191 } 192 193 static efx_rc_t 194 tlv_find( 195 __inout tlv_cursor_t *cursor, 196 __in uint32_t tag) 197 { 198 efx_rc_t rc; 199 200 rc = tlv_rewind(cursor); 201 while (rc == 0) { 202 if (tlv_tag(cursor) == tag) 203 break; 204 205 rc = tlv_advance(cursor); 206 } 207 return (rc); 208 } 209 210 static __checkReturn efx_rc_t 211 tlv_validate_state( 212 __inout tlv_cursor_t *cursor) 213 { 214 efx_rc_t rc; 215 216 /* Check cursor position */ 217 if (cursor->current < cursor->block) { 218 rc = EINVAL; 219 goto fail1; 220 } 221 if (cursor->current > cursor->limit) { 222 rc = EINVAL; 223 goto fail2; 224 } 225 226 if (tlv_tag(cursor) != TLV_TAG_END) { 227 /* Check current item has space for tag and length */ 228 if (cursor->current > (cursor->limit - 1)) { 229 cursor->current = NULL; 230 rc = EFAULT; 231 goto fail3; 232 } 233 234 /* Check we have value data for current item and an END tag */ 235 if (tlv_next_item_ptr(cursor) > cursor->limit) { 236 cursor->current = NULL; 237 rc = EFAULT; 238 goto fail4; 239 } 240 } 241 242 return (0); 243 244 fail4: 245 EFSYS_PROBE(fail4); 246 fail3: 247 EFSYS_PROBE(fail3); 248 fail2: 249 EFSYS_PROBE(fail2); 250 fail1: 251 EFSYS_PROBE1(fail1, efx_rc_t, rc); 252 253 return (rc); 254 } 255 256 static efx_rc_t 257 tlv_init_cursor( 258 __out tlv_cursor_t *cursor, 259 __in uint32_t *block, 260 __in uint32_t *limit, 261 __in uint32_t *current) 262 { 263 cursor->block = block; 264 cursor->limit = limit; 265 266 cursor->current = current; 267 cursor->end = NULL; 268 269 return (tlv_validate_state(cursor)); 270 } 271 272 static __checkReturn efx_rc_t 273 tlv_init_cursor_from_size( 274 __out tlv_cursor_t *cursor, 275 __in_bcount(size) 276 uint8_t *block, 277 __in size_t size) 278 { 279 uint32_t *limit; 280 limit = (uint32_t *)(block + size - sizeof (uint32_t)); 281 return (tlv_init_cursor(cursor, (uint32_t *)block, 282 limit, (uint32_t *)block)); 283 } 284 285 static __checkReturn efx_rc_t 286 tlv_init_cursor_at_offset( 287 __out tlv_cursor_t *cursor, 288 __in_bcount(size) 289 uint8_t *block, 290 __in size_t size, 291 __in size_t offset) 292 { 293 uint32_t *limit; 294 uint32_t *current; 295 limit = (uint32_t *)(block + size - sizeof (uint32_t)); 296 current = (uint32_t *)(block + offset); 297 return (tlv_init_cursor(cursor, (uint32_t *)block, limit, current)); 298 } 299 300 static __checkReturn efx_rc_t 301 tlv_require_end( 302 __inout tlv_cursor_t *cursor) 303 { 304 uint32_t *pos; 305 efx_rc_t rc; 306 307 if (cursor->end == NULL) { 308 pos = cursor->current; 309 if ((rc = tlv_find(cursor, TLV_TAG_END)) != 0) 310 goto fail1; 311 312 cursor->end = cursor->current; 313 cursor->current = pos; 314 } 315 316 return (0); 317 318 fail1: 319 EFSYS_PROBE1(fail1, efx_rc_t, rc); 320 321 return (rc); 322 } 323 324 static size_t 325 tlv_block_length_used( 326 __inout tlv_cursor_t *cursor) 327 { 328 efx_rc_t rc; 329 330 if ((rc = tlv_validate_state(cursor)) != 0) 331 goto fail1; 332 333 if ((rc = tlv_require_end(cursor)) != 0) 334 goto fail2; 335 336 /* Return space used (including the END tag) */ 337 return (cursor->end + 1 - cursor->block) * sizeof (uint32_t); 338 339 fail2: 340 EFSYS_PROBE(fail2); 341 fail1: 342 EFSYS_PROBE1(fail1, efx_rc_t, rc); 343 344 return (0); 345 } 346 347 static uint32_t * 348 tlv_last_segment_end( 349 __in tlv_cursor_t *cursor) 350 { 351 tlv_cursor_t segment_cursor; 352 uint32_t *last_segment_end = cursor->block; 353 uint32_t *segment_start = cursor->block; 354 355 /* 356 * Go through each segment and check that it has an end tag. If there 357 * is no end tag then the previous segment was the last valid one, 358 * so return the pointer to its end tag. 359 */ 360 for (;;) { 361 if (tlv_init_cursor(&segment_cursor, segment_start, 362 cursor->limit, segment_start) != 0) 363 break; 364 if (tlv_require_end(&segment_cursor) != 0) 365 break; 366 last_segment_end = segment_cursor.end; 367 segment_start = segment_cursor.end + 1; 368 } 369 370 return (last_segment_end); 371 } 372 373 static uint32_t * 374 tlv_write( 375 __in tlv_cursor_t *cursor, 376 __in uint32_t tag, 377 __in_bcount(size) uint8_t *data, 378 __in size_t size) 379 { 380 uint32_t len = size; 381 uint32_t *ptr; 382 383 ptr = cursor->current; 384 385 *ptr++ = __CPU_TO_LE_32(tag); 386 *ptr++ = __CPU_TO_LE_32(len); 387 388 if (len > 0) { 389 ptr[(len - 1) / sizeof (uint32_t)] = 0; 390 memcpy(ptr, data, len); 391 ptr += EFX_P2ROUNDUP(uint32_t, len, 392 sizeof (uint32_t)) / sizeof (*ptr); 393 } 394 395 return (ptr); 396 } 397 398 static __checkReturn efx_rc_t 399 tlv_insert( 400 __inout tlv_cursor_t *cursor, 401 __in uint32_t tag, 402 __in_bcount(size) 403 uint8_t *data, 404 __in size_t size) 405 { 406 unsigned int delta; 407 uint32_t *last_segment_end; 408 efx_rc_t rc; 409 410 if ((rc = tlv_validate_state(cursor)) != 0) 411 goto fail1; 412 413 if ((rc = tlv_require_end(cursor)) != 0) 414 goto fail2; 415 416 if (tag == TLV_TAG_END) { 417 rc = EINVAL; 418 goto fail3; 419 } 420 421 last_segment_end = tlv_last_segment_end(cursor); 422 423 delta = TLV_DWORD_COUNT(size); 424 if (last_segment_end + 1 + delta > cursor->limit) { 425 rc = ENOSPC; 426 goto fail4; 427 } 428 429 /* Move data up: new space at cursor->current */ 430 memmove(cursor->current + delta, cursor->current, 431 (last_segment_end + 1 - cursor->current) * sizeof (uint32_t)); 432 433 /* Adjust the end pointer */ 434 cursor->end += delta; 435 436 /* Write new TLV item */ 437 tlv_write(cursor, tag, data, size); 438 439 return (0); 440 441 fail4: 442 EFSYS_PROBE(fail4); 443 fail3: 444 EFSYS_PROBE(fail3); 445 fail2: 446 EFSYS_PROBE(fail2); 447 fail1: 448 EFSYS_PROBE1(fail1, efx_rc_t, rc); 449 450 return (rc); 451 } 452 453 static __checkReturn efx_rc_t 454 tlv_delete( 455 __inout tlv_cursor_t *cursor) 456 { 457 unsigned int delta; 458 uint32_t *last_segment_end; 459 efx_rc_t rc; 460 461 if ((rc = tlv_validate_state(cursor)) != 0) 462 goto fail1; 463 464 if (tlv_tag(cursor) == TLV_TAG_END) { 465 rc = EINVAL; 466 goto fail2; 467 } 468 469 delta = TLV_DWORD_COUNT(tlv_length(cursor)); 470 471 if ((rc = tlv_require_end(cursor)) != 0) 472 goto fail3; 473 474 last_segment_end = tlv_last_segment_end(cursor); 475 476 /* Shuffle things down, destroying the item at cursor->current */ 477 memmove(cursor->current, cursor->current + delta, 478 (last_segment_end + 1 - cursor->current) * sizeof (uint32_t)); 479 /* Zero the new space at the end of the TLV chain */ 480 memset(last_segment_end + 1 - delta, 0, delta * sizeof (uint32_t)); 481 /* Adjust the end pointer */ 482 cursor->end -= delta; 483 484 return (0); 485 486 fail3: 487 EFSYS_PROBE(fail3); 488 fail2: 489 EFSYS_PROBE(fail2); 490 fail1: 491 EFSYS_PROBE1(fail1, efx_rc_t, rc); 492 493 return (rc); 494 } 495 496 static __checkReturn efx_rc_t 497 tlv_modify( 498 __inout tlv_cursor_t *cursor, 499 __in uint32_t tag, 500 __in_bcount(size) 501 uint8_t *data, 502 __in size_t size) 503 { 504 uint32_t *pos; 505 unsigned int old_ndwords; 506 unsigned int new_ndwords; 507 unsigned int delta; 508 uint32_t *last_segment_end; 509 efx_rc_t rc; 510 511 if ((rc = tlv_validate_state(cursor)) != 0) 512 goto fail1; 513 514 if (tlv_tag(cursor) == TLV_TAG_END) { 515 rc = EINVAL; 516 goto fail2; 517 } 518 if (tlv_tag(cursor) != tag) { 519 rc = EINVAL; 520 goto fail3; 521 } 522 523 old_ndwords = TLV_DWORD_COUNT(tlv_length(cursor)); 524 new_ndwords = TLV_DWORD_COUNT(size); 525 526 if ((rc = tlv_require_end(cursor)) != 0) 527 goto fail4; 528 529 last_segment_end = tlv_last_segment_end(cursor); 530 531 if (new_ndwords > old_ndwords) { 532 /* Expand space used for TLV item */ 533 delta = new_ndwords - old_ndwords; 534 pos = cursor->current + old_ndwords; 535 536 if (last_segment_end + 1 + delta > cursor->limit) { 537 rc = ENOSPC; 538 goto fail5; 539 } 540 541 /* Move up: new space at (cursor->current + old_ndwords) */ 542 memmove(pos + delta, pos, 543 (last_segment_end + 1 - pos) * sizeof (uint32_t)); 544 545 /* Adjust the end pointer */ 546 cursor->end += delta; 547 548 } else if (new_ndwords < old_ndwords) { 549 /* Shrink space used for TLV item */ 550 delta = old_ndwords - new_ndwords; 551 pos = cursor->current + new_ndwords; 552 553 /* Move down: remove words at (cursor->current + new_ndwords) */ 554 memmove(pos, pos + delta, 555 (last_segment_end + 1 - pos) * sizeof (uint32_t)); 556 557 /* Zero the new space at the end of the TLV chain */ 558 memset(last_segment_end + 1 - delta, 0, 559 delta * sizeof (uint32_t)); 560 561 /* Adjust the end pointer */ 562 cursor->end -= delta; 563 } 564 565 /* Write new data */ 566 tlv_write(cursor, tag, data, size); 567 568 return (0); 569 570 fail5: 571 EFSYS_PROBE(fail5); 572 fail4: 573 EFSYS_PROBE(fail4); 574 fail3: 575 EFSYS_PROBE(fail3); 576 fail2: 577 EFSYS_PROBE(fail2); 578 fail1: 579 EFSYS_PROBE1(fail1, efx_rc_t, rc); 580 581 return (rc); 582 } 583 584 static uint32_t checksum_tlv_partition( 585 __in nvram_partition_t *partition) 586 { 587 tlv_cursor_t *cursor; 588 uint32_t *ptr; 589 uint32_t *end; 590 uint32_t csum; 591 size_t len; 592 593 cursor = &partition->tlv_cursor; 594 len = tlv_block_length_used(cursor); 595 EFSYS_ASSERT3U((len & 3), ==, 0); 596 597 csum = 0; 598 ptr = partition->data; 599 end = &ptr[len >> 2]; 600 601 while (ptr < end) 602 csum += __LE_TO_CPU_32(*ptr++); 603 604 return (csum); 605 } 606 607 static __checkReturn efx_rc_t 608 tlv_update_partition_len_and_cks( 609 __in tlv_cursor_t *cursor) 610 { 611 efx_rc_t rc; 612 nvram_partition_t partition; 613 struct tlv_partition_header *header; 614 struct tlv_partition_trailer *trailer; 615 size_t new_len; 616 617 /* 618 * We just modified the partition, so the total length may not be 619 * valid. Don't use tlv_find(), which performs some sanity checks 620 * that may fail here. 621 */ 622 partition.data = cursor->block; 623 memcpy(&partition.tlv_cursor, cursor, sizeof (*cursor)); 624 header = (struct tlv_partition_header *)partition.data; 625 /* Sanity check. */ 626 if (__LE_TO_CPU_32(header->tag) != TLV_TAG_PARTITION_HEADER) { 627 rc = EFAULT; 628 goto fail1; 629 } 630 new_len = tlv_block_length_used(&partition.tlv_cursor); 631 if (new_len == 0) { 632 rc = EFAULT; 633 goto fail2; 634 } 635 header->total_length = __CPU_TO_LE_32(new_len); 636 /* Ensure the modified partition always has a new generation count. */ 637 header->generation = __CPU_TO_LE_32( 638 __LE_TO_CPU_32(header->generation) + 1); 639 640 trailer = (struct tlv_partition_trailer *)((uint8_t *)header + 641 new_len - sizeof (*trailer) - sizeof (uint32_t)); 642 trailer->generation = header->generation; 643 trailer->checksum = __CPU_TO_LE_32( 644 __LE_TO_CPU_32(trailer->checksum) - 645 checksum_tlv_partition(&partition)); 646 647 return (0); 648 649 fail2: 650 EFSYS_PROBE(fail2); 651 fail1: 652 EFSYS_PROBE1(fail1, efx_rc_t, rc); 653 654 return (rc); 655 } 656 657 /* Validate buffer contents (before writing to flash) */ 658 __checkReturn efx_rc_t 659 ef10_nvram_buffer_validate( 660 __in uint32_t partn, 661 __in_bcount(partn_size) caddr_t partn_data, 662 __in size_t partn_size) 663 { 664 tlv_cursor_t cursor; 665 struct tlv_partition_header *header; 666 struct tlv_partition_trailer *trailer; 667 size_t total_length; 668 uint32_t cksum; 669 int pos; 670 efx_rc_t rc; 671 672 EFX_STATIC_ASSERT(sizeof (*header) <= EF10_NVRAM_CHUNK); 673 674 if ((partn_data == NULL) || (partn_size == 0)) { 675 rc = EINVAL; 676 goto fail1; 677 } 678 679 /* The partition header must be the first item (at offset zero) */ 680 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)partn_data, 681 partn_size)) != 0) { 682 rc = EFAULT; 683 goto fail2; 684 } 685 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { 686 rc = EINVAL; 687 goto fail3; 688 } 689 header = (struct tlv_partition_header *)tlv_item(&cursor); 690 691 /* Check TLV partition length (includes the END tag) */ 692 total_length = __LE_TO_CPU_32(header->total_length); 693 if (total_length > partn_size) { 694 rc = EFBIG; 695 goto fail4; 696 } 697 698 /* Check partition header matches partn */ 699 if (__LE_TO_CPU_16(header->type_id) != partn) { 700 rc = EINVAL; 701 goto fail5; 702 } 703 704 /* Check partition ends with PARTITION_TRAILER and END tags */ 705 if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { 706 rc = EINVAL; 707 goto fail6; 708 } 709 trailer = (struct tlv_partition_trailer *)tlv_item(&cursor); 710 711 if ((rc = tlv_advance(&cursor)) != 0) { 712 rc = EINVAL; 713 goto fail7; 714 } 715 if (tlv_tag(&cursor) != TLV_TAG_END) { 716 rc = EINVAL; 717 goto fail8; 718 } 719 720 /* Check generation counts are consistent */ 721 if (trailer->generation != header->generation) { 722 rc = EINVAL; 723 goto fail9; 724 } 725 726 /* Verify partition checksum */ 727 cksum = 0; 728 for (pos = 0; (size_t)pos < total_length; pos += sizeof (uint32_t)) { 729 cksum += *((uint32_t *)(partn_data + pos)); 730 } 731 if (cksum != 0) { 732 rc = EINVAL; 733 goto fail10; 734 } 735 736 return (0); 737 738 fail10: 739 EFSYS_PROBE(fail10); 740 fail9: 741 EFSYS_PROBE(fail9); 742 fail8: 743 EFSYS_PROBE(fail8); 744 fail7: 745 EFSYS_PROBE(fail7); 746 fail6: 747 EFSYS_PROBE(fail6); 748 fail5: 749 EFSYS_PROBE(fail5); 750 fail4: 751 EFSYS_PROBE(fail4); 752 fail3: 753 EFSYS_PROBE(fail3); 754 fail2: 755 EFSYS_PROBE(fail2); 756 fail1: 757 EFSYS_PROBE1(fail1, efx_rc_t, rc); 758 759 return (rc); 760 } 761 762 void 763 ef10_nvram_buffer_init( 764 __out_bcount(buffer_size) 765 caddr_t bufferp, 766 __in size_t buffer_size) 767 { 768 uint32_t *buf = (uint32_t *)bufferp; 769 770 memset(buf, 0xff, buffer_size); 771 772 tlv_init_block(buf); 773 } 774 775 __checkReturn efx_rc_t 776 ef10_nvram_buffer_create( 777 __in uint32_t partn_type, 778 __out_bcount(partn_size) 779 caddr_t partn_data, 780 __in size_t partn_size) 781 { 782 uint32_t *buf = (uint32_t *)partn_data; 783 efx_rc_t rc; 784 tlv_cursor_t cursor; 785 struct tlv_partition_header header; 786 struct tlv_partition_trailer trailer; 787 788 unsigned int min_buf_size = sizeof (struct tlv_partition_header) + 789 sizeof (struct tlv_partition_trailer); 790 if (partn_size < min_buf_size) { 791 rc = EINVAL; 792 goto fail1; 793 } 794 795 ef10_nvram_buffer_init(partn_data, partn_size); 796 797 if ((rc = tlv_init_cursor(&cursor, buf, 798 (uint32_t *)((uint8_t *)buf + partn_size), 799 buf)) != 0) { 800 goto fail2; 801 } 802 803 header.tag = __CPU_TO_LE_32(TLV_TAG_PARTITION_HEADER); 804 header.length = __CPU_TO_LE_32(sizeof (header) - 8); 805 header.type_id = __CPU_TO_LE_16(partn_type); 806 header.preset = 0; 807 header.generation = __CPU_TO_LE_32(1); 808 header.total_length = 0; /* This will be fixed below. */ 809 if ((rc = tlv_insert( 810 &cursor, TLV_TAG_PARTITION_HEADER, 811 (uint8_t *)&header.type_id, sizeof (header) - 8)) != 0) 812 goto fail3; 813 if ((rc = tlv_advance(&cursor)) != 0) 814 goto fail4; 815 816 trailer.tag = __CPU_TO_LE_32(TLV_TAG_PARTITION_TRAILER); 817 trailer.length = __CPU_TO_LE_32(sizeof (trailer) - 8); 818 trailer.generation = header.generation; 819 trailer.checksum = 0; /* This will be fixed below. */ 820 if ((rc = tlv_insert(&cursor, TLV_TAG_PARTITION_TRAILER, 821 (uint8_t *)&trailer.generation, sizeof (trailer) - 8)) != 0) 822 goto fail5; 823 824 if ((rc = tlv_update_partition_len_and_cks(&cursor)) != 0) 825 goto fail6; 826 827 /* Check that the partition is valid. */ 828 if ((rc = ef10_nvram_buffer_validate(partn_type, 829 partn_data, partn_size)) != 0) 830 goto fail7; 831 832 return (0); 833 834 fail7: 835 EFSYS_PROBE(fail7); 836 fail6: 837 EFSYS_PROBE(fail6); 838 fail5: 839 EFSYS_PROBE(fail5); 840 fail4: 841 EFSYS_PROBE(fail4); 842 fail3: 843 EFSYS_PROBE(fail3); 844 fail2: 845 EFSYS_PROBE(fail2); 846 fail1: 847 EFSYS_PROBE1(fail1, efx_rc_t, rc); 848 849 return (rc); 850 } 851 852 static uint32_t 853 byte_offset( 854 __in uint32_t *position, 855 __in uint32_t *base) 856 { 857 return (uint32_t)((uint8_t *)position - (uint8_t *)base); 858 } 859 860 __checkReturn efx_rc_t 861 ef10_nvram_buffer_find_item_start( 862 __in_bcount(buffer_size) 863 caddr_t bufferp, 864 __in size_t buffer_size, 865 __out uint32_t *startp) 866 { 867 /* Read past partition header to find start address of the first key */ 868 tlv_cursor_t cursor; 869 efx_rc_t rc; 870 871 /* A PARTITION_HEADER tag must be the first item (at offset zero) */ 872 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp, 873 buffer_size)) != 0) { 874 rc = EFAULT; 875 goto fail1; 876 } 877 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { 878 rc = EINVAL; 879 goto fail2; 880 } 881 882 if ((rc = tlv_advance(&cursor)) != 0) { 883 rc = EINVAL; 884 goto fail3; 885 } 886 *startp = byte_offset(cursor.current, cursor.block); 887 888 if ((rc = tlv_require_end(&cursor)) != 0) 889 goto fail4; 890 891 return (0); 892 893 fail4: 894 EFSYS_PROBE(fail4); 895 fail3: 896 EFSYS_PROBE(fail3); 897 fail2: 898 EFSYS_PROBE(fail2); 899 fail1: 900 EFSYS_PROBE1(fail1, efx_rc_t, rc); 901 902 return (rc); 903 } 904 905 __checkReturn efx_rc_t 906 ef10_nvram_buffer_find_end( 907 __in_bcount(buffer_size) 908 caddr_t bufferp, 909 __in size_t buffer_size, 910 __in uint32_t offset, 911 __out uint32_t *endp) 912 { 913 /* Read to end of partition */ 914 tlv_cursor_t cursor; 915 efx_rc_t rc; 916 uint32_t *segment_used; 917 918 _NOTE(ARGUNUSED(offset)) 919 920 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp, 921 buffer_size)) != 0) { 922 rc = EFAULT; 923 goto fail1; 924 } 925 926 segment_used = cursor.block; 927 928 /* 929 * Go through each segment and check that it has an end tag. If there 930 * is no end tag then the previous segment was the last valid one, 931 * so return the used space including that end tag. 932 */ 933 while (tlv_tag(&cursor) == TLV_TAG_PARTITION_HEADER) { 934 if (tlv_require_end(&cursor) != 0) { 935 if (segment_used == cursor.block) { 936 /* 937 * First segment is corrupt, so there is 938 * no valid data in partition. 939 */ 940 rc = EINVAL; 941 goto fail2; 942 } 943 break; 944 } 945 segment_used = cursor.end + 1; 946 947 cursor.current = segment_used; 948 } 949 /* Return space used (including the END tag) */ 950 *endp = (segment_used - cursor.block) * sizeof (uint32_t); 951 952 return (0); 953 954 fail2: 955 EFSYS_PROBE(fail2); 956 fail1: 957 EFSYS_PROBE1(fail1, efx_rc_t, rc); 958 959 return (rc); 960 } 961 962 __checkReturn __success(return != B_FALSE) boolean_t 963 ef10_nvram_buffer_find_item( 964 __in_bcount(buffer_size) 965 caddr_t bufferp, 966 __in size_t buffer_size, 967 __in uint32_t offset, 968 __out uint32_t *startp, 969 __out uint32_t *lengthp) 970 { 971 /* Find TLV at offset and return key start and length */ 972 tlv_cursor_t cursor; 973 uint8_t *key; 974 uint32_t tag; 975 976 if (tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, 977 buffer_size, offset) != 0) { 978 return (B_FALSE); 979 } 980 981 while ((key = tlv_item(&cursor)) != NULL) { 982 tag = tlv_tag(&cursor); 983 if (tag == TLV_TAG_PARTITION_HEADER || 984 tag == TLV_TAG_PARTITION_TRAILER) { 985 if (tlv_advance(&cursor) != 0) { 986 break; 987 } 988 continue; 989 } 990 *startp = byte_offset(cursor.current, cursor.block); 991 *lengthp = byte_offset(tlv_next_item_ptr(&cursor), 992 cursor.current); 993 return (B_TRUE); 994 } 995 996 return (B_FALSE); 997 } 998 999 __checkReturn efx_rc_t 1000 ef10_nvram_buffer_peek_item( 1001 __in_bcount(buffer_size) 1002 caddr_t bufferp, 1003 __in size_t buffer_size, 1004 __in uint32_t offset, 1005 __out uint32_t *tagp, 1006 __out uint32_t *lengthp, 1007 __out uint32_t *value_offsetp) 1008 { 1009 efx_rc_t rc; 1010 tlv_cursor_t cursor; 1011 uint32_t tag; 1012 1013 if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, 1014 buffer_size, offset)) != 0) { 1015 goto fail1; 1016 } 1017 1018 tag = tlv_tag(&cursor); 1019 *tagp = tag; 1020 if (tag == TLV_TAG_END) { 1021 /* 1022 * To allow stepping over the END tag, report the full tag 1023 * length and a zero length value. 1024 */ 1025 *lengthp = sizeof (tag); 1026 *value_offsetp = sizeof (tag); 1027 } else { 1028 *lengthp = byte_offset(tlv_next_item_ptr(&cursor), 1029 cursor.current); 1030 *value_offsetp = byte_offset((uint32_t *)tlv_value(&cursor), 1031 cursor.current); 1032 } 1033 return (0); 1034 1035 fail1: 1036 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1037 1038 return (rc); 1039 } 1040 1041 __checkReturn efx_rc_t 1042 ef10_nvram_buffer_get_item( 1043 __in_bcount(buffer_size) 1044 caddr_t bufferp, 1045 __in size_t buffer_size, 1046 __in uint32_t offset, 1047 __in uint32_t length, 1048 __out uint32_t *tagp, 1049 __out_bcount_part(value_max_size, *lengthp) 1050 caddr_t valuep, 1051 __in size_t value_max_size, 1052 __out uint32_t *lengthp) 1053 { 1054 efx_rc_t rc; 1055 tlv_cursor_t cursor; 1056 uint32_t value_length; 1057 1058 if (buffer_size < (offset + length)) { 1059 rc = ENOSPC; 1060 goto fail1; 1061 } 1062 1063 if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, 1064 buffer_size, offset)) != 0) { 1065 goto fail2; 1066 } 1067 1068 value_length = tlv_length(&cursor); 1069 if (value_max_size < value_length) { 1070 rc = ENOSPC; 1071 goto fail3; 1072 } 1073 memcpy(valuep, tlv_value(&cursor), value_length); 1074 1075 *tagp = tlv_tag(&cursor); 1076 *lengthp = value_length; 1077 1078 return (0); 1079 1080 fail3: 1081 EFSYS_PROBE(fail3); 1082 fail2: 1083 EFSYS_PROBE(fail2); 1084 fail1: 1085 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1086 1087 return (rc); 1088 } 1089 1090 __checkReturn efx_rc_t 1091 ef10_nvram_buffer_insert_item( 1092 __in_bcount(buffer_size) 1093 caddr_t bufferp, 1094 __in size_t buffer_size, 1095 __in uint32_t offset, 1096 __in uint32_t tag, 1097 __in_bcount(length) caddr_t valuep, 1098 __in uint32_t length, 1099 __out uint32_t *lengthp) 1100 { 1101 efx_rc_t rc; 1102 tlv_cursor_t cursor; 1103 1104 if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, 1105 buffer_size, offset)) != 0) { 1106 goto fail1; 1107 } 1108 1109 rc = tlv_insert(&cursor, tag, (uint8_t *)valuep, length); 1110 1111 if (rc != 0) 1112 goto fail2; 1113 1114 *lengthp = byte_offset(tlv_next_item_ptr(&cursor), 1115 cursor.current); 1116 1117 return (0); 1118 1119 fail2: 1120 EFSYS_PROBE(fail2); 1121 fail1: 1122 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1123 1124 return (rc); 1125 } 1126 1127 __checkReturn efx_rc_t 1128 ef10_nvram_buffer_modify_item( 1129 __in_bcount(buffer_size) 1130 caddr_t bufferp, 1131 __in size_t buffer_size, 1132 __in uint32_t offset, 1133 __in uint32_t tag, 1134 __in_bcount(length) caddr_t valuep, 1135 __in uint32_t length, 1136 __out uint32_t *lengthp) 1137 { 1138 efx_rc_t rc; 1139 tlv_cursor_t cursor; 1140 1141 if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, 1142 buffer_size, offset)) != 0) { 1143 goto fail1; 1144 } 1145 1146 rc = tlv_modify(&cursor, tag, (uint8_t *)valuep, length); 1147 1148 if (rc != 0) { 1149 goto fail2; 1150 } 1151 1152 *lengthp = byte_offset(tlv_next_item_ptr(&cursor), 1153 cursor.current); 1154 1155 return (0); 1156 1157 fail2: 1158 EFSYS_PROBE(fail2); 1159 fail1: 1160 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1161 1162 return (rc); 1163 } 1164 1165 __checkReturn efx_rc_t 1166 ef10_nvram_buffer_delete_item( 1167 __in_bcount(buffer_size) 1168 caddr_t bufferp, 1169 __in size_t buffer_size, 1170 __in uint32_t offset, 1171 __in uint32_t length, 1172 __in uint32_t end) 1173 { 1174 efx_rc_t rc; 1175 tlv_cursor_t cursor; 1176 1177 _NOTE(ARGUNUSED(length, end)) 1178 1179 if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, 1180 buffer_size, offset)) != 0) { 1181 goto fail1; 1182 } 1183 1184 if ((rc = tlv_delete(&cursor)) != 0) 1185 goto fail2; 1186 1187 return (0); 1188 1189 fail2: 1190 EFSYS_PROBE(fail2); 1191 fail1: 1192 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1193 1194 return (rc); 1195 } 1196 1197 __checkReturn efx_rc_t 1198 ef10_nvram_buffer_finish( 1199 __in_bcount(buffer_size) 1200 caddr_t bufferp, 1201 __in size_t buffer_size) 1202 { 1203 efx_rc_t rc; 1204 tlv_cursor_t cursor; 1205 1206 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp, 1207 buffer_size)) != 0) { 1208 rc = EFAULT; 1209 goto fail1; 1210 } 1211 1212 if ((rc = tlv_require_end(&cursor)) != 0) 1213 goto fail2; 1214 1215 if ((rc = tlv_update_partition_len_and_cks(&cursor)) != 0) 1216 goto fail3; 1217 1218 return (0); 1219 1220 fail3: 1221 EFSYS_PROBE(fail3); 1222 fail2: 1223 EFSYS_PROBE(fail2); 1224 fail1: 1225 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1226 1227 return (rc); 1228 } 1229 1230 /* 1231 * Read and validate a segment from a partition. A segment is a complete 1232 * tlv chain between PARTITION_HEADER and PARTITION_END tags. There may 1233 * be multiple segments in a partition, so seg_offset allows segments 1234 * beyond the first to be read. 1235 */ 1236 static __checkReturn efx_rc_t 1237 ef10_nvram_read_tlv_segment( 1238 __in efx_nic_t *enp, 1239 __in uint32_t partn, 1240 __in size_t seg_offset, 1241 __in_bcount(max_seg_size) caddr_t seg_data, 1242 __in size_t max_seg_size) 1243 { 1244 tlv_cursor_t cursor; 1245 struct tlv_partition_header *header; 1246 struct tlv_partition_trailer *trailer; 1247 size_t total_length; 1248 uint32_t cksum; 1249 int pos; 1250 efx_rc_t rc; 1251 1252 EFX_STATIC_ASSERT(sizeof (*header) <= EF10_NVRAM_CHUNK); 1253 1254 if ((seg_data == NULL) || (max_seg_size == 0)) { 1255 rc = EINVAL; 1256 goto fail1; 1257 } 1258 1259 /* Read initial chunk of the segment, starting at offset */ 1260 if ((rc = ef10_nvram_partn_read_mode(enp, partn, seg_offset, seg_data, 1261 EF10_NVRAM_CHUNK, 1262 MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT)) != 0) { 1263 goto fail2; 1264 } 1265 1266 /* A PARTITION_HEADER tag must be the first item at the given offset */ 1267 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data, 1268 max_seg_size)) != 0) { 1269 rc = EFAULT; 1270 goto fail3; 1271 } 1272 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { 1273 rc = EINVAL; 1274 goto fail4; 1275 } 1276 header = (struct tlv_partition_header *)tlv_item(&cursor); 1277 1278 /* Check TLV segment length (includes the END tag) */ 1279 total_length = __LE_TO_CPU_32(header->total_length); 1280 if (total_length > max_seg_size) { 1281 rc = EFBIG; 1282 goto fail5; 1283 } 1284 1285 /* Read the remaining segment content */ 1286 if (total_length > EF10_NVRAM_CHUNK) { 1287 if ((rc = ef10_nvram_partn_read_mode(enp, partn, 1288 seg_offset + EF10_NVRAM_CHUNK, 1289 seg_data + EF10_NVRAM_CHUNK, 1290 total_length - EF10_NVRAM_CHUNK, 1291 MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT)) != 0) 1292 goto fail6; 1293 } 1294 1295 /* Check segment ends with PARTITION_TRAILER and END tags */ 1296 if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { 1297 rc = EINVAL; 1298 goto fail7; 1299 } 1300 trailer = (struct tlv_partition_trailer *)tlv_item(&cursor); 1301 1302 if ((rc = tlv_advance(&cursor)) != 0) { 1303 rc = EINVAL; 1304 goto fail8; 1305 } 1306 if (tlv_tag(&cursor) != TLV_TAG_END) { 1307 rc = EINVAL; 1308 goto fail9; 1309 } 1310 1311 /* Check data read from segment is consistent */ 1312 if (trailer->generation != header->generation) { 1313 /* 1314 * The partition data may have been modified between successive 1315 * MCDI NVRAM_READ requests by the MC or another PCI function. 1316 * 1317 * The caller must retry to obtain consistent partition data. 1318 */ 1319 rc = EAGAIN; 1320 goto fail10; 1321 } 1322 1323 /* Verify segment checksum */ 1324 cksum = 0; 1325 for (pos = 0; (size_t)pos < total_length; pos += sizeof (uint32_t)) { 1326 cksum += *((uint32_t *)(seg_data + pos)); 1327 } 1328 if (cksum != 0) { 1329 rc = EINVAL; 1330 goto fail11; 1331 } 1332 1333 return (0); 1334 1335 fail11: 1336 EFSYS_PROBE(fail11); 1337 fail10: 1338 EFSYS_PROBE(fail10); 1339 fail9: 1340 EFSYS_PROBE(fail9); 1341 fail8: 1342 EFSYS_PROBE(fail8); 1343 fail7: 1344 EFSYS_PROBE(fail7); 1345 fail6: 1346 EFSYS_PROBE(fail6); 1347 fail5: 1348 EFSYS_PROBE(fail5); 1349 fail4: 1350 EFSYS_PROBE(fail4); 1351 fail3: 1352 EFSYS_PROBE(fail3); 1353 fail2: 1354 EFSYS_PROBE(fail2); 1355 fail1: 1356 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1357 1358 return (rc); 1359 } 1360 1361 /* 1362 * Read a single TLV item from a host memory 1363 * buffer containing a TLV formatted segment. 1364 */ 1365 __checkReturn efx_rc_t 1366 ef10_nvram_buf_read_tlv( 1367 __in efx_nic_t *enp, 1368 __in_bcount(max_seg_size) caddr_t seg_data, 1369 __in size_t max_seg_size, 1370 __in uint32_t tag, 1371 __deref_out_bcount_opt(*sizep) caddr_t *datap, 1372 __out size_t *sizep) 1373 { 1374 tlv_cursor_t cursor; 1375 caddr_t data; 1376 size_t length; 1377 caddr_t value; 1378 efx_rc_t rc; 1379 1380 _NOTE(ARGUNUSED(enp)) 1381 1382 if ((seg_data == NULL) || (max_seg_size == 0)) { 1383 rc = EINVAL; 1384 goto fail1; 1385 } 1386 1387 /* Find requested TLV tag in segment data */ 1388 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data, 1389 max_seg_size)) != 0) { 1390 rc = EFAULT; 1391 goto fail2; 1392 } 1393 if ((rc = tlv_find(&cursor, tag)) != 0) { 1394 rc = ENOENT; 1395 goto fail3; 1396 } 1397 value = (caddr_t)tlv_value(&cursor); 1398 length = tlv_length(&cursor); 1399 1400 if (length == 0) 1401 data = NULL; 1402 else { 1403 /* Copy out data from TLV item */ 1404 EFSYS_KMEM_ALLOC(enp->en_esip, length, data); 1405 if (data == NULL) { 1406 rc = ENOMEM; 1407 goto fail4; 1408 } 1409 memcpy(data, value, length); 1410 } 1411 1412 *datap = data; 1413 *sizep = length; 1414 1415 return (0); 1416 1417 fail4: 1418 EFSYS_PROBE(fail4); 1419 fail3: 1420 EFSYS_PROBE(fail3); 1421 fail2: 1422 EFSYS_PROBE(fail2); 1423 fail1: 1424 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1425 1426 return (rc); 1427 } 1428 1429 /* Read a single TLV item from the first segment in a TLV formatted partition */ 1430 __checkReturn efx_rc_t 1431 ef10_nvram_partn_read_tlv( 1432 __in efx_nic_t *enp, 1433 __in uint32_t partn, 1434 __in uint32_t tag, 1435 __deref_out_bcount_opt(*seg_sizep) caddr_t *seg_datap, 1436 __out size_t *seg_sizep) 1437 { 1438 caddr_t seg_data = NULL; 1439 size_t partn_size = 0; 1440 size_t length; 1441 caddr_t data; 1442 int retry; 1443 efx_rc_t rc; 1444 1445 /* Allocate sufficient memory for the entire partition */ 1446 if ((rc = ef10_nvram_partn_size(enp, partn, &partn_size)) != 0) 1447 goto fail1; 1448 1449 if (partn_size == 0) { 1450 rc = ENOENT; 1451 goto fail2; 1452 } 1453 1454 EFSYS_KMEM_ALLOC(enp->en_esip, partn_size, seg_data); 1455 if (seg_data == NULL) { 1456 rc = ENOMEM; 1457 goto fail3; 1458 } 1459 1460 /* 1461 * Read the first segment in a TLV partition. Retry until consistent 1462 * segment contents are returned. Inconsistent data may be read if: 1463 * a) the segment contents are invalid 1464 * b) the MC has rebooted while we were reading the partition 1465 * c) the partition has been modified while we were reading it 1466 * Limit retry attempts to ensure forward progress. 1467 */ 1468 retry = 10; 1469 do { 1470 if ((rc = ef10_nvram_read_tlv_segment(enp, partn, 0, 1471 seg_data, partn_size)) != 0) 1472 --retry; 1473 } while ((rc == EAGAIN) && (retry > 0)); 1474 1475 if (rc != 0) { 1476 /* Failed to obtain consistent segment data */ 1477 if (rc == EAGAIN) 1478 rc = EIO; 1479 1480 goto fail4; 1481 } 1482 1483 if ((rc = ef10_nvram_buf_read_tlv(enp, seg_data, partn_size, 1484 tag, &data, &length)) != 0) 1485 goto fail5; 1486 1487 EFSYS_KMEM_FREE(enp->en_esip, partn_size, seg_data); 1488 1489 *seg_datap = data; 1490 *seg_sizep = length; 1491 1492 return (0); 1493 1494 fail5: 1495 EFSYS_PROBE(fail5); 1496 fail4: 1497 EFSYS_PROBE(fail4); 1498 1499 EFSYS_KMEM_FREE(enp->en_esip, partn_size, seg_data); 1500 fail3: 1501 EFSYS_PROBE(fail3); 1502 fail2: 1503 EFSYS_PROBE(fail2); 1504 fail1: 1505 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1506 1507 return (rc); 1508 } 1509 1510 /* Compute the size of a segment. */ 1511 static __checkReturn efx_rc_t 1512 ef10_nvram_buf_segment_size( 1513 __in caddr_t seg_data, 1514 __in size_t max_seg_size, 1515 __out size_t *seg_sizep) 1516 { 1517 efx_rc_t rc; 1518 tlv_cursor_t cursor; 1519 struct tlv_partition_header *header; 1520 uint32_t cksum; 1521 int pos; 1522 uint32_t *end_tag_position; 1523 uint32_t segment_length; 1524 1525 /* A PARTITION_HEADER tag must be the first item at the given offset */ 1526 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data, 1527 max_seg_size)) != 0) { 1528 rc = EFAULT; 1529 goto fail1; 1530 } 1531 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { 1532 rc = EINVAL; 1533 goto fail2; 1534 } 1535 header = (struct tlv_partition_header *)tlv_item(&cursor); 1536 1537 /* Check TLV segment length (includes the END tag) */ 1538 *seg_sizep = __LE_TO_CPU_32(header->total_length); 1539 if (*seg_sizep > max_seg_size) { 1540 rc = EFBIG; 1541 goto fail3; 1542 } 1543 1544 /* Check segment ends with PARTITION_TRAILER and END tags */ 1545 if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { 1546 rc = EINVAL; 1547 goto fail4; 1548 } 1549 1550 if ((rc = tlv_advance(&cursor)) != 0) { 1551 rc = EINVAL; 1552 goto fail5; 1553 } 1554 if (tlv_tag(&cursor) != TLV_TAG_END) { 1555 rc = EINVAL; 1556 goto fail6; 1557 } 1558 end_tag_position = cursor.current; 1559 1560 /* Verify segment checksum */ 1561 cksum = 0; 1562 for (pos = 0; (size_t)pos < *seg_sizep; pos += sizeof (uint32_t)) { 1563 cksum += *((uint32_t *)(seg_data + pos)); 1564 } 1565 if (cksum != 0) { 1566 rc = EINVAL; 1567 goto fail7; 1568 } 1569 1570 /* 1571 * Calculate total length from HEADER to END tags and compare to 1572 * max_seg_size and the total_length field in the HEADER tag. 1573 */ 1574 segment_length = tlv_block_length_used(&cursor); 1575 1576 if (segment_length > max_seg_size) { 1577 rc = EINVAL; 1578 goto fail8; 1579 } 1580 1581 if (segment_length != *seg_sizep) { 1582 rc = EINVAL; 1583 goto fail9; 1584 } 1585 1586 /* Skip over the first HEADER tag. */ 1587 rc = tlv_rewind(&cursor); 1588 rc = tlv_advance(&cursor); 1589 1590 while (rc == 0) { 1591 if (tlv_tag(&cursor) == TLV_TAG_END) { 1592 /* Check that the END tag is the one found earlier. */ 1593 if (cursor.current != end_tag_position) 1594 goto fail10; 1595 break; 1596 } 1597 /* Check for duplicate HEADER tags before the END tag. */ 1598 if (tlv_tag(&cursor) == TLV_TAG_PARTITION_HEADER) { 1599 rc = EINVAL; 1600 goto fail11; 1601 } 1602 1603 rc = tlv_advance(&cursor); 1604 } 1605 if (rc != 0) 1606 goto fail12; 1607 1608 return (0); 1609 1610 fail12: 1611 EFSYS_PROBE(fail12); 1612 fail11: 1613 EFSYS_PROBE(fail11); 1614 fail10: 1615 EFSYS_PROBE(fail10); 1616 fail9: 1617 EFSYS_PROBE(fail9); 1618 fail8: 1619 EFSYS_PROBE(fail8); 1620 fail7: 1621 EFSYS_PROBE(fail7); 1622 fail6: 1623 EFSYS_PROBE(fail6); 1624 fail5: 1625 EFSYS_PROBE(fail5); 1626 fail4: 1627 EFSYS_PROBE(fail4); 1628 fail3: 1629 EFSYS_PROBE(fail3); 1630 fail2: 1631 EFSYS_PROBE(fail2); 1632 fail1: 1633 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1634 1635 return (rc); 1636 } 1637 1638 /* 1639 * Add or update a single TLV item in a host memory buffer containing a TLV 1640 * formatted segment. Historically partitions consisted of only one segment. 1641 */ 1642 __checkReturn efx_rc_t 1643 ef10_nvram_buf_write_tlv( 1644 __inout_bcount(max_seg_size) caddr_t seg_data, 1645 __in size_t max_seg_size, 1646 __in uint32_t tag, 1647 __in_bcount(tag_size) caddr_t tag_data, 1648 __in size_t tag_size, 1649 __out size_t *total_lengthp) 1650 { 1651 tlv_cursor_t cursor; 1652 struct tlv_partition_header *header; 1653 struct tlv_partition_trailer *trailer; 1654 uint32_t generation; 1655 uint32_t cksum; 1656 int pos; 1657 efx_rc_t rc; 1658 1659 /* A PARTITION_HEADER tag must be the first item (at offset zero) */ 1660 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data, 1661 max_seg_size)) != 0) { 1662 rc = EFAULT; 1663 goto fail1; 1664 } 1665 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { 1666 rc = EINVAL; 1667 goto fail2; 1668 } 1669 header = (struct tlv_partition_header *)tlv_item(&cursor); 1670 1671 /* Update the TLV chain to contain the new data */ 1672 if ((rc = tlv_find(&cursor, tag)) == 0) { 1673 /* Modify existing TLV item */ 1674 if ((rc = tlv_modify(&cursor, tag, 1675 (uint8_t *)tag_data, tag_size)) != 0) 1676 goto fail3; 1677 } else { 1678 /* Insert a new TLV item before the PARTITION_TRAILER */ 1679 rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER); 1680 if (rc != 0) { 1681 rc = EINVAL; 1682 goto fail4; 1683 } 1684 if ((rc = tlv_insert(&cursor, tag, 1685 (uint8_t *)tag_data, tag_size)) != 0) { 1686 rc = EINVAL; 1687 goto fail5; 1688 } 1689 } 1690 1691 /* Find the trailer tag */ 1692 if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { 1693 rc = EINVAL; 1694 goto fail6; 1695 } 1696 trailer = (struct tlv_partition_trailer *)tlv_item(&cursor); 1697 1698 /* Update PARTITION_HEADER and PARTITION_TRAILER fields */ 1699 *total_lengthp = tlv_block_length_used(&cursor); 1700 if (*total_lengthp > max_seg_size) { 1701 rc = ENOSPC; 1702 goto fail7; 1703 } 1704 generation = __LE_TO_CPU_32(header->generation) + 1; 1705 1706 header->total_length = __CPU_TO_LE_32(*total_lengthp); 1707 header->generation = __CPU_TO_LE_32(generation); 1708 trailer->generation = __CPU_TO_LE_32(generation); 1709 1710 /* Recompute PARTITION_TRAILER checksum */ 1711 trailer->checksum = 0; 1712 cksum = 0; 1713 for (pos = 0; (size_t)pos < *total_lengthp; pos += sizeof (uint32_t)) { 1714 cksum += *((uint32_t *)(seg_data + pos)); 1715 } 1716 trailer->checksum = ~cksum + 1; 1717 1718 return (0); 1719 1720 fail7: 1721 EFSYS_PROBE(fail7); 1722 fail6: 1723 EFSYS_PROBE(fail6); 1724 fail5: 1725 EFSYS_PROBE(fail5); 1726 fail4: 1727 EFSYS_PROBE(fail4); 1728 fail3: 1729 EFSYS_PROBE(fail3); 1730 fail2: 1731 EFSYS_PROBE(fail2); 1732 fail1: 1733 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1734 1735 return (rc); 1736 } 1737 1738 /* 1739 * Add or update a single TLV item in the first segment of a TLV formatted 1740 * dynamic config partition. The first segment is the current active 1741 * configuration. 1742 */ 1743 __checkReturn efx_rc_t 1744 ef10_nvram_partn_write_tlv( 1745 __in efx_nic_t *enp, 1746 __in uint32_t partn, 1747 __in uint32_t tag, 1748 __in_bcount(size) caddr_t data, 1749 __in size_t size) 1750 { 1751 return ef10_nvram_partn_write_segment_tlv(enp, partn, tag, data, 1752 size, B_FALSE); 1753 } 1754 1755 /* 1756 * Read a segment from nvram at the given offset into a buffer (segment_data) 1757 * and optionally write a new tag to it. 1758 */ 1759 static __checkReturn efx_rc_t 1760 ef10_nvram_segment_write_tlv( 1761 __in efx_nic_t *enp, 1762 __in uint32_t partn, 1763 __in uint32_t tag, 1764 __in_bcount(size) caddr_t data, 1765 __in size_t size, 1766 __inout caddr_t *seg_datap, 1767 __inout size_t *partn_offsetp, 1768 __inout size_t *src_remain_lenp, 1769 __inout size_t *dest_remain_lenp, 1770 __in boolean_t write) 1771 { 1772 efx_rc_t rc; 1773 efx_rc_t status; 1774 size_t original_segment_size; 1775 size_t modified_segment_size; 1776 1777 /* 1778 * Read the segment from NVRAM into the segment_data buffer and validate 1779 * it, returning if it does not validate. This is not a failure unless 1780 * this is the first segment in a partition. In this case the caller 1781 * must propagate the error. 1782 */ 1783 status = ef10_nvram_read_tlv_segment(enp, partn, *partn_offsetp, 1784 *seg_datap, *src_remain_lenp); 1785 if (status != 0) { 1786 rc = EINVAL; 1787 goto fail1; 1788 } 1789 1790 status = ef10_nvram_buf_segment_size(*seg_datap, 1791 *src_remain_lenp, &original_segment_size); 1792 if (status != 0) { 1793 rc = EINVAL; 1794 goto fail2; 1795 } 1796 1797 if (write) { 1798 /* Update the contents of the segment in the buffer */ 1799 if ((rc = ef10_nvram_buf_write_tlv(*seg_datap, 1800 *dest_remain_lenp, tag, data, size, 1801 &modified_segment_size)) != 0) { 1802 goto fail3; 1803 } 1804 *dest_remain_lenp -= modified_segment_size; 1805 *seg_datap += modified_segment_size; 1806 } else { 1807 /* 1808 * We won't modify this segment, but still need to update the 1809 * remaining lengths and pointers. 1810 */ 1811 *dest_remain_lenp -= original_segment_size; 1812 *seg_datap += original_segment_size; 1813 } 1814 1815 *partn_offsetp += original_segment_size; 1816 *src_remain_lenp -= original_segment_size; 1817 1818 return (0); 1819 1820 fail3: 1821 EFSYS_PROBE(fail3); 1822 fail2: 1823 EFSYS_PROBE(fail2); 1824 fail1: 1825 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1826 1827 return (rc); 1828 } 1829 1830 /* 1831 * Add or update a single TLV item in either the first segment or in all 1832 * segments in a TLV formatted dynamic config partition. Dynamic config 1833 * partitions on boards that support RFID are divided into a number of segments, 1834 * each formatted like a partition, with header, trailer and end tags. The first 1835 * segment is the current active configuration. 1836 * 1837 * The segments are initialised by manftest and each contain a different 1838 * configuration e.g. firmware variant. The firmware can be instructed 1839 * via RFID to copy a segment to replace the first segment, hence changing the 1840 * active configuration. This allows ops to change the configuration of a board 1841 * prior to shipment using RFID. 1842 * 1843 * Changes to the dynamic config may need to be written to all segments (e.g. 1844 * firmware versions) or just the first segment (changes to the active 1845 * configuration). See SF-111324-SW "The use of RFID in Solarflare Products". 1846 * If only the first segment is written the code still needs to be aware of the 1847 * possible presence of subsequent segments as writing to a segment may cause 1848 * its size to increase, which would overwrite the subsequent segments and 1849 * invalidate them. 1850 */ 1851 __checkReturn efx_rc_t 1852 ef10_nvram_partn_write_segment_tlv( 1853 __in efx_nic_t *enp, 1854 __in uint32_t partn, 1855 __in uint32_t tag, 1856 __in_bcount(size) caddr_t data, 1857 __in size_t size, 1858 __in boolean_t all_segments) 1859 { 1860 size_t partn_size = 0; 1861 caddr_t partn_data; 1862 size_t total_length = 0; 1863 efx_rc_t rc; 1864 size_t current_offset = 0; 1865 size_t remaining_original_length; 1866 size_t remaining_modified_length; 1867 caddr_t segment_data; 1868 1869 EFSYS_ASSERT3U(partn, ==, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG); 1870 1871 /* Allocate sufficient memory for the entire partition */ 1872 if ((rc = ef10_nvram_partn_size(enp, partn, &partn_size)) != 0) 1873 goto fail1; 1874 1875 EFSYS_KMEM_ALLOC(enp->en_esip, partn_size, partn_data); 1876 if (partn_data == NULL) { 1877 rc = ENOMEM; 1878 goto fail2; 1879 } 1880 1881 remaining_original_length = partn_size; 1882 remaining_modified_length = partn_size; 1883 segment_data = partn_data; 1884 1885 /* Lock the partition */ 1886 if ((rc = ef10_nvram_partn_lock(enp, partn)) != 0) 1887 goto fail3; 1888 1889 /* Iterate over each (potential) segment to update it. */ 1890 do { 1891 boolean_t write = all_segments || current_offset == 0; 1892 1893 rc = ef10_nvram_segment_write_tlv(enp, partn, tag, data, size, 1894 &segment_data, ¤t_offset, &remaining_original_length, 1895 &remaining_modified_length, write); 1896 if (rc != 0) { 1897 if (current_offset == 0) { 1898 /* 1899 * If no data has been read then the first 1900 * segment is invalid, which is an error. 1901 */ 1902 goto fail4; 1903 } 1904 break; 1905 } 1906 } while (current_offset < partn_size); 1907 1908 total_length = segment_data - partn_data; 1909 1910 /* 1911 * We've run out of space. This should actually be dealt with by 1912 * ef10_nvram_buf_write_tlv returning ENOSPC. 1913 */ 1914 if (total_length > partn_size) { 1915 rc = ENOSPC; 1916 goto fail5; 1917 } 1918 1919 /* Erase the whole partition in NVRAM */ 1920 if ((rc = ef10_nvram_partn_erase(enp, partn, 0, partn_size)) != 0) 1921 goto fail6; 1922 1923 /* Write new partition contents from the buffer to NVRAM */ 1924 if ((rc = ef10_nvram_partn_write(enp, partn, 0, partn_data, 1925 total_length)) != 0) 1926 goto fail7; 1927 1928 /* Unlock the partition */ 1929 (void) ef10_nvram_partn_unlock(enp, partn, NULL); 1930 1931 EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data); 1932 1933 return (0); 1934 1935 fail7: 1936 EFSYS_PROBE(fail7); 1937 fail6: 1938 EFSYS_PROBE(fail6); 1939 fail5: 1940 EFSYS_PROBE(fail5); 1941 fail4: 1942 EFSYS_PROBE(fail4); 1943 1944 (void) ef10_nvram_partn_unlock(enp, partn, NULL); 1945 fail3: 1946 EFSYS_PROBE(fail3); 1947 1948 EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data); 1949 fail2: 1950 EFSYS_PROBE(fail2); 1951 fail1: 1952 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1953 1954 return (rc); 1955 } 1956 1957 /* 1958 * Get the size of a NVRAM partition. This is the total size allocated in nvram, 1959 * not the data used by the segments in the partition. 1960 */ 1961 __checkReturn efx_rc_t 1962 ef10_nvram_partn_size( 1963 __in efx_nic_t *enp, 1964 __in uint32_t partn, 1965 __out size_t *sizep) 1966 { 1967 efx_rc_t rc; 1968 1969 if ((rc = efx_mcdi_nvram_info(enp, partn, sizep, 1970 NULL, NULL, NULL)) != 0) 1971 goto fail1; 1972 1973 return (0); 1974 1975 fail1: 1976 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1977 1978 return (rc); 1979 } 1980 1981 __checkReturn efx_rc_t 1982 ef10_nvram_partn_lock( 1983 __in efx_nic_t *enp, 1984 __in uint32_t partn) 1985 { 1986 efx_rc_t rc; 1987 1988 if ((rc = efx_mcdi_nvram_update_start(enp, partn)) != 0) 1989 goto fail1; 1990 1991 return (0); 1992 1993 fail1: 1994 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1995 1996 return (rc); 1997 } 1998 1999 __checkReturn efx_rc_t 2000 ef10_nvram_partn_read_mode( 2001 __in efx_nic_t *enp, 2002 __in uint32_t partn, 2003 __in unsigned int offset, 2004 __out_bcount(size) caddr_t data, 2005 __in size_t size, 2006 __in uint32_t mode) 2007 { 2008 size_t chunk; 2009 efx_rc_t rc; 2010 2011 while (size > 0) { 2012 chunk = MIN(size, EF10_NVRAM_CHUNK); 2013 2014 if ((rc = efx_mcdi_nvram_read(enp, partn, offset, 2015 data, chunk, mode)) != 0) { 2016 goto fail1; 2017 } 2018 2019 size -= chunk; 2020 data += chunk; 2021 offset += chunk; 2022 } 2023 2024 return (0); 2025 2026 fail1: 2027 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2028 2029 return (rc); 2030 } 2031 2032 __checkReturn efx_rc_t 2033 ef10_nvram_partn_read( 2034 __in efx_nic_t *enp, 2035 __in uint32_t partn, 2036 __in unsigned int offset, 2037 __out_bcount(size) caddr_t data, 2038 __in size_t size) 2039 { 2040 /* 2041 * An A/B partition has two data stores (current and backup). 2042 * Read requests which come in through the EFX API expect to read the 2043 * current, active store of an A/B partition. For non A/B partitions, 2044 * there is only a single store and so the mode param is ignored. 2045 */ 2046 return ef10_nvram_partn_read_mode(enp, partn, offset, data, size, 2047 MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT); 2048 } 2049 2050 __checkReturn efx_rc_t 2051 ef10_nvram_partn_read_backup( 2052 __in efx_nic_t *enp, 2053 __in uint32_t partn, 2054 __in unsigned int offset, 2055 __out_bcount(size) caddr_t data, 2056 __in size_t size) 2057 { 2058 /* 2059 * An A/B partition has two data stores (current and backup). 2060 * Read the backup store of an A/B partition (i.e. the store currently 2061 * being written to if the partition is locked). 2062 * 2063 * This is needed when comparing the existing partition content to avoid 2064 * unnecessary writes, or to read back what has been written to check 2065 * that the writes have succeeded. 2066 */ 2067 return ef10_nvram_partn_read_mode(enp, partn, offset, data, size, 2068 MC_CMD_NVRAM_READ_IN_V2_TARGET_BACKUP); 2069 } 2070 2071 __checkReturn efx_rc_t 2072 ef10_nvram_partn_erase( 2073 __in efx_nic_t *enp, 2074 __in uint32_t partn, 2075 __in unsigned int offset, 2076 __in size_t size) 2077 { 2078 efx_rc_t rc; 2079 uint32_t erase_size; 2080 2081 if ((rc = efx_mcdi_nvram_info(enp, partn, NULL, NULL, 2082 &erase_size, NULL)) != 0) 2083 goto fail1; 2084 2085 if (erase_size == 0) { 2086 if ((rc = efx_mcdi_nvram_erase(enp, partn, offset, size)) != 0) 2087 goto fail2; 2088 } else { 2089 if (size % erase_size != 0) { 2090 rc = EINVAL; 2091 goto fail3; 2092 } 2093 while (size > 0) { 2094 if ((rc = efx_mcdi_nvram_erase(enp, partn, offset, 2095 erase_size)) != 0) 2096 goto fail4; 2097 offset += erase_size; 2098 size -= erase_size; 2099 } 2100 } 2101 2102 return (0); 2103 2104 fail4: 2105 EFSYS_PROBE(fail4); 2106 fail3: 2107 EFSYS_PROBE(fail3); 2108 fail2: 2109 EFSYS_PROBE(fail2); 2110 fail1: 2111 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2112 2113 return (rc); 2114 } 2115 2116 __checkReturn efx_rc_t 2117 ef10_nvram_partn_write( 2118 __in efx_nic_t *enp, 2119 __in uint32_t partn, 2120 __in unsigned int offset, 2121 __in_bcount(size) caddr_t data, 2122 __in size_t size) 2123 { 2124 size_t chunk; 2125 uint32_t write_size; 2126 efx_rc_t rc; 2127 2128 if ((rc = efx_mcdi_nvram_info(enp, partn, NULL, NULL, 2129 NULL, &write_size)) != 0) 2130 goto fail1; 2131 2132 if (write_size != 0) { 2133 /* 2134 * Check that the size is a multiple of the write chunk size if 2135 * the write chunk size is available. 2136 */ 2137 if (size % write_size != 0) { 2138 rc = EINVAL; 2139 goto fail2; 2140 } 2141 } else { 2142 write_size = EF10_NVRAM_CHUNK; 2143 } 2144 2145 while (size > 0) { 2146 chunk = MIN(size, write_size); 2147 2148 if ((rc = efx_mcdi_nvram_write(enp, partn, offset, 2149 data, chunk)) != 0) { 2150 goto fail3; 2151 } 2152 2153 size -= chunk; 2154 data += chunk; 2155 offset += chunk; 2156 } 2157 2158 return (0); 2159 2160 fail3: 2161 EFSYS_PROBE(fail3); 2162 fail2: 2163 EFSYS_PROBE(fail2); 2164 fail1: 2165 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2166 2167 return (rc); 2168 } 2169 2170 __checkReturn efx_rc_t 2171 ef10_nvram_partn_unlock( 2172 __in efx_nic_t *enp, 2173 __in uint32_t partn, 2174 __out_opt uint32_t *verify_resultp) 2175 { 2176 boolean_t reboot = B_FALSE; 2177 efx_rc_t rc; 2178 2179 if (verify_resultp != NULL) 2180 *verify_resultp = MC_CMD_NVRAM_VERIFY_RC_UNKNOWN; 2181 2182 rc = efx_mcdi_nvram_update_finish(enp, partn, reboot, verify_resultp); 2183 if (rc != 0) 2184 goto fail1; 2185 2186 return (0); 2187 2188 fail1: 2189 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2190 2191 return (rc); 2192 } 2193 2194 __checkReturn efx_rc_t 2195 ef10_nvram_partn_set_version( 2196 __in efx_nic_t *enp, 2197 __in uint32_t partn, 2198 __in_ecount(4) uint16_t version[4]) 2199 { 2200 struct tlv_partition_version partn_version; 2201 size_t size; 2202 efx_rc_t rc; 2203 2204 /* Add or modify partition version TLV item */ 2205 partn_version.version_w = __CPU_TO_LE_16(version[0]); 2206 partn_version.version_x = __CPU_TO_LE_16(version[1]); 2207 partn_version.version_y = __CPU_TO_LE_16(version[2]); 2208 partn_version.version_z = __CPU_TO_LE_16(version[3]); 2209 2210 size = sizeof (partn_version) - (2 * sizeof (uint32_t)); 2211 2212 /* Write the version number to all segments in the partition */ 2213 if ((rc = ef10_nvram_partn_write_segment_tlv(enp, 2214 NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 2215 TLV_TAG_PARTITION_VERSION(partn), 2216 (caddr_t)&partn_version.version_w, size, B_TRUE)) != 0) 2217 goto fail1; 2218 2219 return (0); 2220 2221 fail1: 2222 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2223 2224 return (rc); 2225 } 2226 2227 #endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */ 2228 2229 #if EFSYS_OPT_NVRAM 2230 2231 typedef struct ef10_parttbl_entry_s { 2232 unsigned int partn; 2233 unsigned int port_mask; 2234 efx_nvram_type_t nvtype; 2235 } ef10_parttbl_entry_t; 2236 2237 /* Port mask values */ 2238 #define PORT_1 (1u << 1) 2239 #define PORT_2 (1u << 2) 2240 #define PORT_3 (1u << 3) 2241 #define PORT_4 (1u << 4) 2242 #define PORT_ALL (0xffffffffu) 2243 2244 #define PARTN_MAP_ENTRY(partn, port_mask, nvtype) \ 2245 { (NVRAM_PARTITION_TYPE_##partn), (PORT_##port_mask), (EFX_NVRAM_##nvtype) } 2246 2247 /* Translate EFX NVRAM types to firmware partition types */ 2248 static ef10_parttbl_entry_t hunt_parttbl[] = { 2249 /* partn ports nvtype */ 2250 PARTN_MAP_ENTRY(MC_FIRMWARE, ALL, MC_FIRMWARE), 2251 PARTN_MAP_ENTRY(MC_FIRMWARE_BACKUP, ALL, MC_GOLDEN), 2252 PARTN_MAP_ENTRY(EXPANSION_ROM, ALL, BOOTROM), 2253 PARTN_MAP_ENTRY(EXPROM_CONFIG_PORT0, 1, BOOTROM_CFG), 2254 PARTN_MAP_ENTRY(EXPROM_CONFIG_PORT1, 2, BOOTROM_CFG), 2255 PARTN_MAP_ENTRY(EXPROM_CONFIG_PORT2, 3, BOOTROM_CFG), 2256 PARTN_MAP_ENTRY(EXPROM_CONFIG_PORT3, 4, BOOTROM_CFG), 2257 PARTN_MAP_ENTRY(DYNAMIC_CONFIG, ALL, DYNAMIC_CFG), 2258 PARTN_MAP_ENTRY(FPGA, ALL, FPGA), 2259 PARTN_MAP_ENTRY(FPGA_BACKUP, ALL, FPGA_BACKUP), 2260 PARTN_MAP_ENTRY(LICENSE, ALL, LICENSE), 2261 }; 2262 2263 static ef10_parttbl_entry_t medford_parttbl[] = { 2264 /* partn ports nvtype */ 2265 PARTN_MAP_ENTRY(MC_FIRMWARE, ALL, MC_FIRMWARE), 2266 PARTN_MAP_ENTRY(MC_FIRMWARE_BACKUP, ALL, MC_GOLDEN), 2267 PARTN_MAP_ENTRY(EXPANSION_ROM, ALL, BOOTROM), 2268 PARTN_MAP_ENTRY(EXPROM_CONFIG, ALL, BOOTROM_CFG), 2269 PARTN_MAP_ENTRY(DYNAMIC_CONFIG, ALL, DYNAMIC_CFG), 2270 PARTN_MAP_ENTRY(FPGA, ALL, FPGA), 2271 PARTN_MAP_ENTRY(FPGA_BACKUP, ALL, FPGA_BACKUP), 2272 PARTN_MAP_ENTRY(LICENSE, ALL, LICENSE), 2273 PARTN_MAP_ENTRY(EXPANSION_UEFI, ALL, UEFIROM), 2274 PARTN_MAP_ENTRY(MUM_FIRMWARE, ALL, MUM_FIRMWARE), 2275 }; 2276 2277 static ef10_parttbl_entry_t medford2_parttbl[] = { 2278 /* partn ports nvtype */ 2279 PARTN_MAP_ENTRY(MC_FIRMWARE, ALL, MC_FIRMWARE), 2280 PARTN_MAP_ENTRY(MC_FIRMWARE_BACKUP, ALL, MC_GOLDEN), 2281 PARTN_MAP_ENTRY(EXPANSION_ROM, ALL, BOOTROM), 2282 PARTN_MAP_ENTRY(EXPROM_CONFIG, ALL, BOOTROM_CFG), 2283 PARTN_MAP_ENTRY(DYNAMIC_CONFIG, ALL, DYNAMIC_CFG), 2284 PARTN_MAP_ENTRY(FPGA, ALL, FPGA), 2285 PARTN_MAP_ENTRY(FPGA_BACKUP, ALL, FPGA_BACKUP), 2286 PARTN_MAP_ENTRY(LICENSE, ALL, LICENSE), 2287 PARTN_MAP_ENTRY(EXPANSION_UEFI, ALL, UEFIROM), 2288 PARTN_MAP_ENTRY(MUM_FIRMWARE, ALL, MUM_FIRMWARE), 2289 PARTN_MAP_ENTRY(DYNCONFIG_DEFAULTS, ALL, DYNCONFIG_DEFAULTS), 2290 PARTN_MAP_ENTRY(ROMCONFIG_DEFAULTS, ALL, ROMCONFIG_DEFAULTS), 2291 }; 2292 2293 static __checkReturn efx_rc_t 2294 ef10_parttbl_get( 2295 __in efx_nic_t *enp, 2296 __out ef10_parttbl_entry_t **parttblp, 2297 __out size_t *parttbl_rowsp) 2298 { 2299 switch (enp->en_family) { 2300 case EFX_FAMILY_HUNTINGTON: 2301 *parttblp = hunt_parttbl; 2302 *parttbl_rowsp = EFX_ARRAY_SIZE(hunt_parttbl); 2303 break; 2304 2305 case EFX_FAMILY_MEDFORD: 2306 *parttblp = medford_parttbl; 2307 *parttbl_rowsp = EFX_ARRAY_SIZE(medford_parttbl); 2308 break; 2309 2310 case EFX_FAMILY_MEDFORD2: 2311 *parttblp = medford2_parttbl; 2312 *parttbl_rowsp = EFX_ARRAY_SIZE(medford2_parttbl); 2313 break; 2314 2315 default: 2316 EFSYS_ASSERT(B_FALSE); 2317 return (EINVAL); 2318 } 2319 return (0); 2320 } 2321 2322 __checkReturn efx_rc_t 2323 ef10_nvram_type_to_partn( 2324 __in efx_nic_t *enp, 2325 __in efx_nvram_type_t type, 2326 __out uint32_t *partnp) 2327 { 2328 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 2329 ef10_parttbl_entry_t *parttbl = NULL; 2330 size_t parttbl_rows = 0; 2331 unsigned int i; 2332 2333 EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID); 2334 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 2335 EFSYS_ASSERT(partnp != NULL); 2336 2337 if (ef10_parttbl_get(enp, &parttbl, &parttbl_rows) == 0) { 2338 for (i = 0; i < parttbl_rows; i++) { 2339 ef10_parttbl_entry_t *entry = &parttbl[i]; 2340 2341 if ((entry->nvtype == type) && 2342 (entry->port_mask & (1u << emip->emi_port))) { 2343 *partnp = entry->partn; 2344 return (0); 2345 } 2346 } 2347 } 2348 2349 return (ENOTSUP); 2350 } 2351 2352 #if EFSYS_OPT_DIAG 2353 2354 static __checkReturn efx_rc_t 2355 ef10_nvram_partn_to_type( 2356 __in efx_nic_t *enp, 2357 __in uint32_t partn, 2358 __out efx_nvram_type_t *typep) 2359 { 2360 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 2361 ef10_parttbl_entry_t *parttbl = NULL; 2362 size_t parttbl_rows = 0; 2363 unsigned int i; 2364 2365 EFSYS_ASSERT(typep != NULL); 2366 2367 if (ef10_parttbl_get(enp, &parttbl, &parttbl_rows) == 0) { 2368 for (i = 0; i < parttbl_rows; i++) { 2369 ef10_parttbl_entry_t *entry = &parttbl[i]; 2370 2371 if ((entry->partn == partn) && 2372 (entry->port_mask & (1u << emip->emi_port))) { 2373 *typep = entry->nvtype; 2374 return (0); 2375 } 2376 } 2377 } 2378 2379 return (ENOTSUP); 2380 } 2381 2382 __checkReturn efx_rc_t 2383 ef10_nvram_test( 2384 __in efx_nic_t *enp) 2385 { 2386 efx_nvram_type_t type; 2387 unsigned int npartns = 0; 2388 uint32_t *partns = NULL; 2389 size_t size; 2390 unsigned int i; 2391 efx_rc_t rc; 2392 2393 /* Read available partitions from NVRAM partition map */ 2394 size = MC_CMD_NVRAM_PARTITIONS_OUT_TYPE_ID_MAXNUM * sizeof (uint32_t); 2395 EFSYS_KMEM_ALLOC(enp->en_esip, size, partns); 2396 if (partns == NULL) { 2397 rc = ENOMEM; 2398 goto fail1; 2399 } 2400 2401 if ((rc = efx_mcdi_nvram_partitions(enp, (caddr_t)partns, size, 2402 &npartns)) != 0) { 2403 goto fail2; 2404 } 2405 2406 for (i = 0; i < npartns; i++) { 2407 /* Check if the partition is supported for this port */ 2408 if ((rc = ef10_nvram_partn_to_type(enp, partns[i], &type)) != 0) 2409 continue; 2410 2411 if ((rc = efx_mcdi_nvram_test(enp, partns[i])) != 0) 2412 goto fail3; 2413 } 2414 2415 EFSYS_KMEM_FREE(enp->en_esip, size, partns); 2416 return (0); 2417 2418 fail3: 2419 EFSYS_PROBE(fail3); 2420 fail2: 2421 EFSYS_PROBE(fail2); 2422 EFSYS_KMEM_FREE(enp->en_esip, size, partns); 2423 fail1: 2424 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2425 return (rc); 2426 } 2427 2428 #endif /* EFSYS_OPT_DIAG */ 2429 2430 __checkReturn efx_rc_t 2431 ef10_nvram_partn_get_version( 2432 __in efx_nic_t *enp, 2433 __in uint32_t partn, 2434 __out uint32_t *subtypep, 2435 __out_ecount(4) uint16_t version[4]) 2436 { 2437 efx_rc_t rc; 2438 2439 /* FIXME: get highest partn version from all ports */ 2440 /* FIXME: return partn description if available */ 2441 2442 if ((rc = efx_mcdi_nvram_metadata(enp, partn, subtypep, 2443 version, NULL, 0)) != 0) 2444 goto fail1; 2445 2446 return (0); 2447 2448 fail1: 2449 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2450 2451 return (rc); 2452 } 2453 2454 __checkReturn efx_rc_t 2455 ef10_nvram_partn_rw_start( 2456 __in efx_nic_t *enp, 2457 __in uint32_t partn, 2458 __out size_t *chunk_sizep) 2459 { 2460 uint32_t write_size = 0; 2461 efx_rc_t rc; 2462 2463 if ((rc = efx_mcdi_nvram_info(enp, partn, NULL, NULL, 2464 NULL, &write_size)) != 0) 2465 goto fail1; 2466 2467 if ((rc = ef10_nvram_partn_lock(enp, partn)) != 0) 2468 goto fail2; 2469 2470 if (chunk_sizep != NULL) { 2471 if (write_size == 0) 2472 *chunk_sizep = EF10_NVRAM_CHUNK; 2473 else 2474 *chunk_sizep = write_size; 2475 } 2476 2477 return (0); 2478 2479 fail2: 2480 EFSYS_PROBE(fail2); 2481 fail1: 2482 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2483 2484 return (rc); 2485 } 2486 2487 __checkReturn efx_rc_t 2488 ef10_nvram_partn_rw_finish( 2489 __in efx_nic_t *enp, 2490 __in uint32_t partn, 2491 __out_opt uint32_t *verify_resultp) 2492 { 2493 efx_rc_t rc; 2494 2495 if ((rc = ef10_nvram_partn_unlock(enp, partn, verify_resultp)) != 0) 2496 goto fail1; 2497 2498 return (0); 2499 2500 fail1: 2501 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2502 2503 return (rc); 2504 } 2505 2506 #endif /* EFSYS_OPT_NVRAM */ 2507 2508 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */ 2509