xref: /freebsd/sys/dev/sfxge/common/siena_nvram.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
1e948693eSPhilip Paeps /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
4929c7febSAndrew Rybchenko  * Copyright (c) 2009-2016 Solarflare Communications Inc.
53c838a9fSAndrew Rybchenko  * All rights reserved.
6e948693eSPhilip Paeps  *
7e948693eSPhilip Paeps  * Redistribution and use in source and binary forms, with or without
83c838a9fSAndrew Rybchenko  * modification, are permitted provided that the following conditions are met:
9e948693eSPhilip Paeps  *
103c838a9fSAndrew Rybchenko  * 1. Redistributions of source code must retain the above copyright notice,
113c838a9fSAndrew Rybchenko  *    this list of conditions and the following disclaimer.
123c838a9fSAndrew Rybchenko  * 2. Redistributions in binary form must reproduce the above copyright notice,
133c838a9fSAndrew Rybchenko  *    this list of conditions and the following disclaimer in the documentation
143c838a9fSAndrew Rybchenko  *    and/or other materials provided with the distribution.
153c838a9fSAndrew Rybchenko  *
163c838a9fSAndrew Rybchenko  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
173c838a9fSAndrew Rybchenko  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
183c838a9fSAndrew Rybchenko  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
193c838a9fSAndrew Rybchenko  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
203c838a9fSAndrew Rybchenko  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
213c838a9fSAndrew Rybchenko  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
223c838a9fSAndrew Rybchenko  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
233c838a9fSAndrew Rybchenko  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
243c838a9fSAndrew Rybchenko  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
253c838a9fSAndrew Rybchenko  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
263c838a9fSAndrew Rybchenko  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
273c838a9fSAndrew Rybchenko  *
283c838a9fSAndrew Rybchenko  * The views and conclusions contained in the software and documentation are
293c838a9fSAndrew Rybchenko  * those of the authors and should not be interpreted as representing official
303c838a9fSAndrew Rybchenko  * policies, either expressed or implied, of the FreeBSD Project.
31e948693eSPhilip Paeps  */
32e948693eSPhilip Paeps 
335dee87d7SPhilip Paeps #include <sys/cdefs.h>
34e948693eSPhilip Paeps #include "efx.h"
35e948693eSPhilip Paeps #include "efx_impl.h"
36e948693eSPhilip Paeps 
37e948693eSPhilip Paeps #if EFSYS_OPT_SIENA
38e948693eSPhilip Paeps 
39e948693eSPhilip Paeps #if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
40e948693eSPhilip Paeps 
41460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
siena_nvram_partn_size(__in efx_nic_t * enp,__in uint32_t partn,__out size_t * sizep)42e948693eSPhilip Paeps siena_nvram_partn_size(
43e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
448eea4a0aSAndrew Rybchenko 	__in			uint32_t partn,
45e948693eSPhilip Paeps 	__out			size_t *sizep)
46e948693eSPhilip Paeps {
47460cb568SAndrew Rybchenko 	efx_rc_t rc;
48e948693eSPhilip Paeps 
49e948693eSPhilip Paeps 	if ((1 << partn) & ~enp->en_u.siena.enu_partn_mask) {
50e948693eSPhilip Paeps 		rc = ENOTSUP;
51e948693eSPhilip Paeps 		goto fail1;
52e948693eSPhilip Paeps 	}
53e948693eSPhilip Paeps 
549cb71b16SAndrew Rybchenko 	if ((rc = efx_mcdi_nvram_info(enp, partn, sizep,
559cb71b16SAndrew Rybchenko 	    NULL, NULL, NULL)) != 0) {
56e948693eSPhilip Paeps 		goto fail2;
57e948693eSPhilip Paeps 	}
58e948693eSPhilip Paeps 
59e948693eSPhilip Paeps 	return (0);
60e948693eSPhilip Paeps 
61e948693eSPhilip Paeps fail2:
62e948693eSPhilip Paeps 	EFSYS_PROBE(fail2);
63e948693eSPhilip Paeps fail1:
64460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
65e948693eSPhilip Paeps 
66e948693eSPhilip Paeps 	return (rc);
67e948693eSPhilip Paeps }
68e948693eSPhilip Paeps 
69460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
siena_nvram_partn_lock(__in efx_nic_t * enp,__in uint32_t partn)70e948693eSPhilip Paeps siena_nvram_partn_lock(
71e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
728eea4a0aSAndrew Rybchenko 	__in			uint32_t partn)
73e948693eSPhilip Paeps {
74460cb568SAndrew Rybchenko 	efx_rc_t rc;
75e948693eSPhilip Paeps 
763c838a9fSAndrew Rybchenko 	if ((rc = efx_mcdi_nvram_update_start(enp, partn)) != 0) {
77e948693eSPhilip Paeps 		goto fail1;
78e948693eSPhilip Paeps 	}
79e948693eSPhilip Paeps 
80e948693eSPhilip Paeps 	return (0);
81e948693eSPhilip Paeps 
82e948693eSPhilip Paeps fail1:
83460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
84e948693eSPhilip Paeps 
85e948693eSPhilip Paeps 	return (rc);
86e948693eSPhilip Paeps }
87e948693eSPhilip Paeps 
88460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
siena_nvram_partn_read(__in efx_nic_t * enp,__in uint32_t partn,__in unsigned int offset,__out_bcount (size)caddr_t data,__in size_t size)89e948693eSPhilip Paeps siena_nvram_partn_read(
90e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
918eea4a0aSAndrew Rybchenko 	__in			uint32_t partn,
92e948693eSPhilip Paeps 	__in			unsigned int offset,
93e948693eSPhilip Paeps 	__out_bcount(size)	caddr_t data,
94e948693eSPhilip Paeps 	__in			size_t size)
95e948693eSPhilip Paeps {
96e948693eSPhilip Paeps 	size_t chunk;
97460cb568SAndrew Rybchenko 	efx_rc_t rc;
98e948693eSPhilip Paeps 
99e948693eSPhilip Paeps 	while (size > 0) {
100e948693eSPhilip Paeps 		chunk = MIN(size, SIENA_NVRAM_CHUNK);
101e948693eSPhilip Paeps 
1029ad7e03fSAndrew Rybchenko 		if ((rc = efx_mcdi_nvram_read(enp, partn, offset, data, chunk,
1039ad7e03fSAndrew Rybchenko 			    MC_CMD_NVRAM_READ_IN_V2_DEFAULT)) != 0) {
104e948693eSPhilip Paeps 			goto fail1;
105e948693eSPhilip Paeps 		}
106e948693eSPhilip Paeps 
107e948693eSPhilip Paeps 		size -= chunk;
108e948693eSPhilip Paeps 		data += chunk;
109e948693eSPhilip Paeps 		offset += chunk;
110e948693eSPhilip Paeps 	}
111e948693eSPhilip Paeps 
112e948693eSPhilip Paeps 	return (0);
113e948693eSPhilip Paeps 
114e948693eSPhilip Paeps fail1:
115460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
116e948693eSPhilip Paeps 
117e948693eSPhilip Paeps 	return (rc);
118e948693eSPhilip Paeps }
119e948693eSPhilip Paeps 
120460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
siena_nvram_partn_erase(__in efx_nic_t * enp,__in uint32_t partn,__in unsigned int offset,__in size_t size)121e948693eSPhilip Paeps siena_nvram_partn_erase(
122e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
1238eea4a0aSAndrew Rybchenko 	__in			uint32_t partn,
124e948693eSPhilip Paeps 	__in			unsigned int offset,
125e948693eSPhilip Paeps 	__in			size_t size)
126e948693eSPhilip Paeps {
127460cb568SAndrew Rybchenko 	efx_rc_t rc;
128e948693eSPhilip Paeps 
1293c838a9fSAndrew Rybchenko 	if ((rc = efx_mcdi_nvram_erase(enp, partn, offset, size)) != 0) {
130e948693eSPhilip Paeps 		goto fail1;
131e948693eSPhilip Paeps 	}
132e948693eSPhilip Paeps 
133e948693eSPhilip Paeps 	return (0);
134e948693eSPhilip Paeps 
135e948693eSPhilip Paeps fail1:
136460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
137e948693eSPhilip Paeps 
138e948693eSPhilip Paeps 	return (rc);
139e948693eSPhilip Paeps }
140e948693eSPhilip Paeps 
141460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
siena_nvram_partn_write(__in efx_nic_t * enp,__in uint32_t partn,__in unsigned int offset,__out_bcount (size)caddr_t data,__in size_t size)142e948693eSPhilip Paeps siena_nvram_partn_write(
143e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
1448eea4a0aSAndrew Rybchenko 	__in			uint32_t partn,
145e948693eSPhilip Paeps 	__in			unsigned int offset,
146e948693eSPhilip Paeps 	__out_bcount(size)	caddr_t data,
147e948693eSPhilip Paeps 	__in			size_t size)
148e948693eSPhilip Paeps {
149e948693eSPhilip Paeps 	size_t chunk;
150460cb568SAndrew Rybchenko 	efx_rc_t rc;
151e948693eSPhilip Paeps 
152e948693eSPhilip Paeps 	while (size > 0) {
153e948693eSPhilip Paeps 		chunk = MIN(size, SIENA_NVRAM_CHUNK);
154e948693eSPhilip Paeps 
1553c838a9fSAndrew Rybchenko 		if ((rc = efx_mcdi_nvram_write(enp, partn, offset,
1563c838a9fSAndrew Rybchenko 			    data, chunk)) != 0) {
157e948693eSPhilip Paeps 			goto fail1;
158e948693eSPhilip Paeps 		}
159e948693eSPhilip Paeps 
160e948693eSPhilip Paeps 		size -= chunk;
161e948693eSPhilip Paeps 		data += chunk;
162e948693eSPhilip Paeps 		offset += chunk;
163e948693eSPhilip Paeps 	}
164e948693eSPhilip Paeps 
165e948693eSPhilip Paeps 	return (0);
166e948693eSPhilip Paeps 
167e948693eSPhilip Paeps fail1:
168460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
169e948693eSPhilip Paeps 
170e948693eSPhilip Paeps 	return (rc);
171e948693eSPhilip Paeps }
172e948693eSPhilip Paeps 
173e9c123a5SAndrew Rybchenko 	__checkReturn		efx_rc_t
siena_nvram_partn_unlock(__in efx_nic_t * enp,__in uint32_t partn,__out_opt uint32_t * verify_resultp)174e948693eSPhilip Paeps siena_nvram_partn_unlock(
175e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
176a21b2f20SAndrew Rybchenko 	__in			uint32_t partn,
177a21b2f20SAndrew Rybchenko 	__out_opt		uint32_t *verify_resultp)
178e948693eSPhilip Paeps {
1793c838a9fSAndrew Rybchenko 	boolean_t reboot;
180460cb568SAndrew Rybchenko 	efx_rc_t rc;
181e948693eSPhilip Paeps 
182e948693eSPhilip Paeps 	/*
183e948693eSPhilip Paeps 	 * Reboot into the new image only for PHYs. The driver has to
184e948693eSPhilip Paeps 	 * explicitly cope with an MC reboot after a firmware update.
185e948693eSPhilip Paeps 	 */
186e948693eSPhilip Paeps 	reboot = (partn == MC_CMD_NVRAM_TYPE_PHY_PORT0 ||
187e948693eSPhilip Paeps 		    partn == MC_CMD_NVRAM_TYPE_PHY_PORT1 ||
188e948693eSPhilip Paeps 		    partn == MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO);
189e948693eSPhilip Paeps 
190a21b2f20SAndrew Rybchenko 	rc = efx_mcdi_nvram_update_finish(enp, partn, reboot, verify_resultp);
191e9c123a5SAndrew Rybchenko 	if (rc != 0)
192e948693eSPhilip Paeps 		goto fail1;
193e948693eSPhilip Paeps 
194e9c123a5SAndrew Rybchenko 	return (0);
195e948693eSPhilip Paeps 
196e948693eSPhilip Paeps fail1:
197460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
198e9c123a5SAndrew Rybchenko 
199e9c123a5SAndrew Rybchenko 	return (rc);
200e948693eSPhilip Paeps }
201e948693eSPhilip Paeps 
202e948693eSPhilip Paeps #endif	/* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */
203e948693eSPhilip Paeps 
204e948693eSPhilip Paeps #if EFSYS_OPT_NVRAM
205e948693eSPhilip Paeps 
206e948693eSPhilip Paeps typedef struct siena_parttbl_entry_s {
207e948693eSPhilip Paeps 	unsigned int		partn;
208e948693eSPhilip Paeps 	unsigned int		port;
209e948693eSPhilip Paeps 	efx_nvram_type_t	nvtype;
210e948693eSPhilip Paeps } siena_parttbl_entry_t;
211e948693eSPhilip Paeps 
212e948693eSPhilip Paeps static siena_parttbl_entry_t siena_parttbl[] = {
213e948693eSPhilip Paeps 	{MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO,	1, EFX_NVRAM_NULLPHY},
214e948693eSPhilip Paeps 	{MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO,	2, EFX_NVRAM_NULLPHY},
215e948693eSPhilip Paeps 	{MC_CMD_NVRAM_TYPE_MC_FW,		1, EFX_NVRAM_MC_FIRMWARE},
216e948693eSPhilip Paeps 	{MC_CMD_NVRAM_TYPE_MC_FW,		2, EFX_NVRAM_MC_FIRMWARE},
217e948693eSPhilip Paeps 	{MC_CMD_NVRAM_TYPE_MC_FW_BACKUP,	1, EFX_NVRAM_MC_GOLDEN},
218e948693eSPhilip Paeps 	{MC_CMD_NVRAM_TYPE_MC_FW_BACKUP,	2, EFX_NVRAM_MC_GOLDEN},
219e948693eSPhilip Paeps 	{MC_CMD_NVRAM_TYPE_EXP_ROM,		1, EFX_NVRAM_BOOTROM},
220e948693eSPhilip Paeps 	{MC_CMD_NVRAM_TYPE_EXP_ROM,		2, EFX_NVRAM_BOOTROM},
221e948693eSPhilip Paeps 	{MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT0,	1, EFX_NVRAM_BOOTROM_CFG},
222e948693eSPhilip Paeps 	{MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT1,	2, EFX_NVRAM_BOOTROM_CFG},
223e948693eSPhilip Paeps 	{MC_CMD_NVRAM_TYPE_PHY_PORT0,		1, EFX_NVRAM_PHY},
224e948693eSPhilip Paeps 	{MC_CMD_NVRAM_TYPE_PHY_PORT1,		2, EFX_NVRAM_PHY},
225fd7a9912SAndrew Rybchenko 	{MC_CMD_NVRAM_TYPE_FPGA,		1, EFX_NVRAM_FPGA},
226fd7a9912SAndrew Rybchenko 	{MC_CMD_NVRAM_TYPE_FPGA,		2, EFX_NVRAM_FPGA},
227fd7a9912SAndrew Rybchenko 	{MC_CMD_NVRAM_TYPE_FPGA_BACKUP,		1, EFX_NVRAM_FPGA_BACKUP},
228fd7a9912SAndrew Rybchenko 	{MC_CMD_NVRAM_TYPE_FPGA_BACKUP,		2, EFX_NVRAM_FPGA_BACKUP},
229fd7a9912SAndrew Rybchenko 	{MC_CMD_NVRAM_TYPE_FC_FW,		1, EFX_NVRAM_FCFW},
230fd7a9912SAndrew Rybchenko 	{MC_CMD_NVRAM_TYPE_FC_FW,		2, EFX_NVRAM_FCFW},
231fd7a9912SAndrew Rybchenko 	{MC_CMD_NVRAM_TYPE_CPLD,		1, EFX_NVRAM_CPLD},
232fd7a9912SAndrew Rybchenko 	{MC_CMD_NVRAM_TYPE_CPLD,		2, EFX_NVRAM_CPLD},
233dc5427fcSAndrew Rybchenko 	{MC_CMD_NVRAM_TYPE_LICENSE,		1, EFX_NVRAM_LICENSE},
234dc5427fcSAndrew Rybchenko 	{MC_CMD_NVRAM_TYPE_LICENSE,		2, EFX_NVRAM_LICENSE}
235e948693eSPhilip Paeps };
236e948693eSPhilip Paeps 
237bce88e31SAndrew Rybchenko 	__checkReturn		efx_rc_t
siena_nvram_type_to_partn(__in efx_nic_t * enp,__in efx_nvram_type_t type,__out uint32_t * partnp)238bce88e31SAndrew Rybchenko siena_nvram_type_to_partn(
239e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
240bce88e31SAndrew Rybchenko 	__in			efx_nvram_type_t type,
241bce88e31SAndrew Rybchenko 	__out			uint32_t *partnp)
242e948693eSPhilip Paeps {
2433c838a9fSAndrew Rybchenko 	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
2443c838a9fSAndrew Rybchenko 	unsigned int i;
245e948693eSPhilip Paeps 
2460ab1d25fSAndrew Rybchenko 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
247e948693eSPhilip Paeps 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
248bce88e31SAndrew Rybchenko 	EFSYS_ASSERT(partnp != NULL);
249e948693eSPhilip Paeps 
2503c838a9fSAndrew Rybchenko 	for (i = 0; i < EFX_ARRAY_SIZE(siena_parttbl); i++) {
251bce88e31SAndrew Rybchenko 		siena_parttbl_entry_t *entry = &siena_parttbl[i];
2523c838a9fSAndrew Rybchenko 
253bce88e31SAndrew Rybchenko 		if (entry->port == emip->emi_port && entry->nvtype == type) {
254bce88e31SAndrew Rybchenko 			*partnp = entry->partn;
255bce88e31SAndrew Rybchenko 			return (0);
256bce88e31SAndrew Rybchenko 		}
257e948693eSPhilip Paeps 	}
258e948693eSPhilip Paeps 
259bce88e31SAndrew Rybchenko 	return (ENOTSUP);
260e948693eSPhilip Paeps }
261e948693eSPhilip Paeps 
262e948693eSPhilip Paeps #if EFSYS_OPT_DIAG
263e948693eSPhilip Paeps 
264460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
siena_nvram_test(__in efx_nic_t * enp)265e948693eSPhilip Paeps siena_nvram_test(
266e948693eSPhilip Paeps 	__in			efx_nic_t *enp)
267e948693eSPhilip Paeps {
2683c838a9fSAndrew Rybchenko 	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
269e948693eSPhilip Paeps 	siena_parttbl_entry_t *entry;
2703c838a9fSAndrew Rybchenko 	unsigned int i;
271460cb568SAndrew Rybchenko 	efx_rc_t rc;
272e948693eSPhilip Paeps 
273e948693eSPhilip Paeps 	/*
274e948693eSPhilip Paeps 	 * Iterate over the list of supported partition types
275e948693eSPhilip Paeps 	 * applicable to *this* port
276e948693eSPhilip Paeps 	 */
2773c838a9fSAndrew Rybchenko 	for (i = 0; i < EFX_ARRAY_SIZE(siena_parttbl); i++) {
2783c838a9fSAndrew Rybchenko 		entry = &siena_parttbl[i];
2793c838a9fSAndrew Rybchenko 
280e948693eSPhilip Paeps 		if (entry->port != emip->emi_port ||
281e948693eSPhilip Paeps 		    !(enp->en_u.siena.enu_partn_mask & (1 << entry->partn)))
282e948693eSPhilip Paeps 			continue;
283e948693eSPhilip Paeps 
2843c838a9fSAndrew Rybchenko 		if ((rc = efx_mcdi_nvram_test(enp, entry->partn)) != 0) {
285e948693eSPhilip Paeps 			goto fail1;
286e948693eSPhilip Paeps 		}
287e948693eSPhilip Paeps 	}
288e948693eSPhilip Paeps 
289e948693eSPhilip Paeps 	return (0);
290e948693eSPhilip Paeps 
291e948693eSPhilip Paeps fail1:
292460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
293e948693eSPhilip Paeps 
294e948693eSPhilip Paeps 	return (rc);
295e948693eSPhilip Paeps }
296e948693eSPhilip Paeps 
297e948693eSPhilip Paeps #endif	/* EFSYS_OPT_DIAG */
298e948693eSPhilip Paeps 
299e948693eSPhilip Paeps #define	SIENA_DYNAMIC_CFG_SIZE(_nitems)					\
300e948693eSPhilip Paeps 	(sizeof (siena_mc_dynamic_config_hdr_t) + ((_nitems) *		\
301e948693eSPhilip Paeps 	sizeof (((siena_mc_dynamic_config_hdr_t *)NULL)->fw_version[0])))
302e948693eSPhilip Paeps 
303460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
siena_nvram_get_dynamic_cfg(__in efx_nic_t * enp,__in uint32_t partn,__in boolean_t vpd,__out siena_mc_dynamic_config_hdr_t ** dcfgp,__out size_t * sizep)304e948693eSPhilip Paeps siena_nvram_get_dynamic_cfg(
305e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
3068eea4a0aSAndrew Rybchenko 	__in			uint32_t partn,
307e948693eSPhilip Paeps 	__in			boolean_t vpd,
308e948693eSPhilip Paeps 	__out			siena_mc_dynamic_config_hdr_t **dcfgp,
309e948693eSPhilip Paeps 	__out			size_t *sizep)
310e948693eSPhilip Paeps {
3113c838a9fSAndrew Rybchenko 	siena_mc_dynamic_config_hdr_t *dcfg = NULL;
312e948693eSPhilip Paeps 	size_t size;
313e948693eSPhilip Paeps 	uint8_t cksum;
314e948693eSPhilip Paeps 	unsigned int vpd_offset;
315e948693eSPhilip Paeps 	unsigned int vpd_length;
316e948693eSPhilip Paeps 	unsigned int hdr_length;
317e948693eSPhilip Paeps 	unsigned int nversions;
318e948693eSPhilip Paeps 	unsigned int pos;
319e948693eSPhilip Paeps 	unsigned int region;
320460cb568SAndrew Rybchenko 	efx_rc_t rc;
321e948693eSPhilip Paeps 
322e948693eSPhilip Paeps 	EFSYS_ASSERT(partn == MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 ||
323e948693eSPhilip Paeps 		    partn == MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1);
324e948693eSPhilip Paeps 
325e948693eSPhilip Paeps 	/*
326e948693eSPhilip Paeps 	 * Allocate sufficient memory for the entire dynamiccfg area, even
327e948693eSPhilip Paeps 	 * if we're not actually going to read in the VPD.
328e948693eSPhilip Paeps 	 */
329e948693eSPhilip Paeps 	if ((rc = siena_nvram_partn_size(enp, partn, &size)) != 0)
330e948693eSPhilip Paeps 		goto fail1;
331e948693eSPhilip Paeps 
332b20c54ffSAndrew Rybchenko 	if (size < SIENA_NVRAM_CHUNK) {
333b20c54ffSAndrew Rybchenko 		rc = EINVAL;
334b20c54ffSAndrew Rybchenko 		goto fail2;
335b20c54ffSAndrew Rybchenko 	}
336b20c54ffSAndrew Rybchenko 
337e948693eSPhilip Paeps 	EFSYS_KMEM_ALLOC(enp->en_esip, size, dcfg);
338e948693eSPhilip Paeps 	if (dcfg == NULL) {
339e948693eSPhilip Paeps 		rc = ENOMEM;
340b20c54ffSAndrew Rybchenko 		goto fail3;
341e948693eSPhilip Paeps 	}
342e948693eSPhilip Paeps 
343e948693eSPhilip Paeps 	if ((rc = siena_nvram_partn_read(enp, partn, 0,
344e948693eSPhilip Paeps 	    (caddr_t)dcfg, SIENA_NVRAM_CHUNK)) != 0)
345b20c54ffSAndrew Rybchenko 		goto fail4;
346e948693eSPhilip Paeps 
347e948693eSPhilip Paeps 	/* Verify the magic */
348e948693eSPhilip Paeps 	if (EFX_DWORD_FIELD(dcfg->magic, EFX_DWORD_0)
349e948693eSPhilip Paeps 	    != SIENA_MC_DYNAMIC_CONFIG_MAGIC)
350e948693eSPhilip Paeps 		goto invalid1;
351e948693eSPhilip Paeps 
352453130d9SPedro F. Giffuni 	/* All future versions of the structure must be backwards compatible */
353e948693eSPhilip Paeps 	EFX_STATIC_ASSERT(SIENA_MC_DYNAMIC_CONFIG_VERSION == 0);
354e948693eSPhilip Paeps 
355e948693eSPhilip Paeps 	hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0);
356e948693eSPhilip Paeps 	nversions = EFX_DWORD_FIELD(dcfg->num_fw_version_items, EFX_DWORD_0);
357e948693eSPhilip Paeps 	vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0);
358e948693eSPhilip Paeps 	vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0);
359e948693eSPhilip Paeps 
360e948693eSPhilip Paeps 	/* Verify the hdr doesn't overflow the partn size */
361e948693eSPhilip Paeps 	if (hdr_length > size || vpd_offset > size || vpd_length > size ||
362e948693eSPhilip Paeps 	    vpd_length + vpd_offset > size)
363e948693eSPhilip Paeps 		goto invalid2;
364e948693eSPhilip Paeps 
365e948693eSPhilip Paeps 	/* Verify the header has room for all it's versions */
366e948693eSPhilip Paeps 	if (hdr_length < SIENA_DYNAMIC_CFG_SIZE(0) ||
367e948693eSPhilip Paeps 	    hdr_length < SIENA_DYNAMIC_CFG_SIZE(nversions))
368e948693eSPhilip Paeps 		goto invalid3;
369e948693eSPhilip Paeps 
370e948693eSPhilip Paeps 	/*
371e948693eSPhilip Paeps 	 * Read the remaining portion of the dcfg, either including
372e948693eSPhilip Paeps 	 * the whole of VPD (there is no vpd length in this structure,
373e948693eSPhilip Paeps 	 * so we have to parse each tag), or just the dcfg header itself
374e948693eSPhilip Paeps 	 */
375e948693eSPhilip Paeps 	region = vpd ? vpd_offset + vpd_length : hdr_length;
376e948693eSPhilip Paeps 	if (region > SIENA_NVRAM_CHUNK) {
377e948693eSPhilip Paeps 		if ((rc = siena_nvram_partn_read(enp, partn, SIENA_NVRAM_CHUNK,
378e948693eSPhilip Paeps 		    (caddr_t)dcfg + SIENA_NVRAM_CHUNK,
379e948693eSPhilip Paeps 		    region - SIENA_NVRAM_CHUNK)) != 0)
380b20c54ffSAndrew Rybchenko 			goto fail5;
381e948693eSPhilip Paeps 	}
382e948693eSPhilip Paeps 
383e948693eSPhilip Paeps 	/* Verify checksum */
384e948693eSPhilip Paeps 	cksum = 0;
385e948693eSPhilip Paeps 	for (pos = 0; pos < hdr_length; pos++)
386e948693eSPhilip Paeps 		cksum += ((uint8_t *)dcfg)[pos];
387e948693eSPhilip Paeps 	if (cksum != 0)
388e948693eSPhilip Paeps 		goto invalid4;
389e948693eSPhilip Paeps 
390e948693eSPhilip Paeps 	goto done;
391e948693eSPhilip Paeps 
392e948693eSPhilip Paeps invalid4:
393e948693eSPhilip Paeps 	EFSYS_PROBE(invalid4);
394e948693eSPhilip Paeps invalid3:
395e948693eSPhilip Paeps 	EFSYS_PROBE(invalid3);
396e948693eSPhilip Paeps invalid2:
397e948693eSPhilip Paeps 	EFSYS_PROBE(invalid2);
398e948693eSPhilip Paeps invalid1:
399e948693eSPhilip Paeps 	EFSYS_PROBE(invalid1);
400e948693eSPhilip Paeps 
401e948693eSPhilip Paeps 	/*
402e948693eSPhilip Paeps 	 * Construct a new "null" dcfg, with an empty version vector,
403e948693eSPhilip Paeps 	 * and an empty VPD chunk trailing. This has the neat side effect
404e948693eSPhilip Paeps 	 * of testing the exception paths in the write path.
405e948693eSPhilip Paeps 	 */
406e948693eSPhilip Paeps 	EFX_POPULATE_DWORD_1(dcfg->magic,
407e948693eSPhilip Paeps 			    EFX_DWORD_0, SIENA_MC_DYNAMIC_CONFIG_MAGIC);
408e948693eSPhilip Paeps 	EFX_POPULATE_WORD_1(dcfg->length, EFX_WORD_0, sizeof (*dcfg));
409e948693eSPhilip Paeps 	EFX_POPULATE_BYTE_1(dcfg->version, EFX_BYTE_0,
410e948693eSPhilip Paeps 			    SIENA_MC_DYNAMIC_CONFIG_VERSION);
411e948693eSPhilip Paeps 	EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset,
412e948693eSPhilip Paeps 			    EFX_DWORD_0, sizeof (*dcfg));
413e948693eSPhilip Paeps 	EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_length, EFX_DWORD_0, 0);
414e948693eSPhilip Paeps 	EFX_POPULATE_DWORD_1(dcfg->num_fw_version_items, EFX_DWORD_0, 0);
415e948693eSPhilip Paeps 
416e948693eSPhilip Paeps done:
417e948693eSPhilip Paeps 	*dcfgp = dcfg;
418e948693eSPhilip Paeps 	*sizep = size;
419e948693eSPhilip Paeps 
420e948693eSPhilip Paeps 	return (0);
421e948693eSPhilip Paeps 
422b20c54ffSAndrew Rybchenko fail5:
423b20c54ffSAndrew Rybchenko 	EFSYS_PROBE(fail5);
424e948693eSPhilip Paeps fail4:
425e948693eSPhilip Paeps 	EFSYS_PROBE(fail4);
426e948693eSPhilip Paeps 
427e948693eSPhilip Paeps 	EFSYS_KMEM_FREE(enp->en_esip, size, dcfg);
428e948693eSPhilip Paeps 
429b20c54ffSAndrew Rybchenko fail3:
430b20c54ffSAndrew Rybchenko 	EFSYS_PROBE(fail3);
4313c838a9fSAndrew Rybchenko fail2:
4323c838a9fSAndrew Rybchenko 	EFSYS_PROBE(fail2);
433e948693eSPhilip Paeps fail1:
434460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
435e948693eSPhilip Paeps 
436e948693eSPhilip Paeps 	return (rc);
437e948693eSPhilip Paeps }
438e948693eSPhilip Paeps 
439460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
siena_nvram_get_subtype(__in efx_nic_t * enp,__in uint32_t partn,__out uint32_t * subtypep)440e948693eSPhilip Paeps siena_nvram_get_subtype(
441e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
4428eea4a0aSAndrew Rybchenko 	__in			uint32_t partn,
443e948693eSPhilip Paeps 	__out			uint32_t *subtypep)
444e948693eSPhilip Paeps {
445e948693eSPhilip Paeps 	efx_mcdi_req_t req;
446315bbbaaSAndrew Rybchenko 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_BOARD_CFG_IN_LEN,
447315bbbaaSAndrew Rybchenko 		MC_CMD_GET_BOARD_CFG_OUT_LENMAX);
448e948693eSPhilip Paeps 	efx_word_t *fw_list;
449460cb568SAndrew Rybchenko 	efx_rc_t rc;
450e948693eSPhilip Paeps 
451e948693eSPhilip Paeps 	req.emr_cmd = MC_CMD_GET_BOARD_CFG;
4523c838a9fSAndrew Rybchenko 	req.emr_in_buf = payload;
4533c838a9fSAndrew Rybchenko 	req.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN;
4543c838a9fSAndrew Rybchenko 	req.emr_out_buf = payload;
4553c838a9fSAndrew Rybchenko 	req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMAX;
456e948693eSPhilip Paeps 
457e948693eSPhilip Paeps 	efx_mcdi_execute(enp, &req);
458e948693eSPhilip Paeps 
459e948693eSPhilip Paeps 	if (req.emr_rc != 0) {
460e948693eSPhilip Paeps 		rc = req.emr_rc;
461e948693eSPhilip Paeps 		goto fail1;
462e948693eSPhilip Paeps 	}
463e948693eSPhilip Paeps 
4641f697668SAndrew Rybchenko 	if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) {
465e948693eSPhilip Paeps 		rc = EMSGSIZE;
466e948693eSPhilip Paeps 		goto fail2;
467e948693eSPhilip Paeps 	}
468e948693eSPhilip Paeps 
4691f697668SAndrew Rybchenko 	if (req.emr_out_length_used <
4701f697668SAndrew Rybchenko 	    MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_OFST +
4711f697668SAndrew Rybchenko 	    (partn + 1) * sizeof (efx_word_t)) {
4721f697668SAndrew Rybchenko 		rc = ENOENT;
4731f697668SAndrew Rybchenko 		goto fail3;
4741f697668SAndrew Rybchenko 	}
4751f697668SAndrew Rybchenko 
476e948693eSPhilip Paeps 	fw_list = MCDI_OUT2(req, efx_word_t,
477e948693eSPhilip Paeps 			    GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST);
478e948693eSPhilip Paeps 	*subtypep = EFX_WORD_FIELD(fw_list[partn], EFX_WORD_0);
479e948693eSPhilip Paeps 
480e948693eSPhilip Paeps 	return (0);
481e948693eSPhilip Paeps 
4821f697668SAndrew Rybchenko fail3:
4831f697668SAndrew Rybchenko 	EFSYS_PROBE(fail3);
484e948693eSPhilip Paeps fail2:
485e948693eSPhilip Paeps 	EFSYS_PROBE(fail2);
486e948693eSPhilip Paeps fail1:
487460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
488e948693eSPhilip Paeps 
489e948693eSPhilip Paeps 	return (rc);
490e948693eSPhilip Paeps }
491e948693eSPhilip Paeps 
492460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
49392187119SAndrew Rybchenko siena_nvram_partn_get_version(
494e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
49592187119SAndrew Rybchenko 	__in			uint32_t partn,
496e948693eSPhilip Paeps 	__out			uint32_t *subtypep,
497e948693eSPhilip Paeps 	__out_ecount(4)		uint16_t version[4])
498e948693eSPhilip Paeps {
499e948693eSPhilip Paeps 	siena_mc_dynamic_config_hdr_t *dcfg;
500e948693eSPhilip Paeps 	siena_parttbl_entry_t *entry;
5018eea4a0aSAndrew Rybchenko 	uint32_t dcfg_partn;
5023c838a9fSAndrew Rybchenko 	unsigned int i;
503460cb568SAndrew Rybchenko 	efx_rc_t rc;
504e948693eSPhilip Paeps 
505e948693eSPhilip Paeps 	if ((1 << partn) & ~enp->en_u.siena.enu_partn_mask) {
506e948693eSPhilip Paeps 		rc = ENOTSUP;
50792187119SAndrew Rybchenko 		goto fail1;
508e948693eSPhilip Paeps 	}
509e948693eSPhilip Paeps 
510e948693eSPhilip Paeps 	if ((rc = siena_nvram_get_subtype(enp, partn, subtypep)) != 0)
51192187119SAndrew Rybchenko 		goto fail2;
512e948693eSPhilip Paeps 
513e948693eSPhilip Paeps 	/*
514e948693eSPhilip Paeps 	 * Some partitions are accessible from both ports (for instance BOOTROM)
515e948693eSPhilip Paeps 	 * Find the highest version reported by all dcfg structures on ports
516e948693eSPhilip Paeps 	 * that have access to this partition.
517e948693eSPhilip Paeps 	 */
518e948693eSPhilip Paeps 	version[0] = version[1] = version[2] = version[3] = 0;
5193c838a9fSAndrew Rybchenko 	for (i = 0; i < EFX_ARRAY_SIZE(siena_parttbl); i++) {
52092187119SAndrew Rybchenko 		siena_mc_fw_version_t *verp;
521e948693eSPhilip Paeps 		unsigned int nitems;
522e948693eSPhilip Paeps 		uint16_t temp[4];
523e948693eSPhilip Paeps 		size_t length;
524e948693eSPhilip Paeps 
5253c838a9fSAndrew Rybchenko 		entry = &siena_parttbl[i];
526e948693eSPhilip Paeps 		if (entry->partn != partn)
527e948693eSPhilip Paeps 			continue;
528e948693eSPhilip Paeps 
529e948693eSPhilip Paeps 		dcfg_partn = (entry->port == 1)
530e948693eSPhilip Paeps 			? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
531e948693eSPhilip Paeps 			: MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
532e948693eSPhilip Paeps 		/*
533e948693eSPhilip Paeps 		 * Ingore missing partitions on port 2, assuming they're due
534caa7e52fSEitan Adler 		 * to running on a single port part.
535e948693eSPhilip Paeps 		 */
536e948693eSPhilip Paeps 		if ((1 << dcfg_partn) &  ~enp->en_u.siena.enu_partn_mask) {
537e948693eSPhilip Paeps 			if (entry->port == 2)
538e948693eSPhilip Paeps 				continue;
539e948693eSPhilip Paeps 		}
540e948693eSPhilip Paeps 
541e948693eSPhilip Paeps 		if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
542e948693eSPhilip Paeps 		    B_FALSE, &dcfg, &length)) != 0)
54392187119SAndrew Rybchenko 			goto fail3;
544e948693eSPhilip Paeps 
545e948693eSPhilip Paeps 		nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items,
546e948693eSPhilip Paeps 			    EFX_DWORD_0);
547e948693eSPhilip Paeps 		if (nitems < entry->partn)
548e948693eSPhilip Paeps 			goto done;
549e948693eSPhilip Paeps 
55092187119SAndrew Rybchenko 		verp = &dcfg->fw_version[partn];
55192187119SAndrew Rybchenko 		temp[0] = EFX_WORD_FIELD(verp->version_w, EFX_WORD_0);
55292187119SAndrew Rybchenko 		temp[1] = EFX_WORD_FIELD(verp->version_x, EFX_WORD_0);
55392187119SAndrew Rybchenko 		temp[2] = EFX_WORD_FIELD(verp->version_y, EFX_WORD_0);
55492187119SAndrew Rybchenko 		temp[3] = EFX_WORD_FIELD(verp->version_z, EFX_WORD_0);
555e948693eSPhilip Paeps 		if (memcmp(version, temp, sizeof (temp)) < 0)
556e948693eSPhilip Paeps 			memcpy(version, temp, sizeof (temp));
557e948693eSPhilip Paeps 
558e948693eSPhilip Paeps done:
559e948693eSPhilip Paeps 		EFSYS_KMEM_FREE(enp->en_esip, length, dcfg);
560e948693eSPhilip Paeps 	}
561e948693eSPhilip Paeps 
562e948693eSPhilip Paeps 	return (0);
563e948693eSPhilip Paeps 
564e948693eSPhilip Paeps fail3:
565e948693eSPhilip Paeps 	EFSYS_PROBE(fail3);
566e948693eSPhilip Paeps fail2:
567e948693eSPhilip Paeps 	EFSYS_PROBE(fail2);
568e948693eSPhilip Paeps fail1:
569460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
570e948693eSPhilip Paeps 
571e948693eSPhilip Paeps 	return (rc);
572e948693eSPhilip Paeps }
573e948693eSPhilip Paeps 
574460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
siena_nvram_partn_rw_start(__in efx_nic_t * enp,__in uint32_t partn,__out size_t * chunk_sizep)5755d846e87SAndrew Rybchenko siena_nvram_partn_rw_start(
576e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
5775d846e87SAndrew Rybchenko 	__in			uint32_t partn,
578e948693eSPhilip Paeps 	__out			size_t *chunk_sizep)
579e948693eSPhilip Paeps {
580460cb568SAndrew Rybchenko 	efx_rc_t rc;
581e948693eSPhilip Paeps 
582bce88e31SAndrew Rybchenko 	if ((rc = siena_nvram_partn_lock(enp, partn)) != 0)
5835d846e87SAndrew Rybchenko 		goto fail1;
584e948693eSPhilip Paeps 
585e948693eSPhilip Paeps 	if (chunk_sizep != NULL)
586e948693eSPhilip Paeps 		*chunk_sizep = SIENA_NVRAM_CHUNK;
587e948693eSPhilip Paeps 
588e948693eSPhilip Paeps 	return (0);
589e948693eSPhilip Paeps 
590e948693eSPhilip Paeps fail1:
591460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
592e948693eSPhilip Paeps 
593e948693eSPhilip Paeps 	return (rc);
594e948693eSPhilip Paeps }
595e948693eSPhilip Paeps 
596e9c123a5SAndrew Rybchenko 	__checkReturn		efx_rc_t
siena_nvram_partn_rw_finish(__in efx_nic_t * enp,__in uint32_t partn,__out_opt uint32_t * verify_resultp)597eb9703daSAndrew Rybchenko siena_nvram_partn_rw_finish(
598e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
599a21b2f20SAndrew Rybchenko 	__in			uint32_t partn,
600a21b2f20SAndrew Rybchenko 	__out_opt		uint32_t *verify_resultp)
601e948693eSPhilip Paeps {
602e9c123a5SAndrew Rybchenko 	efx_rc_t rc;
603e9c123a5SAndrew Rybchenko 
604a21b2f20SAndrew Rybchenko 	if ((rc = siena_nvram_partn_unlock(enp, partn, verify_resultp)) != 0)
605e9c123a5SAndrew Rybchenko 		goto fail1;
606e9c123a5SAndrew Rybchenko 
607e9c123a5SAndrew Rybchenko 	return (0);
608e9c123a5SAndrew Rybchenko 
609e9c123a5SAndrew Rybchenko fail1:
610e9c123a5SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
611e9c123a5SAndrew Rybchenko 
612e9c123a5SAndrew Rybchenko 	return (rc);
613e948693eSPhilip Paeps }
614e948693eSPhilip Paeps 
615460cb568SAndrew Rybchenko 	__checkReturn		efx_rc_t
6166d0b856cSAndrew Rybchenko siena_nvram_partn_set_version(
617e948693eSPhilip Paeps 	__in			efx_nic_t *enp,
6186d0b856cSAndrew Rybchenko 	__in			uint32_t partn,
6193c838a9fSAndrew Rybchenko 	__in_ecount(4)		uint16_t version[4])
620e948693eSPhilip Paeps {
621bce88e31SAndrew Rybchenko 	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
622e948693eSPhilip Paeps 	siena_mc_dynamic_config_hdr_t *dcfg = NULL;
623bce88e31SAndrew Rybchenko 	siena_mc_fw_version_t *fwverp;
6246d0b856cSAndrew Rybchenko 	uint32_t dcfg_partn;
625bce88e31SAndrew Rybchenko 	size_t dcfg_size;
626e948693eSPhilip Paeps 	unsigned int hdr_length;
627e948693eSPhilip Paeps 	unsigned int vpd_length;
628e948693eSPhilip Paeps 	unsigned int vpd_offset;
629e948693eSPhilip Paeps 	unsigned int nitems;
630e948693eSPhilip Paeps 	unsigned int required_hdr_length;
631e948693eSPhilip Paeps 	unsigned int pos;
632e948693eSPhilip Paeps 	uint8_t cksum;
633e948693eSPhilip Paeps 	uint32_t subtype;
634e948693eSPhilip Paeps 	size_t length;
635460cb568SAndrew Rybchenko 	efx_rc_t rc;
636e948693eSPhilip Paeps 
637bce88e31SAndrew Rybchenko 	dcfg_partn = (emip->emi_port == 1)
638e948693eSPhilip Paeps 		? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
639e948693eSPhilip Paeps 		: MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
640e948693eSPhilip Paeps 
641bce88e31SAndrew Rybchenko 	if ((rc = siena_nvram_partn_size(enp, dcfg_partn, &dcfg_size)) != 0)
6426d0b856cSAndrew Rybchenko 		goto fail1;
643e948693eSPhilip Paeps 
644e948693eSPhilip Paeps 	if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0)
645e948693eSPhilip Paeps 		goto fail2;
646e948693eSPhilip Paeps 
647e948693eSPhilip Paeps 	if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
648e948693eSPhilip Paeps 	    B_TRUE, &dcfg, &length)) != 0)
649e948693eSPhilip Paeps 		goto fail3;
650e948693eSPhilip Paeps 
651e948693eSPhilip Paeps 	hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0);
652e948693eSPhilip Paeps 	nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items, EFX_DWORD_0);
653e948693eSPhilip Paeps 	vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0);
654e948693eSPhilip Paeps 	vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0);
655e948693eSPhilip Paeps 
656e948693eSPhilip Paeps 	/*
657e948693eSPhilip Paeps 	 * NOTE: This function will blatt any fields trailing the version
658e948693eSPhilip Paeps 	 * vector, or the VPD chunk.
659e948693eSPhilip Paeps 	 */
660bce88e31SAndrew Rybchenko 	required_hdr_length = SIENA_DYNAMIC_CFG_SIZE(partn + 1);
661e948693eSPhilip Paeps 	if (required_hdr_length + vpd_length > length) {
662e948693eSPhilip Paeps 		rc = ENOSPC;
663e948693eSPhilip Paeps 		goto fail4;
664e948693eSPhilip Paeps 	}
665e948693eSPhilip Paeps 
666e948693eSPhilip Paeps 	if (vpd_offset < required_hdr_length) {
667e948693eSPhilip Paeps 		(void) memmove((caddr_t)dcfg + required_hdr_length,
668e948693eSPhilip Paeps 			(caddr_t)dcfg + vpd_offset, vpd_length);
669e948693eSPhilip Paeps 		vpd_offset = required_hdr_length;
670e948693eSPhilip Paeps 		EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset,
671e948693eSPhilip Paeps 				    EFX_DWORD_0, vpd_offset);
672e948693eSPhilip Paeps 	}
673e948693eSPhilip Paeps 
674e948693eSPhilip Paeps 	if (hdr_length < required_hdr_length) {
675e948693eSPhilip Paeps 		(void) memset((caddr_t)dcfg + hdr_length, 0,
676e948693eSPhilip Paeps 			required_hdr_length - hdr_length);
677e948693eSPhilip Paeps 		hdr_length = required_hdr_length;
678e948693eSPhilip Paeps 		EFX_POPULATE_WORD_1(dcfg->length,
679e948693eSPhilip Paeps 				    EFX_WORD_0, hdr_length);
680e948693eSPhilip Paeps 	}
681e948693eSPhilip Paeps 
682e948693eSPhilip Paeps 	/* Get the subtype to insert into the fw_subtype array */
683bce88e31SAndrew Rybchenko 	if ((rc = siena_nvram_get_subtype(enp, partn, &subtype)) != 0)
684e948693eSPhilip Paeps 		goto fail5;
685e948693eSPhilip Paeps 
686e948693eSPhilip Paeps 	/* Fill out the new version */
687bce88e31SAndrew Rybchenko 	fwverp = &dcfg->fw_version[partn];
688bce88e31SAndrew Rybchenko 	EFX_POPULATE_DWORD_1(fwverp->fw_subtype, EFX_DWORD_0, subtype);
689bce88e31SAndrew Rybchenko 	EFX_POPULATE_WORD_1(fwverp->version_w, EFX_WORD_0, version[0]);
690bce88e31SAndrew Rybchenko 	EFX_POPULATE_WORD_1(fwverp->version_x, EFX_WORD_0, version[1]);
691bce88e31SAndrew Rybchenko 	EFX_POPULATE_WORD_1(fwverp->version_y, EFX_WORD_0, version[2]);
692bce88e31SAndrew Rybchenko 	EFX_POPULATE_WORD_1(fwverp->version_z, EFX_WORD_0, version[3]);
693e948693eSPhilip Paeps 
694e948693eSPhilip Paeps 	/* Update the version count */
695bce88e31SAndrew Rybchenko 	if (nitems < partn + 1) {
696bce88e31SAndrew Rybchenko 		nitems = partn + 1;
697e948693eSPhilip Paeps 		EFX_POPULATE_DWORD_1(dcfg->num_fw_version_items,
698e948693eSPhilip Paeps 				    EFX_DWORD_0, nitems);
699e948693eSPhilip Paeps 	}
700e948693eSPhilip Paeps 
701e948693eSPhilip Paeps 	/* Update the checksum */
702e948693eSPhilip Paeps 	cksum = 0;
703e948693eSPhilip Paeps 	for (pos = 0; pos < hdr_length; pos++)
704e948693eSPhilip Paeps 		cksum += ((uint8_t *)dcfg)[pos];
705e948693eSPhilip Paeps 	dcfg->csum.eb_u8[0] -= cksum;
706e948693eSPhilip Paeps 
707e948693eSPhilip Paeps 	/* Erase and write the new partition */
708bce88e31SAndrew Rybchenko 	if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, dcfg_size)) != 0)
709e948693eSPhilip Paeps 		goto fail6;
710e948693eSPhilip Paeps 
711e948693eSPhilip Paeps 	/* Write out the new structure to nvram */
712e948693eSPhilip Paeps 	if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0,
713e948693eSPhilip Paeps 	    (caddr_t)dcfg, vpd_offset + vpd_length)) != 0)
714e948693eSPhilip Paeps 		goto fail7;
715e948693eSPhilip Paeps 
716e948693eSPhilip Paeps 	EFSYS_KMEM_FREE(enp->en_esip, length, dcfg);
717e948693eSPhilip Paeps 
718a21b2f20SAndrew Rybchenko 	siena_nvram_partn_unlock(enp, dcfg_partn, NULL);
719e948693eSPhilip Paeps 
720e948693eSPhilip Paeps 	return (0);
721e948693eSPhilip Paeps 
722e948693eSPhilip Paeps fail7:
723e948693eSPhilip Paeps 	EFSYS_PROBE(fail7);
724e948693eSPhilip Paeps fail6:
725e948693eSPhilip Paeps 	EFSYS_PROBE(fail6);
726e948693eSPhilip Paeps fail5:
727e948693eSPhilip Paeps 	EFSYS_PROBE(fail5);
728e948693eSPhilip Paeps fail4:
729e948693eSPhilip Paeps 	EFSYS_PROBE(fail4);
730e948693eSPhilip Paeps 
731e948693eSPhilip Paeps 	EFSYS_KMEM_FREE(enp->en_esip, length, dcfg);
732e948693eSPhilip Paeps fail3:
733e948693eSPhilip Paeps 	EFSYS_PROBE(fail3);
734e948693eSPhilip Paeps fail2:
735e948693eSPhilip Paeps 	EFSYS_PROBE(fail2);
736e948693eSPhilip Paeps fail1:
737460cb568SAndrew Rybchenko 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
738e948693eSPhilip Paeps 
739e948693eSPhilip Paeps 	return (rc);
740e948693eSPhilip Paeps }
741e948693eSPhilip Paeps 
742e948693eSPhilip Paeps #endif	/* EFSYS_OPT_NVRAM */
743e948693eSPhilip Paeps 
744e948693eSPhilip Paeps #endif	/* EFSYS_OPT_SIENA */
745