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