1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2009-2016 Solarflare Communications Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright notice, 11 * this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * The views and conclusions contained in the software and documentation are 29 * those of the authors and should not be interpreted as representing official 30 * policies, either expressed or implied, of the FreeBSD Project. 31 */ 32 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 #include "efx.h" 37 #include "efx_impl.h" 38 39 #if EFSYS_OPT_VPD 40 41 #if EFSYS_OPT_SIENA 42 43 static __checkReturn efx_rc_t 44 siena_vpd_get_static( 45 __in efx_nic_t *enp, 46 __in uint32_t partn, 47 __deref_out_bcount_opt(*sizep) caddr_t *svpdp, 48 __out size_t *sizep) 49 { 50 siena_mc_static_config_hdr_t *scfg; 51 caddr_t svpd; 52 size_t size; 53 uint8_t cksum; 54 unsigned int vpd_offset; 55 unsigned int vpd_length; 56 unsigned int hdr_length; 57 unsigned int pos; 58 unsigned int region; 59 efx_rc_t rc; 60 61 EFSYS_ASSERT(partn == MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0 || 62 partn == MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1); 63 64 /* Allocate sufficient memory for the entire static cfg area */ 65 if ((rc = siena_nvram_partn_size(enp, partn, &size)) != 0) 66 goto fail1; 67 68 if (size < SIENA_NVRAM_CHUNK) { 69 rc = EINVAL; 70 goto fail2; 71 } 72 73 EFSYS_KMEM_ALLOC(enp->en_esip, size, scfg); 74 if (scfg == NULL) { 75 rc = ENOMEM; 76 goto fail3; 77 } 78 79 if ((rc = siena_nvram_partn_read(enp, partn, 0, 80 (caddr_t)scfg, SIENA_NVRAM_CHUNK)) != 0) 81 goto fail4; 82 83 /* Verify the magic number */ 84 if (EFX_DWORD_FIELD(scfg->magic, EFX_DWORD_0) != 85 SIENA_MC_STATIC_CONFIG_MAGIC) { 86 rc = EINVAL; 87 goto fail5; 88 } 89 90 /* All future versions of the structure must be backwards compatible */ 91 EFX_STATIC_ASSERT(SIENA_MC_STATIC_CONFIG_VERSION == 0); 92 93 hdr_length = EFX_WORD_FIELD(scfg->length, EFX_WORD_0); 94 vpd_offset = EFX_DWORD_FIELD(scfg->static_vpd_offset, EFX_DWORD_0); 95 vpd_length = EFX_DWORD_FIELD(scfg->static_vpd_length, EFX_DWORD_0); 96 97 /* Verify the hdr doesn't overflow the sector size */ 98 if (hdr_length > size || vpd_offset > size || vpd_length > size || 99 vpd_length + vpd_offset > size) { 100 rc = EINVAL; 101 goto fail6; 102 } 103 104 /* Read the remainder of scfg + static vpd */ 105 region = vpd_offset + vpd_length; 106 if (region > SIENA_NVRAM_CHUNK) { 107 if ((rc = siena_nvram_partn_read(enp, partn, SIENA_NVRAM_CHUNK, 108 (caddr_t)scfg + SIENA_NVRAM_CHUNK, 109 region - SIENA_NVRAM_CHUNK)) != 0) 110 goto fail7; 111 } 112 113 /* Verify checksum */ 114 cksum = 0; 115 for (pos = 0; pos < hdr_length; pos++) 116 cksum += ((uint8_t *)scfg)[pos]; 117 if (cksum != 0) { 118 rc = EINVAL; 119 goto fail8; 120 } 121 122 if (vpd_length == 0) 123 svpd = NULL; 124 else { 125 /* Copy the vpd data out */ 126 EFSYS_KMEM_ALLOC(enp->en_esip, vpd_length, svpd); 127 if (svpd == NULL) { 128 rc = ENOMEM; 129 goto fail9; 130 } 131 memcpy(svpd, (caddr_t)scfg + vpd_offset, vpd_length); 132 } 133 134 EFSYS_KMEM_FREE(enp->en_esip, size, scfg); 135 136 *svpdp = svpd; 137 *sizep = vpd_length; 138 139 return (0); 140 141 fail9: 142 EFSYS_PROBE(fail9); 143 fail8: 144 EFSYS_PROBE(fail8); 145 fail7: 146 EFSYS_PROBE(fail7); 147 fail6: 148 EFSYS_PROBE(fail6); 149 fail5: 150 EFSYS_PROBE(fail5); 151 fail4: 152 EFSYS_PROBE(fail4); 153 154 EFSYS_KMEM_FREE(enp->en_esip, size, scfg); 155 156 fail3: 157 EFSYS_PROBE(fail3); 158 fail2: 159 EFSYS_PROBE(fail2); 160 fail1: 161 EFSYS_PROBE1(fail1, efx_rc_t, rc); 162 163 return (rc); 164 } 165 166 __checkReturn efx_rc_t 167 siena_vpd_init( 168 __in efx_nic_t *enp) 169 { 170 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 171 caddr_t svpd = NULL; 172 unsigned int partn; 173 size_t size = 0; 174 efx_rc_t rc; 175 176 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 177 178 partn = (emip->emi_port == 1) 179 ? MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0 180 : MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1; 181 182 /* 183 * We need the static VPD sector to present a unified static+dynamic 184 * VPD, that is, basically on every read, write, verify cycle. Since 185 * it should *never* change we can just cache it here. 186 */ 187 if ((rc = siena_vpd_get_static(enp, partn, &svpd, &size)) != 0) 188 goto fail1; 189 190 if (svpd != NULL && size > 0) { 191 if ((rc = efx_vpd_hunk_verify(svpd, size, NULL)) != 0) 192 goto fail2; 193 } 194 195 enp->en_u.siena.enu_svpd = svpd; 196 enp->en_u.siena.enu_svpd_length = size; 197 198 return (0); 199 200 fail2: 201 EFSYS_PROBE(fail2); 202 203 EFSYS_KMEM_FREE(enp->en_esip, size, svpd); 204 fail1: 205 EFSYS_PROBE1(fail1, efx_rc_t, rc); 206 207 return (rc); 208 } 209 210 __checkReturn efx_rc_t 211 siena_vpd_size( 212 __in efx_nic_t *enp, 213 __out size_t *sizep) 214 { 215 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 216 uint32_t partn; 217 efx_rc_t rc; 218 219 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 220 221 /* 222 * This function returns the total size the user should allocate 223 * for all VPD operations. We've already cached the static vpd, 224 * so we just need to return an upper bound on the dynamic vpd. 225 * Since the dynamic_config structure can change under our feet, 226 * (as version numbers are inserted), just be safe and return the 227 * total size of the dynamic_config *sector* 228 */ 229 partn = (emip->emi_port == 1) 230 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 231 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 232 233 if ((rc = siena_nvram_partn_size(enp, partn, sizep)) != 0) 234 goto fail1; 235 236 return (0); 237 238 fail1: 239 EFSYS_PROBE1(fail1, efx_rc_t, rc); 240 241 return (rc); 242 } 243 244 __checkReturn efx_rc_t 245 siena_vpd_read( 246 __in efx_nic_t *enp, 247 __out_bcount(size) caddr_t data, 248 __in size_t size) 249 { 250 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 251 siena_mc_dynamic_config_hdr_t *dcfg = NULL; 252 unsigned int vpd_length; 253 unsigned int vpd_offset; 254 unsigned int dcfg_partn; 255 size_t dcfg_size; 256 efx_rc_t rc; 257 258 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 259 260 dcfg_partn = (emip->emi_port == 1) 261 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 262 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 263 264 if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn, 265 B_TRUE, &dcfg, &dcfg_size)) != 0) 266 goto fail1; 267 268 vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0); 269 vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0); 270 271 if (vpd_length > size) { 272 rc = EFAULT; /* Invalid dcfg: header bigger than sector */ 273 goto fail2; 274 } 275 276 EFSYS_ASSERT3U(vpd_length, <=, size); 277 memcpy(data, (caddr_t)dcfg + vpd_offset, vpd_length); 278 279 /* Pad data with all-1s, consistent with update operations */ 280 memset(data + vpd_length, 0xff, size - vpd_length); 281 282 EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg); 283 284 return (0); 285 286 fail2: 287 EFSYS_PROBE(fail2); 288 289 EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg); 290 fail1: 291 EFSYS_PROBE1(fail1, efx_rc_t, rc); 292 293 return (rc); 294 } 295 296 __checkReturn efx_rc_t 297 siena_vpd_verify( 298 __in efx_nic_t *enp, 299 __in_bcount(size) caddr_t data, 300 __in size_t size) 301 { 302 efx_vpd_tag_t stag; 303 efx_vpd_tag_t dtag; 304 efx_vpd_keyword_t skey; 305 efx_vpd_keyword_t dkey; 306 unsigned int scont; 307 unsigned int dcont; 308 309 efx_rc_t rc; 310 311 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 312 313 /* 314 * Strictly you could take the view that dynamic vpd is optional. 315 * Instead, to conform more closely to the read/verify/reinit() 316 * paradigm, we require dynamic vpd. siena_vpd_reinit() will 317 * reinitialize it as required. 318 */ 319 if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0) 320 goto fail1; 321 322 /* 323 * Verify that there is no duplication between the static and 324 * dynamic cfg sectors. 325 */ 326 if (enp->en_u.siena.enu_svpd_length == 0) 327 goto done; 328 329 dcont = 0; 330 _NOTE(CONSTANTCONDITION) 331 while (1) { 332 if ((rc = efx_vpd_hunk_next(data, size, &dtag, 333 &dkey, NULL, NULL, &dcont)) != 0) 334 goto fail2; 335 if (dcont == 0) 336 break; 337 338 /* 339 * Skip the RV keyword. It should be present in both the static 340 * and dynamic cfg sectors. 341 */ 342 if (dtag == EFX_VPD_RO && dkey == EFX_VPD_KEYWORD('R', 'V')) 343 continue; 344 345 scont = 0; 346 _NOTE(CONSTANTCONDITION) 347 while (1) { 348 if ((rc = efx_vpd_hunk_next( 349 enp->en_u.siena.enu_svpd, 350 enp->en_u.siena.enu_svpd_length, &stag, &skey, 351 NULL, NULL, &scont)) != 0) 352 goto fail3; 353 if (scont == 0) 354 break; 355 356 if (stag == dtag && skey == dkey) { 357 rc = EEXIST; 358 goto fail4; 359 } 360 } 361 } 362 363 done: 364 return (0); 365 366 fail4: 367 EFSYS_PROBE(fail4); 368 fail3: 369 EFSYS_PROBE(fail3); 370 fail2: 371 EFSYS_PROBE(fail2); 372 fail1: 373 EFSYS_PROBE1(fail1, efx_rc_t, rc); 374 375 return (rc); 376 } 377 378 __checkReturn efx_rc_t 379 siena_vpd_reinit( 380 __in efx_nic_t *enp, 381 __in_bcount(size) caddr_t data, 382 __in size_t size) 383 { 384 boolean_t wantpid; 385 efx_rc_t rc; 386 387 /* 388 * Only create a PID if the dynamic cfg doesn't have one 389 */ 390 if (enp->en_u.siena.enu_svpd_length == 0) 391 wantpid = B_TRUE; 392 else { 393 unsigned int offset; 394 uint8_t length; 395 396 rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd, 397 enp->en_u.siena.enu_svpd_length, 398 EFX_VPD_ID, 0, &offset, &length); 399 if (rc == 0) 400 wantpid = B_FALSE; 401 else if (rc == ENOENT) 402 wantpid = B_TRUE; 403 else 404 goto fail1; 405 } 406 407 if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0) 408 goto fail2; 409 410 return (0); 411 412 fail2: 413 EFSYS_PROBE(fail2); 414 fail1: 415 EFSYS_PROBE1(fail1, efx_rc_t, rc); 416 417 return (rc); 418 } 419 420 __checkReturn efx_rc_t 421 siena_vpd_get( 422 __in efx_nic_t *enp, 423 __in_bcount(size) caddr_t data, 424 __in size_t size, 425 __inout efx_vpd_value_t *evvp) 426 { 427 unsigned int offset; 428 uint8_t length; 429 efx_rc_t rc; 430 431 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 432 433 /* Attempt to satisfy the request from svpd first */ 434 if (enp->en_u.siena.enu_svpd_length > 0) { 435 if ((rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd, 436 enp->en_u.siena.enu_svpd_length, evvp->evv_tag, 437 evvp->evv_keyword, &offset, &length)) == 0) { 438 evvp->evv_length = length; 439 memcpy(evvp->evv_value, 440 enp->en_u.siena.enu_svpd + offset, length); 441 return (0); 442 } else if (rc != ENOENT) 443 goto fail1; 444 } 445 446 /* And then from the provided data buffer */ 447 if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag, 448 evvp->evv_keyword, &offset, &length)) != 0) { 449 if (rc == ENOENT) 450 return (rc); 451 452 goto fail2; 453 } 454 455 evvp->evv_length = length; 456 memcpy(evvp->evv_value, data + offset, length); 457 458 return (0); 459 460 fail2: 461 EFSYS_PROBE(fail2); 462 fail1: 463 EFSYS_PROBE1(fail1, efx_rc_t, rc); 464 465 return (rc); 466 } 467 468 __checkReturn efx_rc_t 469 siena_vpd_set( 470 __in efx_nic_t *enp, 471 __in_bcount(size) caddr_t data, 472 __in size_t size, 473 __in efx_vpd_value_t *evvp) 474 { 475 efx_rc_t rc; 476 477 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 478 479 /* If the provided (tag,keyword) exists in svpd, then it is readonly */ 480 if (enp->en_u.siena.enu_svpd_length > 0) { 481 unsigned int offset; 482 uint8_t length; 483 484 if ((rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd, 485 enp->en_u.siena.enu_svpd_length, evvp->evv_tag, 486 evvp->evv_keyword, &offset, &length)) == 0) { 487 rc = EACCES; 488 goto fail1; 489 } 490 } 491 492 if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0) 493 goto fail2; 494 495 return (0); 496 497 fail2: 498 EFSYS_PROBE(fail2); 499 fail1: 500 EFSYS_PROBE1(fail1, efx_rc_t, rc); 501 502 return (rc); 503 } 504 505 __checkReturn efx_rc_t 506 siena_vpd_next( 507 __in efx_nic_t *enp, 508 __in_bcount(size) caddr_t data, 509 __in size_t size, 510 __out efx_vpd_value_t *evvp, 511 __inout unsigned int *contp) 512 { 513 _NOTE(ARGUNUSED(enp, data, size, evvp, contp)) 514 515 return (ENOTSUP); 516 } 517 518 __checkReturn efx_rc_t 519 siena_vpd_write( 520 __in efx_nic_t *enp, 521 __in_bcount(size) caddr_t data, 522 __in size_t size) 523 { 524 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 525 siena_mc_dynamic_config_hdr_t *dcfg = NULL; 526 unsigned int vpd_offset; 527 unsigned int dcfg_partn; 528 unsigned int hdr_length; 529 unsigned int pos; 530 uint8_t cksum; 531 size_t partn_size, dcfg_size; 532 size_t vpd_length; 533 efx_rc_t rc; 534 535 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 536 537 /* Determine total length of all tags */ 538 if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0) 539 goto fail1; 540 541 /* Lock dynamic config sector for write, and read structure only */ 542 dcfg_partn = (emip->emi_port == 1) 543 ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 544 : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 545 546 if ((rc = siena_nvram_partn_size(enp, dcfg_partn, &partn_size)) != 0) 547 goto fail2; 548 549 if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0) 550 goto fail3; 551 552 if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn, 553 B_FALSE, &dcfg, &dcfg_size)) != 0) 554 goto fail4; 555 556 hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0); 557 558 /* Allocated memory should have room for the new VPD */ 559 if (hdr_length + vpd_length > dcfg_size) { 560 rc = ENOSPC; 561 goto fail5; 562 } 563 564 /* Copy in new vpd and update header */ 565 vpd_offset = dcfg_size - vpd_length; 566 EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, EFX_DWORD_0, vpd_offset); 567 memcpy((caddr_t)dcfg + vpd_offset, data, vpd_length); 568 EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_length, EFX_DWORD_0, vpd_length); 569 570 /* Update the checksum */ 571 cksum = 0; 572 for (pos = 0; pos < hdr_length; pos++) 573 cksum += ((uint8_t *)dcfg)[pos]; 574 dcfg->csum.eb_u8[0] -= cksum; 575 576 /* Erase and write the new sector */ 577 if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, partn_size)) != 0) 578 goto fail6; 579 580 /* Write out the new structure to nvram */ 581 if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0, (caddr_t)dcfg, 582 vpd_offset + vpd_length)) != 0) 583 goto fail7; 584 585 EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg); 586 587 siena_nvram_partn_unlock(enp, dcfg_partn, NULL); 588 589 return (0); 590 591 fail7: 592 EFSYS_PROBE(fail7); 593 fail6: 594 EFSYS_PROBE(fail6); 595 fail5: 596 EFSYS_PROBE(fail5); 597 598 EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg); 599 fail4: 600 EFSYS_PROBE(fail4); 601 602 siena_nvram_partn_unlock(enp, dcfg_partn, NULL); 603 fail3: 604 EFSYS_PROBE(fail3); 605 fail2: 606 EFSYS_PROBE(fail2); 607 fail1: 608 EFSYS_PROBE1(fail1, efx_rc_t, rc); 609 610 return (rc); 611 } 612 613 void 614 siena_vpd_fini( 615 __in efx_nic_t *enp) 616 { 617 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 618 619 if (enp->en_u.siena.enu_svpd_length > 0) { 620 EFSYS_KMEM_FREE(enp->en_esip, enp->en_u.siena.enu_svpd_length, 621 enp->en_u.siena.enu_svpd); 622 623 enp->en_u.siena.enu_svpd = NULL; 624 enp->en_u.siena.enu_svpd_length = 0; 625 } 626 } 627 628 #endif /* EFSYS_OPT_SIENA */ 629 630 #endif /* EFSYS_OPT_VPD */ 631