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 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 - 2)) { 234 cursor->current = NULL; 235 rc = EFAULT; 236 goto fail3; 237 } 238 239 /* Check we have value data for current item and another tag */ 240 if (tlv_next_item_ptr(cursor) > (cursor->limit - 1)) { 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 efx_nic_t *enp, 666 __in uint32_t partn, 667 __in_bcount(partn_size) caddr_t partn_data, 668 __in size_t partn_size) 669 { 670 tlv_cursor_t cursor; 671 struct tlv_partition_header *header; 672 struct tlv_partition_trailer *trailer; 673 size_t total_length; 674 uint32_t cksum; 675 int pos; 676 efx_rc_t rc; 677 678 EFX_STATIC_ASSERT(sizeof (*header) <= EF10_NVRAM_CHUNK); 679 680 if ((partn_data == NULL) || (partn_size == 0)) { 681 rc = EINVAL; 682 goto fail1; 683 } 684 685 /* The partition header must be the first item (at offset zero) */ 686 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)partn_data, 687 partn_size)) != 0) { 688 rc = EFAULT; 689 goto fail2; 690 } 691 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { 692 rc = EINVAL; 693 goto fail3; 694 } 695 header = (struct tlv_partition_header *)tlv_item(&cursor); 696 697 /* Check TLV partition length (includes the END tag) */ 698 total_length = __LE_TO_CPU_32(header->total_length); 699 if (total_length > partn_size) { 700 rc = EFBIG; 701 goto fail4; 702 } 703 704 /* Check partition ends with PARTITION_TRAILER and END tags */ 705 if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { 706 rc = EINVAL; 707 goto fail5; 708 } 709 trailer = (struct tlv_partition_trailer *)tlv_item(&cursor); 710 711 if ((rc = tlv_advance(&cursor)) != 0) { 712 rc = EINVAL; 713 goto fail6; 714 } 715 if (tlv_tag(&cursor) != TLV_TAG_END) { 716 rc = EINVAL; 717 goto fail7; 718 } 719 720 /* Check generation counts are consistent */ 721 if (trailer->generation != header->generation) { 722 rc = EINVAL; 723 goto fail8; 724 } 725 726 /* Verify partition checksum */ 727 cksum = 0; 728 for (pos = 0; (size_t)pos < total_length; pos += sizeof (uint32_t)) { 729 cksum += *((uint32_t *)(partn_data + pos)); 730 } 731 if (cksum != 0) { 732 rc = EINVAL; 733 goto fail9; 734 } 735 736 return (0); 737 738 fail9: 739 EFSYS_PROBE(fail9); 740 fail8: 741 EFSYS_PROBE(fail8); 742 fail7: 743 EFSYS_PROBE(fail7); 744 fail6: 745 EFSYS_PROBE(fail6); 746 fail5: 747 EFSYS_PROBE(fail5); 748 fail4: 749 EFSYS_PROBE(fail4); 750 fail3: 751 EFSYS_PROBE(fail3); 752 fail2: 753 EFSYS_PROBE(fail2); 754 fail1: 755 EFSYS_PROBE1(fail1, efx_rc_t, rc); 756 757 return (rc); 758 } 759 760 761 762 __checkReturn efx_rc_t 763 ef10_nvram_buffer_create( 764 __in efx_nic_t *enp, 765 __in uint16_t partn_type, 766 __in_bcount(partn_size) caddr_t partn_data, 767 __in size_t partn_size) 768 { 769 uint32_t *buf = (uint32_t *)partn_data; 770 efx_rc_t rc; 771 tlv_cursor_t cursor; 772 struct tlv_partition_header header; 773 struct tlv_partition_trailer trailer; 774 775 unsigned min_buf_size = sizeof (struct tlv_partition_header) + 776 sizeof (struct tlv_partition_trailer); 777 if (partn_size < min_buf_size) { 778 rc = EINVAL; 779 goto fail1; 780 } 781 782 memset(buf, 0xff, partn_size); 783 784 tlv_init_block(buf); 785 if ((rc = tlv_init_cursor(&cursor, buf, 786 (uint32_t *)((uint8_t *)buf + partn_size), 787 buf)) != 0) { 788 goto fail2; 789 } 790 791 header.tag = __CPU_TO_LE_32(TLV_TAG_PARTITION_HEADER); 792 header.length = __CPU_TO_LE_32(sizeof (header) - 8); 793 header.type_id = __CPU_TO_LE_16(partn_type); 794 header.preset = 0; 795 header.generation = __CPU_TO_LE_32(1); 796 header.total_length = 0; /* This will be fixed below. */ 797 if ((rc = tlv_insert( 798 &cursor, TLV_TAG_PARTITION_HEADER, 799 (uint8_t *)&header.type_id, sizeof (header) - 8)) != 0) 800 goto fail3; 801 if ((rc = tlv_advance(&cursor)) != 0) 802 goto fail4; 803 804 trailer.tag = __CPU_TO_LE_32(TLV_TAG_PARTITION_TRAILER); 805 trailer.length = __CPU_TO_LE_32(sizeof (trailer) - 8); 806 trailer.generation = header.generation; 807 trailer.checksum = 0; /* This will be fixed below. */ 808 if ((rc = tlv_insert(&cursor, TLV_TAG_PARTITION_TRAILER, 809 (uint8_t *)&trailer.generation, sizeof (trailer) - 8)) != 0) 810 goto fail5; 811 812 if ((rc = tlv_update_partition_len_and_cks(&cursor)) != 0) 813 goto fail6; 814 815 /* Check that the partition is valid. */ 816 if ((rc = ef10_nvram_buffer_validate(enp, partn_type, 817 partn_data, partn_size)) != 0) 818 goto fail7; 819 820 return (0); 821 822 fail7: 823 EFSYS_PROBE(fail7); 824 fail6: 825 EFSYS_PROBE(fail6); 826 fail5: 827 EFSYS_PROBE(fail5); 828 fail4: 829 EFSYS_PROBE(fail4); 830 fail3: 831 EFSYS_PROBE(fail3); 832 fail2: 833 EFSYS_PROBE(fail2); 834 fail1: 835 EFSYS_PROBE1(fail1, efx_rc_t, rc); 836 837 return (rc); 838 } 839 840 static uint32_t 841 byte_offset( 842 __in uint32_t *position, 843 __in uint32_t *base) 844 { 845 return (uint32_t)((uint8_t *)position - (uint8_t *)base); 846 } 847 848 __checkReturn efx_rc_t 849 ef10_nvram_buffer_find_item_start( 850 __in_bcount(buffer_size) 851 caddr_t bufferp, 852 __in size_t buffer_size, 853 __out uint32_t *startp) 854 { 855 // Read past partition header to find start address of the first key 856 tlv_cursor_t cursor; 857 efx_rc_t rc; 858 859 /* A PARTITION_HEADER tag must be the first item (at offset zero) */ 860 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp, 861 buffer_size)) != 0) { 862 rc = EFAULT; 863 goto fail1; 864 } 865 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { 866 rc = EINVAL; 867 goto fail2; 868 } 869 870 if ((rc = tlv_advance(&cursor)) != 0) { 871 rc = EINVAL; 872 goto fail3; 873 } 874 *startp = byte_offset(cursor.current, cursor.block); 875 876 if ((rc = tlv_require_end(&cursor)) != 0) 877 goto fail4; 878 879 return (0); 880 881 fail4: 882 EFSYS_PROBE(fail4); 883 fail3: 884 EFSYS_PROBE(fail3); 885 fail2: 886 EFSYS_PROBE(fail2); 887 fail1: 888 EFSYS_PROBE1(fail1, efx_rc_t, rc); 889 890 return (rc); 891 } 892 893 __checkReturn efx_rc_t 894 ef10_nvram_buffer_find_end( 895 __in_bcount(buffer_size) 896 caddr_t bufferp, 897 __in size_t buffer_size, 898 __in uint32_t offset, 899 __out uint32_t *endp) 900 { 901 // Read to end of partition 902 tlv_cursor_t cursor; 903 efx_rc_t rc; 904 uint32_t *segment_used; 905 906 _NOTE(ARGUNUSED(offset)) 907 908 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp, 909 buffer_size)) != 0) { 910 rc = EFAULT; 911 goto fail1; 912 } 913 914 segment_used = cursor.block; 915 916 /* 917 * Go through each segment and check that it has an end tag. If there 918 * is no end tag then the previous segment was the last valid one, 919 * so return the used space including that end tag. 920 */ 921 while (tlv_tag(&cursor) == TLV_TAG_PARTITION_HEADER) { 922 if (tlv_require_end(&cursor) != 0) { 923 if (segment_used == cursor.block) { 924 /* 925 * First segment is corrupt, so there is 926 * no valid data in partition. 927 */ 928 rc = EINVAL; 929 goto fail2; 930 } 931 break; 932 } 933 segment_used = cursor.end + 1; 934 935 cursor.current = segment_used; 936 } 937 /* Return space used (including the END tag) */ 938 *endp = (segment_used - cursor.block) * sizeof (uint32_t); 939 940 return (0); 941 942 fail2: 943 EFSYS_PROBE(fail2); 944 fail1: 945 EFSYS_PROBE1(fail1, efx_rc_t, rc); 946 947 return (rc); 948 } 949 950 __checkReturn __success(return != B_FALSE) boolean_t 951 ef10_nvram_buffer_find_item( 952 __in_bcount(buffer_size) 953 caddr_t bufferp, 954 __in size_t buffer_size, 955 __in uint32_t offset, 956 __out uint32_t *startp, 957 __out uint32_t *lengthp) 958 { 959 // Find TLV at offset and return key start and length 960 tlv_cursor_t cursor; 961 uint8_t *key; 962 uint32_t tag; 963 964 if (tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, 965 buffer_size, offset) != 0) { 966 return (B_FALSE); 967 } 968 969 while ((key = tlv_item(&cursor)) != NULL) { 970 tag = tlv_tag(&cursor); 971 if (tag == TLV_TAG_PARTITION_HEADER || 972 tag == TLV_TAG_PARTITION_TRAILER) { 973 if (tlv_advance(&cursor) != 0) { 974 break; 975 } 976 continue; 977 } 978 *startp = byte_offset(cursor.current, cursor.block); 979 *lengthp = byte_offset(tlv_next_item_ptr(&cursor), 980 cursor.current); 981 return (B_TRUE); 982 } 983 984 return (B_FALSE); 985 } 986 987 __checkReturn efx_rc_t 988 ef10_nvram_buffer_get_item( 989 __in_bcount(buffer_size) 990 caddr_t bufferp, 991 __in size_t buffer_size, 992 __in uint32_t offset, 993 __in uint32_t length, 994 __out_bcount_part(item_max_size, *lengthp) 995 caddr_t itemp, 996 __in size_t item_max_size, 997 __out uint32_t *lengthp) 998 { 999 efx_rc_t rc; 1000 tlv_cursor_t cursor; 1001 uint32_t item_length; 1002 1003 if (item_max_size < length) { 1004 rc = ENOSPC; 1005 goto fail1; 1006 } 1007 1008 if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, 1009 buffer_size, offset)) != 0) { 1010 goto fail2; 1011 } 1012 1013 item_length = tlv_length(&cursor); 1014 if (length < item_length) { 1015 rc = ENOSPC; 1016 goto fail3; 1017 } 1018 memcpy(itemp, tlv_value(&cursor), item_length); 1019 1020 *lengthp = item_length; 1021 1022 return (0); 1023 1024 fail3: 1025 EFSYS_PROBE(fail3); 1026 fail2: 1027 EFSYS_PROBE(fail2); 1028 fail1: 1029 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1030 1031 return (rc); 1032 } 1033 1034 __checkReturn efx_rc_t 1035 ef10_nvram_buffer_insert_item( 1036 __in_bcount(buffer_size) 1037 caddr_t bufferp, 1038 __in size_t buffer_size, 1039 __in uint32_t offset, 1040 __in_bcount(length) caddr_t keyp, 1041 __in uint32_t length, 1042 __out uint32_t *lengthp) 1043 { 1044 efx_rc_t rc; 1045 tlv_cursor_t cursor; 1046 1047 if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, 1048 buffer_size, offset)) != 0) { 1049 goto fail1; 1050 } 1051 1052 rc = tlv_insert(&cursor, TLV_TAG_LICENSE, (uint8_t *)keyp, length); 1053 1054 if (rc != 0) { 1055 goto fail2; 1056 } 1057 1058 *lengthp = byte_offset(tlv_next_item_ptr(&cursor), 1059 cursor.current); 1060 1061 return (0); 1062 1063 fail2: 1064 EFSYS_PROBE(fail2); 1065 fail1: 1066 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1067 1068 return (rc); 1069 } 1070 1071 __checkReturn efx_rc_t 1072 ef10_nvram_buffer_delete_item( 1073 __in_bcount(buffer_size) 1074 caddr_t bufferp, 1075 __in size_t buffer_size, 1076 __in uint32_t offset, 1077 __in uint32_t length, 1078 __in uint32_t end) 1079 { 1080 efx_rc_t rc; 1081 tlv_cursor_t cursor; 1082 1083 _NOTE(ARGUNUSED(length, end)) 1084 1085 if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp, 1086 buffer_size, offset)) != 0) { 1087 goto fail1; 1088 } 1089 1090 if ((rc = tlv_delete(&cursor)) != 0) 1091 goto fail2; 1092 1093 return (0); 1094 1095 fail2: 1096 EFSYS_PROBE(fail2); 1097 fail1: 1098 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1099 1100 return (rc); 1101 } 1102 1103 __checkReturn efx_rc_t 1104 ef10_nvram_buffer_finish( 1105 __in_bcount(buffer_size) 1106 caddr_t bufferp, 1107 __in size_t buffer_size) 1108 { 1109 efx_rc_t rc; 1110 tlv_cursor_t cursor; 1111 1112 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp, 1113 buffer_size)) != 0) { 1114 rc = EFAULT; 1115 goto fail1; 1116 } 1117 1118 if ((rc = tlv_require_end(&cursor)) != 0) 1119 goto fail2; 1120 1121 if ((rc = tlv_update_partition_len_and_cks(&cursor)) != 0) 1122 goto fail3; 1123 1124 return (0); 1125 1126 fail3: 1127 EFSYS_PROBE(fail3); 1128 fail2: 1129 EFSYS_PROBE(fail2); 1130 fail1: 1131 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1132 1133 return (rc); 1134 } 1135 1136 1137 1138 /* 1139 * Read and validate a segment from a partition. A segment is a complete 1140 * tlv chain between PARTITION_HEADER and PARTITION_END tags. There may 1141 * be multiple segments in a partition, so seg_offset allows segments 1142 * beyond the first to be read. 1143 */ 1144 static __checkReturn efx_rc_t 1145 ef10_nvram_read_tlv_segment( 1146 __in efx_nic_t *enp, 1147 __in uint32_t partn, 1148 __in size_t seg_offset, 1149 __in_bcount(max_seg_size) caddr_t seg_data, 1150 __in size_t max_seg_size) 1151 { 1152 tlv_cursor_t cursor; 1153 struct tlv_partition_header *header; 1154 struct tlv_partition_trailer *trailer; 1155 size_t total_length; 1156 uint32_t cksum; 1157 int pos; 1158 efx_rc_t rc; 1159 1160 EFX_STATIC_ASSERT(sizeof (*header) <= EF10_NVRAM_CHUNK); 1161 1162 if ((seg_data == NULL) || (max_seg_size == 0)) { 1163 rc = EINVAL; 1164 goto fail1; 1165 } 1166 1167 /* Read initial chunk of the segment, starting at offset */ 1168 if ((rc = ef10_nvram_partn_read_mode(enp, partn, seg_offset, seg_data, 1169 EF10_NVRAM_CHUNK, 1170 MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT)) != 0) { 1171 goto fail2; 1172 } 1173 1174 /* A PARTITION_HEADER tag must be the first item at the given offset */ 1175 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data, 1176 max_seg_size)) != 0) { 1177 rc = EFAULT; 1178 goto fail3; 1179 } 1180 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { 1181 rc = EINVAL; 1182 goto fail4; 1183 } 1184 header = (struct tlv_partition_header *)tlv_item(&cursor); 1185 1186 /* Check TLV segment length (includes the END tag) */ 1187 total_length = __LE_TO_CPU_32(header->total_length); 1188 if (total_length > max_seg_size) { 1189 rc = EFBIG; 1190 goto fail5; 1191 } 1192 1193 /* Read the remaining segment content */ 1194 if (total_length > EF10_NVRAM_CHUNK) { 1195 if ((rc = ef10_nvram_partn_read_mode(enp, partn, 1196 seg_offset + EF10_NVRAM_CHUNK, 1197 seg_data + EF10_NVRAM_CHUNK, 1198 total_length - EF10_NVRAM_CHUNK, 1199 MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT)) != 0) 1200 goto fail6; 1201 } 1202 1203 /* Check segment ends with PARTITION_TRAILER and END tags */ 1204 if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { 1205 rc = EINVAL; 1206 goto fail7; 1207 } 1208 trailer = (struct tlv_partition_trailer *)tlv_item(&cursor); 1209 1210 if ((rc = tlv_advance(&cursor)) != 0) { 1211 rc = EINVAL; 1212 goto fail8; 1213 } 1214 if (tlv_tag(&cursor) != TLV_TAG_END) { 1215 rc = EINVAL; 1216 goto fail9; 1217 } 1218 1219 /* Check data read from segment is consistent */ 1220 if (trailer->generation != header->generation) { 1221 /* 1222 * The partition data may have been modified between successive 1223 * MCDI NVRAM_READ requests by the MC or another PCI function. 1224 * 1225 * The caller must retry to obtain consistent partition data. 1226 */ 1227 rc = EAGAIN; 1228 goto fail10; 1229 } 1230 1231 /* Verify segment checksum */ 1232 cksum = 0; 1233 for (pos = 0; (size_t)pos < total_length; pos += sizeof (uint32_t)) { 1234 cksum += *((uint32_t *)(seg_data + pos)); 1235 } 1236 if (cksum != 0) { 1237 rc = EINVAL; 1238 goto fail11; 1239 } 1240 1241 return (0); 1242 1243 fail11: 1244 EFSYS_PROBE(fail11); 1245 fail10: 1246 EFSYS_PROBE(fail10); 1247 fail9: 1248 EFSYS_PROBE(fail9); 1249 fail8: 1250 EFSYS_PROBE(fail8); 1251 fail7: 1252 EFSYS_PROBE(fail7); 1253 fail6: 1254 EFSYS_PROBE(fail6); 1255 fail5: 1256 EFSYS_PROBE(fail5); 1257 fail4: 1258 EFSYS_PROBE(fail4); 1259 fail3: 1260 EFSYS_PROBE(fail3); 1261 fail2: 1262 EFSYS_PROBE(fail2); 1263 fail1: 1264 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1265 1266 return (rc); 1267 } 1268 1269 /* 1270 * Read a single TLV item from a host memory 1271 * buffer containing a TLV formatted segment. 1272 */ 1273 __checkReturn efx_rc_t 1274 ef10_nvram_buf_read_tlv( 1275 __in efx_nic_t *enp, 1276 __in_bcount(max_seg_size) caddr_t seg_data, 1277 __in size_t max_seg_size, 1278 __in uint32_t tag, 1279 __deref_out_bcount_opt(*sizep) caddr_t *datap, 1280 __out size_t *sizep) 1281 { 1282 tlv_cursor_t cursor; 1283 caddr_t data; 1284 size_t length; 1285 caddr_t value; 1286 efx_rc_t rc; 1287 1288 if ((seg_data == NULL) || (max_seg_size == 0)) { 1289 rc = EINVAL; 1290 goto fail1; 1291 } 1292 1293 /* Find requested TLV tag in segment data */ 1294 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data, 1295 max_seg_size)) != 0) { 1296 rc = EFAULT; 1297 goto fail2; 1298 } 1299 if ((rc = tlv_find(&cursor, tag)) != 0) { 1300 rc = ENOENT; 1301 goto fail3; 1302 } 1303 value = (caddr_t)tlv_value(&cursor); 1304 length = tlv_length(&cursor); 1305 1306 if (length == 0) 1307 data = NULL; 1308 else { 1309 /* Copy out data from TLV item */ 1310 EFSYS_KMEM_ALLOC(enp->en_esip, length, data); 1311 if (data == NULL) { 1312 rc = ENOMEM; 1313 goto fail4; 1314 } 1315 memcpy(data, value, length); 1316 } 1317 1318 *datap = data; 1319 *sizep = length; 1320 1321 return (0); 1322 1323 fail4: 1324 EFSYS_PROBE(fail4); 1325 fail3: 1326 EFSYS_PROBE(fail3); 1327 fail2: 1328 EFSYS_PROBE(fail2); 1329 fail1: 1330 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1331 1332 return (rc); 1333 } 1334 1335 /* Read a single TLV item from the first segment in a TLV formatted partition */ 1336 __checkReturn efx_rc_t 1337 ef10_nvram_partn_read_tlv( 1338 __in efx_nic_t *enp, 1339 __in uint32_t partn, 1340 __in uint32_t tag, 1341 __deref_out_bcount_opt(*seg_sizep) caddr_t *seg_datap, 1342 __out size_t *seg_sizep) 1343 { 1344 caddr_t seg_data = NULL; 1345 size_t partn_size = 0; 1346 size_t length; 1347 caddr_t data; 1348 int retry; 1349 efx_rc_t rc; 1350 1351 /* Allocate sufficient memory for the entire partition */ 1352 if ((rc = ef10_nvram_partn_size(enp, partn, &partn_size)) != 0) 1353 goto fail1; 1354 1355 if (partn_size == 0) { 1356 rc = ENOENT; 1357 goto fail2; 1358 } 1359 1360 EFSYS_KMEM_ALLOC(enp->en_esip, partn_size, seg_data); 1361 if (seg_data == NULL) { 1362 rc = ENOMEM; 1363 goto fail3; 1364 } 1365 1366 /* 1367 * Read the first segment in a TLV partition. Retry until consistent 1368 * segment contents are returned. Inconsistent data may be read if: 1369 * a) the segment contents are invalid 1370 * b) the MC has rebooted while we were reading the partition 1371 * c) the partition has been modified while we were reading it 1372 * Limit retry attempts to ensure forward progress. 1373 */ 1374 retry = 10; 1375 do { 1376 rc = ef10_nvram_read_tlv_segment(enp, partn, 0, 1377 seg_data, partn_size); 1378 } while ((rc == EAGAIN) && (--retry > 0)); 1379 1380 if (rc != 0) { 1381 /* Failed to obtain consistent segment data */ 1382 goto fail4; 1383 } 1384 1385 if ((rc = ef10_nvram_buf_read_tlv(enp, seg_data, partn_size, 1386 tag, &data, &length)) != 0) 1387 goto fail5; 1388 1389 EFSYS_KMEM_FREE(enp->en_esip, partn_size, seg_data); 1390 1391 *seg_datap = data; 1392 *seg_sizep = length; 1393 1394 return (0); 1395 1396 fail5: 1397 EFSYS_PROBE(fail5); 1398 fail4: 1399 EFSYS_PROBE(fail4); 1400 1401 EFSYS_KMEM_FREE(enp->en_esip, partn_size, seg_data); 1402 fail3: 1403 EFSYS_PROBE(fail3); 1404 fail2: 1405 EFSYS_PROBE(fail2); 1406 fail1: 1407 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1408 1409 return (rc); 1410 } 1411 1412 /* Compute the size of a segment. */ 1413 static __checkReturn efx_rc_t 1414 ef10_nvram_buf_segment_size( 1415 __in caddr_t seg_data, 1416 __in size_t max_seg_size, 1417 __out size_t *seg_sizep) 1418 { 1419 efx_rc_t rc; 1420 tlv_cursor_t cursor; 1421 struct tlv_partition_header *header; 1422 uint32_t cksum; 1423 int pos; 1424 uint32_t *end_tag_position; 1425 uint32_t segment_length; 1426 1427 /* A PARTITION_HEADER tag must be the first item at the given offset */ 1428 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data, 1429 max_seg_size)) != 0) { 1430 rc = EFAULT; 1431 goto fail1; 1432 } 1433 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { 1434 rc = EINVAL; 1435 goto fail2; 1436 } 1437 header = (struct tlv_partition_header *)tlv_item(&cursor); 1438 1439 /* Check TLV segment length (includes the END tag) */ 1440 *seg_sizep = __LE_TO_CPU_32(header->total_length); 1441 if (*seg_sizep > max_seg_size) { 1442 rc = EFBIG; 1443 goto fail3; 1444 } 1445 1446 /* Check segment ends with PARTITION_TRAILER and END tags */ 1447 if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { 1448 rc = EINVAL; 1449 goto fail4; 1450 } 1451 1452 if ((rc = tlv_advance(&cursor)) != 0) { 1453 rc = EINVAL; 1454 goto fail5; 1455 } 1456 if (tlv_tag(&cursor) != TLV_TAG_END) { 1457 rc = EINVAL; 1458 goto fail6; 1459 } 1460 end_tag_position = cursor.current; 1461 1462 /* Verify segment checksum */ 1463 cksum = 0; 1464 for (pos = 0; (size_t)pos < *seg_sizep; pos += sizeof (uint32_t)) { 1465 cksum += *((uint32_t *)(seg_data + pos)); 1466 } 1467 if (cksum != 0) { 1468 rc = EINVAL; 1469 goto fail7; 1470 } 1471 1472 /* 1473 * Calculate total length from HEADER to END tags and compare to 1474 * max_seg_size and the total_length field in the HEADER tag. 1475 */ 1476 segment_length = tlv_block_length_used(&cursor); 1477 1478 if (segment_length > max_seg_size) { 1479 rc = EINVAL; 1480 goto fail8; 1481 } 1482 1483 if (segment_length != *seg_sizep) { 1484 rc = EINVAL; 1485 goto fail9; 1486 } 1487 1488 /* Skip over the first HEADER tag. */ 1489 rc = tlv_rewind(&cursor); 1490 rc = tlv_advance(&cursor); 1491 1492 while (rc == 0) { 1493 if (tlv_tag(&cursor) == TLV_TAG_END) { 1494 /* Check that the END tag is the one found earlier. */ 1495 if (cursor.current != end_tag_position) 1496 goto fail10; 1497 break; 1498 } 1499 /* Check for duplicate HEADER tags before the END tag. */ 1500 if (tlv_tag(&cursor) == TLV_TAG_PARTITION_HEADER) { 1501 rc = EINVAL; 1502 goto fail11; 1503 } 1504 1505 rc = tlv_advance(&cursor); 1506 } 1507 if (rc != 0) 1508 goto fail12; 1509 1510 return (0); 1511 1512 fail12: 1513 EFSYS_PROBE(fail12); 1514 fail11: 1515 EFSYS_PROBE(fail11); 1516 fail10: 1517 EFSYS_PROBE(fail10); 1518 fail9: 1519 EFSYS_PROBE(fail9); 1520 fail8: 1521 EFSYS_PROBE(fail8); 1522 fail7: 1523 EFSYS_PROBE(fail7); 1524 fail6: 1525 EFSYS_PROBE(fail6); 1526 fail5: 1527 EFSYS_PROBE(fail5); 1528 fail4: 1529 EFSYS_PROBE(fail4); 1530 fail3: 1531 EFSYS_PROBE(fail3); 1532 fail2: 1533 EFSYS_PROBE(fail2); 1534 fail1: 1535 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1536 1537 return (rc); 1538 } 1539 1540 /* 1541 * Add or update a single TLV item in a host memory buffer containing a TLV 1542 * formatted segment. Historically partitions consisted of only one segment. 1543 */ 1544 __checkReturn efx_rc_t 1545 ef10_nvram_buf_write_tlv( 1546 __inout_bcount(max_seg_size) caddr_t seg_data, 1547 __in size_t max_seg_size, 1548 __in uint32_t tag, 1549 __in_bcount(tag_size) caddr_t tag_data, 1550 __in size_t tag_size, 1551 __out size_t *total_lengthp) 1552 { 1553 tlv_cursor_t cursor; 1554 struct tlv_partition_header *header; 1555 struct tlv_partition_trailer *trailer; 1556 uint32_t generation; 1557 uint32_t cksum; 1558 int pos; 1559 efx_rc_t rc; 1560 1561 /* A PARTITION_HEADER tag must be the first item (at offset zero) */ 1562 if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data, 1563 max_seg_size)) != 0) { 1564 rc = EFAULT; 1565 goto fail1; 1566 } 1567 if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { 1568 rc = EINVAL; 1569 goto fail2; 1570 } 1571 header = (struct tlv_partition_header *)tlv_item(&cursor); 1572 1573 /* Update the TLV chain to contain the new data */ 1574 if ((rc = tlv_find(&cursor, tag)) == 0) { 1575 /* Modify existing TLV item */ 1576 if ((rc = tlv_modify(&cursor, tag, 1577 (uint8_t *)tag_data, tag_size)) != 0) 1578 goto fail3; 1579 } else { 1580 /* Insert a new TLV item before the PARTITION_TRAILER */ 1581 rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER); 1582 if (rc != 0) { 1583 rc = EINVAL; 1584 goto fail4; 1585 } 1586 if ((rc = tlv_insert(&cursor, tag, 1587 (uint8_t *)tag_data, tag_size)) != 0) { 1588 rc = EINVAL; 1589 goto fail5; 1590 } 1591 } 1592 1593 /* Find the trailer tag */ 1594 if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { 1595 rc = EINVAL; 1596 goto fail6; 1597 } 1598 trailer = (struct tlv_partition_trailer *)tlv_item(&cursor); 1599 1600 /* Update PARTITION_HEADER and PARTITION_TRAILER fields */ 1601 *total_lengthp = tlv_block_length_used(&cursor); 1602 if (*total_lengthp > max_seg_size) { 1603 rc = ENOSPC; 1604 goto fail7; 1605 } 1606 generation = __LE_TO_CPU_32(header->generation) + 1; 1607 1608 header->total_length = __CPU_TO_LE_32(*total_lengthp); 1609 header->generation = __CPU_TO_LE_32(generation); 1610 trailer->generation = __CPU_TO_LE_32(generation); 1611 1612 /* Recompute PARTITION_TRAILER checksum */ 1613 trailer->checksum = 0; 1614 cksum = 0; 1615 for (pos = 0; (size_t)pos < *total_lengthp; pos += sizeof (uint32_t)) { 1616 cksum += *((uint32_t *)(seg_data + pos)); 1617 } 1618 trailer->checksum = ~cksum + 1; 1619 1620 return (0); 1621 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 the first segment of a TLV formatted 1642 * dynamic config partition. The first segment is the current active 1643 * configuration. 1644 */ 1645 __checkReturn efx_rc_t 1646 ef10_nvram_partn_write_tlv( 1647 __in efx_nic_t *enp, 1648 __in uint32_t partn, 1649 __in uint32_t tag, 1650 __in_bcount(size) caddr_t data, 1651 __in size_t size) 1652 { 1653 return ef10_nvram_partn_write_segment_tlv(enp, partn, tag, data, 1654 size, B_FALSE); 1655 } 1656 1657 /* 1658 * Read a segment from nvram at the given offset into a buffer (segment_data) 1659 * and optionally write a new tag to it. 1660 */ 1661 static __checkReturn efx_rc_t 1662 ef10_nvram_segment_write_tlv( 1663 __in efx_nic_t *enp, 1664 __in uint32_t partn, 1665 __in uint32_t tag, 1666 __in_bcount(size) caddr_t data, 1667 __in size_t size, 1668 __inout caddr_t *seg_datap, 1669 __inout size_t *partn_offsetp, 1670 __inout size_t *src_remain_lenp, 1671 __inout size_t *dest_remain_lenp, 1672 __in boolean_t write) 1673 { 1674 efx_rc_t rc; 1675 efx_rc_t status; 1676 size_t original_segment_size; 1677 size_t modified_segment_size; 1678 1679 /* 1680 * Read the segment from NVRAM into the segment_data buffer and validate 1681 * it, returning if it does not validate. This is not a failure unless 1682 * this is the first segment in a partition. In this case the caller 1683 * must propagate the error. 1684 */ 1685 status = ef10_nvram_read_tlv_segment(enp, partn, *partn_offsetp, 1686 *seg_datap, *src_remain_lenp); 1687 if (status != 0) 1688 return (EINVAL); 1689 1690 status = ef10_nvram_buf_segment_size(*seg_datap, 1691 *src_remain_lenp, &original_segment_size); 1692 if (status != 0) 1693 return (EINVAL); 1694 1695 if (write) { 1696 /* Update the contents of the segment in the buffer */ 1697 if ((rc = ef10_nvram_buf_write_tlv(*seg_datap, 1698 *dest_remain_lenp, tag, data, size, 1699 &modified_segment_size)) != 0) 1700 goto fail1; 1701 *dest_remain_lenp -= modified_segment_size; 1702 *seg_datap += modified_segment_size; 1703 } else { 1704 /* 1705 * We won't modify this segment, but still need to update the 1706 * remaining lengths and pointers. 1707 */ 1708 *dest_remain_lenp -= original_segment_size; 1709 *seg_datap += original_segment_size; 1710 } 1711 1712 *partn_offsetp += original_segment_size; 1713 *src_remain_lenp -= original_segment_size; 1714 1715 return (0); 1716 1717 fail1: 1718 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1719 1720 return (rc); 1721 } 1722 1723 /* 1724 * Add or update a single TLV item in either the first segment or in all 1725 * segments in a TLV formatted dynamic config partition. Dynamic config 1726 * partitions on boards that support RFID are divided into a number of segments, 1727 * each formatted like a partition, with header, trailer and end tags. The first 1728 * segment is the current active configuration. 1729 * 1730 * The segments are initialised by manftest and each contain a different 1731 * configuration e.g. firmware variant. The firmware can be instructed 1732 * via RFID to copy a segment to replace the first segment, hence changing the 1733 * active configuration. This allows ops to change the configuration of a board 1734 * prior to shipment using RFID. 1735 * 1736 * Changes to the dynamic config may need to be written to all segments (e.g. 1737 * firmware versions) or just the first segment (changes to the active 1738 * configuration). See SF-111324-SW "The use of RFID in Solarflare Products". 1739 * If only the first segment is written the code still needs to be aware of the 1740 * possible presence of subsequent segments as writing to a segment may cause 1741 * its size to increase, which would overwrite the subsequent segments and 1742 * invalidate them. 1743 */ 1744 __checkReturn efx_rc_t 1745 ef10_nvram_partn_write_segment_tlv( 1746 __in efx_nic_t *enp, 1747 __in uint32_t partn, 1748 __in uint32_t tag, 1749 __in_bcount(size) caddr_t data, 1750 __in size_t size, 1751 __in boolean_t all_segments) 1752 { 1753 size_t partn_size = 0; 1754 caddr_t partn_data; 1755 size_t total_length = 0; 1756 efx_rc_t rc; 1757 size_t current_offset = 0; 1758 size_t remaining_original_length; 1759 size_t remaining_modified_length; 1760 caddr_t segment_data; 1761 1762 EFSYS_ASSERT3U(partn, ==, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG); 1763 1764 /* Allocate sufficient memory for the entire partition */ 1765 if ((rc = ef10_nvram_partn_size(enp, partn, &partn_size)) != 0) 1766 goto fail1; 1767 1768 EFSYS_KMEM_ALLOC(enp->en_esip, partn_size, partn_data); 1769 if (partn_data == NULL) { 1770 rc = ENOMEM; 1771 goto fail2; 1772 } 1773 1774 remaining_original_length = partn_size; 1775 remaining_modified_length = partn_size; 1776 segment_data = partn_data; 1777 1778 /* Lock the partition */ 1779 if ((rc = ef10_nvram_partn_lock(enp, partn)) != 0) 1780 goto fail3; 1781 1782 /* Iterate over each (potential) segment to update it. */ 1783 do { 1784 boolean_t write = all_segments || current_offset == 0; 1785 1786 rc = ef10_nvram_segment_write_tlv(enp, partn, tag, data, size, 1787 &segment_data, ¤t_offset, &remaining_original_length, 1788 &remaining_modified_length, write); 1789 if (rc != 0) { 1790 if (current_offset == 0) { 1791 /* 1792 * If no data has been read then the first 1793 * segment is invalid, which is an error. 1794 */ 1795 goto fail4; 1796 } 1797 break; 1798 } 1799 } while (current_offset < partn_size); 1800 1801 total_length = segment_data - partn_data; 1802 1803 /* 1804 * We've run out of space. This should actually be dealt with by 1805 * ef10_nvram_buf_write_tlv returning ENOSPC. 1806 */ 1807 if (total_length > partn_size) { 1808 rc = ENOSPC; 1809 goto fail5; 1810 } 1811 1812 /* Erase the whole partition in NVRAM */ 1813 if ((rc = ef10_nvram_partn_erase(enp, partn, 0, partn_size)) != 0) 1814 goto fail6; 1815 1816 /* Write new partition contents from the buffer to NVRAM */ 1817 if ((rc = ef10_nvram_partn_write(enp, partn, 0, partn_data, 1818 total_length)) != 0) 1819 goto fail7; 1820 1821 /* Unlock the partition */ 1822 ef10_nvram_partn_unlock(enp, partn); 1823 1824 EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data); 1825 1826 return (0); 1827 1828 fail7: 1829 EFSYS_PROBE(fail7); 1830 fail6: 1831 EFSYS_PROBE(fail6); 1832 fail5: 1833 EFSYS_PROBE(fail5); 1834 fail4: 1835 EFSYS_PROBE(fail4); 1836 1837 ef10_nvram_partn_unlock(enp, partn); 1838 fail3: 1839 EFSYS_PROBE(fail3); 1840 1841 EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data); 1842 fail2: 1843 EFSYS_PROBE(fail2); 1844 fail1: 1845 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1846 1847 return (rc); 1848 } 1849 1850 /* 1851 * Get the size of a NVRAM partition. This is the total size allocated in nvram, 1852 * not the data used by the segments in the partition. 1853 */ 1854 __checkReturn efx_rc_t 1855 ef10_nvram_partn_size( 1856 __in efx_nic_t *enp, 1857 __in uint32_t partn, 1858 __out size_t *sizep) 1859 { 1860 efx_rc_t rc; 1861 1862 if ((rc = efx_mcdi_nvram_info(enp, partn, sizep, 1863 NULL, NULL, NULL)) != 0) 1864 goto fail1; 1865 1866 return (0); 1867 1868 fail1: 1869 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1870 1871 return (rc); 1872 } 1873 1874 __checkReturn efx_rc_t 1875 ef10_nvram_partn_lock( 1876 __in efx_nic_t *enp, 1877 __in uint32_t partn) 1878 { 1879 efx_rc_t rc; 1880 1881 if ((rc = efx_mcdi_nvram_update_start(enp, partn)) != 0) 1882 goto fail1; 1883 1884 return (0); 1885 1886 fail1: 1887 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1888 1889 return (rc); 1890 } 1891 1892 __checkReturn efx_rc_t 1893 ef10_nvram_partn_read_mode( 1894 __in efx_nic_t *enp, 1895 __in uint32_t partn, 1896 __in unsigned int offset, 1897 __out_bcount(size) caddr_t data, 1898 __in size_t size, 1899 __in uint32_t mode) 1900 { 1901 size_t chunk; 1902 efx_rc_t rc; 1903 1904 while (size > 0) { 1905 chunk = MIN(size, EF10_NVRAM_CHUNK); 1906 1907 if ((rc = efx_mcdi_nvram_read(enp, partn, offset, 1908 data, chunk, mode)) != 0) { 1909 goto fail1; 1910 } 1911 1912 size -= chunk; 1913 data += chunk; 1914 offset += chunk; 1915 } 1916 1917 return (0); 1918 1919 fail1: 1920 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1921 1922 return (rc); 1923 } 1924 1925 __checkReturn efx_rc_t 1926 ef10_nvram_partn_read( 1927 __in efx_nic_t *enp, 1928 __in uint32_t partn, 1929 __in unsigned int offset, 1930 __out_bcount(size) caddr_t data, 1931 __in size_t size) 1932 { 1933 /* 1934 * Read requests which come in through the EFX API expect to 1935 * read the current, active partition. 1936 */ 1937 return ef10_nvram_partn_read_mode(enp, partn, offset, data, size, 1938 MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT); 1939 } 1940 1941 __checkReturn efx_rc_t 1942 ef10_nvram_partn_erase( 1943 __in efx_nic_t *enp, 1944 __in uint32_t partn, 1945 __in unsigned int offset, 1946 __in size_t size) 1947 { 1948 efx_rc_t rc; 1949 uint32_t erase_size; 1950 1951 if ((rc = efx_mcdi_nvram_info(enp, partn, NULL, NULL, 1952 &erase_size, NULL)) != 0) 1953 goto fail1; 1954 1955 if (erase_size == 0) { 1956 if ((rc = efx_mcdi_nvram_erase(enp, partn, offset, size)) != 0) 1957 goto fail2; 1958 } else { 1959 if (size % erase_size != 0) { 1960 rc = EINVAL; 1961 goto fail3; 1962 } 1963 while (size > 0) { 1964 if ((rc = efx_mcdi_nvram_erase(enp, partn, offset, 1965 erase_size)) != 0) 1966 goto fail4; 1967 offset += erase_size; 1968 size -= erase_size; 1969 } 1970 } 1971 1972 return (0); 1973 1974 fail4: 1975 EFSYS_PROBE(fail4); 1976 fail3: 1977 EFSYS_PROBE(fail3); 1978 fail2: 1979 EFSYS_PROBE(fail2); 1980 fail1: 1981 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1982 1983 return (rc); 1984 } 1985 1986 __checkReturn efx_rc_t 1987 ef10_nvram_partn_write( 1988 __in efx_nic_t *enp, 1989 __in uint32_t partn, 1990 __in unsigned int offset, 1991 __out_bcount(size) caddr_t data, 1992 __in size_t size) 1993 { 1994 size_t chunk; 1995 uint32_t write_size; 1996 efx_rc_t rc; 1997 1998 if ((rc = efx_mcdi_nvram_info(enp, partn, NULL, NULL, 1999 NULL, &write_size)) != 0) 2000 goto fail1; 2001 2002 if (write_size != 0) { 2003 /* 2004 * Check that the size is a multiple of the write chunk size if 2005 * the write chunk size is available. 2006 */ 2007 if (size % write_size != 0) { 2008 rc = EINVAL; 2009 goto fail2; 2010 } 2011 } else { 2012 write_size = EF10_NVRAM_CHUNK; 2013 } 2014 2015 while (size > 0) { 2016 chunk = MIN(size, write_size); 2017 2018 if ((rc = efx_mcdi_nvram_write(enp, partn, offset, 2019 data, chunk)) != 0) { 2020 goto fail3; 2021 } 2022 2023 size -= chunk; 2024 data += chunk; 2025 offset += chunk; 2026 } 2027 2028 return (0); 2029 2030 fail3: 2031 EFSYS_PROBE(fail3); 2032 fail2: 2033 EFSYS_PROBE(fail2); 2034 fail1: 2035 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2036 2037 return (rc); 2038 } 2039 2040 void 2041 ef10_nvram_partn_unlock( 2042 __in efx_nic_t *enp, 2043 __in uint32_t partn) 2044 { 2045 boolean_t reboot; 2046 efx_rc_t rc; 2047 2048 reboot = B_FALSE; 2049 if ((rc = efx_mcdi_nvram_update_finish(enp, partn, reboot)) != 0) 2050 goto fail1; 2051 2052 return; 2053 2054 fail1: 2055 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2056 } 2057 2058 __checkReturn efx_rc_t 2059 ef10_nvram_partn_set_version( 2060 __in efx_nic_t *enp, 2061 __in uint32_t partn, 2062 __in_ecount(4) uint16_t version[4]) 2063 { 2064 struct tlv_partition_version partn_version; 2065 size_t size; 2066 efx_rc_t rc; 2067 2068 /* Add or modify partition version TLV item */ 2069 partn_version.version_w = __CPU_TO_LE_16(version[0]); 2070 partn_version.version_x = __CPU_TO_LE_16(version[1]); 2071 partn_version.version_y = __CPU_TO_LE_16(version[2]); 2072 partn_version.version_z = __CPU_TO_LE_16(version[3]); 2073 2074 size = sizeof (partn_version) - (2 * sizeof (uint32_t)); 2075 2076 /* Write the version number to all segments in the partition */ 2077 if ((rc = ef10_nvram_partn_write_segment_tlv(enp, 2078 NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 2079 TLV_TAG_PARTITION_VERSION(partn), 2080 (caddr_t)&partn_version.version_w, size, B_TRUE)) != 0) 2081 goto fail1; 2082 2083 return (0); 2084 2085 fail1: 2086 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2087 2088 return (rc); 2089 } 2090 2091 #endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */ 2092 2093 #if EFSYS_OPT_NVRAM 2094 2095 typedef struct ef10_parttbl_entry_s { 2096 unsigned int partn; 2097 unsigned int port; 2098 efx_nvram_type_t nvtype; 2099 } ef10_parttbl_entry_t; 2100 2101 /* Translate EFX NVRAM types to firmware partition types */ 2102 static ef10_parttbl_entry_t hunt_parttbl[] = { 2103 {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 1, EFX_NVRAM_MC_FIRMWARE}, 2104 {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 2, EFX_NVRAM_MC_FIRMWARE}, 2105 {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 3, EFX_NVRAM_MC_FIRMWARE}, 2106 {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 4, EFX_NVRAM_MC_FIRMWARE}, 2107 {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 1, EFX_NVRAM_MC_GOLDEN}, 2108 {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 2, EFX_NVRAM_MC_GOLDEN}, 2109 {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 3, EFX_NVRAM_MC_GOLDEN}, 2110 {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 4, EFX_NVRAM_MC_GOLDEN}, 2111 {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 1, EFX_NVRAM_BOOTROM}, 2112 {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 2, EFX_NVRAM_BOOTROM}, 2113 {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 3, EFX_NVRAM_BOOTROM}, 2114 {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 4, EFX_NVRAM_BOOTROM}, 2115 {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 1, EFX_NVRAM_BOOTROM_CFG}, 2116 {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT1, 2, EFX_NVRAM_BOOTROM_CFG}, 2117 {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT2, 3, EFX_NVRAM_BOOTROM_CFG}, 2118 {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT3, 4, EFX_NVRAM_BOOTROM_CFG}, 2119 {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 1, EFX_NVRAM_DYNAMIC_CFG}, 2120 {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 2, EFX_NVRAM_DYNAMIC_CFG}, 2121 {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 3, EFX_NVRAM_DYNAMIC_CFG}, 2122 {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 4, EFX_NVRAM_DYNAMIC_CFG}, 2123 {NVRAM_PARTITION_TYPE_FPGA, 1, EFX_NVRAM_FPGA}, 2124 {NVRAM_PARTITION_TYPE_FPGA, 2, EFX_NVRAM_FPGA}, 2125 {NVRAM_PARTITION_TYPE_FPGA, 3, EFX_NVRAM_FPGA}, 2126 {NVRAM_PARTITION_TYPE_FPGA, 4, EFX_NVRAM_FPGA}, 2127 {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 1, EFX_NVRAM_FPGA_BACKUP}, 2128 {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 2, EFX_NVRAM_FPGA_BACKUP}, 2129 {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 3, EFX_NVRAM_FPGA_BACKUP}, 2130 {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 4, EFX_NVRAM_FPGA_BACKUP}, 2131 {NVRAM_PARTITION_TYPE_LICENSE, 1, EFX_NVRAM_LICENSE}, 2132 {NVRAM_PARTITION_TYPE_LICENSE, 2, EFX_NVRAM_LICENSE}, 2133 {NVRAM_PARTITION_TYPE_LICENSE, 3, EFX_NVRAM_LICENSE}, 2134 {NVRAM_PARTITION_TYPE_LICENSE, 4, EFX_NVRAM_LICENSE} 2135 }; 2136 2137 static ef10_parttbl_entry_t medford_parttbl[] = { 2138 {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 1, EFX_NVRAM_MC_FIRMWARE}, 2139 {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 2, EFX_NVRAM_MC_FIRMWARE}, 2140 {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 3, EFX_NVRAM_MC_FIRMWARE}, 2141 {NVRAM_PARTITION_TYPE_MC_FIRMWARE, 4, EFX_NVRAM_MC_FIRMWARE}, 2142 {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 1, EFX_NVRAM_MC_GOLDEN}, 2143 {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 2, EFX_NVRAM_MC_GOLDEN}, 2144 {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 3, EFX_NVRAM_MC_GOLDEN}, 2145 {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP, 4, EFX_NVRAM_MC_GOLDEN}, 2146 {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 1, EFX_NVRAM_BOOTROM}, 2147 {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 2, EFX_NVRAM_BOOTROM}, 2148 {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 3, EFX_NVRAM_BOOTROM}, 2149 {NVRAM_PARTITION_TYPE_EXPANSION_ROM, 4, EFX_NVRAM_BOOTROM}, 2150 {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 1, EFX_NVRAM_BOOTROM_CFG}, 2151 {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 2, EFX_NVRAM_BOOTROM_CFG}, 2152 {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 3, EFX_NVRAM_BOOTROM_CFG}, 2153 {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 4, EFX_NVRAM_BOOTROM_CFG}, 2154 {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 1, EFX_NVRAM_DYNAMIC_CFG}, 2155 {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 2, EFX_NVRAM_DYNAMIC_CFG}, 2156 {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 3, EFX_NVRAM_DYNAMIC_CFG}, 2157 {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, 4, EFX_NVRAM_DYNAMIC_CFG}, 2158 {NVRAM_PARTITION_TYPE_FPGA, 1, EFX_NVRAM_FPGA}, 2159 {NVRAM_PARTITION_TYPE_FPGA, 2, EFX_NVRAM_FPGA}, 2160 {NVRAM_PARTITION_TYPE_FPGA, 3, EFX_NVRAM_FPGA}, 2161 {NVRAM_PARTITION_TYPE_FPGA, 4, EFX_NVRAM_FPGA}, 2162 {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 1, EFX_NVRAM_FPGA_BACKUP}, 2163 {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 2, EFX_NVRAM_FPGA_BACKUP}, 2164 {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 3, EFX_NVRAM_FPGA_BACKUP}, 2165 {NVRAM_PARTITION_TYPE_FPGA_BACKUP, 4, EFX_NVRAM_FPGA_BACKUP}, 2166 {NVRAM_PARTITION_TYPE_LICENSE, 1, EFX_NVRAM_LICENSE}, 2167 {NVRAM_PARTITION_TYPE_LICENSE, 2, EFX_NVRAM_LICENSE}, 2168 {NVRAM_PARTITION_TYPE_LICENSE, 3, EFX_NVRAM_LICENSE}, 2169 {NVRAM_PARTITION_TYPE_LICENSE, 4, EFX_NVRAM_LICENSE} 2170 }; 2171 2172 static __checkReturn efx_rc_t 2173 ef10_parttbl_get( 2174 __in efx_nic_t *enp, 2175 __out ef10_parttbl_entry_t **parttblp, 2176 __out size_t *parttbl_rowsp) 2177 { 2178 switch (enp->en_family) { 2179 case EFX_FAMILY_HUNTINGTON: 2180 *parttblp = hunt_parttbl; 2181 *parttbl_rowsp = EFX_ARRAY_SIZE(hunt_parttbl); 2182 break; 2183 2184 case EFX_FAMILY_MEDFORD: 2185 *parttblp = medford_parttbl; 2186 *parttbl_rowsp = EFX_ARRAY_SIZE(medford_parttbl); 2187 break; 2188 2189 default: 2190 EFSYS_ASSERT(B_FALSE); 2191 return (EINVAL); 2192 } 2193 return (0); 2194 } 2195 2196 __checkReturn efx_rc_t 2197 ef10_nvram_type_to_partn( 2198 __in efx_nic_t *enp, 2199 __in efx_nvram_type_t type, 2200 __out uint32_t *partnp) 2201 { 2202 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 2203 ef10_parttbl_entry_t *parttbl = NULL; 2204 size_t parttbl_rows = 0; 2205 unsigned int i; 2206 2207 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 2208 EFSYS_ASSERT(partnp != NULL); 2209 2210 if (ef10_parttbl_get(enp, &parttbl, &parttbl_rows) == 0) { 2211 for (i = 0; i < parttbl_rows; i++) { 2212 ef10_parttbl_entry_t *entry = &parttbl[i]; 2213 2214 if (entry->nvtype == type && 2215 entry->port == emip->emi_port) { 2216 *partnp = entry->partn; 2217 return (0); 2218 } 2219 } 2220 } 2221 2222 return (ENOTSUP); 2223 } 2224 2225 #if EFSYS_OPT_DIAG 2226 2227 static __checkReturn efx_rc_t 2228 ef10_nvram_partn_to_type( 2229 __in efx_nic_t *enp, 2230 __in uint32_t partn, 2231 __out efx_nvram_type_t *typep) 2232 { 2233 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 2234 ef10_parttbl_entry_t *parttbl = NULL; 2235 size_t parttbl_rows = 0; 2236 unsigned int i; 2237 2238 EFSYS_ASSERT(typep != NULL); 2239 2240 if (ef10_parttbl_get(enp, &parttbl, &parttbl_rows) == 0) { 2241 for (i = 0; i < parttbl_rows; i++) { 2242 ef10_parttbl_entry_t *entry = &parttbl[i]; 2243 2244 if (entry->partn == partn && 2245 entry->port == emip->emi_port) { 2246 *typep = entry->nvtype; 2247 return (0); 2248 } 2249 } 2250 } 2251 2252 return (ENOTSUP); 2253 } 2254 2255 __checkReturn efx_rc_t 2256 ef10_nvram_test( 2257 __in efx_nic_t *enp) 2258 { 2259 efx_nvram_type_t type; 2260 unsigned int npartns = 0; 2261 uint32_t *partns = NULL; 2262 size_t size; 2263 unsigned int i; 2264 efx_rc_t rc; 2265 2266 /* Read available partitions from NVRAM partition map */ 2267 size = MC_CMD_NVRAM_PARTITIONS_OUT_TYPE_ID_MAXNUM * sizeof (uint32_t); 2268 EFSYS_KMEM_ALLOC(enp->en_esip, size, partns); 2269 if (partns == NULL) { 2270 rc = ENOMEM; 2271 goto fail1; 2272 } 2273 2274 if ((rc = efx_mcdi_nvram_partitions(enp, (caddr_t)partns, size, 2275 &npartns)) != 0) { 2276 goto fail2; 2277 } 2278 2279 for (i = 0; i < npartns; i++) { 2280 /* Check if the partition is supported for this port */ 2281 if ((rc = ef10_nvram_partn_to_type(enp, partns[i], &type)) != 0) 2282 continue; 2283 2284 if ((rc = efx_mcdi_nvram_test(enp, partns[i])) != 0) 2285 goto fail3; 2286 } 2287 2288 EFSYS_KMEM_FREE(enp->en_esip, size, partns); 2289 return (0); 2290 2291 fail3: 2292 EFSYS_PROBE(fail3); 2293 fail2: 2294 EFSYS_PROBE(fail2); 2295 EFSYS_KMEM_FREE(enp->en_esip, size, partns); 2296 fail1: 2297 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2298 return (rc); 2299 } 2300 2301 #endif /* EFSYS_OPT_DIAG */ 2302 2303 __checkReturn efx_rc_t 2304 ef10_nvram_partn_get_version( 2305 __in efx_nic_t *enp, 2306 __in uint32_t partn, 2307 __out uint32_t *subtypep, 2308 __out_ecount(4) uint16_t version[4]) 2309 { 2310 efx_rc_t rc; 2311 2312 /* FIXME: get highest partn version from all ports */ 2313 /* FIXME: return partn description if available */ 2314 2315 if ((rc = efx_mcdi_nvram_metadata(enp, partn, subtypep, 2316 version, NULL, 0)) != 0) 2317 goto fail1; 2318 2319 return (0); 2320 2321 fail1: 2322 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2323 2324 return (rc); 2325 } 2326 2327 __checkReturn efx_rc_t 2328 ef10_nvram_partn_rw_start( 2329 __in efx_nic_t *enp, 2330 __in uint32_t partn, 2331 __out size_t *chunk_sizep) 2332 { 2333 efx_rc_t rc; 2334 2335 if ((rc = ef10_nvram_partn_lock(enp, partn)) != 0) 2336 goto fail1; 2337 2338 if (chunk_sizep != NULL) 2339 *chunk_sizep = EF10_NVRAM_CHUNK; 2340 2341 return (0); 2342 2343 fail1: 2344 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2345 2346 return (rc); 2347 } 2348 2349 void 2350 ef10_nvram_partn_rw_finish( 2351 __in efx_nic_t *enp, 2352 __in uint32_t partn) 2353 { 2354 ef10_nvram_partn_unlock(enp, partn); 2355 } 2356 2357 #endif /* EFSYS_OPT_NVRAM */ 2358 2359 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ 2360