1 /* 2 * Copyright (c) 2009-2015 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 "efx.h" 32 #include "efx_impl.h" 33 34 #if EFSYS_OPT_VPD 35 36 #define TAG_TYPE_LBN 7 37 #define TAG_TYPE_WIDTH 1 38 #define TAG_TYPE_LARGE_ITEM_DECODE 1 39 #define TAG_TYPE_SMALL_ITEM_DECODE 0 40 41 #define TAG_SMALL_ITEM_NAME_LBN 3 42 #define TAG_SMALL_ITEM_NAME_WIDTH 4 43 #define TAG_SMALL_ITEM_SIZE_LBN 0 44 #define TAG_SMALL_ITEM_SIZE_WIDTH 3 45 46 #define TAG_LARGE_ITEM_NAME_LBN 0 47 #define TAG_LARGE_ITEM_NAME_WIDTH 7 48 49 #define TAG_NAME_END_DECODE 0x0f 50 #define TAG_NAME_ID_STRING_DECODE 0x02 51 #define TAG_NAME_VPD_R_DECODE 0x10 52 #define TAG_NAME_VPD_W_DECODE 0x11 53 54 #if EFSYS_OPT_SIENA 55 56 static const efx_vpd_ops_t __efx_vpd_siena_ops = { 57 siena_vpd_init, /* evpdo_init */ 58 siena_vpd_size, /* evpdo_size */ 59 siena_vpd_read, /* evpdo_read */ 60 siena_vpd_verify, /* evpdo_verify */ 61 siena_vpd_reinit, /* evpdo_reinit */ 62 siena_vpd_get, /* evpdo_get */ 63 siena_vpd_set, /* evpdo_set */ 64 siena_vpd_next, /* evpdo_next */ 65 siena_vpd_write, /* evpdo_write */ 66 siena_vpd_fini, /* evpdo_fini */ 67 }; 68 69 #endif /* EFSYS_OPT_SIENA */ 70 71 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD 72 73 static const efx_vpd_ops_t __efx_vpd_ef10_ops = { 74 ef10_vpd_init, /* evpdo_init */ 75 ef10_vpd_size, /* evpdo_size */ 76 ef10_vpd_read, /* evpdo_read */ 77 ef10_vpd_verify, /* evpdo_verify */ 78 ef10_vpd_reinit, /* evpdo_reinit */ 79 ef10_vpd_get, /* evpdo_get */ 80 ef10_vpd_set, /* evpdo_set */ 81 ef10_vpd_next, /* evpdo_next */ 82 ef10_vpd_write, /* evpdo_write */ 83 ef10_vpd_fini, /* evpdo_fini */ 84 }; 85 86 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ 87 88 __checkReturn efx_rc_t 89 efx_vpd_init( 90 __in efx_nic_t *enp) 91 { 92 const efx_vpd_ops_t *evpdop; 93 efx_rc_t rc; 94 95 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 96 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 97 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_VPD)); 98 99 switch (enp->en_family) { 100 #if EFSYS_OPT_SIENA 101 case EFX_FAMILY_SIENA: 102 evpdop = &__efx_vpd_siena_ops; 103 break; 104 #endif /* EFSYS_OPT_SIENA */ 105 106 #if EFSYS_OPT_HUNTINGTON 107 case EFX_FAMILY_HUNTINGTON: 108 evpdop = &__efx_vpd_ef10_ops; 109 break; 110 #endif /* EFSYS_OPT_HUNTINGTON */ 111 112 #if EFSYS_OPT_MEDFORD 113 case EFX_FAMILY_MEDFORD: 114 evpdop = &__efx_vpd_ef10_ops; 115 break; 116 #endif /* EFSYS_OPT_MEDFORD */ 117 118 default: 119 EFSYS_ASSERT(0); 120 rc = ENOTSUP; 121 goto fail1; 122 } 123 124 if (evpdop->evpdo_init != NULL) { 125 if ((rc = evpdop->evpdo_init(enp)) != 0) 126 goto fail2; 127 } 128 129 enp->en_evpdop = evpdop; 130 enp->en_mod_flags |= EFX_MOD_VPD; 131 132 return (0); 133 134 fail2: 135 EFSYS_PROBE(fail2); 136 fail1: 137 EFSYS_PROBE1(fail1, efx_rc_t, rc); 138 139 return (rc); 140 } 141 142 __checkReturn efx_rc_t 143 efx_vpd_size( 144 __in efx_nic_t *enp, 145 __out size_t *sizep) 146 { 147 const efx_vpd_ops_t *evpdop = enp->en_evpdop; 148 efx_rc_t rc; 149 150 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 151 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); 152 153 if ((rc = evpdop->evpdo_size(enp, sizep)) != 0) 154 goto fail1; 155 156 return (0); 157 158 fail1: 159 EFSYS_PROBE1(fail1, efx_rc_t, rc); 160 161 return (rc); 162 } 163 164 __checkReturn efx_rc_t 165 efx_vpd_read( 166 __in efx_nic_t *enp, 167 __out_bcount(size) caddr_t data, 168 __in size_t size) 169 { 170 const efx_vpd_ops_t *evpdop = enp->en_evpdop; 171 efx_rc_t rc; 172 173 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 174 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); 175 176 if ((rc = evpdop->evpdo_read(enp, data, size)) != 0) 177 goto fail1; 178 179 return (0); 180 181 fail1: 182 EFSYS_PROBE1(fail1, efx_rc_t, rc); 183 184 return (rc); 185 } 186 187 __checkReturn efx_rc_t 188 efx_vpd_verify( 189 __in efx_nic_t *enp, 190 __in_bcount(size) caddr_t data, 191 __in size_t size) 192 { 193 const efx_vpd_ops_t *evpdop = enp->en_evpdop; 194 efx_rc_t rc; 195 196 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 197 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); 198 199 if ((rc = evpdop->evpdo_verify(enp, data, size)) != 0) 200 goto fail1; 201 202 return (0); 203 204 fail1: 205 EFSYS_PROBE1(fail1, efx_rc_t, rc); 206 207 return (rc); 208 } 209 210 __checkReturn efx_rc_t 211 efx_vpd_reinit( 212 __in efx_nic_t *enp, 213 __in_bcount(size) caddr_t data, 214 __in size_t size) 215 { 216 const efx_vpd_ops_t *evpdop = enp->en_evpdop; 217 efx_rc_t rc; 218 219 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 220 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); 221 222 if (evpdop->evpdo_reinit == NULL) { 223 rc = ENOTSUP; 224 goto fail1; 225 } 226 227 if ((rc = evpdop->evpdo_reinit(enp, data, size)) != 0) 228 goto fail2; 229 230 return (0); 231 232 fail2: 233 EFSYS_PROBE(fail2); 234 fail1: 235 EFSYS_PROBE1(fail1, efx_rc_t, rc); 236 237 return (rc); 238 } 239 240 __checkReturn efx_rc_t 241 efx_vpd_get( 242 __in efx_nic_t *enp, 243 __in_bcount(size) caddr_t data, 244 __in size_t size, 245 __inout efx_vpd_value_t *evvp) 246 { 247 const efx_vpd_ops_t *evpdop = enp->en_evpdop; 248 efx_rc_t rc; 249 250 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 251 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); 252 253 if ((rc = evpdop->evpdo_get(enp, data, size, evvp)) != 0) 254 goto fail1; 255 256 return (0); 257 258 fail1: 259 EFSYS_PROBE1(fail1, efx_rc_t, rc); 260 261 return (rc); 262 } 263 264 __checkReturn efx_rc_t 265 efx_vpd_set( 266 __in efx_nic_t *enp, 267 __inout_bcount(size) caddr_t data, 268 __in size_t size, 269 __in efx_vpd_value_t *evvp) 270 { 271 const efx_vpd_ops_t *evpdop = enp->en_evpdop; 272 efx_rc_t rc; 273 274 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 275 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); 276 277 if ((rc = evpdop->evpdo_set(enp, data, size, evvp)) != 0) 278 goto fail1; 279 280 return (0); 281 282 fail1: 283 EFSYS_PROBE1(fail1, efx_rc_t, rc); 284 285 return (rc); 286 } 287 288 __checkReturn efx_rc_t 289 efx_vpd_next( 290 __in efx_nic_t *enp, 291 __inout_bcount(size) caddr_t data, 292 __in size_t size, 293 __out efx_vpd_value_t *evvp, 294 __inout unsigned int *contp) 295 { 296 const efx_vpd_ops_t *evpdop = enp->en_evpdop; 297 efx_rc_t rc; 298 299 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 300 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); 301 302 if ((rc = evpdop->evpdo_next(enp, data, size, evvp, contp)) != 0) 303 goto fail1; 304 305 return (0); 306 307 fail1: 308 EFSYS_PROBE1(fail1, efx_rc_t, rc); 309 310 return (rc); 311 } 312 313 __checkReturn efx_rc_t 314 efx_vpd_write( 315 __in efx_nic_t *enp, 316 __in_bcount(size) caddr_t data, 317 __in size_t size) 318 { 319 const efx_vpd_ops_t *evpdop = enp->en_evpdop; 320 efx_rc_t rc; 321 322 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 323 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); 324 325 if ((rc = evpdop->evpdo_write(enp, data, size)) != 0) 326 goto fail1; 327 328 return (0); 329 330 fail1: 331 EFSYS_PROBE1(fail1, efx_rc_t, rc); 332 333 return (rc); 334 } 335 336 static __checkReturn efx_rc_t 337 efx_vpd_next_tag( 338 __in caddr_t data, 339 __in size_t size, 340 __inout unsigned int *offsetp, 341 __out efx_vpd_tag_t *tagp, 342 __out uint16_t *lengthp) 343 { 344 efx_byte_t byte; 345 efx_word_t word; 346 uint8_t name; 347 uint16_t length; 348 size_t headlen; 349 efx_rc_t rc; 350 351 if (*offsetp >= size) { 352 rc = EFAULT; 353 goto fail1; 354 } 355 356 EFX_POPULATE_BYTE_1(byte, EFX_BYTE_0, data[*offsetp]); 357 358 switch (EFX_BYTE_FIELD(byte, TAG_TYPE)) { 359 case TAG_TYPE_SMALL_ITEM_DECODE: 360 headlen = 1; 361 362 name = EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_NAME); 363 length = (uint16_t)EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_SIZE); 364 365 break; 366 367 case TAG_TYPE_LARGE_ITEM_DECODE: 368 headlen = 3; 369 370 if (*offsetp + headlen > size) { 371 rc = EFAULT; 372 goto fail2; 373 } 374 375 name = EFX_BYTE_FIELD(byte, TAG_LARGE_ITEM_NAME); 376 EFX_POPULATE_WORD_2(word, 377 EFX_BYTE_0, data[*offsetp + 1], 378 EFX_BYTE_1, data[*offsetp + 2]); 379 length = EFX_WORD_FIELD(word, EFX_WORD_0); 380 381 break; 382 383 default: 384 rc = EFAULT; 385 goto fail2; 386 } 387 388 if (*offsetp + headlen + length > size) { 389 rc = EFAULT; 390 goto fail3; 391 } 392 393 EFX_STATIC_ASSERT(TAG_NAME_END_DECODE == EFX_VPD_END); 394 EFX_STATIC_ASSERT(TAG_NAME_ID_STRING_DECODE == EFX_VPD_ID); 395 EFX_STATIC_ASSERT(TAG_NAME_VPD_R_DECODE == EFX_VPD_RO); 396 EFX_STATIC_ASSERT(TAG_NAME_VPD_W_DECODE == EFX_VPD_RW); 397 if (name != EFX_VPD_END && name != EFX_VPD_ID && 398 name != EFX_VPD_RO) { 399 rc = EFAULT; 400 goto fail4; 401 } 402 403 *tagp = name; 404 *lengthp = length; 405 *offsetp += headlen; 406 407 return (0); 408 409 fail4: 410 EFSYS_PROBE(fail4); 411 fail3: 412 EFSYS_PROBE(fail3); 413 fail2: 414 EFSYS_PROBE(fail2); 415 fail1: 416 EFSYS_PROBE1(fail1, efx_rc_t, rc); 417 418 return (rc); 419 } 420 421 static __checkReturn efx_rc_t 422 efx_vpd_next_keyword( 423 __in_bcount(size) caddr_t tag, 424 __in size_t size, 425 __in unsigned int pos, 426 __out efx_vpd_keyword_t *keywordp, 427 __out uint8_t *lengthp) 428 { 429 efx_vpd_keyword_t keyword; 430 uint8_t length; 431 efx_rc_t rc; 432 433 if (pos + 3U > size) { 434 rc = EFAULT; 435 goto fail1; 436 } 437 438 keyword = EFX_VPD_KEYWORD(tag[pos], tag[pos + 1]); 439 length = tag[pos + 2]; 440 441 if (length == 0 || pos + 3U + length > size) { 442 rc = EFAULT; 443 goto fail2; 444 } 445 446 *keywordp = keyword; 447 *lengthp = length; 448 449 return (0); 450 451 fail2: 452 EFSYS_PROBE(fail2); 453 fail1: 454 EFSYS_PROBE1(fail1, efx_rc_t, rc); 455 456 return (rc); 457 } 458 459 __checkReturn efx_rc_t 460 efx_vpd_hunk_length( 461 __in_bcount(size) caddr_t data, 462 __in size_t size, 463 __out size_t *lengthp) 464 { 465 efx_vpd_tag_t tag; 466 unsigned int offset; 467 uint16_t taglen; 468 efx_rc_t rc; 469 470 offset = 0; 471 _NOTE(CONSTANTCONDITION) 472 while (1) { 473 if ((rc = efx_vpd_next_tag(data, size, &offset, 474 &tag, &taglen)) != 0) 475 goto fail1; 476 offset += taglen; 477 if (tag == EFX_VPD_END) 478 break; 479 } 480 481 *lengthp = offset; 482 483 return (0); 484 485 fail1: 486 EFSYS_PROBE1(fail1, efx_rc_t, rc); 487 488 return (rc); 489 } 490 491 __checkReturn efx_rc_t 492 efx_vpd_hunk_verify( 493 __in_bcount(size) caddr_t data, 494 __in size_t size, 495 __out_opt boolean_t *cksummedp) 496 { 497 efx_vpd_tag_t tag; 498 efx_vpd_keyword_t keyword; 499 unsigned int offset; 500 unsigned int pos; 501 unsigned int i; 502 uint16_t taglen; 503 uint8_t keylen; 504 uint8_t cksum; 505 boolean_t cksummed = B_FALSE; 506 efx_rc_t rc; 507 508 /* 509 * Parse every tag,keyword in the existing VPD. If the csum is present, 510 * the assert it is correct, and is the final keyword in the RO block. 511 */ 512 offset = 0; 513 _NOTE(CONSTANTCONDITION) 514 while (1) { 515 if ((rc = efx_vpd_next_tag(data, size, &offset, 516 &tag, &taglen)) != 0) 517 goto fail1; 518 if (tag == EFX_VPD_END) 519 break; 520 else if (tag == EFX_VPD_ID) 521 goto done; 522 523 for (pos = 0; pos != taglen; pos += 3 + keylen) { 524 /* RV keyword must be the last in the block */ 525 if (cksummed) { 526 rc = EFAULT; 527 goto fail2; 528 } 529 530 if ((rc = efx_vpd_next_keyword(data + offset, 531 taglen, pos, &keyword, &keylen)) != 0) 532 goto fail3; 533 534 if (keyword == EFX_VPD_KEYWORD('R', 'V')) { 535 cksum = 0; 536 for (i = 0; i < offset + pos + 4; i++) 537 cksum += data[i]; 538 539 if (cksum != 0) { 540 rc = EFAULT; 541 goto fail4; 542 } 543 544 cksummed = B_TRUE; 545 } 546 } 547 548 done: 549 offset += taglen; 550 } 551 552 if (!cksummed) { 553 rc = EFAULT; 554 goto fail5; 555 } 556 557 if (cksummedp != NULL) 558 *cksummedp = cksummed; 559 560 return (0); 561 562 fail5: 563 EFSYS_PROBE(fail5); 564 fail4: 565 EFSYS_PROBE(fail4); 566 fail3: 567 EFSYS_PROBE(fail3); 568 fail2: 569 EFSYS_PROBE(fail2); 570 fail1: 571 EFSYS_PROBE1(fail1, efx_rc_t, rc); 572 573 return (rc); 574 } 575 576 static uint8_t __efx_vpd_blank_pid[] = { 577 /* Large resource type ID length 1 */ 578 0x82, 0x01, 0x00, 579 /* Product name ' ' */ 580 0x32, 581 }; 582 583 static uint8_t __efx_vpd_blank_r[] = { 584 /* Large resource type VPD-R length 4 */ 585 0x90, 0x04, 0x00, 586 /* RV keyword length 1 */ 587 'R', 'V', 0x01, 588 /* RV payload checksum */ 589 0x00, 590 }; 591 592 __checkReturn efx_rc_t 593 efx_vpd_hunk_reinit( 594 __in_bcount(size) caddr_t data, 595 __in size_t size, 596 __in boolean_t wantpid) 597 { 598 unsigned int offset = 0; 599 unsigned int pos; 600 efx_byte_t byte; 601 uint8_t cksum; 602 efx_rc_t rc; 603 604 if (size < 0x100) { 605 rc = ENOSPC; 606 goto fail1; 607 } 608 609 if (wantpid) { 610 (void) memcpy(data + offset, __efx_vpd_blank_pid, 611 sizeof (__efx_vpd_blank_pid)); 612 offset += sizeof (__efx_vpd_blank_pid); 613 } 614 615 (void) memcpy(data + offset, __efx_vpd_blank_r, 616 sizeof (__efx_vpd_blank_r)); 617 offset += sizeof (__efx_vpd_blank_r); 618 619 /* Update checksum */ 620 cksum = 0; 621 for (pos = 0; pos < offset; pos++) 622 cksum += data[pos]; 623 data[offset - 1] -= cksum; 624 625 /* Append trailing tag */ 626 EFX_POPULATE_BYTE_3(byte, 627 TAG_TYPE, TAG_TYPE_SMALL_ITEM_DECODE, 628 TAG_SMALL_ITEM_NAME, TAG_NAME_END_DECODE, 629 TAG_SMALL_ITEM_SIZE, 0); 630 data[offset] = EFX_BYTE_FIELD(byte, EFX_BYTE_0); 631 offset++; 632 633 return (0); 634 635 fail1: 636 EFSYS_PROBE1(fail1, efx_rc_t, rc); 637 638 return (rc); 639 } 640 641 __checkReturn efx_rc_t 642 efx_vpd_hunk_next( 643 __in_bcount(size) caddr_t data, 644 __in size_t size, 645 __out efx_vpd_tag_t *tagp, 646 __out efx_vpd_keyword_t *keywordp, 647 __out_opt unsigned int *payloadp, 648 __out_opt uint8_t *paylenp, 649 __inout unsigned int *contp) 650 { 651 efx_vpd_tag_t tag; 652 efx_vpd_keyword_t keyword = 0; 653 unsigned int offset; 654 unsigned int pos; 655 unsigned int index; 656 uint16_t taglen; 657 uint8_t keylen; 658 uint8_t paylen; 659 efx_rc_t rc; 660 661 offset = index = 0; 662 _NOTE(CONSTANTCONDITION) 663 while (1) { 664 if ((rc = efx_vpd_next_tag(data, size, &offset, 665 &tag, &taglen)) != 0) 666 goto fail1; 667 668 if (tag == EFX_VPD_END) { 669 keyword = 0; 670 paylen = 0; 671 index = 0; 672 break; 673 } 674 675 if (tag == EFX_VPD_ID) { 676 if (index++ == *contp) { 677 EFSYS_ASSERT3U(taglen, <, 0x100); 678 keyword = 0; 679 paylen = (uint8_t)MIN(taglen, 0xff); 680 681 goto done; 682 } 683 } else { 684 for (pos = 0; pos != taglen; pos += 3 + keylen) { 685 if ((rc = efx_vpd_next_keyword(data + offset, 686 taglen, pos, &keyword, &keylen)) != 0) 687 goto fail2; 688 689 if (index++ == *contp) { 690 offset += pos + 3; 691 paylen = keylen; 692 693 goto done; 694 } 695 } 696 } 697 698 offset += taglen; 699 } 700 701 done: 702 *tagp = tag; 703 *keywordp = keyword; 704 if (payloadp != NULL) 705 *payloadp = offset; 706 if (paylenp != NULL) 707 *paylenp = paylen; 708 709 *contp = index; 710 return (0); 711 712 fail2: 713 EFSYS_PROBE(fail2); 714 fail1: 715 EFSYS_PROBE1(fail1, efx_rc_t, rc); 716 717 return (rc); 718 } 719 720 __checkReturn efx_rc_t 721 efx_vpd_hunk_get( 722 __in_bcount(size) caddr_t data, 723 __in size_t size, 724 __in efx_vpd_tag_t tag, 725 __in efx_vpd_keyword_t keyword, 726 __out unsigned int *payloadp, 727 __out uint8_t *paylenp) 728 { 729 efx_vpd_tag_t itag; 730 efx_vpd_keyword_t ikeyword; 731 unsigned int offset; 732 unsigned int pos; 733 uint16_t taglen; 734 uint8_t keylen; 735 efx_rc_t rc; 736 737 offset = 0; 738 _NOTE(CONSTANTCONDITION) 739 while (1) { 740 if ((rc = efx_vpd_next_tag(data, size, &offset, 741 &itag, &taglen)) != 0) 742 goto fail1; 743 if (itag == EFX_VPD_END) 744 break; 745 746 if (itag == tag) { 747 if (itag == EFX_VPD_ID) { 748 EFSYS_ASSERT3U(taglen, <, 0x100); 749 750 *paylenp = (uint8_t)MIN(taglen, 0xff); 751 *payloadp = offset; 752 return (0); 753 } 754 755 for (pos = 0; pos != taglen; pos += 3 + keylen) { 756 if ((rc = efx_vpd_next_keyword(data + offset, 757 taglen, pos, &ikeyword, &keylen)) != 0) 758 goto fail2; 759 760 if (ikeyword == keyword) { 761 *paylenp = keylen; 762 *payloadp = offset + pos + 3; 763 return (0); 764 } 765 } 766 } 767 768 offset += taglen; 769 } 770 771 /* Not an error */ 772 return (ENOENT); 773 774 fail2: 775 EFSYS_PROBE(fail2); 776 fail1: 777 EFSYS_PROBE1(fail1, efx_rc_t, rc); 778 779 return (rc); 780 } 781 782 __checkReturn efx_rc_t 783 efx_vpd_hunk_set( 784 __in_bcount(size) caddr_t data, 785 __in size_t size, 786 __in efx_vpd_value_t *evvp) 787 { 788 efx_word_t word; 789 efx_vpd_tag_t tag; 790 efx_vpd_keyword_t keyword; 791 unsigned int offset; 792 unsigned int pos; 793 unsigned int taghead; 794 unsigned int source; 795 unsigned int dest; 796 unsigned int i; 797 uint16_t taglen; 798 uint8_t keylen; 799 uint8_t cksum; 800 size_t used; 801 efx_rc_t rc; 802 803 switch (evvp->evv_tag) { 804 case EFX_VPD_ID: 805 if (evvp->evv_keyword != 0) { 806 rc = EINVAL; 807 goto fail1; 808 } 809 810 /* Can't delete the ID keyword */ 811 if (evvp->evv_length == 0) { 812 rc = EINVAL; 813 goto fail1; 814 } 815 break; 816 817 case EFX_VPD_RO: 818 if (evvp->evv_keyword == EFX_VPD_KEYWORD('R', 'V')) { 819 rc = EINVAL; 820 goto fail1; 821 } 822 break; 823 824 default: 825 rc = EINVAL; 826 goto fail1; 827 } 828 829 /* Determine total size of all current tags */ 830 if ((rc = efx_vpd_hunk_length(data, size, &used)) != 0) 831 goto fail2; 832 833 offset = 0; 834 _NOTE(CONSTANTCONDITION) 835 while (1) { 836 taghead = offset; 837 if ((rc = efx_vpd_next_tag(data, size, &offset, 838 &tag, &taglen)) != 0) 839 goto fail3; 840 if (tag == EFX_VPD_END) 841 break; 842 else if (tag != evvp->evv_tag) { 843 offset += taglen; 844 continue; 845 } 846 847 /* We only support modifying large resource tags */ 848 if (offset - taghead != 3) { 849 rc = EINVAL; 850 goto fail4; 851 } 852 853 /* 854 * Work out the offset of the byte immediately after the 855 * old (=source) and new (=dest) new keyword/tag 856 */ 857 pos = 0; 858 if (tag == EFX_VPD_ID) { 859 source = offset + taglen; 860 dest = offset + evvp->evv_length; 861 goto check_space; 862 } 863 864 EFSYS_ASSERT3U(tag, ==, EFX_VPD_RO); 865 source = dest = 0; 866 for (pos = 0; pos != taglen; pos += 3 + keylen) { 867 if ((rc = efx_vpd_next_keyword(data + offset, 868 taglen, pos, &keyword, &keylen)) != 0) 869 goto fail5; 870 871 if (keyword == evvp->evv_keyword && 872 evvp->evv_length == 0) { 873 /* Deleting this keyword */ 874 source = offset + pos + 3 + keylen; 875 dest = offset + pos; 876 break; 877 878 } else if (keyword == evvp->evv_keyword) { 879 /* Adjusting this keyword */ 880 source = offset + pos + 3 + keylen; 881 dest = offset + pos + 3 + evvp->evv_length; 882 break; 883 884 } else if (keyword == EFX_VPD_KEYWORD('R', 'V')) { 885 /* The RV keyword must be at the end */ 886 EFSYS_ASSERT3U(pos + 3 + keylen, ==, taglen); 887 888 /* 889 * The keyword doesn't already exist. If the 890 * user deleting a non-existant keyword then 891 * this is a no-op. 892 */ 893 if (evvp->evv_length == 0) 894 return (0); 895 896 /* Insert this keyword before the RV keyword */ 897 source = offset + pos; 898 dest = offset + pos + 3 + evvp->evv_length; 899 break; 900 } 901 } 902 903 check_space: 904 if (used + dest > size + source) { 905 rc = ENOSPC; 906 goto fail6; 907 } 908 909 /* Move trailing data */ 910 (void) memmove(data + dest, data + source, used - source); 911 912 /* Copy contents */ 913 (void) memcpy(data + dest - evvp->evv_length, evvp->evv_value, 914 evvp->evv_length); 915 916 /* Insert new keyword header if required */ 917 if (tag != EFX_VPD_ID && evvp->evv_length > 0) { 918 EFX_POPULATE_WORD_1(word, EFX_WORD_0, 919 evvp->evv_keyword); 920 data[offset + pos + 0] = 921 EFX_WORD_FIELD(word, EFX_BYTE_0); 922 data[offset + pos + 1] = 923 EFX_WORD_FIELD(word, EFX_BYTE_1); 924 data[offset + pos + 2] = evvp->evv_length; 925 } 926 927 /* Modify tag length (large resource type) */ 928 taglen += (dest - source); 929 EFX_POPULATE_WORD_1(word, EFX_WORD_0, taglen); 930 data[offset - 2] = EFX_WORD_FIELD(word, EFX_BYTE_0); 931 data[offset - 1] = EFX_WORD_FIELD(word, EFX_BYTE_1); 932 933 goto checksum; 934 } 935 936 /* Unable to find the matching tag */ 937 rc = ENOENT; 938 goto fail7; 939 940 checksum: 941 /* Find the RV tag, and update the checksum */ 942 offset = 0; 943 _NOTE(CONSTANTCONDITION) 944 while (1) { 945 if ((rc = efx_vpd_next_tag(data, size, &offset, 946 &tag, &taglen)) != 0) 947 goto fail8; 948 if (tag == EFX_VPD_END) 949 break; 950 if (tag == EFX_VPD_RO) { 951 for (pos = 0; pos != taglen; pos += 3 + keylen) { 952 if ((rc = efx_vpd_next_keyword(data + offset, 953 taglen, pos, &keyword, &keylen)) != 0) 954 goto fail9; 955 956 if (keyword == EFX_VPD_KEYWORD('R', 'V')) { 957 cksum = 0; 958 for (i = 0; i < offset + pos + 3; i++) 959 cksum += data[i]; 960 data[i] = -cksum; 961 break; 962 } 963 } 964 } 965 966 offset += taglen; 967 } 968 969 /* Zero out the unused portion */ 970 (void) memset(data + offset + taglen, 0xff, size - offset - taglen); 971 972 return (0); 973 974 fail9: 975 EFSYS_PROBE(fail9); 976 fail8: 977 EFSYS_PROBE(fail8); 978 fail7: 979 EFSYS_PROBE(fail7); 980 fail6: 981 EFSYS_PROBE(fail6); 982 fail5: 983 EFSYS_PROBE(fail5); 984 fail4: 985 EFSYS_PROBE(fail4); 986 fail3: 987 EFSYS_PROBE(fail3); 988 fail2: 989 EFSYS_PROBE(fail2); 990 fail1: 991 EFSYS_PROBE1(fail1, efx_rc_t, rc); 992 993 return (rc); 994 } 995 996 void 997 efx_vpd_fini( 998 __in efx_nic_t *enp) 999 { 1000 const efx_vpd_ops_t *evpdop = enp->en_evpdop; 1001 1002 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 1003 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 1004 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); 1005 1006 if (evpdop->evpdo_fini != NULL) 1007 evpdop->evpdo_fini(enp); 1008 1009 enp->en_evpdop = NULL; 1010 enp->en_mod_flags &= ~EFX_MOD_VPD; 1011 } 1012 1013 #endif /* EFSYS_OPT_VPD */ 1014