1227569Sphilip/*- 2301388Sarybchik * Copyright (c) 2009-2016 Solarflare Communications Inc. 3284555Sarybchik * All rights reserved. 4227569Sphilip * 5227569Sphilip * Redistribution and use in source and binary forms, with or without 6284555Sarybchik * modification, are permitted provided that the following conditions are met: 7227569Sphilip * 8284555Sarybchik * 1. Redistributions of source code must retain the above copyright notice, 9284555Sarybchik * this list of conditions and the following disclaimer. 10284555Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice, 11284555Sarybchik * this list of conditions and the following disclaimer in the documentation 12284555Sarybchik * and/or other materials provided with the distribution. 13284555Sarybchik * 14284555Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15284555Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16284555Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17284555Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18284555Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19284555Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20284555Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21284555Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22284555Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23284555Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24284555Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25284555Sarybchik * 26284555Sarybchik * The views and conclusions contained in the software and documentation are 27284555Sarybchik * those of the authors and should not be interpreted as representing official 28284555Sarybchik * policies, either expressed or implied, of the FreeBSD Project. 29227569Sphilip */ 30227569Sphilip 31228078Sphilip#include <sys/cdefs.h> 32228078Sphilip__FBSDID("$FreeBSD: stable/10/sys/dev/sfxge/common/siena_vpd.c 311062 2017-01-02 09:12:06Z arybchik $"); 33228078Sphilip 34227569Sphilip#include "efx.h" 35227569Sphilip#include "efx_impl.h" 36227569Sphilip 37227569Sphilip#if EFSYS_OPT_VPD 38227569Sphilip 39227569Sphilip#if EFSYS_OPT_SIENA 40227569Sphilip 41293927Sarybchikstatic __checkReturn efx_rc_t 42227569Sphilipsiena_vpd_get_static( 43227569Sphilip __in efx_nic_t *enp, 44294002Sarybchik __in uint32_t partn, 45227569Sphilip __deref_out_bcount_opt(*sizep) caddr_t *svpdp, 46227569Sphilip __out size_t *sizep) 47227569Sphilip{ 48227569Sphilip siena_mc_static_config_hdr_t *scfg; 49227569Sphilip caddr_t svpd; 50227569Sphilip size_t size; 51227569Sphilip uint8_t cksum; 52227569Sphilip unsigned int vpd_offset; 53227569Sphilip unsigned int vpd_length; 54227569Sphilip unsigned int hdr_length; 55227569Sphilip unsigned int pos; 56227569Sphilip unsigned int region; 57293927Sarybchik efx_rc_t rc; 58227569Sphilip 59227569Sphilip EFSYS_ASSERT(partn == MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0 || 60227569Sphilip partn == MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1); 61227569Sphilip 62227569Sphilip /* Allocate sufficient memory for the entire static cfg area */ 63227569Sphilip if ((rc = siena_nvram_partn_size(enp, partn, &size)) != 0) 64227569Sphilip goto fail1; 65227569Sphilip 66227569Sphilip EFSYS_KMEM_ALLOC(enp->en_esip, size, scfg); 67227569Sphilip if (scfg == NULL) { 68227569Sphilip rc = ENOMEM; 69227569Sphilip goto fail2; 70227569Sphilip } 71227569Sphilip 72227569Sphilip if ((rc = siena_nvram_partn_read(enp, partn, 0, 73227569Sphilip (caddr_t)scfg, SIENA_NVRAM_CHUNK)) != 0) 74227569Sphilip goto fail3; 75227569Sphilip 76227569Sphilip /* Verify the magic number */ 77227569Sphilip if (EFX_DWORD_FIELD(scfg->magic, EFX_DWORD_0) != 78227569Sphilip SIENA_MC_STATIC_CONFIG_MAGIC) { 79227569Sphilip rc = EINVAL; 80227569Sphilip goto fail4; 81227569Sphilip } 82227569Sphilip 83227569Sphilip /* All future versions of the structure must be backwards compatable */ 84227569Sphilip EFX_STATIC_ASSERT(SIENA_MC_STATIC_CONFIG_VERSION == 0); 85227569Sphilip 86227569Sphilip hdr_length = EFX_WORD_FIELD(scfg->length, EFX_WORD_0); 87227569Sphilip vpd_offset = EFX_DWORD_FIELD(scfg->static_vpd_offset, EFX_DWORD_0); 88227569Sphilip vpd_length = EFX_DWORD_FIELD(scfg->static_vpd_length, EFX_DWORD_0); 89227569Sphilip 90227569Sphilip /* Verify the hdr doesn't overflow the sector size */ 91227569Sphilip if (hdr_length > size || vpd_offset > size || vpd_length > size || 92227569Sphilip vpd_length + vpd_offset > size) { 93227569Sphilip rc = EINVAL; 94227569Sphilip goto fail5; 95227569Sphilip } 96227569Sphilip 97227569Sphilip /* Read the remainder of scfg + static vpd */ 98227569Sphilip region = vpd_offset + vpd_length; 99227569Sphilip if (region > SIENA_NVRAM_CHUNK) { 100227569Sphilip if ((rc = siena_nvram_partn_read(enp, partn, SIENA_NVRAM_CHUNK, 101227569Sphilip (caddr_t)scfg + SIENA_NVRAM_CHUNK, 102227569Sphilip region - SIENA_NVRAM_CHUNK)) != 0) 103227569Sphilip goto fail6; 104227569Sphilip } 105227569Sphilip 106227569Sphilip /* Verify checksum */ 107227569Sphilip cksum = 0; 108227569Sphilip for (pos = 0; pos < hdr_length; pos++) 109227569Sphilip cksum += ((uint8_t *)scfg)[pos]; 110227569Sphilip if (cksum != 0) { 111227569Sphilip rc = EINVAL; 112227569Sphilip goto fail7; 113227569Sphilip } 114227569Sphilip 115227569Sphilip if (vpd_length == 0) 116227569Sphilip svpd = NULL; 117227569Sphilip else { 118227569Sphilip /* Copy the vpd data out */ 119227569Sphilip EFSYS_KMEM_ALLOC(enp->en_esip, vpd_length, svpd); 120227569Sphilip if (svpd == NULL) { 121227569Sphilip rc = ENOMEM; 122227569Sphilip goto fail8; 123227569Sphilip } 124227569Sphilip memcpy(svpd, (caddr_t)scfg + vpd_offset, vpd_length); 125227569Sphilip } 126227569Sphilip 127227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, size, scfg); 128227569Sphilip 129227569Sphilip *svpdp = svpd; 130227569Sphilip *sizep = vpd_length; 131227569Sphilip 132227569Sphilip return (0); 133227569Sphilip 134227569Sphilipfail8: 135227569Sphilip EFSYS_PROBE(fail8); 136227569Sphilipfail7: 137227569Sphilip EFSYS_PROBE(fail7); 138227569Sphilipfail6: 139227569Sphilip EFSYS_PROBE(fail6); 140227569Sphilipfail5: 141227569Sphilip EFSYS_PROBE(fail5); 142227569Sphilipfail4: 143227569Sphilip EFSYS_PROBE(fail4); 144227569Sphilipfail3: 145227569Sphilip EFSYS_PROBE(fail3); 146227569Sphilip 147227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, size, scfg); 148227569Sphilip 149284555Sarybchikfail2: 150284555Sarybchik EFSYS_PROBE(fail2); 151227569Sphilipfail1: 152293927Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 153227569Sphilip 154227569Sphilip return (rc); 155227569Sphilip} 156227569Sphilip 157293927Sarybchik __checkReturn efx_rc_t 158227569Sphilipsiena_vpd_init( 159227569Sphilip __in efx_nic_t *enp) 160227569Sphilip{ 161284555Sarybchik efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 162227569Sphilip caddr_t svpd = NULL; 163311062Sarybchik unsigned int partn; 164227569Sphilip size_t size = 0; 165293927Sarybchik efx_rc_t rc; 166227569Sphilip 167227569Sphilip EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 168227569Sphilip 169227569Sphilip partn = (emip->emi_port == 1) 170227569Sphilip ? MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0 171227569Sphilip : MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1; 172227569Sphilip 173227569Sphilip /* 174227569Sphilip * We need the static VPD sector to present a unified static+dynamic 175227569Sphilip * VPD, that is, basically on every read, write, verify cycle. Since 176227569Sphilip * it should *never* change we can just cache it here. 177227569Sphilip */ 178227569Sphilip if ((rc = siena_vpd_get_static(enp, partn, &svpd, &size)) != 0) 179227569Sphilip goto fail1; 180227569Sphilip 181227569Sphilip if (svpd != NULL && size > 0) { 182227569Sphilip if ((rc = efx_vpd_hunk_verify(svpd, size, NULL)) != 0) 183227569Sphilip goto fail2; 184227569Sphilip } 185227569Sphilip 186227569Sphilip enp->en_u.siena.enu_svpd = svpd; 187227569Sphilip enp->en_u.siena.enu_svpd_length = size; 188227569Sphilip 189227569Sphilip return (0); 190227569Sphilip 191227569Sphilipfail2: 192227569Sphilip EFSYS_PROBE(fail2); 193227569Sphilip 194227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, size, svpd); 195227569Sphilipfail1: 196293927Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 197227569Sphilip 198227569Sphilip return (rc); 199227569Sphilip} 200227569Sphilip 201293927Sarybchik __checkReturn efx_rc_t 202227569Sphilipsiena_vpd_size( 203227569Sphilip __in efx_nic_t *enp, 204227569Sphilip __out size_t *sizep) 205227569Sphilip{ 206284555Sarybchik efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 207294002Sarybchik uint32_t partn; 208293927Sarybchik efx_rc_t rc; 209227569Sphilip 210227569Sphilip EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 211227569Sphilip 212227569Sphilip /* 213227569Sphilip * This function returns the total size the user should allocate 214227569Sphilip * for all VPD operations. We've already cached the static vpd, 215227569Sphilip * so we just need to return an upper bound on the dynamic vpd. 216227569Sphilip * Since the dynamic_config structure can change under our feet, 217227569Sphilip * (as version numbers are inserted), just be safe and return the 218227569Sphilip * total size of the dynamic_config *sector* 219227569Sphilip */ 220227569Sphilip partn = (emip->emi_port == 1) 221227569Sphilip ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 222227569Sphilip : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 223227569Sphilip 224227569Sphilip if ((rc = siena_nvram_partn_size(enp, partn, sizep)) != 0) 225227569Sphilip goto fail1; 226227569Sphilip 227227569Sphilip return (0); 228227569Sphilip 229227569Sphilipfail1: 230293927Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 231227569Sphilip 232227569Sphilip return (rc); 233227569Sphilip} 234227569Sphilip 235293927Sarybchik __checkReturn efx_rc_t 236227569Sphilipsiena_vpd_read( 237227569Sphilip __in efx_nic_t *enp, 238227569Sphilip __out_bcount(size) caddr_t data, 239227569Sphilip __in size_t size) 240227569Sphilip{ 241284555Sarybchik efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 242284555Sarybchik siena_mc_dynamic_config_hdr_t *dcfg = NULL; 243227569Sphilip unsigned int vpd_length; 244227569Sphilip unsigned int vpd_offset; 245227569Sphilip unsigned int dcfg_partn; 246227569Sphilip size_t dcfg_size; 247293927Sarybchik efx_rc_t rc; 248227569Sphilip 249227569Sphilip EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 250227569Sphilip 251227569Sphilip dcfg_partn = (emip->emi_port == 1) 252227569Sphilip ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 253227569Sphilip : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 254227569Sphilip 255227569Sphilip if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn, 256227569Sphilip B_TRUE, &dcfg, &dcfg_size)) != 0) 257227569Sphilip goto fail1; 258227569Sphilip 259227569Sphilip vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0); 260227569Sphilip vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0); 261227569Sphilip 262227569Sphilip if (vpd_length > size) { 263227569Sphilip rc = EFAULT; /* Invalid dcfg: header bigger than sector */ 264227569Sphilip goto fail2; 265227569Sphilip } 266227569Sphilip 267227569Sphilip EFSYS_ASSERT3U(vpd_length, <=, size); 268227569Sphilip memcpy(data, (caddr_t)dcfg + vpd_offset, vpd_length); 269227569Sphilip 270227569Sphilip /* Pad data with all-1s, consistent with update operations */ 271227569Sphilip memset(data + vpd_length, 0xff, size - vpd_length); 272227569Sphilip 273227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg); 274227569Sphilip 275227569Sphilip return (0); 276227569Sphilip 277227569Sphilipfail2: 278227569Sphilip EFSYS_PROBE(fail2); 279227569Sphilip 280227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg); 281227569Sphilipfail1: 282293927Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 283227569Sphilip 284227569Sphilip return (rc); 285227569Sphilip} 286227569Sphilip 287293927Sarybchik __checkReturn efx_rc_t 288227569Sphilipsiena_vpd_verify( 289227569Sphilip __in efx_nic_t *enp, 290227569Sphilip __in_bcount(size) caddr_t data, 291227569Sphilip __in size_t size) 292227569Sphilip{ 293227569Sphilip efx_vpd_tag_t stag; 294227569Sphilip efx_vpd_tag_t dtag; 295227569Sphilip efx_vpd_keyword_t skey; 296227569Sphilip efx_vpd_keyword_t dkey; 297227569Sphilip unsigned int scont; 298227569Sphilip unsigned int dcont; 299227569Sphilip 300293927Sarybchik efx_rc_t rc; 301227569Sphilip 302227569Sphilip EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 303227569Sphilip 304227569Sphilip /* 305227569Sphilip * Strictly you could take the view that dynamic vpd is optional. 306227569Sphilip * Instead, to conform more closely to the read/verify/reinit() 307227569Sphilip * paradigm, we require dynamic vpd. siena_vpd_reinit() will 308227569Sphilip * reinitialize it as required. 309227569Sphilip */ 310227569Sphilip if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0) 311227569Sphilip goto fail1; 312227569Sphilip 313227569Sphilip /* 314227569Sphilip * Verify that there is no duplication between the static and 315227569Sphilip * dynamic cfg sectors. 316227569Sphilip */ 317227569Sphilip if (enp->en_u.siena.enu_svpd_length == 0) 318227569Sphilip goto done; 319227569Sphilip 320227569Sphilip dcont = 0; 321227569Sphilip _NOTE(CONSTANTCONDITION) 322227569Sphilip while (1) { 323227569Sphilip if ((rc = efx_vpd_hunk_next(data, size, &dtag, 324227569Sphilip &dkey, NULL, NULL, &dcont)) != 0) 325227569Sphilip goto fail2; 326227569Sphilip if (dcont == 0) 327227569Sphilip break; 328227569Sphilip 329294383Sarybchik /* 330294383Sarybchik * Skip the RV keyword. It should be present in both the static 331294383Sarybchik * and dynamic cfg sectors. 332294383Sarybchik */ 333294383Sarybchik if (dtag == EFX_VPD_RO && dkey == EFX_VPD_KEYWORD('R', 'V')) 334294383Sarybchik continue; 335294383Sarybchik 336227569Sphilip scont = 0; 337227569Sphilip _NOTE(CONSTANTCONDITION) 338227569Sphilip while (1) { 339227569Sphilip if ((rc = efx_vpd_hunk_next( 340227569Sphilip enp->en_u.siena.enu_svpd, 341227569Sphilip enp->en_u.siena.enu_svpd_length, &stag, &skey, 342227569Sphilip NULL, NULL, &scont)) != 0) 343227569Sphilip goto fail3; 344227569Sphilip if (scont == 0) 345227569Sphilip break; 346227569Sphilip 347227569Sphilip if (stag == dtag && skey == dkey) { 348227569Sphilip rc = EEXIST; 349227569Sphilip goto fail4; 350227569Sphilip } 351227569Sphilip } 352227569Sphilip } 353227569Sphilip 354227569Sphilipdone: 355227569Sphilip return (0); 356227569Sphilip 357227569Sphilipfail4: 358227569Sphilip EFSYS_PROBE(fail4); 359227569Sphilipfail3: 360227569Sphilip EFSYS_PROBE(fail3); 361227569Sphilipfail2: 362227569Sphilip EFSYS_PROBE(fail2); 363227569Sphilipfail1: 364293927Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 365227569Sphilip 366227569Sphilip return (rc); 367227569Sphilip} 368227569Sphilip 369293927Sarybchik __checkReturn efx_rc_t 370227569Sphilipsiena_vpd_reinit( 371227569Sphilip __in efx_nic_t *enp, 372227569Sphilip __in_bcount(size) caddr_t data, 373227569Sphilip __in size_t size) 374227569Sphilip{ 375227569Sphilip boolean_t wantpid; 376293927Sarybchik efx_rc_t rc; 377227569Sphilip 378227569Sphilip /* 379227569Sphilip * Only create a PID if the dynamic cfg doesn't have one 380227569Sphilip */ 381227569Sphilip if (enp->en_u.siena.enu_svpd_length == 0) 382227569Sphilip wantpid = B_TRUE; 383227569Sphilip else { 384227569Sphilip unsigned int offset; 385227569Sphilip uint8_t length; 386227569Sphilip 387227569Sphilip rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd, 388227569Sphilip enp->en_u.siena.enu_svpd_length, 389227569Sphilip EFX_VPD_ID, 0, &offset, &length); 390227569Sphilip if (rc == 0) 391227569Sphilip wantpid = B_FALSE; 392227569Sphilip else if (rc == ENOENT) 393227569Sphilip wantpid = B_TRUE; 394227569Sphilip else 395227569Sphilip goto fail1; 396227569Sphilip } 397227569Sphilip 398227569Sphilip if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0) 399227569Sphilip goto fail2; 400227569Sphilip 401227569Sphilip return (0); 402227569Sphilip 403227569Sphilipfail2: 404227569Sphilip EFSYS_PROBE(fail2); 405227569Sphilipfail1: 406293927Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 407227569Sphilip 408227569Sphilip return (rc); 409227569Sphilip} 410227569Sphilip 411293927Sarybchik __checkReturn efx_rc_t 412227569Sphilipsiena_vpd_get( 413227569Sphilip __in efx_nic_t *enp, 414227569Sphilip __in_bcount(size) caddr_t data, 415227569Sphilip __in size_t size, 416227569Sphilip __inout efx_vpd_value_t *evvp) 417227569Sphilip{ 418227569Sphilip unsigned int offset; 419227569Sphilip uint8_t length; 420293927Sarybchik efx_rc_t rc; 421227569Sphilip 422227569Sphilip EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 423227569Sphilip 424227569Sphilip /* Attempt to satisfy the request from svpd first */ 425227569Sphilip if (enp->en_u.siena.enu_svpd_length > 0) { 426227569Sphilip if ((rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd, 427227569Sphilip enp->en_u.siena.enu_svpd_length, evvp->evv_tag, 428227569Sphilip evvp->evv_keyword, &offset, &length)) == 0) { 429227569Sphilip evvp->evv_length = length; 430227569Sphilip memcpy(evvp->evv_value, 431227569Sphilip enp->en_u.siena.enu_svpd + offset, length); 432227569Sphilip return (0); 433227569Sphilip } else if (rc != ENOENT) 434227569Sphilip goto fail1; 435227569Sphilip } 436227569Sphilip 437227569Sphilip /* And then from the provided data buffer */ 438227569Sphilip if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag, 439301363Sarybchik evvp->evv_keyword, &offset, &length)) != 0) { 440301363Sarybchik if (rc == ENOENT) 441301363Sarybchik return (rc); 442301363Sarybchik 443227569Sphilip goto fail2; 444301363Sarybchik } 445227569Sphilip 446227569Sphilip evvp->evv_length = length; 447227569Sphilip memcpy(evvp->evv_value, data + offset, length); 448227569Sphilip 449227569Sphilip return (0); 450227569Sphilip 451227569Sphilipfail2: 452227569Sphilip EFSYS_PROBE(fail2); 453227569Sphilipfail1: 454293927Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 455227569Sphilip 456227569Sphilip return (rc); 457227569Sphilip} 458227569Sphilip 459293927Sarybchik __checkReturn efx_rc_t 460227569Sphilipsiena_vpd_set( 461227569Sphilip __in efx_nic_t *enp, 462227569Sphilip __in_bcount(size) caddr_t data, 463227569Sphilip __in size_t size, 464227569Sphilip __in efx_vpd_value_t *evvp) 465227569Sphilip{ 466293927Sarybchik efx_rc_t rc; 467227569Sphilip 468227569Sphilip EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 469227569Sphilip 470227569Sphilip /* If the provided (tag,keyword) exists in svpd, then it is readonly */ 471227569Sphilip if (enp->en_u.siena.enu_svpd_length > 0) { 472227569Sphilip unsigned int offset; 473227569Sphilip uint8_t length; 474227569Sphilip 475227569Sphilip if ((rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd, 476227569Sphilip enp->en_u.siena.enu_svpd_length, evvp->evv_tag, 477227569Sphilip evvp->evv_keyword, &offset, &length)) == 0) { 478227569Sphilip rc = EACCES; 479227569Sphilip goto fail1; 480227569Sphilip } 481227569Sphilip } 482227569Sphilip 483227569Sphilip if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0) 484227569Sphilip goto fail2; 485227569Sphilip 486227569Sphilip return (0); 487227569Sphilip 488227569Sphilipfail2: 489227569Sphilip EFSYS_PROBE(fail2); 490227569Sphilipfail1: 491293927Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 492227569Sphilip 493227569Sphilip return (rc); 494227569Sphilip} 495227569Sphilip 496293927Sarybchik __checkReturn efx_rc_t 497227569Sphilipsiena_vpd_next( 498227569Sphilip __in efx_nic_t *enp, 499227569Sphilip __in_bcount(size) caddr_t data, 500227569Sphilip __in size_t size, 501227569Sphilip __out efx_vpd_value_t *evvp, 502227569Sphilip __inout unsigned int *contp) 503227569Sphilip{ 504227569Sphilip _NOTE(ARGUNUSED(enp, data, size, evvp, contp)) 505227569Sphilip 506227569Sphilip return (ENOTSUP); 507227569Sphilip} 508227569Sphilip 509293927Sarybchik __checkReturn efx_rc_t 510227569Sphilipsiena_vpd_write( 511227569Sphilip __in efx_nic_t *enp, 512227569Sphilip __in_bcount(size) caddr_t data, 513227569Sphilip __in size_t size) 514227569Sphilip{ 515284555Sarybchik efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 516284555Sarybchik siena_mc_dynamic_config_hdr_t *dcfg = NULL; 517227569Sphilip unsigned int vpd_offset; 518227569Sphilip unsigned int dcfg_partn; 519227569Sphilip unsigned int hdr_length; 520227569Sphilip unsigned int pos; 521227569Sphilip uint8_t cksum; 522227569Sphilip size_t partn_size, dcfg_size; 523227569Sphilip size_t vpd_length; 524293927Sarybchik efx_rc_t rc; 525227569Sphilip 526227569Sphilip EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 527227569Sphilip 528227569Sphilip /* Determine total length of all tags */ 529227569Sphilip if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0) 530227569Sphilip goto fail1; 531227569Sphilip 532227569Sphilip /* Lock dynamic config sector for write, and read structure only */ 533227569Sphilip dcfg_partn = (emip->emi_port == 1) 534227569Sphilip ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 535227569Sphilip : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 536227569Sphilip 537227569Sphilip if ((rc = siena_nvram_partn_size(enp, dcfg_partn, &partn_size)) != 0) 538227569Sphilip goto fail2; 539227569Sphilip 540227569Sphilip if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0) 541284555Sarybchik goto fail3; 542227569Sphilip 543227569Sphilip if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn, 544227569Sphilip B_FALSE, &dcfg, &dcfg_size)) != 0) 545284555Sarybchik goto fail4; 546227569Sphilip 547227569Sphilip hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0); 548227569Sphilip 549227569Sphilip /* Allocated memory should have room for the new VPD */ 550227569Sphilip if (hdr_length + vpd_length > dcfg_size) { 551227569Sphilip rc = ENOSPC; 552284555Sarybchik goto fail5; 553227569Sphilip } 554227569Sphilip 555227569Sphilip /* Copy in new vpd and update header */ 556227569Sphilip vpd_offset = dcfg_size - vpd_length; 557280535Sarybchik EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, EFX_DWORD_0, vpd_offset); 558227569Sphilip memcpy((caddr_t)dcfg + vpd_offset, data, vpd_length); 559280535Sarybchik EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_length, EFX_DWORD_0, vpd_length); 560227569Sphilip 561227569Sphilip /* Update the checksum */ 562227569Sphilip cksum = 0; 563227569Sphilip for (pos = 0; pos < hdr_length; pos++) 564227569Sphilip cksum += ((uint8_t *)dcfg)[pos]; 565227569Sphilip dcfg->csum.eb_u8[0] -= cksum; 566227569Sphilip 567227569Sphilip /* Erase and write the new sector */ 568227569Sphilip if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, partn_size)) != 0) 569284555Sarybchik goto fail6; 570227569Sphilip 571227569Sphilip /* Write out the new structure to nvram */ 572227569Sphilip if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0, (caddr_t)dcfg, 573227569Sphilip vpd_offset + vpd_length)) != 0) 574284555Sarybchik goto fail7; 575227569Sphilip 576227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg); 577227569Sphilip 578227569Sphilip siena_nvram_partn_unlock(enp, dcfg_partn); 579227569Sphilip 580227569Sphilip return (0); 581227569Sphilip 582284555Sarybchikfail7: 583284555Sarybchik EFSYS_PROBE(fail7); 584284555Sarybchikfail6: 585284555Sarybchik EFSYS_PROBE(fail6); 586227569Sphilipfail5: 587227569Sphilip EFSYS_PROBE(fail5); 588284555Sarybchik 589284555Sarybchik EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg); 590227569Sphilipfail4: 591227569Sphilip EFSYS_PROBE(fail4); 592284555Sarybchik 593284555Sarybchik siena_nvram_partn_unlock(enp, dcfg_partn); 594227569Sphilipfail3: 595227569Sphilip EFSYS_PROBE(fail3); 596227569Sphilipfail2: 597227569Sphilip EFSYS_PROBE(fail2); 598227569Sphilipfail1: 599293927Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 600227569Sphilip 601227569Sphilip return (rc); 602227569Sphilip} 603227569Sphilip 604227569Sphilip void 605227569Sphilipsiena_vpd_fini( 606227569Sphilip __in efx_nic_t *enp) 607227569Sphilip{ 608227569Sphilip EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 609227569Sphilip 610227569Sphilip if (enp->en_u.siena.enu_svpd_length > 0) { 611227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, enp->en_u.siena.enu_svpd_length, 612227569Sphilip enp->en_u.siena.enu_svpd); 613227569Sphilip 614227569Sphilip enp->en_u.siena.enu_svpd = NULL; 615227569Sphilip enp->en_u.siena.enu_svpd_length = 0; 616227569Sphilip } 617227569Sphilip} 618227569Sphilip 619227569Sphilip#endif /* EFSYS_OPT_SIENA */ 620227569Sphilip 621227569Sphilip#endif /* EFSYS_OPT_VPD */ 622