1227569Sphilip/*- 2227569Sphilip * Copyright 2009 Solarflare Communications Inc. All rights reserved. 3227569Sphilip * 4227569Sphilip * Redistribution and use in source and binary forms, with or without 5227569Sphilip * modification, are permitted provided that the following conditions 6227569Sphilip * are met: 7227569Sphilip * 1. Redistributions of source code must retain the above copyright 8227569Sphilip * notice, this list of conditions and the following disclaimer. 9227569Sphilip * 2. Redistributions in binary form must reproduce the above copyright 10227569Sphilip * notice, this list of conditions and the following disclaimer in the 11227569Sphilip * documentation and/or other materials provided with the distribution. 12227569Sphilip * 13227569Sphilip * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND 14227569Sphilip * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15227569Sphilip * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16227569Sphilip * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17227569Sphilip * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18227569Sphilip * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19227569Sphilip * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20227569Sphilip * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21227569Sphilip * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22227569Sphilip * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23227569Sphilip * SUCH DAMAGE. 24227569Sphilip */ 25227569Sphilip 26228100Sphilip#include <sys/cdefs.h> 27228100Sphilip__FBSDID("$FreeBSD$"); 28228100Sphilip 29227569Sphilip#include "efsys.h" 30227569Sphilip#include "efx.h" 31227569Sphilip#include "efx_types.h" 32227569Sphilip#include "efx_regs.h" 33227569Sphilip#include "efx_impl.h" 34227569Sphilip 35227569Sphilip#if EFSYS_OPT_VPD 36227569Sphilip 37227569Sphilip#if EFSYS_OPT_SIENA 38227569Sphilip 39227569Sphilipstatic __checkReturn int 40227569Sphilipsiena_vpd_get_static( 41227569Sphilip __in efx_nic_t *enp, 42227569Sphilip __in unsigned int partn, 43227569Sphilip __deref_out_bcount_opt(*sizep) caddr_t *svpdp, 44227569Sphilip __out size_t *sizep) 45227569Sphilip{ 46227569Sphilip siena_mc_static_config_hdr_t *scfg; 47227569Sphilip caddr_t svpd; 48227569Sphilip size_t size; 49227569Sphilip uint8_t cksum; 50227569Sphilip unsigned int vpd_offset; 51227569Sphilip unsigned int vpd_length; 52227569Sphilip unsigned int hdr_length; 53227569Sphilip unsigned int pos; 54227569Sphilip unsigned int region; 55227569Sphilip int rc; 56227569Sphilip 57227569Sphilip EFSYS_ASSERT(partn == MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0 || 58227569Sphilip partn == MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1); 59227569Sphilip 60227569Sphilip /* Allocate sufficient memory for the entire static cfg area */ 61227569Sphilip if ((rc = siena_nvram_partn_size(enp, partn, &size)) != 0) 62227569Sphilip goto fail1; 63227569Sphilip 64227569Sphilip EFSYS_KMEM_ALLOC(enp->en_esip, size, scfg); 65227569Sphilip if (scfg == NULL) { 66227569Sphilip rc = ENOMEM; 67227569Sphilip goto fail2; 68227569Sphilip } 69227569Sphilip 70227569Sphilip if ((rc = siena_nvram_partn_read(enp, partn, 0, 71227569Sphilip (caddr_t)scfg, SIENA_NVRAM_CHUNK)) != 0) 72227569Sphilip goto fail3; 73227569Sphilip 74227569Sphilip /* Verify the magic number */ 75227569Sphilip if (EFX_DWORD_FIELD(scfg->magic, EFX_DWORD_0) != 76227569Sphilip SIENA_MC_STATIC_CONFIG_MAGIC) { 77227569Sphilip rc = EINVAL; 78227569Sphilip goto fail4; 79227569Sphilip } 80227569Sphilip 81227569Sphilip /* All future versions of the structure must be backwards compatable */ 82227569Sphilip EFX_STATIC_ASSERT(SIENA_MC_STATIC_CONFIG_VERSION == 0); 83227569Sphilip 84227569Sphilip hdr_length = EFX_WORD_FIELD(scfg->length, EFX_WORD_0); 85227569Sphilip vpd_offset = EFX_DWORD_FIELD(scfg->static_vpd_offset, EFX_DWORD_0); 86227569Sphilip vpd_length = EFX_DWORD_FIELD(scfg->static_vpd_length, EFX_DWORD_0); 87227569Sphilip 88227569Sphilip /* Verify the hdr doesn't overflow the sector size */ 89227569Sphilip if (hdr_length > size || vpd_offset > size || vpd_length > size || 90227569Sphilip vpd_length + vpd_offset > size) { 91227569Sphilip rc = EINVAL; 92227569Sphilip goto fail5; 93227569Sphilip } 94227569Sphilip 95227569Sphilip /* Read the remainder of scfg + static vpd */ 96227569Sphilip region = vpd_offset + vpd_length; 97227569Sphilip if (region > SIENA_NVRAM_CHUNK) { 98227569Sphilip if ((rc = siena_nvram_partn_read(enp, partn, SIENA_NVRAM_CHUNK, 99227569Sphilip (caddr_t)scfg + SIENA_NVRAM_CHUNK, 100227569Sphilip region - SIENA_NVRAM_CHUNK)) != 0) 101227569Sphilip goto fail6; 102227569Sphilip } 103227569Sphilip 104227569Sphilip /* Verify checksum */ 105227569Sphilip cksum = 0; 106227569Sphilip for (pos = 0; pos < hdr_length; pos++) 107227569Sphilip cksum += ((uint8_t *)scfg)[pos]; 108227569Sphilip if (cksum != 0) { 109227569Sphilip rc = EINVAL; 110227569Sphilip goto fail7; 111227569Sphilip } 112227569Sphilip 113227569Sphilip if (vpd_length == 0) 114227569Sphilip svpd = NULL; 115227569Sphilip else { 116227569Sphilip /* Copy the vpd data out */ 117227569Sphilip EFSYS_KMEM_ALLOC(enp->en_esip, vpd_length, svpd); 118227569Sphilip if (svpd == NULL) { 119227569Sphilip rc = ENOMEM; 120227569Sphilip goto fail8; 121227569Sphilip } 122227569Sphilip memcpy(svpd, (caddr_t)scfg + vpd_offset, vpd_length); 123227569Sphilip } 124227569Sphilip 125227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, size, scfg); 126227569Sphilip 127227569Sphilip *svpdp = svpd; 128227569Sphilip *sizep = vpd_length; 129227569Sphilip 130227569Sphilip return (0); 131227569Sphilip 132227569Sphilipfail8: 133227569Sphilip EFSYS_PROBE(fail8); 134227569Sphilipfail7: 135227569Sphilip EFSYS_PROBE(fail7); 136227569Sphilipfail6: 137227569Sphilip EFSYS_PROBE(fail6); 138227569Sphilipfail5: 139227569Sphilip EFSYS_PROBE(fail5); 140227569Sphilipfail4: 141227569Sphilip EFSYS_PROBE(fail4); 142227569Sphilipfail3: 143227569Sphilip EFSYS_PROBE(fail3); 144227569Sphilipfail2: 145227569Sphilip EFSYS_PROBE(fail2); 146227569Sphilip 147227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, size, scfg); 148227569Sphilip 149227569Sphilipfail1: 150227569Sphilip EFSYS_PROBE1(fail1, int, rc); 151227569Sphilip 152227569Sphilip return (rc); 153227569Sphilip} 154227569Sphilip 155227569Sphilip __checkReturn int 156227569Sphilipsiena_vpd_init( 157227569Sphilip __in efx_nic_t *enp) 158227569Sphilip{ 159227569Sphilip efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 160227569Sphilip caddr_t svpd = NULL; 161227569Sphilip unsigned partn; 162227569Sphilip size_t size = 0; 163227569Sphilip int rc; 164227569Sphilip 165227569Sphilip EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 166227569Sphilip 167227569Sphilip partn = (emip->emi_port == 1) 168227569Sphilip ? MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0 169227569Sphilip : MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1; 170227569Sphilip 171227569Sphilip /* 172227569Sphilip * We need the static VPD sector to present a unified static+dynamic 173227569Sphilip * VPD, that is, basically on every read, write, verify cycle. Since 174227569Sphilip * it should *never* change we can just cache it here. 175227569Sphilip */ 176227569Sphilip if ((rc = siena_vpd_get_static(enp, partn, &svpd, &size)) != 0) 177227569Sphilip goto fail1; 178227569Sphilip 179227569Sphilip if (svpd != NULL && size > 0) { 180227569Sphilip if ((rc = efx_vpd_hunk_verify(svpd, size, NULL)) != 0) 181227569Sphilip goto fail2; 182227569Sphilip } 183227569Sphilip 184227569Sphilip enp->en_u.siena.enu_svpd = svpd; 185227569Sphilip enp->en_u.siena.enu_svpd_length = size; 186227569Sphilip 187227569Sphilip return (0); 188227569Sphilip 189227569Sphilipfail2: 190227569Sphilip EFSYS_PROBE(fail2); 191227569Sphilip 192227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, size, svpd); 193227569Sphilipfail1: 194227569Sphilip EFSYS_PROBE1(fail1, int, rc); 195227569Sphilip 196227569Sphilip return (rc); 197227569Sphilip} 198227569Sphilip 199227569Sphilip __checkReturn int 200227569Sphilipsiena_vpd_size( 201227569Sphilip __in efx_nic_t *enp, 202227569Sphilip __out size_t *sizep) 203227569Sphilip{ 204227569Sphilip efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 205227569Sphilip unsigned int partn; 206227569Sphilip int rc; 207227569Sphilip 208227569Sphilip EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 209227569Sphilip 210227569Sphilip /* 211227569Sphilip * This function returns the total size the user should allocate 212227569Sphilip * for all VPD operations. We've already cached the static vpd, 213227569Sphilip * so we just need to return an upper bound on the dynamic vpd. 214227569Sphilip * Since the dynamic_config structure can change under our feet, 215227569Sphilip * (as version numbers are inserted), just be safe and return the 216227569Sphilip * total size of the dynamic_config *sector* 217227569Sphilip */ 218227569Sphilip partn = (emip->emi_port == 1) 219227569Sphilip ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 220227569Sphilip : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 221227569Sphilip 222227569Sphilip if ((rc = siena_nvram_partn_size(enp, partn, sizep)) != 0) 223227569Sphilip goto fail1; 224227569Sphilip 225227569Sphilip return (0); 226227569Sphilip 227227569Sphilipfail1: 228227569Sphilip EFSYS_PROBE1(fail1, int, rc); 229227569Sphilip 230227569Sphilip return (rc); 231227569Sphilip} 232227569Sphilip 233227569Sphilip __checkReturn int 234227569Sphilipsiena_vpd_read( 235227569Sphilip __in efx_nic_t *enp, 236227569Sphilip __out_bcount(size) caddr_t data, 237227569Sphilip __in size_t size) 238227569Sphilip{ 239227569Sphilip efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 240227569Sphilip siena_mc_dynamic_config_hdr_t *dcfg; 241227569Sphilip unsigned int vpd_length; 242227569Sphilip unsigned int vpd_offset; 243227569Sphilip unsigned int dcfg_partn; 244227569Sphilip size_t dcfg_size; 245227569Sphilip int rc; 246227569Sphilip 247227569Sphilip EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 248227569Sphilip 249227569Sphilip dcfg_partn = (emip->emi_port == 1) 250227569Sphilip ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 251227569Sphilip : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 252227569Sphilip 253227569Sphilip if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn, 254227569Sphilip B_TRUE, &dcfg, &dcfg_size)) != 0) 255227569Sphilip goto fail1; 256227569Sphilip 257227569Sphilip vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0); 258227569Sphilip vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0); 259227569Sphilip 260227569Sphilip if (vpd_length > size) { 261227569Sphilip rc = EFAULT; /* Invalid dcfg: header bigger than sector */ 262227569Sphilip goto fail2; 263227569Sphilip } 264227569Sphilip 265227569Sphilip EFSYS_ASSERT3U(vpd_length, <=, size); 266227569Sphilip memcpy(data, (caddr_t)dcfg + vpd_offset, vpd_length); 267227569Sphilip 268227569Sphilip /* Pad data with all-1s, consistent with update operations */ 269227569Sphilip memset(data + vpd_length, 0xff, size - vpd_length); 270227569Sphilip 271227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg); 272227569Sphilip 273227569Sphilip return (0); 274227569Sphilip 275227569Sphilipfail2: 276227569Sphilip EFSYS_PROBE(fail2); 277227569Sphilip 278227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg); 279227569Sphilipfail1: 280227569Sphilip EFSYS_PROBE1(fail1, int, rc); 281227569Sphilip 282227569Sphilip return (rc); 283227569Sphilip} 284227569Sphilip 285227569Sphilip __checkReturn int 286227569Sphilipsiena_vpd_verify( 287227569Sphilip __in efx_nic_t *enp, 288227569Sphilip __in_bcount(size) caddr_t data, 289227569Sphilip __in size_t size) 290227569Sphilip{ 291227569Sphilip efx_vpd_tag_t stag; 292227569Sphilip efx_vpd_tag_t dtag; 293227569Sphilip efx_vpd_keyword_t skey; 294227569Sphilip efx_vpd_keyword_t dkey; 295227569Sphilip unsigned int scont; 296227569Sphilip unsigned int dcont; 297227569Sphilip 298227569Sphilip int rc; 299227569Sphilip 300227569Sphilip EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 301227569Sphilip 302227569Sphilip /* 303227569Sphilip * Strictly you could take the view that dynamic vpd is optional. 304227569Sphilip * Instead, to conform more closely to the read/verify/reinit() 305227569Sphilip * paradigm, we require dynamic vpd. siena_vpd_reinit() will 306227569Sphilip * reinitialize it as required. 307227569Sphilip */ 308227569Sphilip if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0) 309227569Sphilip goto fail1; 310227569Sphilip 311227569Sphilip /* 312227569Sphilip * Verify that there is no duplication between the static and 313227569Sphilip * dynamic cfg sectors. 314227569Sphilip */ 315227569Sphilip if (enp->en_u.siena.enu_svpd_length == 0) 316227569Sphilip goto done; 317227569Sphilip 318227569Sphilip dcont = 0; 319227569Sphilip _NOTE(CONSTANTCONDITION) 320227569Sphilip while (1) { 321227569Sphilip if ((rc = efx_vpd_hunk_next(data, size, &dtag, 322227569Sphilip &dkey, NULL, NULL, &dcont)) != 0) 323227569Sphilip goto fail2; 324227569Sphilip if (dcont == 0) 325227569Sphilip break; 326227569Sphilip 327227569Sphilip scont = 0; 328227569Sphilip _NOTE(CONSTANTCONDITION) 329227569Sphilip while (1) { 330227569Sphilip if ((rc = efx_vpd_hunk_next( 331227569Sphilip enp->en_u.siena.enu_svpd, 332227569Sphilip enp->en_u.siena.enu_svpd_length, &stag, &skey, 333227569Sphilip NULL, NULL, &scont)) != 0) 334227569Sphilip goto fail3; 335227569Sphilip if (scont == 0) 336227569Sphilip break; 337227569Sphilip 338227569Sphilip if (stag == dtag && skey == dkey) { 339227569Sphilip rc = EEXIST; 340227569Sphilip goto fail4; 341227569Sphilip } 342227569Sphilip } 343227569Sphilip } 344227569Sphilip 345227569Sphilipdone: 346227569Sphilip return (0); 347227569Sphilip 348227569Sphilipfail4: 349227569Sphilip EFSYS_PROBE(fail4); 350227569Sphilipfail3: 351227569Sphilip EFSYS_PROBE(fail3); 352227569Sphilipfail2: 353227569Sphilip EFSYS_PROBE(fail2); 354227569Sphilipfail1: 355227569Sphilip EFSYS_PROBE1(fail1, int, rc); 356227569Sphilip 357227569Sphilip return (rc); 358227569Sphilip} 359227569Sphilip 360227569Sphilip __checkReturn int 361227569Sphilipsiena_vpd_reinit( 362227569Sphilip __in efx_nic_t *enp, 363227569Sphilip __in_bcount(size) caddr_t data, 364227569Sphilip __in size_t size) 365227569Sphilip{ 366227569Sphilip boolean_t wantpid; 367227569Sphilip int rc; 368227569Sphilip 369227569Sphilip /* 370227569Sphilip * Only create a PID if the dynamic cfg doesn't have one 371227569Sphilip */ 372227569Sphilip if (enp->en_u.siena.enu_svpd_length == 0) 373227569Sphilip wantpid = B_TRUE; 374227569Sphilip else { 375227569Sphilip unsigned int offset; 376227569Sphilip uint8_t length; 377227569Sphilip 378227569Sphilip rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd, 379227569Sphilip enp->en_u.siena.enu_svpd_length, 380227569Sphilip EFX_VPD_ID, 0, &offset, &length); 381227569Sphilip if (rc == 0) 382227569Sphilip wantpid = B_FALSE; 383227569Sphilip else if (rc == ENOENT) 384227569Sphilip wantpid = B_TRUE; 385227569Sphilip else 386227569Sphilip goto fail1; 387227569Sphilip } 388227569Sphilip 389227569Sphilip if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0) 390227569Sphilip goto fail2; 391227569Sphilip 392227569Sphilip return (0); 393227569Sphilip 394227569Sphilipfail2: 395227569Sphilip EFSYS_PROBE(fail2); 396227569Sphilipfail1: 397227569Sphilip EFSYS_PROBE1(fail1, int, rc); 398227569Sphilip 399227569Sphilip return (rc); 400227569Sphilip} 401227569Sphilip 402227569Sphilip __checkReturn int 403227569Sphilipsiena_vpd_get( 404227569Sphilip __in efx_nic_t *enp, 405227569Sphilip __in_bcount(size) caddr_t data, 406227569Sphilip __in size_t size, 407227569Sphilip __inout efx_vpd_value_t *evvp) 408227569Sphilip{ 409227569Sphilip unsigned int offset; 410227569Sphilip uint8_t length; 411227569Sphilip int rc; 412227569Sphilip 413227569Sphilip EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 414227569Sphilip 415227569Sphilip /* Attempt to satisfy the request from svpd first */ 416227569Sphilip if (enp->en_u.siena.enu_svpd_length > 0) { 417227569Sphilip if ((rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd, 418227569Sphilip enp->en_u.siena.enu_svpd_length, evvp->evv_tag, 419227569Sphilip evvp->evv_keyword, &offset, &length)) == 0) { 420227569Sphilip evvp->evv_length = length; 421227569Sphilip memcpy(evvp->evv_value, 422227569Sphilip enp->en_u.siena.enu_svpd + offset, length); 423227569Sphilip return (0); 424227569Sphilip } else if (rc != ENOENT) 425227569Sphilip goto fail1; 426227569Sphilip } 427227569Sphilip 428227569Sphilip /* And then from the provided data buffer */ 429227569Sphilip if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag, 430227569Sphilip evvp->evv_keyword, &offset, &length)) != 0) 431227569Sphilip goto fail2; 432227569Sphilip 433227569Sphilip evvp->evv_length = length; 434227569Sphilip memcpy(evvp->evv_value, data + offset, length); 435227569Sphilip 436227569Sphilip return (0); 437227569Sphilip 438227569Sphilipfail2: 439227569Sphilip EFSYS_PROBE(fail2); 440227569Sphilipfail1: 441227569Sphilip EFSYS_PROBE1(fail1, int, rc); 442227569Sphilip 443227569Sphilip return (rc); 444227569Sphilip} 445227569Sphilip 446227569Sphilip __checkReturn int 447227569Sphilipsiena_vpd_set( 448227569Sphilip __in efx_nic_t *enp, 449227569Sphilip __in_bcount(size) caddr_t data, 450227569Sphilip __in size_t size, 451227569Sphilip __in efx_vpd_value_t *evvp) 452227569Sphilip{ 453227569Sphilip int rc; 454227569Sphilip 455227569Sphilip EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 456227569Sphilip 457227569Sphilip /* If the provided (tag,keyword) exists in svpd, then it is readonly */ 458227569Sphilip if (enp->en_u.siena.enu_svpd_length > 0) { 459227569Sphilip unsigned int offset; 460227569Sphilip uint8_t length; 461227569Sphilip 462227569Sphilip if ((rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd, 463227569Sphilip enp->en_u.siena.enu_svpd_length, evvp->evv_tag, 464227569Sphilip evvp->evv_keyword, &offset, &length)) == 0) { 465227569Sphilip rc = EACCES; 466227569Sphilip goto fail1; 467227569Sphilip } 468227569Sphilip } 469227569Sphilip 470227569Sphilip if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0) 471227569Sphilip goto fail2; 472227569Sphilip 473227569Sphilip return (0); 474227569Sphilip 475227569Sphilipfail2: 476227569Sphilip EFSYS_PROBE(fail2); 477227569Sphilipfail1: 478227569Sphilip EFSYS_PROBE1(fail1, int, rc); 479227569Sphilip 480227569Sphilip return (rc); 481227569Sphilip} 482227569Sphilip 483227569Sphilip __checkReturn int 484227569Sphilipsiena_vpd_next( 485227569Sphilip __in efx_nic_t *enp, 486227569Sphilip __in_bcount(size) caddr_t data, 487227569Sphilip __in size_t size, 488227569Sphilip __out efx_vpd_value_t *evvp, 489227569Sphilip __inout unsigned int *contp) 490227569Sphilip{ 491227569Sphilip _NOTE(ARGUNUSED(enp, data, size, evvp, contp)) 492227569Sphilip 493227569Sphilip return (ENOTSUP); 494227569Sphilip} 495227569Sphilip 496227569Sphilip __checkReturn int 497227569Sphilipsiena_vpd_write( 498227569Sphilip __in efx_nic_t *enp, 499227569Sphilip __in_bcount(size) caddr_t data, 500227569Sphilip __in size_t size) 501227569Sphilip{ 502227569Sphilip efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 503227569Sphilip siena_mc_dynamic_config_hdr_t *dcfg; 504227569Sphilip unsigned int vpd_offset; 505227569Sphilip unsigned int dcfg_partn; 506227569Sphilip unsigned int hdr_length; 507227569Sphilip unsigned int pos; 508227569Sphilip uint8_t cksum; 509227569Sphilip size_t partn_size, dcfg_size; 510227569Sphilip size_t vpd_length; 511227569Sphilip int rc; 512227569Sphilip 513227569Sphilip EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 514227569Sphilip 515227569Sphilip /* Determine total length of all tags */ 516227569Sphilip if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0) 517227569Sphilip goto fail1; 518227569Sphilip 519227569Sphilip /* Lock dynamic config sector for write, and read structure only */ 520227569Sphilip dcfg_partn = (emip->emi_port == 1) 521227569Sphilip ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 522227569Sphilip : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 523227569Sphilip 524227569Sphilip if ((rc = siena_nvram_partn_size(enp, dcfg_partn, &partn_size)) != 0) 525227569Sphilip goto fail2; 526227569Sphilip 527227569Sphilip if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0) 528227569Sphilip goto fail2; 529227569Sphilip 530227569Sphilip if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn, 531227569Sphilip B_FALSE, &dcfg, &dcfg_size)) != 0) 532227569Sphilip goto fail3; 533227569Sphilip 534227569Sphilip hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0); 535227569Sphilip 536227569Sphilip /* Allocated memory should have room for the new VPD */ 537227569Sphilip if (hdr_length + vpd_length > dcfg_size) { 538227569Sphilip rc = ENOSPC; 539227569Sphilip goto fail3; 540227569Sphilip } 541227569Sphilip 542227569Sphilip /* Copy in new vpd and update header */ 543227569Sphilip vpd_offset = dcfg_size - vpd_length; 544227569Sphilip EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, 545227569Sphilip EFX_DWORD_0, vpd_offset); 546227569Sphilip memcpy((caddr_t)dcfg + vpd_offset, data, vpd_length); 547227569Sphilip EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_length, 548227569Sphilip EFX_DWORD_0, vpd_length); 549227569Sphilip 550227569Sphilip /* Update the checksum */ 551227569Sphilip cksum = 0; 552227569Sphilip for (pos = 0; pos < hdr_length; pos++) 553227569Sphilip cksum += ((uint8_t *)dcfg)[pos]; 554227569Sphilip dcfg->csum.eb_u8[0] -= cksum; 555227569Sphilip 556227569Sphilip /* Erase and write the new sector */ 557227569Sphilip if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, partn_size)) != 0) 558227569Sphilip goto fail4; 559227569Sphilip 560227569Sphilip /* Write out the new structure to nvram */ 561227569Sphilip if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0, (caddr_t)dcfg, 562227569Sphilip vpd_offset + vpd_length)) != 0) 563227569Sphilip goto fail5; 564227569Sphilip 565227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg); 566227569Sphilip 567227569Sphilip siena_nvram_partn_unlock(enp, dcfg_partn); 568227569Sphilip 569227569Sphilip return (0); 570227569Sphilip 571227569Sphilipfail5: 572227569Sphilip EFSYS_PROBE(fail5); 573227569Sphilipfail4: 574227569Sphilip EFSYS_PROBE(fail4); 575227569Sphilipfail3: 576227569Sphilip EFSYS_PROBE(fail3); 577227569Sphilip 578227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg); 579227569Sphilipfail2: 580227569Sphilip EFSYS_PROBE(fail2); 581227569Sphilip 582227569Sphilip siena_nvram_partn_unlock(enp, dcfg_partn); 583227569Sphilipfail1: 584227569Sphilip EFSYS_PROBE1(fail1, int, rc); 585227569Sphilip 586227569Sphilip return (rc); 587227569Sphilip} 588227569Sphilip 589227569Sphilip void 590227569Sphilipsiena_vpd_fini( 591227569Sphilip __in efx_nic_t *enp) 592227569Sphilip{ 593227569Sphilip EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 594227569Sphilip 595227569Sphilip if (enp->en_u.siena.enu_svpd_length > 0) { 596227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, enp->en_u.siena.enu_svpd_length, 597227569Sphilip enp->en_u.siena.enu_svpd); 598227569Sphilip 599227569Sphilip enp->en_u.siena.enu_svpd = NULL; 600227569Sphilip enp->en_u.siena.enu_svpd_length = 0; 601227569Sphilip } 602227569Sphilip} 603227569Sphilip 604227569Sphilip#endif /* EFSYS_OPT_SIENA */ 605227569Sphilip 606227569Sphilip#endif /* EFSYS_OPT_VPD */ 607