15e111ed8SAndrew Rybchenko /* SPDX-License-Identifier: BSD-3-Clause
25e111ed8SAndrew Rybchenko *
3*672386c1SAndrew Rybchenko * Copyright(c) 2019-2021 Xilinx, Inc.
45e111ed8SAndrew Rybchenko * Copyright(c) 2009-2019 Solarflare Communications Inc.
55e111ed8SAndrew Rybchenko */
65e111ed8SAndrew Rybchenko
75e111ed8SAndrew Rybchenko #include "efx.h"
85e111ed8SAndrew Rybchenko #include "efx_impl.h"
95e111ed8SAndrew Rybchenko
105e111ed8SAndrew Rybchenko #if EFSYS_OPT_VPD
115e111ed8SAndrew Rybchenko
125e111ed8SAndrew Rybchenko #define TAG_TYPE_LBN 7
135e111ed8SAndrew Rybchenko #define TAG_TYPE_WIDTH 1
145e111ed8SAndrew Rybchenko #define TAG_TYPE_LARGE_ITEM_DECODE 1
155e111ed8SAndrew Rybchenko #define TAG_TYPE_SMALL_ITEM_DECODE 0
165e111ed8SAndrew Rybchenko
175e111ed8SAndrew Rybchenko #define TAG_SMALL_ITEM_NAME_LBN 3
185e111ed8SAndrew Rybchenko #define TAG_SMALL_ITEM_NAME_WIDTH 4
195e111ed8SAndrew Rybchenko #define TAG_SMALL_ITEM_SIZE_LBN 0
205e111ed8SAndrew Rybchenko #define TAG_SMALL_ITEM_SIZE_WIDTH 3
215e111ed8SAndrew Rybchenko
225e111ed8SAndrew Rybchenko #define TAG_LARGE_ITEM_NAME_LBN 0
235e111ed8SAndrew Rybchenko #define TAG_LARGE_ITEM_NAME_WIDTH 7
245e111ed8SAndrew Rybchenko
255e111ed8SAndrew Rybchenko #define TAG_NAME_END_DECODE 0x0f
265e111ed8SAndrew Rybchenko #define TAG_NAME_ID_STRING_DECODE 0x02
275e111ed8SAndrew Rybchenko #define TAG_NAME_VPD_R_DECODE 0x10
285e111ed8SAndrew Rybchenko #define TAG_NAME_VPD_W_DECODE 0x11
295e111ed8SAndrew Rybchenko
305e111ed8SAndrew Rybchenko #if EFSYS_OPT_SIENA
315e111ed8SAndrew Rybchenko
325e111ed8SAndrew Rybchenko static const efx_vpd_ops_t __efx_vpd_siena_ops = {
335e111ed8SAndrew Rybchenko siena_vpd_init, /* evpdo_init */
345e111ed8SAndrew Rybchenko siena_vpd_size, /* evpdo_size */
355e111ed8SAndrew Rybchenko siena_vpd_read, /* evpdo_read */
365e111ed8SAndrew Rybchenko siena_vpd_verify, /* evpdo_verify */
375e111ed8SAndrew Rybchenko siena_vpd_reinit, /* evpdo_reinit */
385e111ed8SAndrew Rybchenko siena_vpd_get, /* evpdo_get */
395e111ed8SAndrew Rybchenko siena_vpd_set, /* evpdo_set */
405e111ed8SAndrew Rybchenko siena_vpd_next, /* evpdo_next */
415e111ed8SAndrew Rybchenko siena_vpd_write, /* evpdo_write */
425e111ed8SAndrew Rybchenko siena_vpd_fini, /* evpdo_fini */
435e111ed8SAndrew Rybchenko };
445e111ed8SAndrew Rybchenko
455e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */
465e111ed8SAndrew Rybchenko
475e111ed8SAndrew Rybchenko #if EFX_OPTS_EF10()
485e111ed8SAndrew Rybchenko
495e111ed8SAndrew Rybchenko static const efx_vpd_ops_t __efx_vpd_ef10_ops = {
505e111ed8SAndrew Rybchenko ef10_vpd_init, /* evpdo_init */
515e111ed8SAndrew Rybchenko ef10_vpd_size, /* evpdo_size */
525e111ed8SAndrew Rybchenko ef10_vpd_read, /* evpdo_read */
535e111ed8SAndrew Rybchenko ef10_vpd_verify, /* evpdo_verify */
545e111ed8SAndrew Rybchenko ef10_vpd_reinit, /* evpdo_reinit */
555e111ed8SAndrew Rybchenko ef10_vpd_get, /* evpdo_get */
565e111ed8SAndrew Rybchenko ef10_vpd_set, /* evpdo_set */
575e111ed8SAndrew Rybchenko ef10_vpd_next, /* evpdo_next */
585e111ed8SAndrew Rybchenko ef10_vpd_write, /* evpdo_write */
595e111ed8SAndrew Rybchenko ef10_vpd_fini, /* evpdo_fini */
605e111ed8SAndrew Rybchenko };
615e111ed8SAndrew Rybchenko
625e111ed8SAndrew Rybchenko #endif /* EFX_OPTS_EF10() */
635e111ed8SAndrew Rybchenko
645e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_vpd_init(__in efx_nic_t * enp)655e111ed8SAndrew Rybchenko efx_vpd_init(
665e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
675e111ed8SAndrew Rybchenko {
685e111ed8SAndrew Rybchenko const efx_vpd_ops_t *evpdop;
695e111ed8SAndrew Rybchenko efx_rc_t rc;
705e111ed8SAndrew Rybchenko
715e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
725e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
735e111ed8SAndrew Rybchenko EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_VPD));
745e111ed8SAndrew Rybchenko
755e111ed8SAndrew Rybchenko switch (enp->en_family) {
765e111ed8SAndrew Rybchenko #if EFSYS_OPT_SIENA
775e111ed8SAndrew Rybchenko case EFX_FAMILY_SIENA:
785e111ed8SAndrew Rybchenko evpdop = &__efx_vpd_siena_ops;
795e111ed8SAndrew Rybchenko break;
805e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */
815e111ed8SAndrew Rybchenko
825e111ed8SAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON
835e111ed8SAndrew Rybchenko case EFX_FAMILY_HUNTINGTON:
845e111ed8SAndrew Rybchenko evpdop = &__efx_vpd_ef10_ops;
855e111ed8SAndrew Rybchenko break;
865e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_HUNTINGTON */
875e111ed8SAndrew Rybchenko
885e111ed8SAndrew Rybchenko #if EFSYS_OPT_MEDFORD
895e111ed8SAndrew Rybchenko case EFX_FAMILY_MEDFORD:
905e111ed8SAndrew Rybchenko evpdop = &__efx_vpd_ef10_ops;
915e111ed8SAndrew Rybchenko break;
925e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD */
935e111ed8SAndrew Rybchenko
945e111ed8SAndrew Rybchenko #if EFSYS_OPT_MEDFORD2
955e111ed8SAndrew Rybchenko case EFX_FAMILY_MEDFORD2:
965e111ed8SAndrew Rybchenko evpdop = &__efx_vpd_ef10_ops;
975e111ed8SAndrew Rybchenko break;
985e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD2 */
995e111ed8SAndrew Rybchenko
1005e111ed8SAndrew Rybchenko default:
1015e111ed8SAndrew Rybchenko EFSYS_ASSERT(0);
1025e111ed8SAndrew Rybchenko rc = ENOTSUP;
1035e111ed8SAndrew Rybchenko goto fail1;
1045e111ed8SAndrew Rybchenko }
1055e111ed8SAndrew Rybchenko
1065e111ed8SAndrew Rybchenko if (evpdop->evpdo_init != NULL) {
1075e111ed8SAndrew Rybchenko if ((rc = evpdop->evpdo_init(enp)) != 0)
1085e111ed8SAndrew Rybchenko goto fail2;
1095e111ed8SAndrew Rybchenko }
1105e111ed8SAndrew Rybchenko
1115e111ed8SAndrew Rybchenko enp->en_evpdop = evpdop;
1125e111ed8SAndrew Rybchenko enp->en_mod_flags |= EFX_MOD_VPD;
1135e111ed8SAndrew Rybchenko
1145e111ed8SAndrew Rybchenko return (0);
1155e111ed8SAndrew Rybchenko
1165e111ed8SAndrew Rybchenko fail2:
1175e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
1185e111ed8SAndrew Rybchenko fail1:
1195e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
1205e111ed8SAndrew Rybchenko
1215e111ed8SAndrew Rybchenko return (rc);
1225e111ed8SAndrew Rybchenko }
1235e111ed8SAndrew Rybchenko
1245e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_vpd_size(__in efx_nic_t * enp,__out size_t * sizep)1255e111ed8SAndrew Rybchenko efx_vpd_size(
1265e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
1275e111ed8SAndrew Rybchenko __out size_t *sizep)
1285e111ed8SAndrew Rybchenko {
1295e111ed8SAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop;
1305e111ed8SAndrew Rybchenko efx_rc_t rc;
1315e111ed8SAndrew Rybchenko
1325e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1335e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
1345e111ed8SAndrew Rybchenko
1355e111ed8SAndrew Rybchenko if ((rc = evpdop->evpdo_size(enp, sizep)) != 0)
1365e111ed8SAndrew Rybchenko goto fail1;
1375e111ed8SAndrew Rybchenko
1385e111ed8SAndrew Rybchenko return (0);
1395e111ed8SAndrew Rybchenko
1405e111ed8SAndrew Rybchenko fail1:
1415e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
1425e111ed8SAndrew Rybchenko
1435e111ed8SAndrew Rybchenko return (rc);
1445e111ed8SAndrew Rybchenko }
1455e111ed8SAndrew Rybchenko
1465e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_vpd_read(__in efx_nic_t * enp,__out_bcount (size)caddr_t data,__in size_t size)1475e111ed8SAndrew Rybchenko efx_vpd_read(
1485e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
1495e111ed8SAndrew Rybchenko __out_bcount(size) caddr_t data,
1505e111ed8SAndrew Rybchenko __in size_t size)
1515e111ed8SAndrew Rybchenko {
1525e111ed8SAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop;
1535e111ed8SAndrew Rybchenko efx_rc_t rc;
1545e111ed8SAndrew Rybchenko
1555e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1565e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
1575e111ed8SAndrew Rybchenko
1585e111ed8SAndrew Rybchenko if ((rc = evpdop->evpdo_read(enp, data, size)) != 0)
1595e111ed8SAndrew Rybchenko goto fail1;
1605e111ed8SAndrew Rybchenko
1615e111ed8SAndrew Rybchenko return (0);
1625e111ed8SAndrew Rybchenko
1635e111ed8SAndrew Rybchenko fail1:
1645e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
1655e111ed8SAndrew Rybchenko
1665e111ed8SAndrew Rybchenko return (rc);
1675e111ed8SAndrew Rybchenko }
1685e111ed8SAndrew Rybchenko
1695e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_vpd_verify(__in efx_nic_t * enp,__in_bcount (size)caddr_t data,__in size_t size)1705e111ed8SAndrew Rybchenko efx_vpd_verify(
1715e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
1725e111ed8SAndrew Rybchenko __in_bcount(size) caddr_t data,
1735e111ed8SAndrew Rybchenko __in size_t size)
1745e111ed8SAndrew Rybchenko {
1755e111ed8SAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop;
1765e111ed8SAndrew Rybchenko efx_rc_t rc;
1775e111ed8SAndrew Rybchenko
1785e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1795e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
1805e111ed8SAndrew Rybchenko
1815e111ed8SAndrew Rybchenko if ((rc = evpdop->evpdo_verify(enp, data, size)) != 0)
1825e111ed8SAndrew Rybchenko goto fail1;
1835e111ed8SAndrew Rybchenko
1845e111ed8SAndrew Rybchenko return (0);
1855e111ed8SAndrew Rybchenko
1865e111ed8SAndrew Rybchenko fail1:
1875e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
1885e111ed8SAndrew Rybchenko
1895e111ed8SAndrew Rybchenko return (rc);
1905e111ed8SAndrew Rybchenko }
1915e111ed8SAndrew Rybchenko
1925e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_vpd_reinit(__in efx_nic_t * enp,__in_bcount (size)caddr_t data,__in size_t size)1935e111ed8SAndrew Rybchenko efx_vpd_reinit(
1945e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
1955e111ed8SAndrew Rybchenko __in_bcount(size) caddr_t data,
1965e111ed8SAndrew Rybchenko __in size_t size)
1975e111ed8SAndrew Rybchenko {
1985e111ed8SAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop;
1995e111ed8SAndrew Rybchenko efx_rc_t rc;
2005e111ed8SAndrew Rybchenko
2015e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
2025e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
2035e111ed8SAndrew Rybchenko
2045e111ed8SAndrew Rybchenko if (evpdop->evpdo_reinit == NULL) {
2055e111ed8SAndrew Rybchenko rc = ENOTSUP;
2065e111ed8SAndrew Rybchenko goto fail1;
2075e111ed8SAndrew Rybchenko }
2085e111ed8SAndrew Rybchenko
2095e111ed8SAndrew Rybchenko if ((rc = evpdop->evpdo_reinit(enp, data, size)) != 0)
2105e111ed8SAndrew Rybchenko goto fail2;
2115e111ed8SAndrew Rybchenko
2125e111ed8SAndrew Rybchenko return (0);
2135e111ed8SAndrew Rybchenko
2145e111ed8SAndrew Rybchenko fail2:
2155e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
2165e111ed8SAndrew Rybchenko fail1:
2175e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
2185e111ed8SAndrew Rybchenko
2195e111ed8SAndrew Rybchenko return (rc);
2205e111ed8SAndrew Rybchenko }
2215e111ed8SAndrew Rybchenko
2225e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_vpd_get(__in efx_nic_t * enp,__in_bcount (size)caddr_t data,__in size_t size,__inout efx_vpd_value_t * evvp)2235e111ed8SAndrew Rybchenko efx_vpd_get(
2245e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
2255e111ed8SAndrew Rybchenko __in_bcount(size) caddr_t data,
2265e111ed8SAndrew Rybchenko __in size_t size,
2275e111ed8SAndrew Rybchenko __inout efx_vpd_value_t *evvp)
2285e111ed8SAndrew Rybchenko {
2295e111ed8SAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop;
2305e111ed8SAndrew Rybchenko efx_rc_t rc;
2315e111ed8SAndrew Rybchenko
2325e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
2335e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
2345e111ed8SAndrew Rybchenko
2355e111ed8SAndrew Rybchenko if ((rc = evpdop->evpdo_get(enp, data, size, evvp)) != 0) {
2365e111ed8SAndrew Rybchenko if (rc == ENOENT)
2375e111ed8SAndrew Rybchenko return (rc);
2385e111ed8SAndrew Rybchenko
2395e111ed8SAndrew Rybchenko goto fail1;
2405e111ed8SAndrew Rybchenko }
2415e111ed8SAndrew Rybchenko
2425e111ed8SAndrew Rybchenko return (0);
2435e111ed8SAndrew Rybchenko
2445e111ed8SAndrew Rybchenko fail1:
2455e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
2465e111ed8SAndrew Rybchenko
2475e111ed8SAndrew Rybchenko return (rc);
2485e111ed8SAndrew Rybchenko }
2495e111ed8SAndrew Rybchenko
2505e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_vpd_set(__in efx_nic_t * enp,__inout_bcount (size)caddr_t data,__in size_t size,__in efx_vpd_value_t * evvp)2515e111ed8SAndrew Rybchenko efx_vpd_set(
2525e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
2535e111ed8SAndrew Rybchenko __inout_bcount(size) caddr_t data,
2545e111ed8SAndrew Rybchenko __in size_t size,
2555e111ed8SAndrew Rybchenko __in efx_vpd_value_t *evvp)
2565e111ed8SAndrew Rybchenko {
2575e111ed8SAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop;
2585e111ed8SAndrew Rybchenko efx_rc_t rc;
2595e111ed8SAndrew Rybchenko
2605e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
2615e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
2625e111ed8SAndrew Rybchenko
2635e111ed8SAndrew Rybchenko if ((rc = evpdop->evpdo_set(enp, data, size, evvp)) != 0)
2645e111ed8SAndrew Rybchenko goto fail1;
2655e111ed8SAndrew Rybchenko
2665e111ed8SAndrew Rybchenko return (0);
2675e111ed8SAndrew Rybchenko
2685e111ed8SAndrew Rybchenko fail1:
2695e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
2705e111ed8SAndrew Rybchenko
2715e111ed8SAndrew Rybchenko return (rc);
2725e111ed8SAndrew Rybchenko }
2735e111ed8SAndrew Rybchenko
2745e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_vpd_next(__in efx_nic_t * enp,__inout_bcount (size)caddr_t data,__in size_t size,__out efx_vpd_value_t * evvp,__inout unsigned int * contp)2755e111ed8SAndrew Rybchenko efx_vpd_next(
2765e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
2775e111ed8SAndrew Rybchenko __inout_bcount(size) caddr_t data,
2785e111ed8SAndrew Rybchenko __in size_t size,
2795e111ed8SAndrew Rybchenko __out efx_vpd_value_t *evvp,
2805e111ed8SAndrew Rybchenko __inout unsigned int *contp)
2815e111ed8SAndrew Rybchenko {
2825e111ed8SAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop;
2835e111ed8SAndrew Rybchenko efx_rc_t rc;
2845e111ed8SAndrew Rybchenko
2855e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
2865e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
2875e111ed8SAndrew Rybchenko
2885e111ed8SAndrew Rybchenko if ((rc = evpdop->evpdo_next(enp, data, size, evvp, contp)) != 0)
2895e111ed8SAndrew Rybchenko goto fail1;
2905e111ed8SAndrew Rybchenko
2915e111ed8SAndrew Rybchenko return (0);
2925e111ed8SAndrew Rybchenko
2935e111ed8SAndrew Rybchenko fail1:
2945e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
2955e111ed8SAndrew Rybchenko
2965e111ed8SAndrew Rybchenko return (rc);
2975e111ed8SAndrew Rybchenko }
2985e111ed8SAndrew Rybchenko
2995e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_vpd_write(__in efx_nic_t * enp,__in_bcount (size)caddr_t data,__in size_t size)3005e111ed8SAndrew Rybchenko efx_vpd_write(
3015e111ed8SAndrew Rybchenko __in efx_nic_t *enp,
3025e111ed8SAndrew Rybchenko __in_bcount(size) caddr_t data,
3035e111ed8SAndrew Rybchenko __in size_t size)
3045e111ed8SAndrew Rybchenko {
3055e111ed8SAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop;
3065e111ed8SAndrew Rybchenko efx_rc_t rc;
3075e111ed8SAndrew Rybchenko
3085e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
3095e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
3105e111ed8SAndrew Rybchenko
3115e111ed8SAndrew Rybchenko if ((rc = evpdop->evpdo_write(enp, data, size)) != 0)
3125e111ed8SAndrew Rybchenko goto fail1;
3135e111ed8SAndrew Rybchenko
3145e111ed8SAndrew Rybchenko return (0);
3155e111ed8SAndrew Rybchenko
3165e111ed8SAndrew Rybchenko fail1:
3175e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
3185e111ed8SAndrew Rybchenko
3195e111ed8SAndrew Rybchenko return (rc);
3205e111ed8SAndrew Rybchenko }
3215e111ed8SAndrew Rybchenko
3225e111ed8SAndrew Rybchenko static __checkReturn efx_rc_t
efx_vpd_next_tag(__in caddr_t data,__in size_t size,__inout unsigned int * offsetp,__out efx_vpd_tag_t * tagp,__out uint16_t * lengthp)3235e111ed8SAndrew Rybchenko efx_vpd_next_tag(
3245e111ed8SAndrew Rybchenko __in caddr_t data,
3255e111ed8SAndrew Rybchenko __in size_t size,
3265e111ed8SAndrew Rybchenko __inout unsigned int *offsetp,
3275e111ed8SAndrew Rybchenko __out efx_vpd_tag_t *tagp,
3285e111ed8SAndrew Rybchenko __out uint16_t *lengthp)
3295e111ed8SAndrew Rybchenko {
3305e111ed8SAndrew Rybchenko efx_byte_t byte;
3315e111ed8SAndrew Rybchenko efx_word_t word;
3325e111ed8SAndrew Rybchenko uint8_t name;
3335e111ed8SAndrew Rybchenko uint16_t length;
3345e111ed8SAndrew Rybchenko size_t headlen;
3355e111ed8SAndrew Rybchenko efx_rc_t rc;
3365e111ed8SAndrew Rybchenko
3375e111ed8SAndrew Rybchenko if (*offsetp >= size) {
3385e111ed8SAndrew Rybchenko rc = EFAULT;
3395e111ed8SAndrew Rybchenko goto fail1;
3405e111ed8SAndrew Rybchenko }
3415e111ed8SAndrew Rybchenko
3425e111ed8SAndrew Rybchenko EFX_POPULATE_BYTE_1(byte, EFX_BYTE_0, data[*offsetp]);
3435e111ed8SAndrew Rybchenko
3445e111ed8SAndrew Rybchenko switch (EFX_BYTE_FIELD(byte, TAG_TYPE)) {
3455e111ed8SAndrew Rybchenko case TAG_TYPE_SMALL_ITEM_DECODE:
3465e111ed8SAndrew Rybchenko headlen = 1;
3475e111ed8SAndrew Rybchenko
3485e111ed8SAndrew Rybchenko name = EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_NAME);
3495e111ed8SAndrew Rybchenko length = (uint16_t)EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_SIZE);
3505e111ed8SAndrew Rybchenko
3515e111ed8SAndrew Rybchenko break;
3525e111ed8SAndrew Rybchenko
3535e111ed8SAndrew Rybchenko case TAG_TYPE_LARGE_ITEM_DECODE:
3545e111ed8SAndrew Rybchenko headlen = 3;
3555e111ed8SAndrew Rybchenko
3565e111ed8SAndrew Rybchenko if (*offsetp + headlen > size) {
3575e111ed8SAndrew Rybchenko rc = EFAULT;
3585e111ed8SAndrew Rybchenko goto fail2;
3595e111ed8SAndrew Rybchenko }
3605e111ed8SAndrew Rybchenko
3615e111ed8SAndrew Rybchenko name = EFX_BYTE_FIELD(byte, TAG_LARGE_ITEM_NAME);
3625e111ed8SAndrew Rybchenko EFX_POPULATE_WORD_2(word,
3635e111ed8SAndrew Rybchenko EFX_BYTE_0, data[*offsetp + 1],
3645e111ed8SAndrew Rybchenko EFX_BYTE_1, data[*offsetp + 2]);
3655e111ed8SAndrew Rybchenko length = EFX_WORD_FIELD(word, EFX_WORD_0);
3665e111ed8SAndrew Rybchenko
3675e111ed8SAndrew Rybchenko break;
3685e111ed8SAndrew Rybchenko
3695e111ed8SAndrew Rybchenko default:
3705e111ed8SAndrew Rybchenko rc = EFAULT;
3715e111ed8SAndrew Rybchenko goto fail2;
3725e111ed8SAndrew Rybchenko }
3735e111ed8SAndrew Rybchenko
3745e111ed8SAndrew Rybchenko if (*offsetp + headlen + length > size) {
3755e111ed8SAndrew Rybchenko rc = EFAULT;
3765e111ed8SAndrew Rybchenko goto fail3;
3775e111ed8SAndrew Rybchenko }
3785e111ed8SAndrew Rybchenko
3795e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(TAG_NAME_END_DECODE == EFX_VPD_END);
3805e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(TAG_NAME_ID_STRING_DECODE == EFX_VPD_ID);
3815e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(TAG_NAME_VPD_R_DECODE == EFX_VPD_RO);
3825e111ed8SAndrew Rybchenko EFX_STATIC_ASSERT(TAG_NAME_VPD_W_DECODE == EFX_VPD_RW);
3835e111ed8SAndrew Rybchenko if (name != EFX_VPD_END && name != EFX_VPD_ID &&
3845e111ed8SAndrew Rybchenko name != EFX_VPD_RO) {
3855e111ed8SAndrew Rybchenko rc = EFAULT;
3865e111ed8SAndrew Rybchenko goto fail4;
3875e111ed8SAndrew Rybchenko }
3885e111ed8SAndrew Rybchenko
3895e111ed8SAndrew Rybchenko *tagp = name;
3905e111ed8SAndrew Rybchenko *lengthp = length;
3915e111ed8SAndrew Rybchenko *offsetp += headlen;
3925e111ed8SAndrew Rybchenko
3935e111ed8SAndrew Rybchenko return (0);
3945e111ed8SAndrew Rybchenko
3955e111ed8SAndrew Rybchenko fail4:
3965e111ed8SAndrew Rybchenko EFSYS_PROBE(fail4);
3975e111ed8SAndrew Rybchenko fail3:
3985e111ed8SAndrew Rybchenko EFSYS_PROBE(fail3);
3995e111ed8SAndrew Rybchenko fail2:
4005e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
4015e111ed8SAndrew Rybchenko fail1:
4025e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
4035e111ed8SAndrew Rybchenko
4045e111ed8SAndrew Rybchenko return (rc);
4055e111ed8SAndrew Rybchenko }
4065e111ed8SAndrew Rybchenko
4075e111ed8SAndrew Rybchenko static __checkReturn efx_rc_t
efx_vpd_next_keyword(__in_bcount (size)caddr_t tag,__in size_t size,__in unsigned int pos,__out efx_vpd_keyword_t * keywordp,__out uint8_t * lengthp)4085e111ed8SAndrew Rybchenko efx_vpd_next_keyword(
4095e111ed8SAndrew Rybchenko __in_bcount(size) caddr_t tag,
4105e111ed8SAndrew Rybchenko __in size_t size,
4115e111ed8SAndrew Rybchenko __in unsigned int pos,
4125e111ed8SAndrew Rybchenko __out efx_vpd_keyword_t *keywordp,
4135e111ed8SAndrew Rybchenko __out uint8_t *lengthp)
4145e111ed8SAndrew Rybchenko {
4155e111ed8SAndrew Rybchenko efx_vpd_keyword_t keyword;
4165e111ed8SAndrew Rybchenko uint8_t length;
4175e111ed8SAndrew Rybchenko efx_rc_t rc;
4185e111ed8SAndrew Rybchenko
4195e111ed8SAndrew Rybchenko if (pos + 3U > size) {
4205e111ed8SAndrew Rybchenko rc = EFAULT;
4215e111ed8SAndrew Rybchenko goto fail1;
4225e111ed8SAndrew Rybchenko }
4235e111ed8SAndrew Rybchenko
4245e111ed8SAndrew Rybchenko keyword = EFX_VPD_KEYWORD(tag[pos], tag[pos + 1]);
4255e111ed8SAndrew Rybchenko length = tag[pos + 2];
4265e111ed8SAndrew Rybchenko
4275e111ed8SAndrew Rybchenko if (length == 0 || pos + 3U + length > size) {
4285e111ed8SAndrew Rybchenko rc = EFAULT;
4295e111ed8SAndrew Rybchenko goto fail2;
4305e111ed8SAndrew Rybchenko }
4315e111ed8SAndrew Rybchenko
4325e111ed8SAndrew Rybchenko *keywordp = keyword;
4335e111ed8SAndrew Rybchenko *lengthp = length;
4345e111ed8SAndrew Rybchenko
4355e111ed8SAndrew Rybchenko return (0);
4365e111ed8SAndrew Rybchenko
4375e111ed8SAndrew Rybchenko fail2:
4385e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
4395e111ed8SAndrew Rybchenko fail1:
4405e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
4415e111ed8SAndrew Rybchenko
4425e111ed8SAndrew Rybchenko return (rc);
4435e111ed8SAndrew Rybchenko }
4445e111ed8SAndrew Rybchenko
4455e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_vpd_hunk_length(__in_bcount (size)caddr_t data,__in size_t size,__out size_t * lengthp)4465e111ed8SAndrew Rybchenko efx_vpd_hunk_length(
4475e111ed8SAndrew Rybchenko __in_bcount(size) caddr_t data,
4485e111ed8SAndrew Rybchenko __in size_t size,
4495e111ed8SAndrew Rybchenko __out size_t *lengthp)
4505e111ed8SAndrew Rybchenko {
4515e111ed8SAndrew Rybchenko efx_vpd_tag_t tag;
4525e111ed8SAndrew Rybchenko unsigned int offset;
4535e111ed8SAndrew Rybchenko uint16_t taglen;
4545e111ed8SAndrew Rybchenko efx_rc_t rc;
4555e111ed8SAndrew Rybchenko
4565e111ed8SAndrew Rybchenko offset = 0;
4575e111ed8SAndrew Rybchenko _NOTE(CONSTANTCONDITION)
4585e111ed8SAndrew Rybchenko while (1) {
4595e111ed8SAndrew Rybchenko if ((rc = efx_vpd_next_tag(data, size, &offset,
4605e111ed8SAndrew Rybchenko &tag, &taglen)) != 0)
4615e111ed8SAndrew Rybchenko goto fail1;
4625e111ed8SAndrew Rybchenko offset += taglen;
4635e111ed8SAndrew Rybchenko if (tag == EFX_VPD_END)
4645e111ed8SAndrew Rybchenko break;
4655e111ed8SAndrew Rybchenko }
4665e111ed8SAndrew Rybchenko
4675e111ed8SAndrew Rybchenko *lengthp = offset;
4685e111ed8SAndrew Rybchenko
4695e111ed8SAndrew Rybchenko return (0);
4705e111ed8SAndrew Rybchenko
4715e111ed8SAndrew Rybchenko fail1:
4725e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
4735e111ed8SAndrew Rybchenko
4745e111ed8SAndrew Rybchenko return (rc);
4755e111ed8SAndrew Rybchenko }
4765e111ed8SAndrew Rybchenko
4775e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_vpd_hunk_verify(__in_bcount (size)caddr_t data,__in size_t size,__out_opt boolean_t * cksummedp)4785e111ed8SAndrew Rybchenko efx_vpd_hunk_verify(
4795e111ed8SAndrew Rybchenko __in_bcount(size) caddr_t data,
4805e111ed8SAndrew Rybchenko __in size_t size,
4815e111ed8SAndrew Rybchenko __out_opt boolean_t *cksummedp)
4825e111ed8SAndrew Rybchenko {
4835e111ed8SAndrew Rybchenko efx_vpd_tag_t tag;
4845e111ed8SAndrew Rybchenko efx_vpd_keyword_t keyword;
4855e111ed8SAndrew Rybchenko unsigned int offset;
4865e111ed8SAndrew Rybchenko unsigned int pos;
4875e111ed8SAndrew Rybchenko unsigned int i;
4885e111ed8SAndrew Rybchenko uint16_t taglen;
4895e111ed8SAndrew Rybchenko uint8_t keylen;
4905e111ed8SAndrew Rybchenko uint8_t cksum;
4915e111ed8SAndrew Rybchenko boolean_t cksummed = B_FALSE;
4925e111ed8SAndrew Rybchenko efx_rc_t rc;
4935e111ed8SAndrew Rybchenko
4945e111ed8SAndrew Rybchenko /*
4955e111ed8SAndrew Rybchenko * Parse every tag,keyword in the existing VPD. If the csum is present,
4965e111ed8SAndrew Rybchenko * the assert it is correct, and is the final keyword in the RO block.
4975e111ed8SAndrew Rybchenko */
4985e111ed8SAndrew Rybchenko offset = 0;
4995e111ed8SAndrew Rybchenko _NOTE(CONSTANTCONDITION)
5005e111ed8SAndrew Rybchenko while (1) {
5015e111ed8SAndrew Rybchenko if ((rc = efx_vpd_next_tag(data, size, &offset,
5025e111ed8SAndrew Rybchenko &tag, &taglen)) != 0)
5035e111ed8SAndrew Rybchenko goto fail1;
5045e111ed8SAndrew Rybchenko if (tag == EFX_VPD_END)
5055e111ed8SAndrew Rybchenko break;
5065e111ed8SAndrew Rybchenko else if (tag == EFX_VPD_ID)
5075e111ed8SAndrew Rybchenko goto done;
5085e111ed8SAndrew Rybchenko
5095e111ed8SAndrew Rybchenko for (pos = 0; pos != taglen; pos += 3 + keylen) {
5105e111ed8SAndrew Rybchenko /* RV keyword must be the last in the block */
5115e111ed8SAndrew Rybchenko if (cksummed) {
5125e111ed8SAndrew Rybchenko rc = EFAULT;
5135e111ed8SAndrew Rybchenko goto fail2;
5145e111ed8SAndrew Rybchenko }
5155e111ed8SAndrew Rybchenko
5165e111ed8SAndrew Rybchenko if ((rc = efx_vpd_next_keyword(data + offset,
5175e111ed8SAndrew Rybchenko taglen, pos, &keyword, &keylen)) != 0)
5185e111ed8SAndrew Rybchenko goto fail3;
5195e111ed8SAndrew Rybchenko
5205e111ed8SAndrew Rybchenko if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
5215e111ed8SAndrew Rybchenko cksum = 0;
5225e111ed8SAndrew Rybchenko for (i = 0; i < offset + pos + 4; i++)
5235e111ed8SAndrew Rybchenko cksum += data[i];
5245e111ed8SAndrew Rybchenko
5255e111ed8SAndrew Rybchenko if (cksum != 0) {
5265e111ed8SAndrew Rybchenko rc = EFAULT;
5275e111ed8SAndrew Rybchenko goto fail4;
5285e111ed8SAndrew Rybchenko }
5295e111ed8SAndrew Rybchenko
5305e111ed8SAndrew Rybchenko cksummed = B_TRUE;
5315e111ed8SAndrew Rybchenko }
5325e111ed8SAndrew Rybchenko }
5335e111ed8SAndrew Rybchenko
5345e111ed8SAndrew Rybchenko done:
5355e111ed8SAndrew Rybchenko offset += taglen;
5365e111ed8SAndrew Rybchenko }
5375e111ed8SAndrew Rybchenko
5385e111ed8SAndrew Rybchenko if (!cksummed) {
5395e111ed8SAndrew Rybchenko rc = EFAULT;
5405e111ed8SAndrew Rybchenko goto fail5;
5415e111ed8SAndrew Rybchenko }
5425e111ed8SAndrew Rybchenko
5435e111ed8SAndrew Rybchenko if (cksummedp != NULL)
5445e111ed8SAndrew Rybchenko *cksummedp = cksummed;
5455e111ed8SAndrew Rybchenko
5465e111ed8SAndrew Rybchenko return (0);
5475e111ed8SAndrew Rybchenko
5485e111ed8SAndrew Rybchenko fail5:
5495e111ed8SAndrew Rybchenko EFSYS_PROBE(fail5);
5505e111ed8SAndrew Rybchenko fail4:
5515e111ed8SAndrew Rybchenko EFSYS_PROBE(fail4);
5525e111ed8SAndrew Rybchenko fail3:
5535e111ed8SAndrew Rybchenko EFSYS_PROBE(fail3);
5545e111ed8SAndrew Rybchenko fail2:
5555e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
5565e111ed8SAndrew Rybchenko fail1:
5575e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
5585e111ed8SAndrew Rybchenko
5595e111ed8SAndrew Rybchenko return (rc);
5605e111ed8SAndrew Rybchenko }
5615e111ed8SAndrew Rybchenko
5625e111ed8SAndrew Rybchenko static uint8_t __efx_vpd_blank_pid[] = {
5635e111ed8SAndrew Rybchenko /* Large resource type ID length 1 */
5645e111ed8SAndrew Rybchenko 0x82, 0x01, 0x00,
5655e111ed8SAndrew Rybchenko /* Product name ' ' */
5665e111ed8SAndrew Rybchenko 0x32,
5675e111ed8SAndrew Rybchenko };
5685e111ed8SAndrew Rybchenko
5695e111ed8SAndrew Rybchenko static uint8_t __efx_vpd_blank_r[] = {
5705e111ed8SAndrew Rybchenko /* Large resource type VPD-R length 4 */
5715e111ed8SAndrew Rybchenko 0x90, 0x04, 0x00,
5725e111ed8SAndrew Rybchenko /* RV keyword length 1 */
5735e111ed8SAndrew Rybchenko 'R', 'V', 0x01,
5745e111ed8SAndrew Rybchenko /* RV payload checksum */
5755e111ed8SAndrew Rybchenko 0x00,
5765e111ed8SAndrew Rybchenko };
5775e111ed8SAndrew Rybchenko
5785e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_vpd_hunk_reinit(__in_bcount (size)caddr_t data,__in size_t size,__in boolean_t wantpid)5795e111ed8SAndrew Rybchenko efx_vpd_hunk_reinit(
5805e111ed8SAndrew Rybchenko __in_bcount(size) caddr_t data,
5815e111ed8SAndrew Rybchenko __in size_t size,
5825e111ed8SAndrew Rybchenko __in boolean_t wantpid)
5835e111ed8SAndrew Rybchenko {
5845e111ed8SAndrew Rybchenko unsigned int offset = 0;
5855e111ed8SAndrew Rybchenko unsigned int pos;
5865e111ed8SAndrew Rybchenko efx_byte_t byte;
5875e111ed8SAndrew Rybchenko uint8_t cksum;
5885e111ed8SAndrew Rybchenko efx_rc_t rc;
5895e111ed8SAndrew Rybchenko
5905e111ed8SAndrew Rybchenko if (size < 0x100) {
5915e111ed8SAndrew Rybchenko rc = ENOSPC;
5925e111ed8SAndrew Rybchenko goto fail1;
5935e111ed8SAndrew Rybchenko }
5945e111ed8SAndrew Rybchenko
5955e111ed8SAndrew Rybchenko if (wantpid) {
5965e111ed8SAndrew Rybchenko memcpy(data + offset, __efx_vpd_blank_pid,
5975e111ed8SAndrew Rybchenko sizeof (__efx_vpd_blank_pid));
5985e111ed8SAndrew Rybchenko offset += sizeof (__efx_vpd_blank_pid);
5995e111ed8SAndrew Rybchenko }
6005e111ed8SAndrew Rybchenko
6015e111ed8SAndrew Rybchenko memcpy(data + offset, __efx_vpd_blank_r, sizeof (__efx_vpd_blank_r));
6025e111ed8SAndrew Rybchenko offset += sizeof (__efx_vpd_blank_r);
6035e111ed8SAndrew Rybchenko
6045e111ed8SAndrew Rybchenko /* Update checksum */
6055e111ed8SAndrew Rybchenko cksum = 0;
6065e111ed8SAndrew Rybchenko for (pos = 0; pos < offset; pos++)
6075e111ed8SAndrew Rybchenko cksum += data[pos];
6085e111ed8SAndrew Rybchenko data[offset - 1] -= cksum;
6095e111ed8SAndrew Rybchenko
6105e111ed8SAndrew Rybchenko /* Append trailing tag */
6115e111ed8SAndrew Rybchenko EFX_POPULATE_BYTE_3(byte,
6125e111ed8SAndrew Rybchenko TAG_TYPE, TAG_TYPE_SMALL_ITEM_DECODE,
6135e111ed8SAndrew Rybchenko TAG_SMALL_ITEM_NAME, TAG_NAME_END_DECODE,
6145e111ed8SAndrew Rybchenko TAG_SMALL_ITEM_SIZE, 0);
6155e111ed8SAndrew Rybchenko data[offset] = EFX_BYTE_FIELD(byte, EFX_BYTE_0);
6165e111ed8SAndrew Rybchenko offset++;
6175e111ed8SAndrew Rybchenko
6185e111ed8SAndrew Rybchenko return (0);
6195e111ed8SAndrew Rybchenko
6205e111ed8SAndrew Rybchenko fail1:
6215e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
6225e111ed8SAndrew Rybchenko
6235e111ed8SAndrew Rybchenko return (rc);
6245e111ed8SAndrew Rybchenko }
6255e111ed8SAndrew Rybchenko
6265e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_vpd_hunk_next(__in_bcount (size)caddr_t data,__in size_t size,__out efx_vpd_tag_t * tagp,__out efx_vpd_keyword_t * keywordp,__out_opt unsigned int * payloadp,__out_opt uint8_t * paylenp,__inout unsigned int * contp)6275e111ed8SAndrew Rybchenko efx_vpd_hunk_next(
6285e111ed8SAndrew Rybchenko __in_bcount(size) caddr_t data,
6295e111ed8SAndrew Rybchenko __in size_t size,
6305e111ed8SAndrew Rybchenko __out efx_vpd_tag_t *tagp,
6315e111ed8SAndrew Rybchenko __out efx_vpd_keyword_t *keywordp,
6325e111ed8SAndrew Rybchenko __out_opt unsigned int *payloadp,
6335e111ed8SAndrew Rybchenko __out_opt uint8_t *paylenp,
6345e111ed8SAndrew Rybchenko __inout unsigned int *contp)
6355e111ed8SAndrew Rybchenko {
6365e111ed8SAndrew Rybchenko efx_vpd_tag_t tag;
6375e111ed8SAndrew Rybchenko efx_vpd_keyword_t keyword = 0;
6385e111ed8SAndrew Rybchenko unsigned int offset;
6395e111ed8SAndrew Rybchenko unsigned int pos;
6405e111ed8SAndrew Rybchenko unsigned int index;
6415e111ed8SAndrew Rybchenko uint16_t taglen;
6425e111ed8SAndrew Rybchenko uint8_t keylen;
6435e111ed8SAndrew Rybchenko uint8_t paylen;
6445e111ed8SAndrew Rybchenko efx_rc_t rc;
6455e111ed8SAndrew Rybchenko
6465e111ed8SAndrew Rybchenko offset = index = 0;
6475e111ed8SAndrew Rybchenko _NOTE(CONSTANTCONDITION)
6485e111ed8SAndrew Rybchenko while (1) {
6495e111ed8SAndrew Rybchenko if ((rc = efx_vpd_next_tag(data, size, &offset,
6505e111ed8SAndrew Rybchenko &tag, &taglen)) != 0)
6515e111ed8SAndrew Rybchenko goto fail1;
6525e111ed8SAndrew Rybchenko
6535e111ed8SAndrew Rybchenko if (tag == EFX_VPD_END) {
6545e111ed8SAndrew Rybchenko keyword = 0;
6555e111ed8SAndrew Rybchenko paylen = 0;
6565e111ed8SAndrew Rybchenko index = 0;
6575e111ed8SAndrew Rybchenko break;
6585e111ed8SAndrew Rybchenko }
6595e111ed8SAndrew Rybchenko
6605e111ed8SAndrew Rybchenko if (tag == EFX_VPD_ID) {
6615e111ed8SAndrew Rybchenko if (index++ == *contp) {
6625e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(taglen, <, 0x100);
6635e111ed8SAndrew Rybchenko keyword = 0;
6645e111ed8SAndrew Rybchenko paylen = (uint8_t)MIN(taglen, 0xff);
6655e111ed8SAndrew Rybchenko
6665e111ed8SAndrew Rybchenko goto done;
6675e111ed8SAndrew Rybchenko }
6685e111ed8SAndrew Rybchenko } else {
6695e111ed8SAndrew Rybchenko for (pos = 0; pos != taglen; pos += 3 + keylen) {
6705e111ed8SAndrew Rybchenko if ((rc = efx_vpd_next_keyword(data + offset,
6715e111ed8SAndrew Rybchenko taglen, pos, &keyword, &keylen)) != 0)
6725e111ed8SAndrew Rybchenko goto fail2;
6735e111ed8SAndrew Rybchenko
6745e111ed8SAndrew Rybchenko if (index++ == *contp) {
6755e111ed8SAndrew Rybchenko offset += pos + 3;
6765e111ed8SAndrew Rybchenko paylen = keylen;
6775e111ed8SAndrew Rybchenko
6785e111ed8SAndrew Rybchenko goto done;
6795e111ed8SAndrew Rybchenko }
6805e111ed8SAndrew Rybchenko }
6815e111ed8SAndrew Rybchenko }
6825e111ed8SAndrew Rybchenko
6835e111ed8SAndrew Rybchenko offset += taglen;
6845e111ed8SAndrew Rybchenko }
6855e111ed8SAndrew Rybchenko
6865e111ed8SAndrew Rybchenko done:
6875e111ed8SAndrew Rybchenko *tagp = tag;
6885e111ed8SAndrew Rybchenko *keywordp = keyword;
6895e111ed8SAndrew Rybchenko if (payloadp != NULL)
6905e111ed8SAndrew Rybchenko *payloadp = offset;
6915e111ed8SAndrew Rybchenko if (paylenp != NULL)
6925e111ed8SAndrew Rybchenko *paylenp = paylen;
6935e111ed8SAndrew Rybchenko
6945e111ed8SAndrew Rybchenko *contp = index;
6955e111ed8SAndrew Rybchenko return (0);
6965e111ed8SAndrew Rybchenko
6975e111ed8SAndrew Rybchenko fail2:
6985e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
6995e111ed8SAndrew Rybchenko fail1:
7005e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
7015e111ed8SAndrew Rybchenko
7025e111ed8SAndrew Rybchenko return (rc);
7035e111ed8SAndrew Rybchenko }
7045e111ed8SAndrew Rybchenko
7055e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_vpd_hunk_get(__in_bcount (size)caddr_t data,__in size_t size,__in efx_vpd_tag_t tag,__in efx_vpd_keyword_t keyword,__out unsigned int * payloadp,__out uint8_t * paylenp)7065e111ed8SAndrew Rybchenko efx_vpd_hunk_get(
7075e111ed8SAndrew Rybchenko __in_bcount(size) caddr_t data,
7085e111ed8SAndrew Rybchenko __in size_t size,
7095e111ed8SAndrew Rybchenko __in efx_vpd_tag_t tag,
7105e111ed8SAndrew Rybchenko __in efx_vpd_keyword_t keyword,
7115e111ed8SAndrew Rybchenko __out unsigned int *payloadp,
7125e111ed8SAndrew Rybchenko __out uint8_t *paylenp)
7135e111ed8SAndrew Rybchenko {
7145e111ed8SAndrew Rybchenko efx_vpd_tag_t itag;
7155e111ed8SAndrew Rybchenko efx_vpd_keyword_t ikeyword;
7165e111ed8SAndrew Rybchenko unsigned int offset;
7175e111ed8SAndrew Rybchenko unsigned int pos;
7185e111ed8SAndrew Rybchenko uint16_t taglen;
7195e111ed8SAndrew Rybchenko uint8_t keylen;
7205e111ed8SAndrew Rybchenko efx_rc_t rc;
7215e111ed8SAndrew Rybchenko
7225e111ed8SAndrew Rybchenko offset = 0;
7235e111ed8SAndrew Rybchenko _NOTE(CONSTANTCONDITION)
7245e111ed8SAndrew Rybchenko while (1) {
7255e111ed8SAndrew Rybchenko if ((rc = efx_vpd_next_tag(data, size, &offset,
7265e111ed8SAndrew Rybchenko &itag, &taglen)) != 0)
7275e111ed8SAndrew Rybchenko goto fail1;
7285e111ed8SAndrew Rybchenko if (itag == EFX_VPD_END)
7295e111ed8SAndrew Rybchenko break;
7305e111ed8SAndrew Rybchenko
7315e111ed8SAndrew Rybchenko if (itag == tag) {
7325e111ed8SAndrew Rybchenko if (itag == EFX_VPD_ID) {
7335e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(taglen, <, 0x100);
7345e111ed8SAndrew Rybchenko
7355e111ed8SAndrew Rybchenko *paylenp = (uint8_t)MIN(taglen, 0xff);
7365e111ed8SAndrew Rybchenko *payloadp = offset;
7375e111ed8SAndrew Rybchenko return (0);
7385e111ed8SAndrew Rybchenko }
7395e111ed8SAndrew Rybchenko
7405e111ed8SAndrew Rybchenko for (pos = 0; pos != taglen; pos += 3 + keylen) {
7415e111ed8SAndrew Rybchenko if ((rc = efx_vpd_next_keyword(data + offset,
7425e111ed8SAndrew Rybchenko taglen, pos, &ikeyword, &keylen)) != 0)
7435e111ed8SAndrew Rybchenko goto fail2;
7445e111ed8SAndrew Rybchenko
7455e111ed8SAndrew Rybchenko if (ikeyword == keyword) {
7465e111ed8SAndrew Rybchenko *paylenp = keylen;
7475e111ed8SAndrew Rybchenko *payloadp = offset + pos + 3;
7485e111ed8SAndrew Rybchenko return (0);
7495e111ed8SAndrew Rybchenko }
7505e111ed8SAndrew Rybchenko }
7515e111ed8SAndrew Rybchenko }
7525e111ed8SAndrew Rybchenko
7535e111ed8SAndrew Rybchenko offset += taglen;
7545e111ed8SAndrew Rybchenko }
7555e111ed8SAndrew Rybchenko
7565e111ed8SAndrew Rybchenko /* Not an error */
7575e111ed8SAndrew Rybchenko return (ENOENT);
7585e111ed8SAndrew Rybchenko
7595e111ed8SAndrew Rybchenko fail2:
7605e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
7615e111ed8SAndrew Rybchenko fail1:
7625e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
7635e111ed8SAndrew Rybchenko
7645e111ed8SAndrew Rybchenko return (rc);
7655e111ed8SAndrew Rybchenko }
7665e111ed8SAndrew Rybchenko
7675e111ed8SAndrew Rybchenko __checkReturn efx_rc_t
efx_vpd_hunk_set(__in_bcount (size)caddr_t data,__in size_t size,__in efx_vpd_value_t * evvp)7685e111ed8SAndrew Rybchenko efx_vpd_hunk_set(
7695e111ed8SAndrew Rybchenko __in_bcount(size) caddr_t data,
7705e111ed8SAndrew Rybchenko __in size_t size,
7715e111ed8SAndrew Rybchenko __in efx_vpd_value_t *evvp)
7725e111ed8SAndrew Rybchenko {
7735e111ed8SAndrew Rybchenko efx_word_t word;
7745e111ed8SAndrew Rybchenko efx_vpd_tag_t tag;
7755e111ed8SAndrew Rybchenko efx_vpd_keyword_t keyword;
7765e111ed8SAndrew Rybchenko unsigned int offset;
7775e111ed8SAndrew Rybchenko unsigned int pos;
7785e111ed8SAndrew Rybchenko unsigned int taghead;
7795e111ed8SAndrew Rybchenko unsigned int source;
7805e111ed8SAndrew Rybchenko unsigned int dest;
7815e111ed8SAndrew Rybchenko unsigned int i;
7825e111ed8SAndrew Rybchenko uint16_t taglen;
7835e111ed8SAndrew Rybchenko uint8_t keylen;
7845e111ed8SAndrew Rybchenko uint8_t cksum;
7855e111ed8SAndrew Rybchenko size_t used;
7865e111ed8SAndrew Rybchenko efx_rc_t rc;
7875e111ed8SAndrew Rybchenko
7885e111ed8SAndrew Rybchenko switch (evvp->evv_tag) {
7895e111ed8SAndrew Rybchenko case EFX_VPD_ID:
7905e111ed8SAndrew Rybchenko if (evvp->evv_keyword != 0) {
7915e111ed8SAndrew Rybchenko rc = EINVAL;
7925e111ed8SAndrew Rybchenko goto fail1;
7935e111ed8SAndrew Rybchenko }
7945e111ed8SAndrew Rybchenko
7955e111ed8SAndrew Rybchenko /* Can't delete the ID keyword */
7965e111ed8SAndrew Rybchenko if (evvp->evv_length == 0) {
7975e111ed8SAndrew Rybchenko rc = EINVAL;
7985e111ed8SAndrew Rybchenko goto fail1;
7995e111ed8SAndrew Rybchenko }
8005e111ed8SAndrew Rybchenko break;
8015e111ed8SAndrew Rybchenko
8025e111ed8SAndrew Rybchenko case EFX_VPD_RO:
8035e111ed8SAndrew Rybchenko if (evvp->evv_keyword == EFX_VPD_KEYWORD('R', 'V')) {
8045e111ed8SAndrew Rybchenko rc = EINVAL;
8055e111ed8SAndrew Rybchenko goto fail1;
8065e111ed8SAndrew Rybchenko }
8075e111ed8SAndrew Rybchenko break;
8085e111ed8SAndrew Rybchenko
8095e111ed8SAndrew Rybchenko default:
8105e111ed8SAndrew Rybchenko rc = EINVAL;
8115e111ed8SAndrew Rybchenko goto fail1;
8125e111ed8SAndrew Rybchenko }
8135e111ed8SAndrew Rybchenko
8145e111ed8SAndrew Rybchenko /* Determine total size of all current tags */
8155e111ed8SAndrew Rybchenko if ((rc = efx_vpd_hunk_length(data, size, &used)) != 0)
8165e111ed8SAndrew Rybchenko goto fail2;
8175e111ed8SAndrew Rybchenko
8185e111ed8SAndrew Rybchenko offset = 0;
8195e111ed8SAndrew Rybchenko _NOTE(CONSTANTCONDITION)
8205e111ed8SAndrew Rybchenko while (1) {
8215e111ed8SAndrew Rybchenko taghead = offset;
8225e111ed8SAndrew Rybchenko if ((rc = efx_vpd_next_tag(data, size, &offset,
8235e111ed8SAndrew Rybchenko &tag, &taglen)) != 0)
8245e111ed8SAndrew Rybchenko goto fail3;
8255e111ed8SAndrew Rybchenko if (tag == EFX_VPD_END)
8265e111ed8SAndrew Rybchenko break;
8275e111ed8SAndrew Rybchenko else if (tag != evvp->evv_tag) {
8285e111ed8SAndrew Rybchenko offset += taglen;
8295e111ed8SAndrew Rybchenko continue;
8305e111ed8SAndrew Rybchenko }
8315e111ed8SAndrew Rybchenko
8325e111ed8SAndrew Rybchenko /* We only support modifying large resource tags */
8335e111ed8SAndrew Rybchenko if (offset - taghead != 3) {
8345e111ed8SAndrew Rybchenko rc = EINVAL;
8355e111ed8SAndrew Rybchenko goto fail4;
8365e111ed8SAndrew Rybchenko }
8375e111ed8SAndrew Rybchenko
8385e111ed8SAndrew Rybchenko /*
8395e111ed8SAndrew Rybchenko * Work out the offset of the byte immediately after the
8405e111ed8SAndrew Rybchenko * old (=source) and new (=dest) new keyword/tag
8415e111ed8SAndrew Rybchenko */
8425e111ed8SAndrew Rybchenko pos = 0;
8435e111ed8SAndrew Rybchenko if (tag == EFX_VPD_ID) {
8445e111ed8SAndrew Rybchenko source = offset + taglen;
8455e111ed8SAndrew Rybchenko dest = offset + evvp->evv_length;
8465e111ed8SAndrew Rybchenko goto check_space;
8475e111ed8SAndrew Rybchenko }
8485e111ed8SAndrew Rybchenko
8495e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(tag, ==, EFX_VPD_RO);
8505e111ed8SAndrew Rybchenko source = dest = 0;
8515e111ed8SAndrew Rybchenko for (pos = 0; pos != taglen; pos += 3 + keylen) {
8525e111ed8SAndrew Rybchenko if ((rc = efx_vpd_next_keyword(data + offset,
8535e111ed8SAndrew Rybchenko taglen, pos, &keyword, &keylen)) != 0)
8545e111ed8SAndrew Rybchenko goto fail5;
8555e111ed8SAndrew Rybchenko
8565e111ed8SAndrew Rybchenko if (keyword == evvp->evv_keyword &&
8575e111ed8SAndrew Rybchenko evvp->evv_length == 0) {
8585e111ed8SAndrew Rybchenko /* Deleting this keyword */
8595e111ed8SAndrew Rybchenko source = offset + pos + 3 + keylen;
8605e111ed8SAndrew Rybchenko dest = offset + pos;
8615e111ed8SAndrew Rybchenko break;
8625e111ed8SAndrew Rybchenko
8635e111ed8SAndrew Rybchenko } else if (keyword == evvp->evv_keyword) {
8645e111ed8SAndrew Rybchenko /* Adjusting this keyword */
8655e111ed8SAndrew Rybchenko source = offset + pos + 3 + keylen;
8665e111ed8SAndrew Rybchenko dest = offset + pos + 3 + evvp->evv_length;
8675e111ed8SAndrew Rybchenko break;
8685e111ed8SAndrew Rybchenko
8695e111ed8SAndrew Rybchenko } else if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
8705e111ed8SAndrew Rybchenko /* The RV keyword must be at the end */
8715e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(pos + 3 + keylen, ==, taglen);
8725e111ed8SAndrew Rybchenko
8735e111ed8SAndrew Rybchenko /*
8745e111ed8SAndrew Rybchenko * The keyword doesn't already exist. If the
8755e111ed8SAndrew Rybchenko * user deleting a non-existant keyword then
8765e111ed8SAndrew Rybchenko * this is a no-op.
8775e111ed8SAndrew Rybchenko */
8785e111ed8SAndrew Rybchenko if (evvp->evv_length == 0)
8795e111ed8SAndrew Rybchenko return (0);
8805e111ed8SAndrew Rybchenko
8815e111ed8SAndrew Rybchenko /* Insert this keyword before the RV keyword */
8825e111ed8SAndrew Rybchenko source = offset + pos;
8835e111ed8SAndrew Rybchenko dest = offset + pos + 3 + evvp->evv_length;
8845e111ed8SAndrew Rybchenko break;
8855e111ed8SAndrew Rybchenko }
8865e111ed8SAndrew Rybchenko }
8875e111ed8SAndrew Rybchenko
8885e111ed8SAndrew Rybchenko check_space:
8895e111ed8SAndrew Rybchenko if (used + dest > size + source) {
8905e111ed8SAndrew Rybchenko rc = ENOSPC;
8915e111ed8SAndrew Rybchenko goto fail6;
8925e111ed8SAndrew Rybchenko }
8935e111ed8SAndrew Rybchenko
8945e111ed8SAndrew Rybchenko /* Move trailing data */
8955e111ed8SAndrew Rybchenko (void) memmove(data + dest, data + source, used - source);
8965e111ed8SAndrew Rybchenko
8975e111ed8SAndrew Rybchenko /* Copy contents */
8985e111ed8SAndrew Rybchenko memcpy(data + dest - evvp->evv_length, evvp->evv_value,
8995e111ed8SAndrew Rybchenko evvp->evv_length);
9005e111ed8SAndrew Rybchenko
9015e111ed8SAndrew Rybchenko /* Insert new keyword header if required */
9025e111ed8SAndrew Rybchenko if (tag != EFX_VPD_ID && evvp->evv_length > 0) {
9035e111ed8SAndrew Rybchenko EFX_POPULATE_WORD_1(word, EFX_WORD_0,
9045e111ed8SAndrew Rybchenko evvp->evv_keyword);
9055e111ed8SAndrew Rybchenko data[offset + pos + 0] =
9065e111ed8SAndrew Rybchenko EFX_WORD_FIELD(word, EFX_BYTE_0);
9075e111ed8SAndrew Rybchenko data[offset + pos + 1] =
9085e111ed8SAndrew Rybchenko EFX_WORD_FIELD(word, EFX_BYTE_1);
9095e111ed8SAndrew Rybchenko data[offset + pos + 2] = evvp->evv_length;
9105e111ed8SAndrew Rybchenko }
9115e111ed8SAndrew Rybchenko
9125e111ed8SAndrew Rybchenko /* Modify tag length (large resource type) */
9135e111ed8SAndrew Rybchenko taglen += (uint16_t)(dest - source);
9145e111ed8SAndrew Rybchenko EFX_POPULATE_WORD_1(word, EFX_WORD_0, taglen);
9155e111ed8SAndrew Rybchenko data[offset - 2] = EFX_WORD_FIELD(word, EFX_BYTE_0);
9165e111ed8SAndrew Rybchenko data[offset - 1] = EFX_WORD_FIELD(word, EFX_BYTE_1);
9175e111ed8SAndrew Rybchenko
9185e111ed8SAndrew Rybchenko goto checksum;
9195e111ed8SAndrew Rybchenko }
9205e111ed8SAndrew Rybchenko
9215e111ed8SAndrew Rybchenko /* Unable to find the matching tag */
9225e111ed8SAndrew Rybchenko rc = ENOENT;
9235e111ed8SAndrew Rybchenko goto fail7;
9245e111ed8SAndrew Rybchenko
9255e111ed8SAndrew Rybchenko checksum:
9265e111ed8SAndrew Rybchenko /* Find the RV tag, and update the checksum */
9275e111ed8SAndrew Rybchenko offset = 0;
9285e111ed8SAndrew Rybchenko _NOTE(CONSTANTCONDITION)
9295e111ed8SAndrew Rybchenko while (1) {
9305e111ed8SAndrew Rybchenko if ((rc = efx_vpd_next_tag(data, size, &offset,
9315e111ed8SAndrew Rybchenko &tag, &taglen)) != 0)
9325e111ed8SAndrew Rybchenko goto fail8;
9335e111ed8SAndrew Rybchenko if (tag == EFX_VPD_END)
9345e111ed8SAndrew Rybchenko break;
9355e111ed8SAndrew Rybchenko if (tag == EFX_VPD_RO) {
9365e111ed8SAndrew Rybchenko for (pos = 0; pos != taglen; pos += 3 + keylen) {
9375e111ed8SAndrew Rybchenko if ((rc = efx_vpd_next_keyword(data + offset,
9385e111ed8SAndrew Rybchenko taglen, pos, &keyword, &keylen)) != 0)
9395e111ed8SAndrew Rybchenko goto fail9;
9405e111ed8SAndrew Rybchenko
9415e111ed8SAndrew Rybchenko if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
9425e111ed8SAndrew Rybchenko cksum = 0;
9435e111ed8SAndrew Rybchenko for (i = 0; i < offset + pos + 3; i++)
9445e111ed8SAndrew Rybchenko cksum += data[i];
9455e111ed8SAndrew Rybchenko data[i] = -cksum;
9465e111ed8SAndrew Rybchenko break;
9475e111ed8SAndrew Rybchenko }
9485e111ed8SAndrew Rybchenko }
9495e111ed8SAndrew Rybchenko }
9505e111ed8SAndrew Rybchenko
9515e111ed8SAndrew Rybchenko offset += taglen;
9525e111ed8SAndrew Rybchenko }
9535e111ed8SAndrew Rybchenko
9545e111ed8SAndrew Rybchenko /* Zero out the unused portion */
9555e111ed8SAndrew Rybchenko (void) memset(data + offset + taglen, 0xff, size - offset - taglen);
9565e111ed8SAndrew Rybchenko
9575e111ed8SAndrew Rybchenko return (0);
9585e111ed8SAndrew Rybchenko
9595e111ed8SAndrew Rybchenko fail9:
9605e111ed8SAndrew Rybchenko EFSYS_PROBE(fail9);
9615e111ed8SAndrew Rybchenko fail8:
9625e111ed8SAndrew Rybchenko EFSYS_PROBE(fail8);
9635e111ed8SAndrew Rybchenko fail7:
9645e111ed8SAndrew Rybchenko EFSYS_PROBE(fail7);
9655e111ed8SAndrew Rybchenko fail6:
9665e111ed8SAndrew Rybchenko EFSYS_PROBE(fail6);
9675e111ed8SAndrew Rybchenko fail5:
9685e111ed8SAndrew Rybchenko EFSYS_PROBE(fail5);
9695e111ed8SAndrew Rybchenko fail4:
9705e111ed8SAndrew Rybchenko EFSYS_PROBE(fail4);
9715e111ed8SAndrew Rybchenko fail3:
9725e111ed8SAndrew Rybchenko EFSYS_PROBE(fail3);
9735e111ed8SAndrew Rybchenko fail2:
9745e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2);
9755e111ed8SAndrew Rybchenko fail1:
9765e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc);
9775e111ed8SAndrew Rybchenko
9785e111ed8SAndrew Rybchenko return (rc);
9795e111ed8SAndrew Rybchenko }
9805e111ed8SAndrew Rybchenko
9815e111ed8SAndrew Rybchenko void
efx_vpd_fini(__in efx_nic_t * enp)9825e111ed8SAndrew Rybchenko efx_vpd_fini(
9835e111ed8SAndrew Rybchenko __in efx_nic_t *enp)
9845e111ed8SAndrew Rybchenko {
9855e111ed8SAndrew Rybchenko const efx_vpd_ops_t *evpdop = enp->en_evpdop;
9865e111ed8SAndrew Rybchenko
9875e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
9885e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
9895e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
9905e111ed8SAndrew Rybchenko
9915e111ed8SAndrew Rybchenko if (evpdop->evpdo_fini != NULL)
9925e111ed8SAndrew Rybchenko evpdop->evpdo_fini(enp);
9935e111ed8SAndrew Rybchenko
9945e111ed8SAndrew Rybchenko enp->en_evpdop = NULL;
9955e111ed8SAndrew Rybchenko enp->en_mod_flags &= ~EFX_MOD_VPD;
9965e111ed8SAndrew Rybchenko }
9975e111ed8SAndrew Rybchenko
9985e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_VPD */
999