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 26228078Sphilip#include <sys/cdefs.h> 27228078Sphilip__FBSDID("$FreeBSD$"); 28228078Sphilip 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_SIENA 36227569Sphilip 37227569Sphilip#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM 38227569Sphilip 39227569Sphilip __checkReturn int 40227569Sphilipsiena_nvram_partn_size( 41227569Sphilip __in efx_nic_t *enp, 42227569Sphilip __in unsigned int partn, 43227569Sphilip __out size_t *sizep) 44227569Sphilip{ 45227569Sphilip efx_mcdi_req_t req; 46227569Sphilip uint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN, 47227569Sphilip MC_CMD_NVRAM_INFO_OUT_LEN)]; 48227569Sphilip int rc; 49227569Sphilip 50227569Sphilip if ((1 << partn) & ~enp->en_u.siena.enu_partn_mask) { 51227569Sphilip rc = ENOTSUP; 52227569Sphilip goto fail1; 53227569Sphilip } 54227569Sphilip 55227569Sphilip req.emr_cmd = MC_CMD_NVRAM_INFO; 56227569Sphilip req.emr_in_buf = payload; 57227569Sphilip req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN; 58227569Sphilip req.emr_out_buf = payload; 59227569Sphilip req.emr_out_length = MC_CMD_NVRAM_INFO_OUT_LEN; 60227569Sphilip 61227569Sphilip MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn); 62227569Sphilip 63227569Sphilip efx_mcdi_execute(enp, &req); 64227569Sphilip 65227569Sphilip if (req.emr_rc != 0) { 66227569Sphilip rc = req.emr_rc; 67227569Sphilip goto fail2; 68227569Sphilip } 69227569Sphilip 70227569Sphilip if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) { 71227569Sphilip rc = EMSGSIZE; 72227569Sphilip goto fail3; 73227569Sphilip } 74227569Sphilip 75227569Sphilip *sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE); 76227569Sphilip 77227569Sphilip return (0); 78227569Sphilip 79227569Sphilipfail3: 80227569Sphilip EFSYS_PROBE(fail3); 81227569Sphilipfail2: 82227569Sphilip EFSYS_PROBE(fail2); 83227569Sphilipfail1: 84227569Sphilip EFSYS_PROBE1(fail1, int, rc); 85227569Sphilip 86227569Sphilip return (rc); 87227569Sphilip} 88227569Sphilip 89227569Sphilip __checkReturn int 90227569Sphilipsiena_nvram_partn_lock( 91227569Sphilip __in efx_nic_t *enp, 92227569Sphilip __in unsigned int partn) 93227569Sphilip{ 94227569Sphilip efx_mcdi_req_t req; 95227569Sphilip uint8_t payload[MC_CMD_NVRAM_UPDATE_START_IN_LEN]; 96227569Sphilip int rc; 97227569Sphilip 98227569Sphilip req.emr_cmd = MC_CMD_NVRAM_UPDATE_START; 99227569Sphilip req.emr_in_buf = payload; 100227569Sphilip req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_IN_LEN; 101227569Sphilip EFX_STATIC_ASSERT(MC_CMD_NVRAM_UPDATE_START_OUT_LEN == 0); 102227569Sphilip req.emr_out_buf = NULL; 103227569Sphilip req.emr_out_length = 0; 104227569Sphilip 105227569Sphilip MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_IN_TYPE, partn); 106227569Sphilip 107227569Sphilip efx_mcdi_execute(enp, &req); 108227569Sphilip 109227569Sphilip if (req.emr_rc != 0) { 110227569Sphilip rc = req.emr_rc; 111227569Sphilip goto fail1; 112227569Sphilip } 113227569Sphilip 114227569Sphilip return (0); 115227569Sphilip 116227569Sphilipfail1: 117227569Sphilip EFSYS_PROBE1(fail1, int, rc); 118227569Sphilip 119227569Sphilip return (rc); 120227569Sphilip} 121227569Sphilip 122227569Sphilip __checkReturn int 123227569Sphilipsiena_nvram_partn_read( 124227569Sphilip __in efx_nic_t *enp, 125227569Sphilip __in unsigned int partn, 126227569Sphilip __in unsigned int offset, 127227569Sphilip __out_bcount(size) caddr_t data, 128227569Sphilip __in size_t size) 129227569Sphilip{ 130227569Sphilip efx_mcdi_req_t req; 131227569Sphilip uint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_LEN, 132227569Sphilip MC_CMD_NVRAM_READ_OUT_LEN(SIENA_NVRAM_CHUNK))]; 133227569Sphilip size_t chunk; 134227569Sphilip int rc; 135227569Sphilip 136227569Sphilip while (size > 0) { 137227569Sphilip chunk = MIN(size, SIENA_NVRAM_CHUNK); 138227569Sphilip 139227569Sphilip req.emr_cmd = MC_CMD_NVRAM_READ; 140227569Sphilip req.emr_in_buf = payload; 141227569Sphilip req.emr_in_length = MC_CMD_NVRAM_READ_IN_LEN; 142227569Sphilip req.emr_out_buf = payload; 143227569Sphilip req.emr_out_length = 144227569Sphilip MC_CMD_NVRAM_READ_OUT_LEN(SIENA_NVRAM_CHUNK); 145227569Sphilip 146227569Sphilip MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_TYPE, partn); 147227569Sphilip MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_OFFSET, offset); 148227569Sphilip MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_LENGTH, chunk); 149227569Sphilip 150227569Sphilip efx_mcdi_execute(enp, &req); 151227569Sphilip 152227569Sphilip if (req.emr_rc != 0) { 153227569Sphilip rc = req.emr_rc; 154227569Sphilip goto fail1; 155227569Sphilip } 156227569Sphilip 157227569Sphilip if (req.emr_out_length_used < 158227569Sphilip MC_CMD_NVRAM_READ_OUT_LEN(chunk)) { 159227569Sphilip rc = EMSGSIZE; 160227569Sphilip goto fail2; 161227569Sphilip } 162227569Sphilip 163227569Sphilip memcpy(data, 164227569Sphilip MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER), 165227569Sphilip chunk); 166227569Sphilip 167227569Sphilip size -= chunk; 168227569Sphilip data += chunk; 169227569Sphilip offset += chunk; 170227569Sphilip } 171227569Sphilip 172227569Sphilip return (0); 173227569Sphilip 174227569Sphilipfail2: 175227569Sphilip EFSYS_PROBE(fail2); 176227569Sphilipfail1: 177227569Sphilip EFSYS_PROBE1(fail1, int, rc); 178227569Sphilip 179227569Sphilip return (rc); 180227569Sphilip} 181227569Sphilip 182227569Sphilip __checkReturn int 183227569Sphilipsiena_nvram_partn_erase( 184227569Sphilip __in efx_nic_t *enp, 185227569Sphilip __in unsigned int partn, 186227569Sphilip __in unsigned int offset, 187227569Sphilip __in size_t size) 188227569Sphilip{ 189227569Sphilip efx_mcdi_req_t req; 190227569Sphilip uint8_t payload[MC_CMD_NVRAM_ERASE_IN_LEN]; 191227569Sphilip int rc; 192227569Sphilip 193227569Sphilip req.emr_cmd = MC_CMD_NVRAM_ERASE; 194227569Sphilip req.emr_in_buf = payload; 195227569Sphilip req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN; 196227569Sphilip EFX_STATIC_ASSERT(MC_CMD_NVRAM_ERASE_OUT_LEN == 0); 197227569Sphilip req.emr_out_buf = NULL; 198227569Sphilip req.emr_out_length = 0; 199227569Sphilip 200227569Sphilip MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn); 201227569Sphilip MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset); 202227569Sphilip MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size); 203227569Sphilip 204227569Sphilip efx_mcdi_execute(enp, &req); 205227569Sphilip 206227569Sphilip if (req.emr_rc != 0) { 207227569Sphilip rc = req.emr_rc; 208227569Sphilip goto fail1; 209227569Sphilip } 210227569Sphilip 211227569Sphilip return (0); 212227569Sphilip 213227569Sphilipfail1: 214227569Sphilip EFSYS_PROBE1(fail1, int, rc); 215227569Sphilip 216227569Sphilip return (rc); 217227569Sphilip} 218227569Sphilip 219227569Sphilip __checkReturn int 220227569Sphilipsiena_nvram_partn_write( 221227569Sphilip __in efx_nic_t *enp, 222227569Sphilip __in unsigned int partn, 223227569Sphilip __in unsigned int offset, 224227569Sphilip __out_bcount(size) caddr_t data, 225227569Sphilip __in size_t size) 226227569Sphilip{ 227227569Sphilip efx_mcdi_req_t req; 228227569Sphilip uint8_t payload[MC_CMD_NVRAM_WRITE_IN_LEN(SIENA_NVRAM_CHUNK)]; 229227569Sphilip size_t chunk; 230227569Sphilip int rc; 231227569Sphilip 232227569Sphilip while (size > 0) { 233227569Sphilip chunk = MIN(size, SIENA_NVRAM_CHUNK); 234227569Sphilip 235227569Sphilip req.emr_cmd = MC_CMD_NVRAM_WRITE; 236227569Sphilip req.emr_in_buf = payload; 237227569Sphilip req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(chunk); 238227569Sphilip EFX_STATIC_ASSERT(MC_CMD_NVRAM_WRITE_OUT_LEN == 0); 239227569Sphilip req.emr_out_buf = NULL; 240227569Sphilip req.emr_out_length = 0; 241227569Sphilip 242227569Sphilip MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn); 243227569Sphilip MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset); 244227569Sphilip MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, chunk); 245227569Sphilip 246227569Sphilip memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER), 247227569Sphilip data, chunk); 248227569Sphilip 249227569Sphilip efx_mcdi_execute(enp, &req); 250227569Sphilip 251227569Sphilip if (req.emr_rc != 0) { 252227569Sphilip rc = req.emr_rc; 253227569Sphilip goto fail1; 254227569Sphilip } 255227569Sphilip 256227569Sphilip size -= chunk; 257227569Sphilip data += chunk; 258227569Sphilip offset += chunk; 259227569Sphilip } 260227569Sphilip 261227569Sphilip return (0); 262227569Sphilip 263227569Sphilipfail1: 264227569Sphilip EFSYS_PROBE1(fail1, int, rc); 265227569Sphilip 266227569Sphilip return (rc); 267227569Sphilip} 268227569Sphilip 269227569Sphilip void 270227569Sphilipsiena_nvram_partn_unlock( 271227569Sphilip __in efx_nic_t *enp, 272227569Sphilip __in unsigned int partn) 273227569Sphilip{ 274227569Sphilip efx_mcdi_req_t req; 275227569Sphilip uint8_t payload[MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN]; 276227569Sphilip uint32_t reboot; 277227569Sphilip int rc; 278227569Sphilip 279227569Sphilip req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH; 280227569Sphilip req.emr_in_buf = payload; 281227569Sphilip req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN; 282227569Sphilip EFX_STATIC_ASSERT(MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN == 0); 283227569Sphilip req.emr_out_buf = NULL; 284227569Sphilip req.emr_out_length = 0; 285227569Sphilip 286227569Sphilip /* 287227569Sphilip * Reboot into the new image only for PHYs. The driver has to 288227569Sphilip * explicitly cope with an MC reboot after a firmware update. 289227569Sphilip */ 290227569Sphilip reboot = (partn == MC_CMD_NVRAM_TYPE_PHY_PORT0 || 291227569Sphilip partn == MC_CMD_NVRAM_TYPE_PHY_PORT1 || 292227569Sphilip partn == MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO); 293227569Sphilip 294227569Sphilip MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_TYPE, partn); 295227569Sphilip MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_REBOOT, reboot); 296227569Sphilip 297227569Sphilip efx_mcdi_execute(enp, &req); 298227569Sphilip 299227569Sphilip if (req.emr_rc != 0) { 300227569Sphilip rc = req.emr_rc; 301227569Sphilip goto fail1; 302227569Sphilip } 303227569Sphilip 304227569Sphilip return; 305227569Sphilip 306227569Sphilipfail1: 307227569Sphilip EFSYS_PROBE1(fail1, int, rc); 308227569Sphilip} 309227569Sphilip 310227569Sphilip#endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */ 311227569Sphilip 312227569Sphilip#if EFSYS_OPT_NVRAM 313227569Sphilip 314227569Sphiliptypedef struct siena_parttbl_entry_s { 315227569Sphilip unsigned int partn; 316227569Sphilip unsigned int port; 317227569Sphilip efx_nvram_type_t nvtype; 318227569Sphilip} siena_parttbl_entry_t; 319227569Sphilip 320227569Sphilipstatic siena_parttbl_entry_t siena_parttbl[] = { 321227569Sphilip {MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO, 1, EFX_NVRAM_NULLPHY}, 322227569Sphilip {MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO, 2, EFX_NVRAM_NULLPHY}, 323227569Sphilip {MC_CMD_NVRAM_TYPE_MC_FW, 1, EFX_NVRAM_MC_FIRMWARE}, 324227569Sphilip {MC_CMD_NVRAM_TYPE_MC_FW, 2, EFX_NVRAM_MC_FIRMWARE}, 325227569Sphilip {MC_CMD_NVRAM_TYPE_MC_FW_BACKUP, 1, EFX_NVRAM_MC_GOLDEN}, 326227569Sphilip {MC_CMD_NVRAM_TYPE_MC_FW_BACKUP, 2, EFX_NVRAM_MC_GOLDEN}, 327227569Sphilip {MC_CMD_NVRAM_TYPE_EXP_ROM, 1, EFX_NVRAM_BOOTROM}, 328227569Sphilip {MC_CMD_NVRAM_TYPE_EXP_ROM, 2, EFX_NVRAM_BOOTROM}, 329227569Sphilip {MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT0, 1, EFX_NVRAM_BOOTROM_CFG}, 330227569Sphilip {MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT1, 2, EFX_NVRAM_BOOTROM_CFG}, 331227569Sphilip {MC_CMD_NVRAM_TYPE_PHY_PORT0, 1, EFX_NVRAM_PHY}, 332227569Sphilip {MC_CMD_NVRAM_TYPE_PHY_PORT1, 2, EFX_NVRAM_PHY}, 333227569Sphilip {0, 0, 0}, 334227569Sphilip}; 335227569Sphilip 336227569Sphilipstatic __checkReturn siena_parttbl_entry_t * 337227569Sphilipsiena_parttbl_entry( 338227569Sphilip __in efx_nic_t *enp, 339227569Sphilip __in efx_nvram_type_t type) 340227569Sphilip{ 341227569Sphilip efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 342227569Sphilip siena_parttbl_entry_t *entry; 343227569Sphilip 344227569Sphilip EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); 345227569Sphilip 346227569Sphilip for (entry = siena_parttbl; entry->port > 0; ++entry) { 347227569Sphilip if (entry->port == emip->emi_port && entry->nvtype == type) 348227569Sphilip return (entry); 349227569Sphilip } 350227569Sphilip 351227569Sphilip return (NULL); 352227569Sphilip} 353227569Sphilip 354227569Sphilip#if EFSYS_OPT_DIAG 355227569Sphilip 356227569Sphilip __checkReturn int 357227569Sphilipsiena_nvram_test( 358227569Sphilip __in efx_nic_t *enp) 359227569Sphilip{ 360227569Sphilip efx_mcdi_iface_t *emip = &(enp->en_u.siena.enu_mip); 361227569Sphilip siena_parttbl_entry_t *entry; 362227569Sphilip efx_mcdi_req_t req; 363227569Sphilip uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN, 364227569Sphilip MC_CMD_NVRAM_TEST_OUT_LEN)]; 365227569Sphilip int result; 366227569Sphilip int rc; 367227569Sphilip 368227569Sphilip req.emr_cmd = MC_CMD_NVRAM_TEST; 369227569Sphilip req.emr_in_buf = payload; 370227569Sphilip req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN; 371227569Sphilip req.emr_out_buf = payload; 372227569Sphilip req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN; 373227569Sphilip 374227569Sphilip /* 375227569Sphilip * Iterate over the list of supported partition types 376227569Sphilip * applicable to *this* port 377227569Sphilip */ 378227569Sphilip for (entry = siena_parttbl; entry->port > 0; ++entry) { 379227569Sphilip if (entry->port != emip->emi_port || 380227569Sphilip !(enp->en_u.siena.enu_partn_mask & (1 << entry->partn))) 381227569Sphilip continue; 382227569Sphilip 383227569Sphilip MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, entry->partn); 384227569Sphilip 385227569Sphilip efx_mcdi_execute(enp, &req); 386227569Sphilip 387227569Sphilip if (req.emr_rc != 0) { 388227569Sphilip rc = req.emr_rc; 389227569Sphilip goto fail1; 390227569Sphilip } 391227569Sphilip 392227569Sphilip if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) { 393227569Sphilip rc = EMSGSIZE; 394227569Sphilip goto fail2; 395227569Sphilip } 396227569Sphilip 397227569Sphilip result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT); 398227569Sphilip if (result == MC_CMD_NVRAM_TEST_FAIL) { 399227569Sphilip 400227569Sphilip EFSYS_PROBE1(nvram_test_failure, int, entry->partn); 401227569Sphilip 402227569Sphilip rc = (EINVAL); 403227569Sphilip goto fail3; 404227569Sphilip } 405227569Sphilip } 406227569Sphilip 407227569Sphilip return (0); 408227569Sphilip 409227569Sphilipfail3: 410227569Sphilip EFSYS_PROBE(fail3); 411227569Sphilipfail2: 412227569Sphilip EFSYS_PROBE(fail2); 413227569Sphilipfail1: 414227569Sphilip EFSYS_PROBE1(fail1, int, rc); 415227569Sphilip 416227569Sphilip return (rc); 417227569Sphilip} 418227569Sphilip 419227569Sphilip#endif /* EFSYS_OPT_DIAG */ 420227569Sphilip 421227569Sphilip __checkReturn int 422227569Sphilipsiena_nvram_size( 423227569Sphilip __in efx_nic_t *enp, 424227569Sphilip __in efx_nvram_type_t type, 425227569Sphilip __out size_t *sizep) 426227569Sphilip{ 427227569Sphilip siena_parttbl_entry_t *entry; 428227569Sphilip int rc; 429227569Sphilip 430227569Sphilip if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 431227569Sphilip rc = ENOTSUP; 432227569Sphilip goto fail1; 433227569Sphilip } 434227569Sphilip 435227569Sphilip if ((rc = siena_nvram_partn_size(enp, entry->partn, sizep)) != 0) 436227569Sphilip goto fail2; 437227569Sphilip 438227569Sphilip return (0); 439227569Sphilip 440227569Sphilipfail2: 441227569Sphilip EFSYS_PROBE(fail2); 442227569Sphilipfail1: 443227569Sphilip EFSYS_PROBE1(fail1, int, rc); 444227569Sphilip 445227569Sphilip *sizep = 0; 446227569Sphilip 447227569Sphilip return (rc); 448227569Sphilip} 449227569Sphilip 450227569Sphilip#define SIENA_DYNAMIC_CFG_SIZE(_nitems) \ 451227569Sphilip (sizeof (siena_mc_dynamic_config_hdr_t) + ((_nitems) * \ 452227569Sphilip sizeof (((siena_mc_dynamic_config_hdr_t *)NULL)->fw_version[0]))) 453227569Sphilip 454227569Sphilip __checkReturn int 455227569Sphilipsiena_nvram_get_dynamic_cfg( 456227569Sphilip __in efx_nic_t *enp, 457227569Sphilip __in unsigned int partn, 458227569Sphilip __in boolean_t vpd, 459227569Sphilip __out siena_mc_dynamic_config_hdr_t **dcfgp, 460227569Sphilip __out size_t *sizep) 461227569Sphilip{ 462227569Sphilip siena_mc_dynamic_config_hdr_t *dcfg; 463227569Sphilip size_t size; 464227569Sphilip uint8_t cksum; 465227569Sphilip unsigned int vpd_offset; 466227569Sphilip unsigned int vpd_length; 467227569Sphilip unsigned int hdr_length; 468227569Sphilip unsigned int nversions; 469227569Sphilip unsigned int pos; 470227569Sphilip unsigned int region; 471227569Sphilip int rc; 472227569Sphilip 473227569Sphilip EFSYS_ASSERT(partn == MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 || 474227569Sphilip partn == MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1); 475227569Sphilip 476227569Sphilip /* 477227569Sphilip * Allocate sufficient memory for the entire dynamiccfg area, even 478227569Sphilip * if we're not actually going to read in the VPD. 479227569Sphilip */ 480227569Sphilip if ((rc = siena_nvram_partn_size(enp, partn, &size)) != 0) 481227569Sphilip goto fail1; 482227569Sphilip 483227569Sphilip EFSYS_KMEM_ALLOC(enp->en_esip, size, dcfg); 484227569Sphilip if (dcfg == NULL) { 485227569Sphilip rc = ENOMEM; 486227569Sphilip goto fail2; 487227569Sphilip } 488227569Sphilip 489227569Sphilip if ((rc = siena_nvram_partn_read(enp, partn, 0, 490227569Sphilip (caddr_t)dcfg, SIENA_NVRAM_CHUNK)) != 0) 491227569Sphilip goto fail3; 492227569Sphilip 493227569Sphilip /* Verify the magic */ 494227569Sphilip if (EFX_DWORD_FIELD(dcfg->magic, EFX_DWORD_0) 495227569Sphilip != SIENA_MC_DYNAMIC_CONFIG_MAGIC) 496227569Sphilip goto invalid1; 497227569Sphilip 498227569Sphilip /* All future versions of the structure must be backwards compatable */ 499227569Sphilip EFX_STATIC_ASSERT(SIENA_MC_DYNAMIC_CONFIG_VERSION == 0); 500227569Sphilip 501227569Sphilip hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0); 502227569Sphilip nversions = EFX_DWORD_FIELD(dcfg->num_fw_version_items, EFX_DWORD_0); 503227569Sphilip vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0); 504227569Sphilip vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0); 505227569Sphilip 506227569Sphilip /* Verify the hdr doesn't overflow the partn size */ 507227569Sphilip if (hdr_length > size || vpd_offset > size || vpd_length > size || 508227569Sphilip vpd_length + vpd_offset > size) 509227569Sphilip goto invalid2; 510227569Sphilip 511227569Sphilip /* Verify the header has room for all it's versions */ 512227569Sphilip if (hdr_length < SIENA_DYNAMIC_CFG_SIZE(0) || 513227569Sphilip hdr_length < SIENA_DYNAMIC_CFG_SIZE(nversions)) 514227569Sphilip goto invalid3; 515227569Sphilip 516227569Sphilip /* 517227569Sphilip * Read the remaining portion of the dcfg, either including 518227569Sphilip * the whole of VPD (there is no vpd length in this structure, 519227569Sphilip * so we have to parse each tag), or just the dcfg header itself 520227569Sphilip */ 521227569Sphilip region = vpd ? vpd_offset + vpd_length : hdr_length; 522227569Sphilip if (region > SIENA_NVRAM_CHUNK) { 523227569Sphilip if ((rc = siena_nvram_partn_read(enp, partn, SIENA_NVRAM_CHUNK, 524227569Sphilip (caddr_t)dcfg + SIENA_NVRAM_CHUNK, 525227569Sphilip region - SIENA_NVRAM_CHUNK)) != 0) 526227569Sphilip goto fail4; 527227569Sphilip } 528227569Sphilip 529227569Sphilip /* Verify checksum */ 530227569Sphilip cksum = 0; 531227569Sphilip for (pos = 0; pos < hdr_length; pos++) 532227569Sphilip cksum += ((uint8_t *)dcfg)[pos]; 533227569Sphilip if (cksum != 0) 534227569Sphilip goto invalid4; 535227569Sphilip 536227569Sphilip goto done; 537227569Sphilip 538227569Sphilipinvalid4: 539227569Sphilip EFSYS_PROBE(invalid4); 540227569Sphilipinvalid3: 541227569Sphilip EFSYS_PROBE(invalid3); 542227569Sphilipinvalid2: 543227569Sphilip EFSYS_PROBE(invalid2); 544227569Sphilipinvalid1: 545227569Sphilip EFSYS_PROBE(invalid1); 546227569Sphilip 547227569Sphilip /* 548227569Sphilip * Construct a new "null" dcfg, with an empty version vector, 549227569Sphilip * and an empty VPD chunk trailing. This has the neat side effect 550227569Sphilip * of testing the exception paths in the write path. 551227569Sphilip */ 552227569Sphilip EFX_POPULATE_DWORD_1(dcfg->magic, 553227569Sphilip EFX_DWORD_0, SIENA_MC_DYNAMIC_CONFIG_MAGIC); 554227569Sphilip EFX_POPULATE_WORD_1(dcfg->length, EFX_WORD_0, sizeof (*dcfg)); 555227569Sphilip EFX_POPULATE_BYTE_1(dcfg->version, EFX_BYTE_0, 556227569Sphilip SIENA_MC_DYNAMIC_CONFIG_VERSION); 557227569Sphilip EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, 558227569Sphilip EFX_DWORD_0, sizeof (*dcfg)); 559227569Sphilip EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_length, EFX_DWORD_0, 0); 560227569Sphilip EFX_POPULATE_DWORD_1(dcfg->num_fw_version_items, EFX_DWORD_0, 0); 561227569Sphilip 562227569Sphilipdone: 563227569Sphilip *dcfgp = dcfg; 564227569Sphilip *sizep = size; 565227569Sphilip 566227569Sphilip return (0); 567227569Sphilip 568227569Sphilipfail4: 569227569Sphilip EFSYS_PROBE(fail4); 570227569Sphilipfail3: 571227569Sphilip EFSYS_PROBE(fail3); 572227569Sphilipfail2: 573227569Sphilip EFSYS_PROBE(fail2); 574227569Sphilip 575227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, size, dcfg); 576227569Sphilip 577227569Sphilipfail1: 578227569Sphilip EFSYS_PROBE1(fail1, int, rc); 579227569Sphilip 580227569Sphilip return (rc); 581227569Sphilip} 582227569Sphilip 583227569Sphilipstatic __checkReturn int 584227569Sphilipsiena_nvram_get_subtype( 585227569Sphilip __in efx_nic_t *enp, 586227569Sphilip __in unsigned int partn, 587227569Sphilip __out uint32_t *subtypep) 588227569Sphilip{ 589227569Sphilip efx_mcdi_req_t req; 590227569Sphilip uint8_t outbuf[MC_CMD_GET_BOARD_CFG_OUT_LEN]; 591227569Sphilip efx_word_t *fw_list; 592227569Sphilip int rc; 593227569Sphilip 594227569Sphilip req.emr_cmd = MC_CMD_GET_BOARD_CFG; 595227569Sphilip EFX_STATIC_ASSERT(MC_CMD_GET_BOARD_CFG_IN_LEN == 0); 596227569Sphilip req.emr_in_buf = NULL; 597227569Sphilip req.emr_in_length = 0; 598227569Sphilip req.emr_out_buf = outbuf; 599227569Sphilip req.emr_out_length = sizeof (outbuf); 600227569Sphilip 601227569Sphilip efx_mcdi_execute(enp, &req); 602227569Sphilip 603227569Sphilip if (req.emr_rc != 0) { 604227569Sphilip rc = req.emr_rc; 605227569Sphilip goto fail1; 606227569Sphilip } 607227569Sphilip 608227569Sphilip if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LEN) { 609227569Sphilip rc = EMSGSIZE; 610227569Sphilip goto fail2; 611227569Sphilip } 612227569Sphilip 613227569Sphilip fw_list = MCDI_OUT2(req, efx_word_t, 614227569Sphilip GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST); 615227569Sphilip *subtypep = EFX_WORD_FIELD(fw_list[partn], EFX_WORD_0); 616227569Sphilip 617227569Sphilip return (0); 618227569Sphilip 619227569Sphilipfail2: 620227569Sphilip EFSYS_PROBE(fail2); 621227569Sphilipfail1: 622227569Sphilip EFSYS_PROBE1(fail1, int, rc); 623227569Sphilip 624227569Sphilip return (rc); 625227569Sphilip} 626227569Sphilip 627227569Sphilip __checkReturn int 628227569Sphilipsiena_nvram_get_version( 629227569Sphilip __in efx_nic_t *enp, 630227569Sphilip __in efx_nvram_type_t type, 631227569Sphilip __out uint32_t *subtypep, 632227569Sphilip __out_ecount(4) uint16_t version[4]) 633227569Sphilip{ 634227569Sphilip siena_mc_dynamic_config_hdr_t *dcfg; 635227569Sphilip siena_parttbl_entry_t *entry; 636227569Sphilip unsigned int dcfg_partn; 637227569Sphilip unsigned int partn; 638227569Sphilip int rc; 639227569Sphilip 640227569Sphilip if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 641227569Sphilip rc = ENOTSUP; 642227569Sphilip goto fail1; 643227569Sphilip } 644227569Sphilip partn = entry->partn; 645227569Sphilip 646227569Sphilip if ((1 << partn) & ~enp->en_u.siena.enu_partn_mask) { 647227569Sphilip rc = ENOTSUP; 648227569Sphilip goto fail2; 649227569Sphilip } 650227569Sphilip 651227569Sphilip if ((rc = siena_nvram_get_subtype(enp, partn, subtypep)) != 0) 652227569Sphilip goto fail3; 653227569Sphilip 654227569Sphilip /* 655227569Sphilip * Some partitions are accessible from both ports (for instance BOOTROM) 656227569Sphilip * Find the highest version reported by all dcfg structures on ports 657227569Sphilip * that have access to this partition. 658227569Sphilip */ 659227569Sphilip version[0] = version[1] = version[2] = version[3] = 0; 660227569Sphilip for (entry = siena_parttbl; entry->port > 0; ++entry) { 661227569Sphilip unsigned int nitems; 662227569Sphilip uint16_t temp[4]; 663227569Sphilip size_t length; 664227569Sphilip 665227569Sphilip if (entry->partn != partn) 666227569Sphilip continue; 667227569Sphilip 668227569Sphilip dcfg_partn = (entry->port == 1) 669227569Sphilip ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 670227569Sphilip : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 671227569Sphilip /* 672227569Sphilip * Ingore missing partitions on port 2, assuming they're due 673227569Sphilip * to to running on a single port part. 674227569Sphilip */ 675227569Sphilip if ((1 << dcfg_partn) & ~enp->en_u.siena.enu_partn_mask) { 676227569Sphilip if (entry->port == 2) 677227569Sphilip continue; 678227569Sphilip } 679227569Sphilip 680227569Sphilip if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn, 681227569Sphilip B_FALSE, &dcfg, &length)) != 0) 682227569Sphilip goto fail4; 683227569Sphilip 684227569Sphilip nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items, 685227569Sphilip EFX_DWORD_0); 686227569Sphilip if (nitems < entry->partn) 687227569Sphilip goto done; 688227569Sphilip 689227569Sphilip temp[0] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_w, 690227569Sphilip EFX_WORD_0); 691227569Sphilip temp[1] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_x, 692227569Sphilip EFX_WORD_0); 693227569Sphilip temp[2] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_y, 694227569Sphilip EFX_WORD_0); 695227569Sphilip temp[3] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_z, 696227569Sphilip EFX_WORD_0); 697227569Sphilip if (memcmp(version, temp, sizeof (temp)) < 0) 698227569Sphilip memcpy(version, temp, sizeof (temp)); 699227569Sphilip 700227569Sphilip done: 701227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 702227569Sphilip } 703227569Sphilip 704227569Sphilip return (0); 705227569Sphilip 706227569Sphilipfail4: 707227569Sphilip EFSYS_PROBE(fail4); 708227569Sphilipfail3: 709227569Sphilip EFSYS_PROBE(fail3); 710227569Sphilipfail2: 711227569Sphilip EFSYS_PROBE(fail2); 712227569Sphilipfail1: 713227569Sphilip EFSYS_PROBE1(fail1, int, rc); 714227569Sphilip 715227569Sphilip return (rc); 716227569Sphilip} 717227569Sphilip 718227569Sphilip __checkReturn int 719227569Sphilipsiena_nvram_rw_start( 720227569Sphilip __in efx_nic_t *enp, 721227569Sphilip __in efx_nvram_type_t type, 722227569Sphilip __out size_t *chunk_sizep) 723227569Sphilip{ 724227569Sphilip siena_parttbl_entry_t *entry; 725227569Sphilip int rc; 726227569Sphilip 727227569Sphilip if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 728227569Sphilip rc = ENOTSUP; 729227569Sphilip goto fail1; 730227569Sphilip } 731227569Sphilip 732227569Sphilip if ((rc = siena_nvram_partn_lock(enp, entry->partn)) != 0) 733227569Sphilip goto fail2; 734227569Sphilip 735227569Sphilip if (chunk_sizep != NULL) 736227569Sphilip *chunk_sizep = SIENA_NVRAM_CHUNK; 737227569Sphilip 738227569Sphilip return (0); 739227569Sphilip 740227569Sphilipfail2: 741227569Sphilip EFSYS_PROBE(fail2); 742227569Sphilipfail1: 743227569Sphilip EFSYS_PROBE1(fail1, int, rc); 744227569Sphilip 745227569Sphilip return (rc); 746227569Sphilip} 747227569Sphilip 748227569Sphilip __checkReturn int 749227569Sphilipsiena_nvram_read_chunk( 750227569Sphilip __in efx_nic_t *enp, 751227569Sphilip __in efx_nvram_type_t type, 752227569Sphilip __in unsigned int offset, 753227569Sphilip __out_bcount(size) caddr_t data, 754227569Sphilip __in size_t size) 755227569Sphilip{ 756227569Sphilip siena_parttbl_entry_t *entry; 757227569Sphilip int rc; 758227569Sphilip 759227569Sphilip if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 760227569Sphilip rc = ENOTSUP; 761227569Sphilip goto fail1; 762227569Sphilip } 763227569Sphilip 764227569Sphilip if ((rc = siena_nvram_partn_read(enp, entry->partn, 765227569Sphilip offset, data, size)) != 0) 766227569Sphilip goto fail2; 767227569Sphilip 768227569Sphilip return (0); 769227569Sphilip 770227569Sphilipfail2: 771227569Sphilip EFSYS_PROBE(fail2); 772227569Sphilipfail1: 773227569Sphilip EFSYS_PROBE1(fail1, int, rc); 774227569Sphilip 775227569Sphilip return (rc); 776227569Sphilip} 777227569Sphilip 778227569Sphilip __checkReturn int 779227569Sphilipsiena_nvram_erase( 780227569Sphilip __in efx_nic_t *enp, 781227569Sphilip __in efx_nvram_type_t type) 782227569Sphilip{ 783227569Sphilip siena_parttbl_entry_t *entry; 784227569Sphilip size_t size; 785227569Sphilip int rc; 786227569Sphilip 787227569Sphilip if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 788227569Sphilip rc = ENOTSUP; 789227569Sphilip goto fail1; 790227569Sphilip } 791227569Sphilip 792227569Sphilip if ((rc = siena_nvram_partn_size(enp, entry->partn, &size)) != 0) 793227569Sphilip goto fail2; 794227569Sphilip 795227569Sphilip if ((rc = siena_nvram_partn_erase(enp, entry->partn, 0, size)) != 0) 796227569Sphilip goto fail3; 797227569Sphilip 798227569Sphilip return (0); 799227569Sphilip 800227569Sphilipfail3: 801227569Sphilip EFSYS_PROBE(fail3); 802227569Sphilipfail2: 803227569Sphilip EFSYS_PROBE(fail2); 804227569Sphilipfail1: 805227569Sphilip EFSYS_PROBE1(fail1, int, rc); 806227569Sphilip 807227569Sphilip return (rc); 808227569Sphilip} 809227569Sphilip 810227569Sphilip __checkReturn int 811227569Sphilipsiena_nvram_write_chunk( 812227569Sphilip __in efx_nic_t *enp, 813227569Sphilip __in efx_nvram_type_t type, 814227569Sphilip __in unsigned int offset, 815227569Sphilip __in_bcount(size) caddr_t data, 816227569Sphilip __in size_t size) 817227569Sphilip{ 818227569Sphilip siena_parttbl_entry_t *entry; 819227569Sphilip int rc; 820227569Sphilip 821227569Sphilip if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 822227569Sphilip rc = ENOTSUP; 823227569Sphilip goto fail1; 824227569Sphilip } 825227569Sphilip 826227569Sphilip if ((rc = siena_nvram_partn_write(enp, entry->partn, 827227569Sphilip offset, data, size)) != 0) 828227569Sphilip goto fail2; 829227569Sphilip 830227569Sphilip return (0); 831227569Sphilip 832227569Sphilipfail2: 833227569Sphilip EFSYS_PROBE(fail2); 834227569Sphilipfail1: 835227569Sphilip EFSYS_PROBE1(fail1, int, rc); 836227569Sphilip 837227569Sphilip return (rc); 838227569Sphilip} 839227569Sphilip 840227569Sphilip void 841227569Sphilipsiena_nvram_rw_finish( 842227569Sphilip __in efx_nic_t *enp, 843227569Sphilip __in efx_nvram_type_t type) 844227569Sphilip{ 845227569Sphilip siena_parttbl_entry_t *entry; 846227569Sphilip 847227569Sphilip if ((entry = siena_parttbl_entry(enp, type)) != NULL) 848227569Sphilip siena_nvram_partn_unlock(enp, entry->partn); 849227569Sphilip} 850227569Sphilip 851227569Sphilip __checkReturn int 852227569Sphilipsiena_nvram_set_version( 853227569Sphilip __in efx_nic_t *enp, 854227569Sphilip __in efx_nvram_type_t type, 855227569Sphilip __out uint16_t version[4]) 856227569Sphilip{ 857227569Sphilip siena_mc_dynamic_config_hdr_t *dcfg = NULL; 858227569Sphilip siena_parttbl_entry_t *entry; 859227569Sphilip unsigned int dcfg_partn; 860227569Sphilip size_t partn_size; 861227569Sphilip unsigned int hdr_length; 862227569Sphilip unsigned int vpd_length; 863227569Sphilip unsigned int vpd_offset; 864227569Sphilip unsigned int nitems; 865227569Sphilip unsigned int required_hdr_length; 866227569Sphilip unsigned int pos; 867227569Sphilip uint8_t cksum; 868227569Sphilip uint32_t subtype; 869227569Sphilip size_t length; 870227569Sphilip int rc; 871227569Sphilip 872227569Sphilip if ((entry = siena_parttbl_entry(enp, type)) == NULL) { 873227569Sphilip rc = ENOTSUP; 874227569Sphilip goto fail1; 875227569Sphilip } 876227569Sphilip 877227569Sphilip dcfg_partn = (entry->port == 1) 878227569Sphilip ? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 879227569Sphilip : MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1; 880227569Sphilip 881227569Sphilip if ((rc = siena_nvram_partn_size(enp, dcfg_partn, &partn_size)) != 0) 882227569Sphilip goto fail2; 883227569Sphilip 884227569Sphilip if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0) 885227569Sphilip goto fail2; 886227569Sphilip 887227569Sphilip if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn, 888227569Sphilip B_TRUE, &dcfg, &length)) != 0) 889227569Sphilip goto fail3; 890227569Sphilip 891227569Sphilip hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0); 892227569Sphilip nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items, EFX_DWORD_0); 893227569Sphilip vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0); 894227569Sphilip vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0); 895227569Sphilip 896227569Sphilip /* 897227569Sphilip * NOTE: This function will blatt any fields trailing the version 898227569Sphilip * vector, or the VPD chunk. 899227569Sphilip */ 900227569Sphilip required_hdr_length = SIENA_DYNAMIC_CFG_SIZE(entry->partn + 1); 901227569Sphilip if (required_hdr_length + vpd_length > length) { 902227569Sphilip rc = ENOSPC; 903227569Sphilip goto fail4; 904227569Sphilip } 905227569Sphilip 906227569Sphilip if (vpd_offset < required_hdr_length) { 907227569Sphilip (void) memmove((caddr_t)dcfg + required_hdr_length, 908227569Sphilip (caddr_t)dcfg + vpd_offset, vpd_length); 909227569Sphilip vpd_offset = required_hdr_length; 910227569Sphilip EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, 911227569Sphilip EFX_DWORD_0, vpd_offset); 912227569Sphilip } 913227569Sphilip 914227569Sphilip if (hdr_length < required_hdr_length) { 915227569Sphilip (void) memset((caddr_t)dcfg + hdr_length, 0, 916227569Sphilip required_hdr_length - hdr_length); 917227569Sphilip hdr_length = required_hdr_length; 918227569Sphilip EFX_POPULATE_WORD_1(dcfg->length, 919227569Sphilip EFX_WORD_0, hdr_length); 920227569Sphilip } 921227569Sphilip 922227569Sphilip /* Get the subtype to insert into the fw_subtype array */ 923227569Sphilip if ((rc = siena_nvram_get_subtype(enp, entry->partn, &subtype)) != 0) 924227569Sphilip goto fail5; 925227569Sphilip 926227569Sphilip /* Fill out the new version */ 927227569Sphilip EFX_POPULATE_DWORD_1(dcfg->fw_version[entry->partn].fw_subtype, 928227569Sphilip EFX_DWORD_0, subtype); 929227569Sphilip EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_w, 930227569Sphilip EFX_WORD_0, version[0]); 931227569Sphilip EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_x, 932227569Sphilip EFX_WORD_0, version[1]); 933227569Sphilip EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_y, 934227569Sphilip EFX_WORD_0, version[2]); 935227569Sphilip EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_z, 936227569Sphilip EFX_WORD_0, version[3]); 937227569Sphilip 938227569Sphilip /* Update the version count */ 939227569Sphilip if (nitems < entry->partn + 1) { 940227569Sphilip nitems = entry->partn + 1; 941227569Sphilip EFX_POPULATE_DWORD_1(dcfg->num_fw_version_items, 942227569Sphilip EFX_DWORD_0, nitems); 943227569Sphilip } 944227569Sphilip 945227569Sphilip /* Update the checksum */ 946227569Sphilip cksum = 0; 947227569Sphilip for (pos = 0; pos < hdr_length; pos++) 948227569Sphilip cksum += ((uint8_t *)dcfg)[pos]; 949227569Sphilip dcfg->csum.eb_u8[0] -= cksum; 950227569Sphilip 951227569Sphilip /* Erase and write the new partition */ 952227569Sphilip if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, partn_size)) != 0) 953227569Sphilip goto fail6; 954227569Sphilip 955227569Sphilip /* Write out the new structure to nvram */ 956227569Sphilip if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0, 957227569Sphilip (caddr_t)dcfg, vpd_offset + vpd_length)) != 0) 958227569Sphilip goto fail7; 959227569Sphilip 960227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 961227569Sphilip 962227569Sphilip siena_nvram_partn_unlock(enp, dcfg_partn); 963227569Sphilip 964227569Sphilip return (0); 965227569Sphilip 966227569Sphilipfail7: 967227569Sphilip EFSYS_PROBE(fail7); 968227569Sphilipfail6: 969227569Sphilip EFSYS_PROBE(fail6); 970227569Sphilipfail5: 971227569Sphilip EFSYS_PROBE(fail5); 972227569Sphilipfail4: 973227569Sphilip EFSYS_PROBE(fail4); 974227569Sphilip 975227569Sphilip EFSYS_KMEM_FREE(enp->en_esip, length, dcfg); 976227569Sphilipfail3: 977227569Sphilip EFSYS_PROBE(fail3); 978227569Sphilipfail2: 979227569Sphilip EFSYS_PROBE(fail2); 980227569Sphilipfail1: 981227569Sphilip EFSYS_PROBE1(fail1, int, rc); 982227569Sphilip 983227569Sphilip return (rc); 984227569Sphilip} 985227569Sphilip 986227569Sphilip#endif /* EFSYS_OPT_NVRAM */ 987227569Sphilip 988227569Sphilip#endif /* EFSYS_OPT_SIENA */ 989