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