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