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