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