1e948693eSPhilip Paeps /*- 2718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3718cf2ccSPedro F. Giffuni * 4929c7febSAndrew Rybchenko * Copyright (c) 2009-2016 Solarflare Communications Inc. 53c838a9fSAndrew Rybchenko * All rights reserved. 6e948693eSPhilip Paeps * 7e948693eSPhilip Paeps * Redistribution and use in source and binary forms, with or without 83c838a9fSAndrew Rybchenko * modification, are permitted provided that the following conditions are met: 9e948693eSPhilip Paeps * 103c838a9fSAndrew Rybchenko * 1. Redistributions of source code must retain the above copyright notice, 113c838a9fSAndrew Rybchenko * this list of conditions and the following disclaimer. 123c838a9fSAndrew Rybchenko * 2. Redistributions in binary form must reproduce the above copyright notice, 133c838a9fSAndrew Rybchenko * this list of conditions and the following disclaimer in the documentation 143c838a9fSAndrew Rybchenko * and/or other materials provided with the distribution. 153c838a9fSAndrew Rybchenko * 163c838a9fSAndrew Rybchenko * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 173c838a9fSAndrew Rybchenko * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 183c838a9fSAndrew Rybchenko * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 193c838a9fSAndrew Rybchenko * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 203c838a9fSAndrew Rybchenko * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 213c838a9fSAndrew Rybchenko * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 223c838a9fSAndrew Rybchenko * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 233c838a9fSAndrew Rybchenko * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 243c838a9fSAndrew Rybchenko * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 253c838a9fSAndrew Rybchenko * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 263c838a9fSAndrew Rybchenko * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 273c838a9fSAndrew Rybchenko * 283c838a9fSAndrew Rybchenko * The views and conclusions contained in the software and documentation are 293c838a9fSAndrew Rybchenko * those of the authors and should not be interpreted as representing official 303c838a9fSAndrew Rybchenko * policies, either expressed or implied, of the FreeBSD Project. 31e948693eSPhilip Paeps */ 32e948693eSPhilip Paeps 335dee87d7SPhilip Paeps #include <sys/cdefs.h> 345dee87d7SPhilip Paeps __FBSDID("$FreeBSD$"); 355dee87d7SPhilip Paeps 36e948693eSPhilip Paeps #include "efx.h" 37e948693eSPhilip Paeps #include "efx_impl.h" 38e948693eSPhilip Paeps 39e948693eSPhilip Paeps #if EFSYS_OPT_VPD 40e948693eSPhilip Paeps 41e948693eSPhilip Paeps #define TAG_TYPE_LBN 7 42e948693eSPhilip Paeps #define TAG_TYPE_WIDTH 1 43e948693eSPhilip Paeps #define TAG_TYPE_LARGE_ITEM_DECODE 1 44e948693eSPhilip Paeps #define TAG_TYPE_SMALL_ITEM_DECODE 0 45e948693eSPhilip Paeps 46e948693eSPhilip Paeps #define TAG_SMALL_ITEM_NAME_LBN 3 47e948693eSPhilip Paeps #define TAG_SMALL_ITEM_NAME_WIDTH 4 48e948693eSPhilip Paeps #define TAG_SMALL_ITEM_SIZE_LBN 0 49e948693eSPhilip Paeps #define TAG_SMALL_ITEM_SIZE_WIDTH 3 50e948693eSPhilip Paeps 51e948693eSPhilip Paeps #define TAG_LARGE_ITEM_NAME_LBN 0 52e948693eSPhilip Paeps #define TAG_LARGE_ITEM_NAME_WIDTH 7 53e948693eSPhilip Paeps 54e948693eSPhilip Paeps #define TAG_NAME_END_DECODE 0x0f 55e948693eSPhilip Paeps #define TAG_NAME_ID_STRING_DECODE 0x02 56e948693eSPhilip Paeps #define TAG_NAME_VPD_R_DECODE 0x10 57e948693eSPhilip Paeps #define TAG_NAME_VPD_W_DECODE 0x11 58e948693eSPhilip Paeps 59e948693eSPhilip Paeps #if EFSYS_OPT_SIENA 60e948693eSPhilip Paeps 61ec831f7fSAndrew Rybchenko static const efx_vpd_ops_t __efx_vpd_siena_ops = { 62e948693eSPhilip Paeps siena_vpd_init, /* evpdo_init */ 63e948693eSPhilip Paeps siena_vpd_size, /* evpdo_size */ 64e948693eSPhilip Paeps siena_vpd_read, /* evpdo_read */ 65e948693eSPhilip Paeps siena_vpd_verify, /* evpdo_verify */ 66e948693eSPhilip Paeps siena_vpd_reinit, /* evpdo_reinit */ 67e948693eSPhilip Paeps siena_vpd_get, /* evpdo_get */ 68e948693eSPhilip Paeps siena_vpd_set, /* evpdo_set */ 69e948693eSPhilip Paeps siena_vpd_next, /* evpdo_next */ 70e948693eSPhilip Paeps siena_vpd_write, /* evpdo_write */ 71e948693eSPhilip Paeps siena_vpd_fini, /* evpdo_fini */ 72e948693eSPhilip Paeps }; 73e948693eSPhilip Paeps 74e948693eSPhilip Paeps #endif /* EFSYS_OPT_SIENA */ 75e948693eSPhilip Paeps 76*77226f89SAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 773c838a9fSAndrew Rybchenko 78ec831f7fSAndrew Rybchenko static const efx_vpd_ops_t __efx_vpd_ef10_ops = { 795311abfaSAndrew Rybchenko ef10_vpd_init, /* evpdo_init */ 805311abfaSAndrew Rybchenko ef10_vpd_size, /* evpdo_size */ 815311abfaSAndrew Rybchenko ef10_vpd_read, /* evpdo_read */ 825311abfaSAndrew Rybchenko ef10_vpd_verify, /* evpdo_verify */ 835311abfaSAndrew Rybchenko ef10_vpd_reinit, /* evpdo_reinit */ 845311abfaSAndrew Rybchenko ef10_vpd_get, /* evpdo_get */ 855311abfaSAndrew Rybchenko ef10_vpd_set, /* evpdo_set */ 865311abfaSAndrew Rybchenko ef10_vpd_next, /* evpdo_next */ 875311abfaSAndrew Rybchenko ef10_vpd_write, /* evpdo_write */ 885311abfaSAndrew Rybchenko ef10_vpd_fini, /* evpdo_fini */ 893c838a9fSAndrew Rybchenko }; 903c838a9fSAndrew Rybchenko 91*77226f89SAndrew Rybchenko #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */ 923c838a9fSAndrew Rybchenko 93460cb568SAndrew Rybchenko __checkReturn efx_rc_t 94e948693eSPhilip Paeps efx_vpd_init( 95e948693eSPhilip Paeps __in efx_nic_t *enp) 96e948693eSPhilip Paeps { 97ec831f7fSAndrew Rybchenko const efx_vpd_ops_t *evpdop; 98460cb568SAndrew Rybchenko efx_rc_t rc; 99e948693eSPhilip Paeps 100e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 101e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 102e948693eSPhilip Paeps EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_VPD)); 103e948693eSPhilip Paeps 104e948693eSPhilip Paeps switch (enp->en_family) { 105e948693eSPhilip Paeps #if EFSYS_OPT_SIENA 106e948693eSPhilip Paeps case EFX_FAMILY_SIENA: 107ec831f7fSAndrew Rybchenko evpdop = &__efx_vpd_siena_ops; 108e948693eSPhilip Paeps break; 109e948693eSPhilip Paeps #endif /* EFSYS_OPT_SIENA */ 110e948693eSPhilip Paeps 1113c838a9fSAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON 1123c838a9fSAndrew Rybchenko case EFX_FAMILY_HUNTINGTON: 113ec831f7fSAndrew Rybchenko evpdop = &__efx_vpd_ef10_ops; 1143c838a9fSAndrew Rybchenko break; 1153c838a9fSAndrew Rybchenko #endif /* EFSYS_OPT_HUNTINGTON */ 1163c838a9fSAndrew Rybchenko 1175311abfaSAndrew Rybchenko #if EFSYS_OPT_MEDFORD 1185311abfaSAndrew Rybchenko case EFX_FAMILY_MEDFORD: 119ec831f7fSAndrew Rybchenko evpdop = &__efx_vpd_ef10_ops; 1205311abfaSAndrew Rybchenko break; 1215311abfaSAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD */ 1225311abfaSAndrew Rybchenko 123*77226f89SAndrew Rybchenko #if EFSYS_OPT_MEDFORD2 124*77226f89SAndrew Rybchenko case EFX_FAMILY_MEDFORD2: 125*77226f89SAndrew Rybchenko evpdop = &__efx_vpd_ef10_ops; 126*77226f89SAndrew Rybchenko break; 127*77226f89SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD2 */ 128*77226f89SAndrew Rybchenko 129e948693eSPhilip Paeps default: 130e948693eSPhilip Paeps EFSYS_ASSERT(0); 131e948693eSPhilip Paeps rc = ENOTSUP; 132e948693eSPhilip Paeps goto fail1; 133e948693eSPhilip Paeps } 134e948693eSPhilip Paeps 135e948693eSPhilip Paeps if (evpdop->evpdo_init != NULL) { 136e948693eSPhilip Paeps if ((rc = evpdop->evpdo_init(enp)) != 0) 137e948693eSPhilip Paeps goto fail2; 138e948693eSPhilip Paeps } 139e948693eSPhilip Paeps 140e948693eSPhilip Paeps enp->en_evpdop = evpdop; 141e948693eSPhilip Paeps enp->en_mod_flags |= EFX_MOD_VPD; 142e948693eSPhilip Paeps 143e948693eSPhilip Paeps return (0); 144e948693eSPhilip Paeps 145e948693eSPhilip Paeps fail2: 146e948693eSPhilip Paeps EFSYS_PROBE(fail2); 147e948693eSPhilip Paeps fail1: 148460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 149e948693eSPhilip Paeps 150e948693eSPhilip Paeps return (rc); 151e948693eSPhilip Paeps } 152e948693eSPhilip Paeps 153460cb568SAndrew Rybchenko __checkReturn efx_rc_t 154e948693eSPhilip Paeps efx_vpd_size( 155e948693eSPhilip Paeps __in efx_nic_t *enp, 156e948693eSPhilip Paeps __out size_t *sizep) 157e948693eSPhilip Paeps { 158ec831f7fSAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop; 159460cb568SAndrew Rybchenko efx_rc_t rc; 160e948693eSPhilip Paeps 161e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 162e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); 163e948693eSPhilip Paeps 164e948693eSPhilip Paeps if ((rc = evpdop->evpdo_size(enp, sizep)) != 0) 165e948693eSPhilip Paeps goto fail1; 166e948693eSPhilip Paeps 167e948693eSPhilip Paeps return (0); 168e948693eSPhilip Paeps 169e948693eSPhilip Paeps fail1: 170460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 171e948693eSPhilip Paeps 172e948693eSPhilip Paeps return (rc); 173e948693eSPhilip Paeps } 174e948693eSPhilip Paeps 175460cb568SAndrew Rybchenko __checkReturn efx_rc_t 176e948693eSPhilip Paeps efx_vpd_read( 177e948693eSPhilip Paeps __in efx_nic_t *enp, 178e948693eSPhilip Paeps __out_bcount(size) caddr_t data, 179e948693eSPhilip Paeps __in size_t size) 180e948693eSPhilip Paeps { 181ec831f7fSAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop; 182460cb568SAndrew Rybchenko efx_rc_t rc; 183e948693eSPhilip Paeps 184e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 185e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); 186e948693eSPhilip Paeps 187e948693eSPhilip Paeps if ((rc = evpdop->evpdo_read(enp, data, size)) != 0) 188e948693eSPhilip Paeps goto fail1; 189e948693eSPhilip Paeps 190e948693eSPhilip Paeps return (0); 191e948693eSPhilip Paeps 192e948693eSPhilip Paeps fail1: 193460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 194e948693eSPhilip Paeps 195e948693eSPhilip Paeps return (rc); 196e948693eSPhilip Paeps } 197e948693eSPhilip Paeps 198460cb568SAndrew Rybchenko __checkReturn efx_rc_t 199e948693eSPhilip Paeps efx_vpd_verify( 200e948693eSPhilip Paeps __in efx_nic_t *enp, 201e948693eSPhilip Paeps __in_bcount(size) caddr_t data, 202e948693eSPhilip Paeps __in size_t size) 203e948693eSPhilip Paeps { 204ec831f7fSAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop; 205460cb568SAndrew Rybchenko efx_rc_t rc; 206e948693eSPhilip Paeps 207e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 208e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); 209e948693eSPhilip Paeps 210e948693eSPhilip Paeps if ((rc = evpdop->evpdo_verify(enp, data, size)) != 0) 211e948693eSPhilip Paeps goto fail1; 212e948693eSPhilip Paeps 213e948693eSPhilip Paeps return (0); 214e948693eSPhilip Paeps 215e948693eSPhilip Paeps fail1: 216460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 217e948693eSPhilip Paeps 218e948693eSPhilip Paeps return (rc); 219e948693eSPhilip Paeps } 220e948693eSPhilip Paeps 221460cb568SAndrew Rybchenko __checkReturn efx_rc_t 222e948693eSPhilip Paeps efx_vpd_reinit( 223e948693eSPhilip Paeps __in efx_nic_t *enp, 224e948693eSPhilip Paeps __in_bcount(size) caddr_t data, 225e948693eSPhilip Paeps __in size_t size) 226e948693eSPhilip Paeps { 227ec831f7fSAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop; 228460cb568SAndrew Rybchenko efx_rc_t rc; 229e948693eSPhilip Paeps 230e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 231e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); 232e948693eSPhilip Paeps 233e948693eSPhilip Paeps if (evpdop->evpdo_reinit == NULL) { 234e948693eSPhilip Paeps rc = ENOTSUP; 235e948693eSPhilip Paeps goto fail1; 236e948693eSPhilip Paeps } 237e948693eSPhilip Paeps 238e948693eSPhilip Paeps if ((rc = evpdop->evpdo_reinit(enp, data, size)) != 0) 239e948693eSPhilip Paeps goto fail2; 240e948693eSPhilip Paeps 241e948693eSPhilip Paeps return (0); 242e948693eSPhilip Paeps 243e948693eSPhilip Paeps fail2: 244e948693eSPhilip Paeps EFSYS_PROBE(fail2); 245e948693eSPhilip Paeps fail1: 246460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 247e948693eSPhilip Paeps 248e948693eSPhilip Paeps return (rc); 249e948693eSPhilip Paeps } 250e948693eSPhilip Paeps 251460cb568SAndrew Rybchenko __checkReturn efx_rc_t 252e948693eSPhilip Paeps efx_vpd_get( 253e948693eSPhilip Paeps __in efx_nic_t *enp, 254e948693eSPhilip Paeps __in_bcount(size) caddr_t data, 255e948693eSPhilip Paeps __in size_t size, 256e948693eSPhilip Paeps __inout efx_vpd_value_t *evvp) 257e948693eSPhilip Paeps { 258ec831f7fSAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop; 259460cb568SAndrew Rybchenko efx_rc_t rc; 260e948693eSPhilip Paeps 261e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 262e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); 263e948693eSPhilip Paeps 26401215be2SAndrew Rybchenko if ((rc = evpdop->evpdo_get(enp, data, size, evvp)) != 0) { 26501215be2SAndrew Rybchenko if (rc == ENOENT) 26601215be2SAndrew Rybchenko return (rc); 26701215be2SAndrew Rybchenko 268e948693eSPhilip Paeps goto fail1; 26901215be2SAndrew Rybchenko } 270e948693eSPhilip Paeps 271e948693eSPhilip Paeps return (0); 272e948693eSPhilip Paeps 273e948693eSPhilip Paeps fail1: 274460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 275e948693eSPhilip Paeps 276e948693eSPhilip Paeps return (rc); 277e948693eSPhilip Paeps } 278e948693eSPhilip Paeps 279460cb568SAndrew Rybchenko __checkReturn efx_rc_t 280e948693eSPhilip Paeps efx_vpd_set( 281e948693eSPhilip Paeps __in efx_nic_t *enp, 282e948693eSPhilip Paeps __inout_bcount(size) caddr_t data, 283e948693eSPhilip Paeps __in size_t size, 284e948693eSPhilip Paeps __in efx_vpd_value_t *evvp) 285e948693eSPhilip Paeps { 286ec831f7fSAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop; 287460cb568SAndrew Rybchenko efx_rc_t rc; 288e948693eSPhilip Paeps 289e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 290e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); 291e948693eSPhilip Paeps 292e948693eSPhilip Paeps if ((rc = evpdop->evpdo_set(enp, data, size, evvp)) != 0) 293e948693eSPhilip Paeps goto fail1; 294e948693eSPhilip Paeps 295e948693eSPhilip Paeps return (0); 296e948693eSPhilip Paeps 297e948693eSPhilip Paeps fail1: 298460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 299e948693eSPhilip Paeps 300e948693eSPhilip Paeps return (rc); 301e948693eSPhilip Paeps } 302e948693eSPhilip Paeps 303460cb568SAndrew Rybchenko __checkReturn efx_rc_t 304e948693eSPhilip Paeps efx_vpd_next( 305e948693eSPhilip Paeps __in efx_nic_t *enp, 306e948693eSPhilip Paeps __inout_bcount(size) caddr_t data, 307e948693eSPhilip Paeps __in size_t size, 308e948693eSPhilip Paeps __out efx_vpd_value_t *evvp, 309e948693eSPhilip Paeps __inout unsigned int *contp) 310e948693eSPhilip Paeps { 311ec831f7fSAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop; 312460cb568SAndrew Rybchenko efx_rc_t rc; 313e948693eSPhilip Paeps 314e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 315e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); 316e948693eSPhilip Paeps 317e948693eSPhilip Paeps if ((rc = evpdop->evpdo_next(enp, data, size, evvp, contp)) != 0) 318e948693eSPhilip Paeps goto fail1; 319e948693eSPhilip Paeps 320e948693eSPhilip Paeps return (0); 321e948693eSPhilip Paeps 322e948693eSPhilip Paeps fail1: 323460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 324e948693eSPhilip Paeps 325e948693eSPhilip Paeps return (rc); 326e948693eSPhilip Paeps } 327e948693eSPhilip Paeps 328460cb568SAndrew Rybchenko __checkReturn efx_rc_t 329e948693eSPhilip Paeps efx_vpd_write( 330e948693eSPhilip Paeps __in efx_nic_t *enp, 331e948693eSPhilip Paeps __in_bcount(size) caddr_t data, 332e948693eSPhilip Paeps __in size_t size) 333e948693eSPhilip Paeps { 334ec831f7fSAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop; 335460cb568SAndrew Rybchenko efx_rc_t rc; 336e948693eSPhilip Paeps 337e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 338e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); 339e948693eSPhilip Paeps 340e948693eSPhilip Paeps if ((rc = evpdop->evpdo_write(enp, data, size)) != 0) 341e948693eSPhilip Paeps goto fail1; 342e948693eSPhilip Paeps 343e948693eSPhilip Paeps return (0); 344e948693eSPhilip Paeps 345e948693eSPhilip Paeps fail1: 346460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 347e948693eSPhilip Paeps 348e948693eSPhilip Paeps return (rc); 349e948693eSPhilip Paeps } 350e948693eSPhilip Paeps 351460cb568SAndrew Rybchenko static __checkReturn efx_rc_t 352e948693eSPhilip Paeps efx_vpd_next_tag( 353e948693eSPhilip Paeps __in caddr_t data, 354e948693eSPhilip Paeps __in size_t size, 355e948693eSPhilip Paeps __inout unsigned int *offsetp, 356e948693eSPhilip Paeps __out efx_vpd_tag_t *tagp, 357e948693eSPhilip Paeps __out uint16_t *lengthp) 358e948693eSPhilip Paeps { 359e948693eSPhilip Paeps efx_byte_t byte; 360e948693eSPhilip Paeps efx_word_t word; 361e948693eSPhilip Paeps uint8_t name; 362e948693eSPhilip Paeps uint16_t length; 363e948693eSPhilip Paeps size_t headlen; 364460cb568SAndrew Rybchenko efx_rc_t rc; 365e948693eSPhilip Paeps 366e948693eSPhilip Paeps if (*offsetp >= size) { 367e948693eSPhilip Paeps rc = EFAULT; 368e948693eSPhilip Paeps goto fail1; 369e948693eSPhilip Paeps } 370e948693eSPhilip Paeps 371e948693eSPhilip Paeps EFX_POPULATE_BYTE_1(byte, EFX_BYTE_0, data[*offsetp]); 372e948693eSPhilip Paeps 373e948693eSPhilip Paeps switch (EFX_BYTE_FIELD(byte, TAG_TYPE)) { 374e948693eSPhilip Paeps case TAG_TYPE_SMALL_ITEM_DECODE: 375e948693eSPhilip Paeps headlen = 1; 376e948693eSPhilip Paeps 377e948693eSPhilip Paeps name = EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_NAME); 378e948693eSPhilip Paeps length = (uint16_t)EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_SIZE); 379e948693eSPhilip Paeps 380e948693eSPhilip Paeps break; 381e948693eSPhilip Paeps 382e948693eSPhilip Paeps case TAG_TYPE_LARGE_ITEM_DECODE: 383e948693eSPhilip Paeps headlen = 3; 384e948693eSPhilip Paeps 385e948693eSPhilip Paeps if (*offsetp + headlen > size) { 386e948693eSPhilip Paeps rc = EFAULT; 387e948693eSPhilip Paeps goto fail2; 388e948693eSPhilip Paeps } 389e948693eSPhilip Paeps 390e948693eSPhilip Paeps name = EFX_BYTE_FIELD(byte, TAG_LARGE_ITEM_NAME); 391e948693eSPhilip Paeps EFX_POPULATE_WORD_2(word, 392e948693eSPhilip Paeps EFX_BYTE_0, data[*offsetp + 1], 393e948693eSPhilip Paeps EFX_BYTE_1, data[*offsetp + 2]); 394e948693eSPhilip Paeps length = EFX_WORD_FIELD(word, EFX_WORD_0); 395e948693eSPhilip Paeps 396e948693eSPhilip Paeps break; 397e948693eSPhilip Paeps 398e948693eSPhilip Paeps default: 399e948693eSPhilip Paeps rc = EFAULT; 400e948693eSPhilip Paeps goto fail2; 401e948693eSPhilip Paeps } 402e948693eSPhilip Paeps 403e948693eSPhilip Paeps if (*offsetp + headlen + length > size) { 404e948693eSPhilip Paeps rc = EFAULT; 405e948693eSPhilip Paeps goto fail3; 406e948693eSPhilip Paeps } 407e948693eSPhilip Paeps 408e948693eSPhilip Paeps EFX_STATIC_ASSERT(TAG_NAME_END_DECODE == EFX_VPD_END); 409e948693eSPhilip Paeps EFX_STATIC_ASSERT(TAG_NAME_ID_STRING_DECODE == EFX_VPD_ID); 410e948693eSPhilip Paeps EFX_STATIC_ASSERT(TAG_NAME_VPD_R_DECODE == EFX_VPD_RO); 411e948693eSPhilip Paeps EFX_STATIC_ASSERT(TAG_NAME_VPD_W_DECODE == EFX_VPD_RW); 412e948693eSPhilip Paeps if (name != EFX_VPD_END && name != EFX_VPD_ID && 413e948693eSPhilip Paeps name != EFX_VPD_RO) { 414e948693eSPhilip Paeps rc = EFAULT; 415e948693eSPhilip Paeps goto fail4; 416e948693eSPhilip Paeps } 417e948693eSPhilip Paeps 418e948693eSPhilip Paeps *tagp = name; 419e948693eSPhilip Paeps *lengthp = length; 420e948693eSPhilip Paeps *offsetp += headlen; 421e948693eSPhilip Paeps 422e948693eSPhilip Paeps return (0); 423e948693eSPhilip Paeps 424e948693eSPhilip Paeps fail4: 425e948693eSPhilip Paeps EFSYS_PROBE(fail4); 426e948693eSPhilip Paeps fail3: 427e948693eSPhilip Paeps EFSYS_PROBE(fail3); 428e948693eSPhilip Paeps fail2: 429e948693eSPhilip Paeps EFSYS_PROBE(fail2); 430e948693eSPhilip Paeps fail1: 431460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 432e948693eSPhilip Paeps 433e948693eSPhilip Paeps return (rc); 434e948693eSPhilip Paeps } 435e948693eSPhilip Paeps 436460cb568SAndrew Rybchenko static __checkReturn efx_rc_t 437e948693eSPhilip Paeps efx_vpd_next_keyword( 438e948693eSPhilip Paeps __in_bcount(size) caddr_t tag, 439e948693eSPhilip Paeps __in size_t size, 440e948693eSPhilip Paeps __in unsigned int pos, 441e948693eSPhilip Paeps __out efx_vpd_keyword_t *keywordp, 442e948693eSPhilip Paeps __out uint8_t *lengthp) 443e948693eSPhilip Paeps { 444e948693eSPhilip Paeps efx_vpd_keyword_t keyword; 445e948693eSPhilip Paeps uint8_t length; 446460cb568SAndrew Rybchenko efx_rc_t rc; 447e948693eSPhilip Paeps 448e948693eSPhilip Paeps if (pos + 3U > size) { 449e948693eSPhilip Paeps rc = EFAULT; 450e948693eSPhilip Paeps goto fail1; 451e948693eSPhilip Paeps } 452e948693eSPhilip Paeps 453e948693eSPhilip Paeps keyword = EFX_VPD_KEYWORD(tag[pos], tag[pos + 1]); 454e948693eSPhilip Paeps length = tag[pos + 2]; 455e948693eSPhilip Paeps 456e948693eSPhilip Paeps if (length == 0 || pos + 3U + length > size) { 457e948693eSPhilip Paeps rc = EFAULT; 458e948693eSPhilip Paeps goto fail2; 459e948693eSPhilip Paeps } 460e948693eSPhilip Paeps 461e948693eSPhilip Paeps *keywordp = keyword; 462e948693eSPhilip Paeps *lengthp = length; 463e948693eSPhilip Paeps 464e948693eSPhilip Paeps return (0); 465e948693eSPhilip Paeps 466e948693eSPhilip Paeps fail2: 467e948693eSPhilip Paeps EFSYS_PROBE(fail2); 468e948693eSPhilip Paeps fail1: 469460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 470e948693eSPhilip Paeps 471e948693eSPhilip Paeps return (rc); 472e948693eSPhilip Paeps } 473e948693eSPhilip Paeps 474460cb568SAndrew Rybchenko __checkReturn efx_rc_t 475e948693eSPhilip Paeps efx_vpd_hunk_length( 476e948693eSPhilip Paeps __in_bcount(size) caddr_t data, 477e948693eSPhilip Paeps __in size_t size, 478e948693eSPhilip Paeps __out size_t *lengthp) 479e948693eSPhilip Paeps { 480e948693eSPhilip Paeps efx_vpd_tag_t tag; 481e948693eSPhilip Paeps unsigned int offset; 482e948693eSPhilip Paeps uint16_t taglen; 483460cb568SAndrew Rybchenko efx_rc_t rc; 484e948693eSPhilip Paeps 485e948693eSPhilip Paeps offset = 0; 486e948693eSPhilip Paeps _NOTE(CONSTANTCONDITION) 487e948693eSPhilip Paeps while (1) { 488e948693eSPhilip Paeps if ((rc = efx_vpd_next_tag(data, size, &offset, 489e948693eSPhilip Paeps &tag, &taglen)) != 0) 490e948693eSPhilip Paeps goto fail1; 491e948693eSPhilip Paeps offset += taglen; 492e948693eSPhilip Paeps if (tag == EFX_VPD_END) 493e948693eSPhilip Paeps break; 494e948693eSPhilip Paeps } 495e948693eSPhilip Paeps 496e948693eSPhilip Paeps *lengthp = offset; 497e948693eSPhilip Paeps 498e948693eSPhilip Paeps return (0); 499e948693eSPhilip Paeps 500e948693eSPhilip Paeps fail1: 501460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 502e948693eSPhilip Paeps 503e948693eSPhilip Paeps return (rc); 504e948693eSPhilip Paeps } 505e948693eSPhilip Paeps 506460cb568SAndrew Rybchenko __checkReturn efx_rc_t 507e948693eSPhilip Paeps efx_vpd_hunk_verify( 508e948693eSPhilip Paeps __in_bcount(size) caddr_t data, 509e948693eSPhilip Paeps __in size_t size, 510e948693eSPhilip Paeps __out_opt boolean_t *cksummedp) 511e948693eSPhilip Paeps { 512e948693eSPhilip Paeps efx_vpd_tag_t tag; 513e948693eSPhilip Paeps efx_vpd_keyword_t keyword; 514e948693eSPhilip Paeps unsigned int offset; 515e948693eSPhilip Paeps unsigned int pos; 516e948693eSPhilip Paeps unsigned int i; 517e948693eSPhilip Paeps uint16_t taglen; 518e948693eSPhilip Paeps uint8_t keylen; 519e948693eSPhilip Paeps uint8_t cksum; 520e948693eSPhilip Paeps boolean_t cksummed = B_FALSE; 521460cb568SAndrew Rybchenko efx_rc_t rc; 522e948693eSPhilip Paeps 523e948693eSPhilip Paeps /* 524e948693eSPhilip Paeps * Parse every tag,keyword in the existing VPD. If the csum is present, 525e948693eSPhilip Paeps * the assert it is correct, and is the final keyword in the RO block. 526e948693eSPhilip Paeps */ 527e948693eSPhilip Paeps offset = 0; 528e948693eSPhilip Paeps _NOTE(CONSTANTCONDITION) 529e948693eSPhilip Paeps while (1) { 530e948693eSPhilip Paeps if ((rc = efx_vpd_next_tag(data, size, &offset, 531e948693eSPhilip Paeps &tag, &taglen)) != 0) 532e948693eSPhilip Paeps goto fail1; 533e948693eSPhilip Paeps if (tag == EFX_VPD_END) 534e948693eSPhilip Paeps break; 535e948693eSPhilip Paeps else if (tag == EFX_VPD_ID) 536e948693eSPhilip Paeps goto done; 537e948693eSPhilip Paeps 538e948693eSPhilip Paeps for (pos = 0; pos != taglen; pos += 3 + keylen) { 539e948693eSPhilip Paeps /* RV keyword must be the last in the block */ 5409dbc22c5SAndrew Rybchenko if (cksummed) { 5419dbc22c5SAndrew Rybchenko rc = EFAULT; 542e948693eSPhilip Paeps goto fail2; 5439dbc22c5SAndrew Rybchenko } 544e948693eSPhilip Paeps 545e948693eSPhilip Paeps if ((rc = efx_vpd_next_keyword(data + offset, 546e948693eSPhilip Paeps taglen, pos, &keyword, &keylen)) != 0) 547e948693eSPhilip Paeps goto fail3; 548e948693eSPhilip Paeps 549e948693eSPhilip Paeps if (keyword == EFX_VPD_KEYWORD('R', 'V')) { 550e948693eSPhilip Paeps cksum = 0; 551e948693eSPhilip Paeps for (i = 0; i < offset + pos + 4; i++) 552e948693eSPhilip Paeps cksum += data[i]; 553e948693eSPhilip Paeps 554e948693eSPhilip Paeps if (cksum != 0) { 555e948693eSPhilip Paeps rc = EFAULT; 556e948693eSPhilip Paeps goto fail4; 557e948693eSPhilip Paeps } 558e948693eSPhilip Paeps 559e948693eSPhilip Paeps cksummed = B_TRUE; 560e948693eSPhilip Paeps } 561e948693eSPhilip Paeps } 562e948693eSPhilip Paeps 563e948693eSPhilip Paeps done: 564e948693eSPhilip Paeps offset += taglen; 565e948693eSPhilip Paeps } 566e948693eSPhilip Paeps 567e948693eSPhilip Paeps if (!cksummed) { 568e948693eSPhilip Paeps rc = EFAULT; 569e948693eSPhilip Paeps goto fail5; 570e948693eSPhilip Paeps } 571e948693eSPhilip Paeps 572e948693eSPhilip Paeps if (cksummedp != NULL) 573e948693eSPhilip Paeps *cksummedp = cksummed; 574e948693eSPhilip Paeps 575e948693eSPhilip Paeps return (0); 576e948693eSPhilip Paeps 577e948693eSPhilip Paeps fail5: 578e948693eSPhilip Paeps EFSYS_PROBE(fail5); 579e948693eSPhilip Paeps fail4: 580e948693eSPhilip Paeps EFSYS_PROBE(fail4); 581e948693eSPhilip Paeps fail3: 582e948693eSPhilip Paeps EFSYS_PROBE(fail3); 583e948693eSPhilip Paeps fail2: 584e948693eSPhilip Paeps EFSYS_PROBE(fail2); 585e948693eSPhilip Paeps fail1: 586460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 587e948693eSPhilip Paeps 588e948693eSPhilip Paeps return (rc); 589e948693eSPhilip Paeps } 590e948693eSPhilip Paeps 5913c838a9fSAndrew Rybchenko static uint8_t __efx_vpd_blank_pid[] = { 592e948693eSPhilip Paeps /* Large resource type ID length 1 */ 593e948693eSPhilip Paeps 0x82, 0x01, 0x00, 594e948693eSPhilip Paeps /* Product name ' ' */ 595e948693eSPhilip Paeps 0x32, 596e948693eSPhilip Paeps }; 597e948693eSPhilip Paeps 5983c838a9fSAndrew Rybchenko static uint8_t __efx_vpd_blank_r[] = { 599e948693eSPhilip Paeps /* Large resource type VPD-R length 4 */ 600e948693eSPhilip Paeps 0x90, 0x04, 0x00, 601e948693eSPhilip Paeps /* RV keyword length 1 */ 602e948693eSPhilip Paeps 'R', 'V', 0x01, 603e948693eSPhilip Paeps /* RV payload checksum */ 604e948693eSPhilip Paeps 0x00, 605e948693eSPhilip Paeps }; 606e948693eSPhilip Paeps 607460cb568SAndrew Rybchenko __checkReturn efx_rc_t 608e948693eSPhilip Paeps efx_vpd_hunk_reinit( 6093c838a9fSAndrew Rybchenko __in_bcount(size) caddr_t data, 610e948693eSPhilip Paeps __in size_t size, 611e948693eSPhilip Paeps __in boolean_t wantpid) 612e948693eSPhilip Paeps { 613e948693eSPhilip Paeps unsigned int offset = 0; 614e948693eSPhilip Paeps unsigned int pos; 615e948693eSPhilip Paeps efx_byte_t byte; 616e948693eSPhilip Paeps uint8_t cksum; 617460cb568SAndrew Rybchenko efx_rc_t rc; 618e948693eSPhilip Paeps 619e948693eSPhilip Paeps if (size < 0x100) { 620e948693eSPhilip Paeps rc = ENOSPC; 621e948693eSPhilip Paeps goto fail1; 622e948693eSPhilip Paeps } 623e948693eSPhilip Paeps 624e948693eSPhilip Paeps if (wantpid) { 625e948693eSPhilip Paeps memcpy(data + offset, __efx_vpd_blank_pid, 626e948693eSPhilip Paeps sizeof (__efx_vpd_blank_pid)); 627e948693eSPhilip Paeps offset += sizeof (__efx_vpd_blank_pid); 628e948693eSPhilip Paeps } 629e948693eSPhilip Paeps 630e948693eSPhilip Paeps memcpy(data + offset, __efx_vpd_blank_r, sizeof (__efx_vpd_blank_r)); 631e948693eSPhilip Paeps offset += sizeof (__efx_vpd_blank_r); 632e948693eSPhilip Paeps 633e948693eSPhilip Paeps /* Update checksum */ 634e948693eSPhilip Paeps cksum = 0; 635e948693eSPhilip Paeps for (pos = 0; pos < offset; pos++) 636e948693eSPhilip Paeps cksum += data[pos]; 637e948693eSPhilip Paeps data[offset - 1] -= cksum; 638e948693eSPhilip Paeps 639e948693eSPhilip Paeps /* Append trailing tag */ 640e948693eSPhilip Paeps EFX_POPULATE_BYTE_3(byte, 641e948693eSPhilip Paeps TAG_TYPE, TAG_TYPE_SMALL_ITEM_DECODE, 642e948693eSPhilip Paeps TAG_SMALL_ITEM_NAME, TAG_NAME_END_DECODE, 643e948693eSPhilip Paeps TAG_SMALL_ITEM_SIZE, 0); 644e948693eSPhilip Paeps data[offset] = EFX_BYTE_FIELD(byte, EFX_BYTE_0); 645e948693eSPhilip Paeps offset++; 646e948693eSPhilip Paeps 647e948693eSPhilip Paeps return (0); 648e948693eSPhilip Paeps 649e948693eSPhilip Paeps fail1: 650460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 651e948693eSPhilip Paeps 652e948693eSPhilip Paeps return (rc); 653e948693eSPhilip Paeps } 654e948693eSPhilip Paeps 655460cb568SAndrew Rybchenko __checkReturn efx_rc_t 656e948693eSPhilip Paeps efx_vpd_hunk_next( 657e948693eSPhilip Paeps __in_bcount(size) caddr_t data, 658e948693eSPhilip Paeps __in size_t size, 659e948693eSPhilip Paeps __out efx_vpd_tag_t *tagp, 660e948693eSPhilip Paeps __out efx_vpd_keyword_t *keywordp, 66172cda832SAndrew Rybchenko __out_opt unsigned int *payloadp, 662e948693eSPhilip Paeps __out_opt uint8_t *paylenp, 663e948693eSPhilip Paeps __inout unsigned int *contp) 664e948693eSPhilip Paeps { 665e948693eSPhilip Paeps efx_vpd_tag_t tag; 666e948693eSPhilip Paeps efx_vpd_keyword_t keyword = 0; 667e948693eSPhilip Paeps unsigned int offset; 668e948693eSPhilip Paeps unsigned int pos; 669e948693eSPhilip Paeps unsigned int index; 670e948693eSPhilip Paeps uint16_t taglen; 671e948693eSPhilip Paeps uint8_t keylen; 672e948693eSPhilip Paeps uint8_t paylen; 673460cb568SAndrew Rybchenko efx_rc_t rc; 674e948693eSPhilip Paeps 675e948693eSPhilip Paeps offset = index = 0; 676e948693eSPhilip Paeps _NOTE(CONSTANTCONDITION) 677e948693eSPhilip Paeps while (1) { 678e948693eSPhilip Paeps if ((rc = efx_vpd_next_tag(data, size, &offset, 679e948693eSPhilip Paeps &tag, &taglen)) != 0) 680e948693eSPhilip Paeps goto fail1; 68172cda832SAndrew Rybchenko 68272cda832SAndrew Rybchenko if (tag == EFX_VPD_END) { 68372cda832SAndrew Rybchenko keyword = 0; 68472cda832SAndrew Rybchenko paylen = 0; 68572cda832SAndrew Rybchenko index = 0; 686e948693eSPhilip Paeps break; 68772cda832SAndrew Rybchenko } 688e948693eSPhilip Paeps 689e948693eSPhilip Paeps if (tag == EFX_VPD_ID) { 69072cda832SAndrew Rybchenko if (index++ == *contp) { 691e948693eSPhilip Paeps EFSYS_ASSERT3U(taglen, <, 0x100); 69272cda832SAndrew Rybchenko keyword = 0; 693e948693eSPhilip Paeps paylen = (uint8_t)MIN(taglen, 0xff); 694e948693eSPhilip Paeps 695e948693eSPhilip Paeps goto done; 696e948693eSPhilip Paeps } 697e948693eSPhilip Paeps } else { 698e948693eSPhilip Paeps for (pos = 0; pos != taglen; pos += 3 + keylen) { 699e948693eSPhilip Paeps if ((rc = efx_vpd_next_keyword(data + offset, 700e948693eSPhilip Paeps taglen, pos, &keyword, &keylen)) != 0) 701e948693eSPhilip Paeps goto fail2; 702e948693eSPhilip Paeps 70372cda832SAndrew Rybchenko if (index++ == *contp) { 704e948693eSPhilip Paeps offset += pos + 3; 705e948693eSPhilip Paeps paylen = keylen; 706e948693eSPhilip Paeps 707e948693eSPhilip Paeps goto done; 708e948693eSPhilip Paeps } 709e948693eSPhilip Paeps } 710e948693eSPhilip Paeps } 711e948693eSPhilip Paeps 712e948693eSPhilip Paeps offset += taglen; 713e948693eSPhilip Paeps } 714e948693eSPhilip Paeps 715e948693eSPhilip Paeps done: 716e948693eSPhilip Paeps *tagp = tag; 717e948693eSPhilip Paeps *keywordp = keyword; 718e948693eSPhilip Paeps if (payloadp != NULL) 719e948693eSPhilip Paeps *payloadp = offset; 720e948693eSPhilip Paeps if (paylenp != NULL) 721e948693eSPhilip Paeps *paylenp = paylen; 722e948693eSPhilip Paeps 72372cda832SAndrew Rybchenko *contp = index; 724e948693eSPhilip Paeps return (0); 725e948693eSPhilip Paeps 726e948693eSPhilip Paeps fail2: 727e948693eSPhilip Paeps EFSYS_PROBE(fail2); 728e948693eSPhilip Paeps fail1: 729460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 730e948693eSPhilip Paeps 731e948693eSPhilip Paeps return (rc); 732e948693eSPhilip Paeps } 733e948693eSPhilip Paeps 734460cb568SAndrew Rybchenko __checkReturn efx_rc_t 735e948693eSPhilip Paeps efx_vpd_hunk_get( 736e948693eSPhilip Paeps __in_bcount(size) caddr_t data, 737e948693eSPhilip Paeps __in size_t size, 738e948693eSPhilip Paeps __in efx_vpd_tag_t tag, 739e948693eSPhilip Paeps __in efx_vpd_keyword_t keyword, 740e948693eSPhilip Paeps __out unsigned int *payloadp, 741e948693eSPhilip Paeps __out uint8_t *paylenp) 742e948693eSPhilip Paeps { 743e948693eSPhilip Paeps efx_vpd_tag_t itag; 744e948693eSPhilip Paeps efx_vpd_keyword_t ikeyword; 745e948693eSPhilip Paeps unsigned int offset; 746e948693eSPhilip Paeps unsigned int pos; 747e948693eSPhilip Paeps uint16_t taglen; 748e948693eSPhilip Paeps uint8_t keylen; 749460cb568SAndrew Rybchenko efx_rc_t rc; 750e948693eSPhilip Paeps 751e948693eSPhilip Paeps offset = 0; 752e948693eSPhilip Paeps _NOTE(CONSTANTCONDITION) 753e948693eSPhilip Paeps while (1) { 754e948693eSPhilip Paeps if ((rc = efx_vpd_next_tag(data, size, &offset, 755e948693eSPhilip Paeps &itag, &taglen)) != 0) 756e948693eSPhilip Paeps goto fail1; 757e948693eSPhilip Paeps if (itag == EFX_VPD_END) 758e948693eSPhilip Paeps break; 759e948693eSPhilip Paeps 760e948693eSPhilip Paeps if (itag == tag) { 761e948693eSPhilip Paeps if (itag == EFX_VPD_ID) { 762e948693eSPhilip Paeps EFSYS_ASSERT3U(taglen, <, 0x100); 763e948693eSPhilip Paeps 764e948693eSPhilip Paeps *paylenp = (uint8_t)MIN(taglen, 0xff); 765e948693eSPhilip Paeps *payloadp = offset; 766e948693eSPhilip Paeps return (0); 767e948693eSPhilip Paeps } 768e948693eSPhilip Paeps 769e948693eSPhilip Paeps for (pos = 0; pos != taglen; pos += 3 + keylen) { 770e948693eSPhilip Paeps if ((rc = efx_vpd_next_keyword(data + offset, 771e948693eSPhilip Paeps taglen, pos, &ikeyword, &keylen)) != 0) 772e948693eSPhilip Paeps goto fail2; 773e948693eSPhilip Paeps 774e948693eSPhilip Paeps if (ikeyword == keyword) { 775e948693eSPhilip Paeps *paylenp = keylen; 776e948693eSPhilip Paeps *payloadp = offset + pos + 3; 777e948693eSPhilip Paeps return (0); 778e948693eSPhilip Paeps } 779e948693eSPhilip Paeps } 780e948693eSPhilip Paeps } 781e948693eSPhilip Paeps 782e948693eSPhilip Paeps offset += taglen; 783e948693eSPhilip Paeps } 784e948693eSPhilip Paeps 785e948693eSPhilip Paeps /* Not an error */ 786e948693eSPhilip Paeps return (ENOENT); 787e948693eSPhilip Paeps 788e948693eSPhilip Paeps fail2: 789e948693eSPhilip Paeps EFSYS_PROBE(fail2); 790e948693eSPhilip Paeps fail1: 791460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 792e948693eSPhilip Paeps 793e948693eSPhilip Paeps return (rc); 794e948693eSPhilip Paeps } 795e948693eSPhilip Paeps 796460cb568SAndrew Rybchenko __checkReturn efx_rc_t 797e948693eSPhilip Paeps efx_vpd_hunk_set( 798e948693eSPhilip Paeps __in_bcount(size) caddr_t data, 799e948693eSPhilip Paeps __in size_t size, 800e948693eSPhilip Paeps __in efx_vpd_value_t *evvp) 801e948693eSPhilip Paeps { 802e948693eSPhilip Paeps efx_word_t word; 803e948693eSPhilip Paeps efx_vpd_tag_t tag; 804e948693eSPhilip Paeps efx_vpd_keyword_t keyword; 805e948693eSPhilip Paeps unsigned int offset; 806e948693eSPhilip Paeps unsigned int pos; 807e948693eSPhilip Paeps unsigned int taghead; 808e948693eSPhilip Paeps unsigned int source; 809e948693eSPhilip Paeps unsigned int dest; 810e948693eSPhilip Paeps unsigned int i; 811e948693eSPhilip Paeps uint16_t taglen; 812e948693eSPhilip Paeps uint8_t keylen; 813e948693eSPhilip Paeps uint8_t cksum; 814e948693eSPhilip Paeps size_t used; 815460cb568SAndrew Rybchenko efx_rc_t rc; 816e948693eSPhilip Paeps 817e948693eSPhilip Paeps switch (evvp->evv_tag) { 818e948693eSPhilip Paeps case EFX_VPD_ID: 819e948693eSPhilip Paeps if (evvp->evv_keyword != 0) { 820e948693eSPhilip Paeps rc = EINVAL; 821e948693eSPhilip Paeps goto fail1; 822e948693eSPhilip Paeps } 823e948693eSPhilip Paeps 824e948693eSPhilip Paeps /* Can't delete the ID keyword */ 825e948693eSPhilip Paeps if (evvp->evv_length == 0) { 826e948693eSPhilip Paeps rc = EINVAL; 827e948693eSPhilip Paeps goto fail1; 828e948693eSPhilip Paeps } 829e948693eSPhilip Paeps break; 830e948693eSPhilip Paeps 831e948693eSPhilip Paeps case EFX_VPD_RO: 832e948693eSPhilip Paeps if (evvp->evv_keyword == EFX_VPD_KEYWORD('R', 'V')) { 833e948693eSPhilip Paeps rc = EINVAL; 834e948693eSPhilip Paeps goto fail1; 835e948693eSPhilip Paeps } 836e948693eSPhilip Paeps break; 837e948693eSPhilip Paeps 838e948693eSPhilip Paeps default: 839e948693eSPhilip Paeps rc = EINVAL; 840e948693eSPhilip Paeps goto fail1; 841e948693eSPhilip Paeps } 842e948693eSPhilip Paeps 843e948693eSPhilip Paeps /* Determine total size of all current tags */ 844e948693eSPhilip Paeps if ((rc = efx_vpd_hunk_length(data, size, &used)) != 0) 845e948693eSPhilip Paeps goto fail2; 846e948693eSPhilip Paeps 847e948693eSPhilip Paeps offset = 0; 848e948693eSPhilip Paeps _NOTE(CONSTANTCONDITION) 849e948693eSPhilip Paeps while (1) { 850e948693eSPhilip Paeps taghead = offset; 851e948693eSPhilip Paeps if ((rc = efx_vpd_next_tag(data, size, &offset, 852e948693eSPhilip Paeps &tag, &taglen)) != 0) 853e948693eSPhilip Paeps goto fail3; 854e948693eSPhilip Paeps if (tag == EFX_VPD_END) 855e948693eSPhilip Paeps break; 856e948693eSPhilip Paeps else if (tag != evvp->evv_tag) { 857e948693eSPhilip Paeps offset += taglen; 858e948693eSPhilip Paeps continue; 859e948693eSPhilip Paeps } 860e948693eSPhilip Paeps 861e948693eSPhilip Paeps /* We only support modifying large resource tags */ 862e948693eSPhilip Paeps if (offset - taghead != 3) { 863e948693eSPhilip Paeps rc = EINVAL; 864e948693eSPhilip Paeps goto fail4; 865e948693eSPhilip Paeps } 866e948693eSPhilip Paeps 867e948693eSPhilip Paeps /* 868e948693eSPhilip Paeps * Work out the offset of the byte immediately after the 869e948693eSPhilip Paeps * old (=source) and new (=dest) new keyword/tag 870e948693eSPhilip Paeps */ 871e948693eSPhilip Paeps pos = 0; 872e948693eSPhilip Paeps if (tag == EFX_VPD_ID) { 873e948693eSPhilip Paeps source = offset + taglen; 874e948693eSPhilip Paeps dest = offset + evvp->evv_length; 875e948693eSPhilip Paeps goto check_space; 876e948693eSPhilip Paeps } 877e948693eSPhilip Paeps 878e948693eSPhilip Paeps EFSYS_ASSERT3U(tag, ==, EFX_VPD_RO); 879e948693eSPhilip Paeps source = dest = 0; 880e948693eSPhilip Paeps for (pos = 0; pos != taglen; pos += 3 + keylen) { 881e948693eSPhilip Paeps if ((rc = efx_vpd_next_keyword(data + offset, 882e948693eSPhilip Paeps taglen, pos, &keyword, &keylen)) != 0) 883e948693eSPhilip Paeps goto fail5; 884e948693eSPhilip Paeps 885e948693eSPhilip Paeps if (keyword == evvp->evv_keyword && 886e948693eSPhilip Paeps evvp->evv_length == 0) { 887e948693eSPhilip Paeps /* Deleting this keyword */ 888e948693eSPhilip Paeps source = offset + pos + 3 + keylen; 889e948693eSPhilip Paeps dest = offset + pos; 890e948693eSPhilip Paeps break; 891e948693eSPhilip Paeps 892e948693eSPhilip Paeps } else if (keyword == evvp->evv_keyword) { 893e948693eSPhilip Paeps /* Adjusting this keyword */ 894e948693eSPhilip Paeps source = offset + pos + 3 + keylen; 895e948693eSPhilip Paeps dest = offset + pos + 3 + evvp->evv_length; 896e948693eSPhilip Paeps break; 897e948693eSPhilip Paeps 898e948693eSPhilip Paeps } else if (keyword == EFX_VPD_KEYWORD('R', 'V')) { 899e948693eSPhilip Paeps /* The RV keyword must be at the end */ 900e948693eSPhilip Paeps EFSYS_ASSERT3U(pos + 3 + keylen, ==, taglen); 901e948693eSPhilip Paeps 902e948693eSPhilip Paeps /* 903e948693eSPhilip Paeps * The keyword doesn't already exist. If the 904e948693eSPhilip Paeps * user deleting a non-existant keyword then 905e948693eSPhilip Paeps * this is a no-op. 906e948693eSPhilip Paeps */ 907e948693eSPhilip Paeps if (evvp->evv_length == 0) 908e948693eSPhilip Paeps return (0); 909e948693eSPhilip Paeps 910e948693eSPhilip Paeps /* Insert this keyword before the RV keyword */ 911e948693eSPhilip Paeps source = offset + pos; 912e948693eSPhilip Paeps dest = offset + pos + 3 + evvp->evv_length; 913e948693eSPhilip Paeps break; 914e948693eSPhilip Paeps } 915e948693eSPhilip Paeps } 916e948693eSPhilip Paeps 917e948693eSPhilip Paeps check_space: 918e948693eSPhilip Paeps if (used + dest > size + source) { 919e948693eSPhilip Paeps rc = ENOSPC; 920e948693eSPhilip Paeps goto fail6; 921e948693eSPhilip Paeps } 922e948693eSPhilip Paeps 923e948693eSPhilip Paeps /* Move trailing data */ 924e948693eSPhilip Paeps (void) memmove(data + dest, data + source, used - source); 925e948693eSPhilip Paeps 926e948693eSPhilip Paeps /* Copy contents */ 927e948693eSPhilip Paeps memcpy(data + dest - evvp->evv_length, evvp->evv_value, 928e948693eSPhilip Paeps evvp->evv_length); 929e948693eSPhilip Paeps 930e948693eSPhilip Paeps /* Insert new keyword header if required */ 931e948693eSPhilip Paeps if (tag != EFX_VPD_ID && evvp->evv_length > 0) { 932e948693eSPhilip Paeps EFX_POPULATE_WORD_1(word, EFX_WORD_0, 933e948693eSPhilip Paeps evvp->evv_keyword); 934e948693eSPhilip Paeps data[offset + pos + 0] = 935e948693eSPhilip Paeps EFX_WORD_FIELD(word, EFX_BYTE_0); 936e948693eSPhilip Paeps data[offset + pos + 1] = 937e948693eSPhilip Paeps EFX_WORD_FIELD(word, EFX_BYTE_1); 938e948693eSPhilip Paeps data[offset + pos + 2] = evvp->evv_length; 939e948693eSPhilip Paeps } 940e948693eSPhilip Paeps 941e948693eSPhilip Paeps /* Modify tag length (large resource type) */ 9425ef1830cSAndrew Rybchenko taglen += (uint16_t)(dest - source); 943e948693eSPhilip Paeps EFX_POPULATE_WORD_1(word, EFX_WORD_0, taglen); 944e948693eSPhilip Paeps data[offset - 2] = EFX_WORD_FIELD(word, EFX_BYTE_0); 945e948693eSPhilip Paeps data[offset - 1] = EFX_WORD_FIELD(word, EFX_BYTE_1); 946e948693eSPhilip Paeps 947e948693eSPhilip Paeps goto checksum; 948e948693eSPhilip Paeps } 949e948693eSPhilip Paeps 950e948693eSPhilip Paeps /* Unable to find the matching tag */ 951e948693eSPhilip Paeps rc = ENOENT; 952e948693eSPhilip Paeps goto fail7; 953e948693eSPhilip Paeps 954e948693eSPhilip Paeps checksum: 955e948693eSPhilip Paeps /* Find the RV tag, and update the checksum */ 956e948693eSPhilip Paeps offset = 0; 957e948693eSPhilip Paeps _NOTE(CONSTANTCONDITION) 958e948693eSPhilip Paeps while (1) { 959e948693eSPhilip Paeps if ((rc = efx_vpd_next_tag(data, size, &offset, 960e948693eSPhilip Paeps &tag, &taglen)) != 0) 961e948693eSPhilip Paeps goto fail8; 962e948693eSPhilip Paeps if (tag == EFX_VPD_END) 963e948693eSPhilip Paeps break; 964e948693eSPhilip Paeps if (tag == EFX_VPD_RO) { 965e948693eSPhilip Paeps for (pos = 0; pos != taglen; pos += 3 + keylen) { 966e948693eSPhilip Paeps if ((rc = efx_vpd_next_keyword(data + offset, 967e948693eSPhilip Paeps taglen, pos, &keyword, &keylen)) != 0) 968e948693eSPhilip Paeps goto fail9; 969e948693eSPhilip Paeps 970e948693eSPhilip Paeps if (keyword == EFX_VPD_KEYWORD('R', 'V')) { 971e948693eSPhilip Paeps cksum = 0; 972e948693eSPhilip Paeps for (i = 0; i < offset + pos + 3; i++) 973e948693eSPhilip Paeps cksum += data[i]; 974e948693eSPhilip Paeps data[i] = -cksum; 975e948693eSPhilip Paeps break; 976e948693eSPhilip Paeps } 977e948693eSPhilip Paeps } 978e948693eSPhilip Paeps } 979e948693eSPhilip Paeps 980e948693eSPhilip Paeps offset += taglen; 981e948693eSPhilip Paeps } 982e948693eSPhilip Paeps 983e948693eSPhilip Paeps /* Zero out the unused portion */ 984e948693eSPhilip Paeps (void) memset(data + offset + taglen, 0xff, size - offset - taglen); 985e948693eSPhilip Paeps 986e948693eSPhilip Paeps return (0); 987e948693eSPhilip Paeps 988e948693eSPhilip Paeps fail9: 989e948693eSPhilip Paeps EFSYS_PROBE(fail9); 990e948693eSPhilip Paeps fail8: 991e948693eSPhilip Paeps EFSYS_PROBE(fail8); 992e948693eSPhilip Paeps fail7: 993e948693eSPhilip Paeps EFSYS_PROBE(fail7); 994e948693eSPhilip Paeps fail6: 995e948693eSPhilip Paeps EFSYS_PROBE(fail6); 996e948693eSPhilip Paeps fail5: 997e948693eSPhilip Paeps EFSYS_PROBE(fail5); 998e948693eSPhilip Paeps fail4: 999e948693eSPhilip Paeps EFSYS_PROBE(fail4); 1000e948693eSPhilip Paeps fail3: 1001e948693eSPhilip Paeps EFSYS_PROBE(fail3); 1002e948693eSPhilip Paeps fail2: 1003e948693eSPhilip Paeps EFSYS_PROBE(fail2); 1004e948693eSPhilip Paeps fail1: 1005460cb568SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 1006e948693eSPhilip Paeps 1007e948693eSPhilip Paeps return (rc); 1008e948693eSPhilip Paeps } 1009e948693eSPhilip Paeps 1010e948693eSPhilip Paeps void 1011e948693eSPhilip Paeps efx_vpd_fini( 1012e948693eSPhilip Paeps __in efx_nic_t *enp) 1013e948693eSPhilip Paeps { 1014ec831f7fSAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop; 1015e948693eSPhilip Paeps 1016e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 1017e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 1018e948693eSPhilip Paeps EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); 1019e948693eSPhilip Paeps 1020e948693eSPhilip Paeps if (evpdop->evpdo_fini != NULL) 1021e948693eSPhilip Paeps evpdop->evpdo_fini(enp); 1022e948693eSPhilip Paeps 1023e948693eSPhilip Paeps enp->en_evpdop = NULL; 1024e948693eSPhilip Paeps enp->en_mod_flags &= ~EFX_MOD_VPD; 1025e948693eSPhilip Paeps } 1026e948693eSPhilip Paeps 1027e948693eSPhilip Paeps #endif /* EFSYS_OPT_VPD */ 1028