efx_nvram.c revision 294201
1273562Smarcel/*- 2287111Smarcel * Copyright (c) 2009-2015 Solarflare Communications Inc. 3287111Smarcel * All rights reserved. 4298083Sphil * 5298083Sphil * Redistribution and use in source and binary forms, with or without 6298083Sphil * modification, are permitted provided that the following conditions are met: 7298083Sphil * 8298083Sphil * 1. Redistributions of source code must retain the above copyright notice, 9298083Sphil * this list of conditions and the following disclaimer. 10298083Sphil * 2. Redistributions in binary form must reproduce the above copyright notice, 11298083Sphil * this list of conditions and the following disclaimer in the documentation 12277353Smarcel * and/or other materials provided with the distribution. 13277353Smarcel * 14277353Smarcel * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15273562Smarcel * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16273562Smarcel * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17273562Smarcel * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18273562Smarcel * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19273562Smarcel * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20273562Smarcel * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21277353Smarcel * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22273562Smarcel * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23273562Smarcel * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24273562Smarcel * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25273562Smarcel * 26273562Smarcel * The views and conclusions contained in the software and documentation are 27273562Smarcel * those of the authors and should not be interpreted as representing official 28277353Smarcel * policies, either expressed or implied, of the FreeBSD Project. 29273562Smarcel */ 30273562Smarcel 31273562Smarcel#include <sys/cdefs.h> 32273562Smarcel__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/efx_nvram.c 294201 2016-01-17 05:12:37Z arybchik $"); 33273562Smarcel 34273562Smarcel#include "efx.h" 35277353Smarcel#include "efx_impl.h" 36273562Smarcel 37273562Smarcel#if EFSYS_OPT_NVRAM 38273562Smarcel 39273562Smarcel#if EFSYS_OPT_FALCON 40273562Smarcel 41273562Smarcelstatic efx_nvram_ops_t __efx_nvram_falcon_ops = { 42277353Smarcel#if EFSYS_OPT_DIAG 43273562Smarcel falcon_nvram_test, /* envo_test */ 44273562Smarcel#endif /* EFSYS_OPT_DIAG */ 45273562Smarcel falcon_nvram_get_version, /* envo_get_version */ 46273562Smarcel falcon_nvram_write_chunk, /* envo_write_chunk */ 47273562Smarcel falcon_nvram_rw_finish, /* envo_rw_finish */ 48273562Smarcel falcon_nvram_set_version, /* envo_set_version */ 49287111Smarcel falcon_nvram_type_to_partn, /* envo_type_to_partn */ 50273562Smarcel falcon_nvram_partn_size, /* envo_partn_size */ 51273562Smarcel falcon_nvram_partn_rw_start, /* envo_partn_rw_start */ 52273562Smarcel falcon_nvram_partn_read, /* envo_partn_read */ 53273562Smarcel falcon_nvram_partn_erase, /* envo_partn_erase */ 54273562Smarcel}; 55273562Smarcel 56273562Smarcel#endif /* EFSYS_OPT_FALCON */ 57273562Smarcel 58273562Smarcel#if EFSYS_OPT_SIENA 59273562Smarcel 60273562Smarcelstatic efx_nvram_ops_t __efx_nvram_siena_ops = { 61273562Smarcel#if EFSYS_OPT_DIAG 62273562Smarcel siena_nvram_test, /* envo_test */ 63273562Smarcel#endif /* EFSYS_OPT_DIAG */ 64273562Smarcel siena_nvram_get_version, /* envo_get_version */ 65273562Smarcel siena_nvram_write_chunk, /* envo_write_chunk */ 66273562Smarcel siena_nvram_rw_finish, /* envo_rw_finish */ 67273562Smarcel siena_nvram_set_version, /* envo_set_version */ 68273562Smarcel siena_nvram_type_to_partn, /* envo_type_to_partn */ 69273562Smarcel siena_nvram_partn_size, /* envo_partn_size */ 70273562Smarcel siena_nvram_partn_rw_start, /* envo_partn_rw_start */ 71273562Smarcel siena_nvram_partn_read, /* envo_partn_read */ 72273562Smarcel siena_nvram_partn_erase, /* envo_partn_erase */ 73273562Smarcel}; 74273562Smarcel 75273562Smarcel#endif /* EFSYS_OPT_SIENA */ 76273562Smarcel 77273562Smarcel#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD 78273562Smarcel 79273562Smarcelstatic efx_nvram_ops_t __efx_nvram_ef10_ops = { 80273562Smarcel#if EFSYS_OPT_DIAG 81273562Smarcel ef10_nvram_test, /* envo_test */ 82273562Smarcel#endif /* EFSYS_OPT_DIAG */ 83273562Smarcel ef10_nvram_get_version, /* envo_get_version */ 84273562Smarcel ef10_nvram_write_chunk, /* envo_write_chunk */ 85287111Smarcel ef10_nvram_rw_finish, /* envo_rw_finish */ 86287111Smarcel ef10_nvram_set_version, /* envo_set_version */ 87273562Smarcel ef10_nvram_type_to_partn, /* envo_type_to_partn */ 88273562Smarcel ef10_nvram_partn_size, /* envo_partn_size */ 89273562Smarcel ef10_nvram_partn_rw_start, /* envo_partn_rw_start */ 90273562Smarcel ef10_nvram_partn_read, /* envo_partn_read */ 91273562Smarcel ef10_nvram_partn_erase, /* envo_partn_erase */ 92273562Smarcel}; 93273562Smarcel 94287111Smarcel#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ 95287111Smarcel 96277353Smarcel __checkReturn efx_rc_t 97277353Smarcelefx_nvram_init( 98277353Smarcel __in efx_nic_t *enp) 99277353Smarcel{ 100277353Smarcel efx_nvram_ops_t *envop; 101287111Smarcel efx_rc_t rc; 102277353Smarcel 103277353Smarcel EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 104298067Sphil EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 105298067Sphil EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NVRAM)); 106298067Sphil 107298067Sphil switch (enp->en_family) { 108298067Sphil#if EFSYS_OPT_FALCON 109298067Sphil case EFX_FAMILY_FALCON: 110298067Sphil envop = (efx_nvram_ops_t *)&__efx_nvram_falcon_ops; 111298067Sphil break; 112298067Sphil#endif /* EFSYS_OPT_FALCON */ 113298067Sphil 114273562Smarcel#if EFSYS_OPT_SIENA 115 case EFX_FAMILY_SIENA: 116 envop = (efx_nvram_ops_t *)&__efx_nvram_siena_ops; 117 break; 118#endif /* EFSYS_OPT_SIENA */ 119 120#if EFSYS_OPT_HUNTINGTON 121 case EFX_FAMILY_HUNTINGTON: 122 envop = (efx_nvram_ops_t *)&__efx_nvram_ef10_ops; 123 break; 124#endif /* EFSYS_OPT_HUNTINGTON */ 125 126#if EFSYS_OPT_MEDFORD 127 case EFX_FAMILY_MEDFORD: 128 envop = (efx_nvram_ops_t *)&__efx_nvram_ef10_ops; 129 break; 130#endif /* EFSYS_OPT_MEDFORD */ 131 132 default: 133 EFSYS_ASSERT(0); 134 rc = ENOTSUP; 135 goto fail1; 136 } 137 138 enp->en_envop = envop; 139 enp->en_mod_flags |= EFX_MOD_NVRAM; 140 141 return (0); 142 143fail1: 144 EFSYS_PROBE1(fail1, efx_rc_t, rc); 145 146 return (rc); 147} 148 149#if EFSYS_OPT_DIAG 150 151 __checkReturn efx_rc_t 152efx_nvram_test( 153 __in efx_nic_t *enp) 154{ 155 efx_nvram_ops_t *envop = enp->en_envop; 156 efx_rc_t rc; 157 158 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 159 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 160 161 if ((rc = envop->envo_test(enp)) != 0) 162 goto fail1; 163 164 return (0); 165 166fail1: 167 EFSYS_PROBE1(fail1, efx_rc_t, rc); 168 169 return (rc); 170} 171 172#endif /* EFSYS_OPT_DIAG */ 173 174 __checkReturn efx_rc_t 175efx_nvram_size( 176 __in efx_nic_t *enp, 177 __in efx_nvram_type_t type, 178 __out size_t *sizep) 179{ 180 efx_nvram_ops_t *envop = enp->en_envop; 181 uint32_t partn; 182 efx_rc_t rc; 183 184 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 185 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 186 187 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 188 189 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 190 goto fail1; 191 192 if ((rc = envop->envo_partn_size(enp, partn, sizep)) != 0) 193 goto fail2; 194 195 return (0); 196 197fail2: 198 EFSYS_PROBE(fail2); 199fail1: 200 EFSYS_PROBE1(fail1, efx_rc_t, rc); 201 *sizep = 0; 202 203 return (rc); 204} 205 206 __checkReturn efx_rc_t 207efx_nvram_get_version( 208 __in efx_nic_t *enp, 209 __in efx_nvram_type_t type, 210 __out uint32_t *subtypep, 211 __out_ecount(4) uint16_t version[4]) 212{ 213 efx_nvram_ops_t *envop = enp->en_envop; 214 efx_rc_t rc; 215 216 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 217 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 218 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 219 220 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 221 222 if ((rc = envop->envo_get_version(enp, type, subtypep, version)) != 0) 223 goto fail1; 224 225 return (0); 226 227fail1: 228 EFSYS_PROBE1(fail1, efx_rc_t, rc); 229 230 return (rc); 231} 232 233 __checkReturn efx_rc_t 234efx_nvram_rw_start( 235 __in efx_nic_t *enp, 236 __in efx_nvram_type_t type, 237 __out_opt size_t *chunk_sizep) 238{ 239 efx_nvram_ops_t *envop = enp->en_envop; 240 uint32_t partn; 241 efx_rc_t rc; 242 243 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 244 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 245 246 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 247 EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID); 248 249 EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID); 250 251 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 252 goto fail1; 253 254 if ((rc = envop->envo_partn_rw_start(enp, partn, chunk_sizep)) != 0) 255 goto fail2; 256 257 enp->en_nvram_locked = type; 258 259 return (0); 260 261fail2: 262 EFSYS_PROBE(fail2); 263fail1: 264 EFSYS_PROBE1(fail1, efx_rc_t, rc); 265 266 return (rc); 267} 268 269 __checkReturn efx_rc_t 270efx_nvram_read_chunk( 271 __in efx_nic_t *enp, 272 __in efx_nvram_type_t type, 273 __in unsigned int offset, 274 __out_bcount(size) caddr_t data, 275 __in size_t size) 276{ 277 efx_nvram_ops_t *envop = enp->en_envop; 278 uint32_t partn; 279 efx_rc_t rc; 280 281 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 282 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 283 284 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 285 EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID); 286 287 EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type); 288 289 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 290 goto fail1; 291 292 if ((rc = envop->envo_partn_read(enp, partn, offset, data, size)) != 0) 293 goto fail2; 294 295 return (0); 296 297fail2: 298 EFSYS_PROBE(fail2); 299fail1: 300 EFSYS_PROBE1(fail1, efx_rc_t, rc); 301 302 return (rc); 303} 304 305 __checkReturn efx_rc_t 306efx_nvram_erase( 307 __in efx_nic_t *enp, 308 __in efx_nvram_type_t type) 309{ 310 efx_nvram_ops_t *envop = enp->en_envop; 311 unsigned int offset = 0; 312 size_t size = 0; 313 uint32_t partn; 314 efx_rc_t rc; 315 316 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 317 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 318 319 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 320 EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID); 321 322 EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type); 323 324 if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) 325 goto fail1; 326 327 if ((rc = envop->envo_partn_size(enp, partn, &size)) != 0) 328 goto fail2; 329 330 if ((rc = envop->envo_partn_erase(enp, partn, offset, size)) != 0) 331 goto fail3; 332 333 return (0); 334 335fail3: 336 EFSYS_PROBE(fail3); 337fail2: 338 EFSYS_PROBE(fail2); 339fail1: 340 EFSYS_PROBE1(fail1, efx_rc_t, rc); 341 342 return (rc); 343} 344 345 __checkReturn efx_rc_t 346efx_nvram_write_chunk( 347 __in efx_nic_t *enp, 348 __in efx_nvram_type_t type, 349 __in unsigned int offset, 350 __in_bcount(size) caddr_t data, 351 __in size_t size) 352{ 353 efx_nvram_ops_t *envop = enp->en_envop; 354 efx_rc_t rc; 355 356 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 357 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 358 359 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 360 EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID); 361 362 EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type); 363 364 if ((rc = envop->envo_write_chunk(enp, type, offset, data, size)) != 0) 365 goto fail1; 366 367 return (0); 368 369fail1: 370 EFSYS_PROBE1(fail1, efx_rc_t, rc); 371 372 return (rc); 373} 374 375 void 376efx_nvram_rw_finish( 377 __in efx_nic_t *enp, 378 __in efx_nvram_type_t type) 379{ 380 efx_nvram_ops_t *envop = enp->en_envop; 381 382 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 383 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 384 385 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 386 EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID); 387 388 EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type); 389 390 envop->envo_rw_finish(enp, type); 391 392 enp->en_nvram_locked = EFX_NVRAM_INVALID; 393} 394 395 __checkReturn efx_rc_t 396efx_nvram_set_version( 397 __in efx_nic_t *enp, 398 __in efx_nvram_type_t type, 399 __in_ecount(4) uint16_t version[4]) 400{ 401 efx_nvram_ops_t *envop = enp->en_envop; 402 efx_rc_t rc; 403 404 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 405 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 406 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 407 408 EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 409 410 /* 411 * The Siena implementation of envo_set_version() will attempt to 412 * acquire the NVRAM_UPDATE lock for the DYNAMIC_CONFIG sector. 413 * Therefore, you can't have already acquired the NVRAM_UPDATE lock. 414 */ 415 EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID); 416 417 if ((rc = envop->envo_set_version(enp, type, version)) != 0) 418 goto fail1; 419 420 return (0); 421 422fail1: 423 EFSYS_PROBE1(fail1, efx_rc_t, rc); 424 425 return (rc); 426} 427 428void 429efx_nvram_fini( 430 __in efx_nic_t *enp) 431{ 432 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 433 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 434 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); 435 436 EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID); 437 438 enp->en_envop = NULL; 439 enp->en_mod_flags &= ~EFX_MOD_NVRAM; 440} 441 442#endif /* EFSYS_OPT_NVRAM */ 443 444#if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD 445 446/* 447 * Internal MCDI request handling 448 */ 449 450 __checkReturn efx_rc_t 451efx_mcdi_nvram_partitions( 452 __in efx_nic_t *enp, 453 __out_bcount(size) caddr_t data, 454 __in size_t size, 455 __out unsigned int *npartnp) 456{ 457 efx_mcdi_req_t req; 458 uint8_t payload[MAX(MC_CMD_NVRAM_PARTITIONS_IN_LEN, 459 MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX)]; 460 unsigned int npartn; 461 efx_rc_t rc; 462 463 (void) memset(payload, 0, sizeof (payload)); 464 req.emr_cmd = MC_CMD_NVRAM_PARTITIONS; 465 req.emr_in_buf = payload; 466 req.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN; 467 req.emr_out_buf = payload; 468 req.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX; 469 470 efx_mcdi_execute(enp, &req); 471 472 if (req.emr_rc != 0) { 473 rc = req.emr_rc; 474 goto fail1; 475 } 476 477 if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) { 478 rc = EMSGSIZE; 479 goto fail2; 480 } 481 npartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS); 482 483 if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) { 484 rc = ENOENT; 485 goto fail3; 486 } 487 488 if (size < npartn * sizeof (uint32_t)) { 489 rc = ENOSPC; 490 goto fail3; 491 } 492 493 *npartnp = npartn; 494 495 memcpy(data, 496 MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID), 497 (npartn * sizeof (uint32_t))); 498 499 return (0); 500 501fail3: 502 EFSYS_PROBE(fail3); 503fail2: 504 EFSYS_PROBE(fail2); 505fail1: 506 EFSYS_PROBE1(fail1, efx_rc_t, rc); 507 508 return (rc); 509} 510 511 __checkReturn efx_rc_t 512efx_mcdi_nvram_metadata( 513 __in efx_nic_t *enp, 514 __in uint32_t partn, 515 __out uint32_t *subtypep, 516 __out_ecount(4) uint16_t version[4], 517 __out_bcount_opt(size) char *descp, 518 __in size_t size) 519{ 520 efx_mcdi_req_t req; 521 uint8_t payload[MAX(MC_CMD_NVRAM_METADATA_IN_LEN, 522 MC_CMD_NVRAM_METADATA_OUT_LENMAX)]; 523 efx_rc_t rc; 524 525 (void) memset(payload, 0, sizeof (payload)); 526 req.emr_cmd = MC_CMD_NVRAM_METADATA; 527 req.emr_in_buf = payload; 528 req.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN; 529 req.emr_out_buf = payload; 530 req.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX; 531 532 MCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn); 533 534 efx_mcdi_execute(enp, &req); 535 536 if (req.emr_rc != 0) { 537 rc = req.emr_rc; 538 goto fail1; 539 } 540 541 if (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) { 542 rc = EMSGSIZE; 543 goto fail2; 544 } 545 546 if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS, 547 NVRAM_METADATA_OUT_SUBTYPE_VALID)) { 548 *subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE); 549 } else { 550 *subtypep = 0; 551 } 552 553 if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS, 554 NVRAM_METADATA_OUT_VERSION_VALID)) { 555 version[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W); 556 version[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X); 557 version[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y); 558 version[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z); 559 } else { 560 version[0] = version[1] = version[2] = version[3] = 0; 561 } 562 563 if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS, 564 NVRAM_METADATA_OUT_DESCRIPTION_VALID)) { 565 /* Return optional descrition string */ 566 if ((descp != NULL) && (size > 0)) { 567 size_t desclen; 568 569 descp[0] = '\0'; 570 desclen = (req.emr_out_length_used 571 - MC_CMD_NVRAM_METADATA_OUT_LEN(0)); 572 573 EFSYS_ASSERT3U(desclen, <=, 574 MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM); 575 576 if (size < desclen) { 577 rc = ENOSPC; 578 goto fail3; 579 } 580 581 memcpy(descp, MCDI_OUT2(req, char, 582 NVRAM_METADATA_OUT_DESCRIPTION), 583 desclen); 584 585 /* Ensure string is NUL terminated */ 586 descp[desclen] = '\0'; 587 } 588 } 589 590 return (0); 591 592fail3: 593 EFSYS_PROBE(fail3); 594fail2: 595 EFSYS_PROBE(fail2); 596fail1: 597 EFSYS_PROBE1(fail1, efx_rc_t, rc); 598 599 return (rc); 600} 601 602 __checkReturn efx_rc_t 603efx_mcdi_nvram_info( 604 __in efx_nic_t *enp, 605 __in uint32_t partn, 606 __out_opt size_t *sizep, 607 __out_opt uint32_t *addressp, 608 __out_opt uint32_t *erase_sizep, 609 __out_opt uint32_t *write_sizep) 610{ 611 uint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN, 612 MC_CMD_NVRAM_INFO_V2_OUT_LEN)]; 613 efx_mcdi_req_t req; 614 efx_rc_t rc; 615 616 (void) memset(payload, 0, sizeof (payload)); 617 req.emr_cmd = MC_CMD_NVRAM_INFO; 618 req.emr_in_buf = payload; 619 req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN; 620 req.emr_out_buf = payload; 621 req.emr_out_length = MC_CMD_NVRAM_INFO_V2_OUT_LEN; 622 623 MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn); 624 625 efx_mcdi_execute_quiet(enp, &req); 626 627 if (req.emr_rc != 0) { 628 rc = req.emr_rc; 629 goto fail1; 630 } 631 632 if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) { 633 rc = EMSGSIZE; 634 goto fail2; 635 } 636 637 if (sizep) 638 *sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE); 639 640 if (addressp) 641 *addressp = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR); 642 643 if (erase_sizep) 644 *erase_sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE); 645 646 if (write_sizep) { 647 *write_sizep = 648 (req.emr_out_length_used < 649 MC_CMD_NVRAM_INFO_V2_OUT_LEN) ? 650 0 : MCDI_OUT_DWORD(req, NVRAM_INFO_V2_OUT_WRITESIZE); 651 } 652 653 return (0); 654 655fail2: 656 EFSYS_PROBE(fail2); 657fail1: 658 EFSYS_PROBE1(fail1, efx_rc_t, rc); 659 660 return (rc); 661} 662 663 __checkReturn efx_rc_t 664efx_mcdi_nvram_update_start( 665 __in efx_nic_t *enp, 666 __in uint32_t partn) 667{ 668 uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_START_IN_LEN, 669 MC_CMD_NVRAM_UPDATE_START_OUT_LEN)]; 670 efx_mcdi_req_t req; 671 efx_rc_t rc; 672 673 (void) memset(payload, 0, sizeof (payload)); 674 req.emr_cmd = MC_CMD_NVRAM_UPDATE_START; 675 req.emr_in_buf = payload; 676 req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_IN_LEN; 677 req.emr_out_buf = payload; 678 req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN; 679 680 MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_IN_TYPE, partn); 681 682 efx_mcdi_execute(enp, &req); 683 684 if (req.emr_rc != 0) { 685 rc = req.emr_rc; 686 goto fail1; 687 } 688 689 return (0); 690 691fail1: 692 EFSYS_PROBE1(fail1, efx_rc_t, rc); 693 694 return (rc); 695} 696 697 __checkReturn efx_rc_t 698efx_mcdi_nvram_read( 699 __in efx_nic_t *enp, 700 __in uint32_t partn, 701 __in uint32_t offset, 702 __out_bcount(size) caddr_t data, 703 __in size_t size) 704{ 705 efx_mcdi_req_t req; 706 uint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_LEN, 707 MC_CMD_NVRAM_READ_OUT_LENMAX)]; 708 efx_rc_t rc; 709 710 if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) { 711 rc = EINVAL; 712 goto fail1; 713 } 714 715 (void) memset(payload, 0, sizeof (payload)); 716 req.emr_cmd = MC_CMD_NVRAM_READ; 717 req.emr_in_buf = payload; 718 req.emr_in_length = MC_CMD_NVRAM_READ_IN_LEN; 719 req.emr_out_buf = payload; 720 req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX; 721 722 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_TYPE, partn); 723 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_OFFSET, offset); 724 MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_LENGTH, size); 725 726 efx_mcdi_execute(enp, &req); 727 728 if (req.emr_rc != 0) { 729 rc = req.emr_rc; 730 goto fail1; 731 } 732 733 if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) { 734 rc = EMSGSIZE; 735 goto fail2; 736 } 737 738 memcpy(data, 739 MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER), 740 size); 741 742 return (0); 743 744fail2: 745 EFSYS_PROBE(fail2); 746fail1: 747 EFSYS_PROBE1(fail1, efx_rc_t, rc); 748 749 return (rc); 750} 751 752 __checkReturn efx_rc_t 753efx_mcdi_nvram_erase( 754 __in efx_nic_t *enp, 755 __in uint32_t partn, 756 __in uint32_t offset, 757 __in size_t size) 758{ 759 efx_mcdi_req_t req; 760 uint8_t payload[MAX(MC_CMD_NVRAM_ERASE_IN_LEN, 761 MC_CMD_NVRAM_ERASE_OUT_LEN)]; 762 efx_rc_t rc; 763 764 (void) memset(payload, 0, sizeof (payload)); 765 req.emr_cmd = MC_CMD_NVRAM_ERASE; 766 req.emr_in_buf = payload; 767 req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN; 768 req.emr_out_buf = payload; 769 req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN; 770 771 MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn); 772 MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset); 773 MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size); 774 775 efx_mcdi_execute(enp, &req); 776 777 if (req.emr_rc != 0) { 778 rc = req.emr_rc; 779 goto fail1; 780 } 781 782 return (0); 783 784fail1: 785 EFSYS_PROBE1(fail1, efx_rc_t, rc); 786 787 return (rc); 788} 789 790/* 791 * The NVRAM_WRITE MCDI command is a V1 command and so is supported by both 792 * Sienna and EF10 based boards. However EF10 based boards support the use 793 * of this command with payloads up to the maximum MCDI V2 payload length. 794 */ 795 __checkReturn efx_rc_t 796efx_mcdi_nvram_write( 797 __in efx_nic_t *enp, 798 __in uint32_t partn, 799 __in uint32_t offset, 800 __out_bcount(size) caddr_t data, 801 __in size_t size) 802{ 803 efx_mcdi_req_t req; 804 uint8_t payload[MAX(MCDI_CTL_SDU_LEN_MAX_V1, 805 MCDI_CTL_SDU_LEN_MAX_V2)]; 806 efx_rc_t rc; 807 size_t max_data_size; 808 809 max_data_size = enp->en_nic_cfg.enc_mcdi_max_payload_length 810 - MC_CMD_NVRAM_WRITE_IN_LEN(0); 811 EFSYS_ASSERT3U(enp->en_nic_cfg.enc_mcdi_max_payload_length, >, 0); 812 EFSYS_ASSERT3U(max_data_size, <, 813 enp->en_nic_cfg.enc_mcdi_max_payload_length); 814 815 if (size > max_data_size) { 816 rc = EINVAL; 817 goto fail1; 818 } 819 820 (void) memset(payload, 0, sizeof (payload)); 821 req.emr_cmd = MC_CMD_NVRAM_WRITE; 822 req.emr_in_buf = payload; 823 req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size); 824 req.emr_out_buf = payload; 825 req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN; 826 827 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn); 828 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset); 829 MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size); 830 831 memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER), 832 data, size); 833 834 efx_mcdi_execute(enp, &req); 835 836 if (req.emr_rc != 0) { 837 rc = req.emr_rc; 838 goto fail2; 839 } 840 841 return (0); 842 843fail2: 844 EFSYS_PROBE(fail2); 845fail1: 846 EFSYS_PROBE1(fail1, efx_rc_t, rc); 847 848 return (rc); 849} 850 851 __checkReturn efx_rc_t 852efx_mcdi_nvram_update_finish( 853 __in efx_nic_t *enp, 854 __in uint32_t partn, 855 __in boolean_t reboot) 856{ 857 efx_mcdi_req_t req; 858 uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN, 859 MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN)]; 860 efx_rc_t rc; 861 862 (void) memset(payload, 0, sizeof (payload)); 863 req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH; 864 req.emr_in_buf = payload; 865 req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN; 866 req.emr_out_buf = payload; 867 req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN; 868 869 MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_TYPE, partn); 870 MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_REBOOT, reboot); 871 872 efx_mcdi_execute(enp, &req); 873 874 if (req.emr_rc != 0) { 875 rc = req.emr_rc; 876 goto fail1; 877 } 878 879 return (0); 880 881fail1: 882 EFSYS_PROBE1(fail1, efx_rc_t, rc); 883 884 return (rc); 885} 886 887#if EFSYS_OPT_DIAG 888 889 __checkReturn efx_rc_t 890efx_mcdi_nvram_test( 891 __in efx_nic_t *enp, 892 __in uint32_t partn) 893{ 894 efx_mcdi_req_t req; 895 uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN, 896 MC_CMD_NVRAM_TEST_OUT_LEN)]; 897 int result; 898 efx_rc_t rc; 899 900 (void) memset(payload, 0, sizeof (payload)); 901 req.emr_cmd = MC_CMD_NVRAM_TEST; 902 req.emr_in_buf = payload; 903 req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN; 904 req.emr_out_buf = payload; 905 req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN; 906 907 MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn); 908 909 efx_mcdi_execute(enp, &req); 910 911 if (req.emr_rc != 0) { 912 rc = req.emr_rc; 913 goto fail1; 914 } 915 916 if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) { 917 rc = EMSGSIZE; 918 goto fail2; 919 } 920 921 result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT); 922 if (result == MC_CMD_NVRAM_TEST_FAIL) { 923 924 EFSYS_PROBE1(nvram_test_failure, int, partn); 925 926 rc = (EINVAL); 927 goto fail3; 928 } 929 930 return (0); 931 932fail3: 933 EFSYS_PROBE(fail3); 934fail2: 935 EFSYS_PROBE(fail2); 936fail1: 937 EFSYS_PROBE1(fail1, efx_rc_t, rc); 938 939 return (rc); 940} 941 942#endif /* EFSYS_OPT_DIAG */ 943 944 945#endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */ 946