xref: /freebsd/sys/dev/sfxge/common/siena_nvram.c (revision fc7284da06408923f7850a0e4e954a903b8ee038)
1 /*-
2  * Copyright (c) 2009-2015 Solarflare Communications Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * The views and conclusions contained in the software and documentation are
27  * those of the authors and should not be interpreted as representing official
28  * policies, either expressed or implied, of the FreeBSD Project.
29  */
30 
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33 
34 #include "efsys.h"
35 #include "efx.h"
36 #include "efx_types.h"
37 #include "efx_regs.h"
38 #include "efx_impl.h"
39 
40 #if EFSYS_OPT_SIENA
41 
42 #if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
43 
44 	__checkReturn		efx_rc_t
45 siena_nvram_partn_size(
46 	__in			efx_nic_t *enp,
47 	__in			unsigned int partn,
48 	__out			size_t *sizep)
49 {
50 	efx_rc_t rc;
51 
52 	if ((1 << partn) & ~enp->en_u.siena.enu_partn_mask) {
53 		rc = ENOTSUP;
54 		goto fail1;
55 	}
56 
57 	if ((rc = efx_mcdi_nvram_info(enp, partn, sizep,
58 	    NULL, NULL, NULL)) != 0) {
59 		goto fail2;
60 	}
61 
62 	return (0);
63 
64 fail2:
65 	EFSYS_PROBE(fail2);
66 fail1:
67 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
68 
69 	return (rc);
70 }
71 
72 	__checkReturn		efx_rc_t
73 siena_nvram_partn_lock(
74 	__in			efx_nic_t *enp,
75 	__in			unsigned int partn)
76 {
77 	efx_rc_t rc;
78 
79 	if ((rc = efx_mcdi_nvram_update_start(enp, partn)) != 0) {
80 		goto fail1;
81 	}
82 
83 	return (0);
84 
85 fail1:
86 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
87 
88 	return (rc);
89 }
90 
91 	__checkReturn		efx_rc_t
92 siena_nvram_partn_read(
93 	__in			efx_nic_t *enp,
94 	__in			unsigned int partn,
95 	__in			unsigned int offset,
96 	__out_bcount(size)	caddr_t data,
97 	__in			size_t size)
98 {
99 	size_t chunk;
100 	efx_rc_t rc;
101 
102 	while (size > 0) {
103 		chunk = MIN(size, SIENA_NVRAM_CHUNK);
104 
105 		if ((rc = efx_mcdi_nvram_read(enp, partn, offset,
106 			    data, chunk)) != 0) {
107 			goto fail1;
108 		}
109 
110 		size -= chunk;
111 		data += chunk;
112 		offset += chunk;
113 	}
114 
115 	return (0);
116 
117 fail1:
118 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
119 
120 	return (rc);
121 }
122 
123 	__checkReturn		efx_rc_t
124 siena_nvram_partn_erase(
125 	__in			efx_nic_t *enp,
126 	__in			unsigned int partn,
127 	__in			unsigned int offset,
128 	__in			size_t size)
129 {
130 	efx_rc_t rc;
131 
132 	if ((rc = efx_mcdi_nvram_erase(enp, partn, offset, size)) != 0) {
133 		goto fail1;
134 	}
135 
136 	return (0);
137 
138 fail1:
139 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
140 
141 	return (rc);
142 }
143 
144 	__checkReturn		efx_rc_t
145 siena_nvram_partn_write(
146 	__in			efx_nic_t *enp,
147 	__in			unsigned int partn,
148 	__in			unsigned int offset,
149 	__out_bcount(size)	caddr_t data,
150 	__in			size_t size)
151 {
152 	size_t chunk;
153 	efx_rc_t rc;
154 
155 	while (size > 0) {
156 		chunk = MIN(size, SIENA_NVRAM_CHUNK);
157 
158 		if ((rc = efx_mcdi_nvram_write(enp, partn, offset,
159 			    data, chunk)) != 0) {
160 			goto fail1;
161 		}
162 
163 		size -= chunk;
164 		data += chunk;
165 		offset += chunk;
166 	}
167 
168 	return (0);
169 
170 fail1:
171 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
172 
173 	return (rc);
174 }
175 
176 				void
177 siena_nvram_partn_unlock(
178 	__in			efx_nic_t *enp,
179 	__in			unsigned int partn)
180 {
181 	boolean_t reboot;
182 	efx_rc_t rc;
183 
184 	/*
185 	 * Reboot into the new image only for PHYs. The driver has to
186 	 * explicitly cope with an MC reboot after a firmware update.
187 	 */
188 	reboot = (partn == MC_CMD_NVRAM_TYPE_PHY_PORT0 ||
189 		    partn == MC_CMD_NVRAM_TYPE_PHY_PORT1 ||
190 		    partn == MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO);
191 
192 	if ((rc = efx_mcdi_nvram_update_finish(enp, partn, reboot)) != 0) {
193 		goto fail1;
194 	}
195 
196 	return;
197 
198 fail1:
199 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
200 }
201 
202 #endif	/* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */
203 
204 #if EFSYS_OPT_NVRAM
205 
206 typedef struct siena_parttbl_entry_s {
207 	unsigned int		partn;
208 	unsigned int		port;
209 	efx_nvram_type_t	nvtype;
210 } siena_parttbl_entry_t;
211 
212 static siena_parttbl_entry_t siena_parttbl[] = {
213 	{MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO,	1, EFX_NVRAM_NULLPHY},
214 	{MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO,	2, EFX_NVRAM_NULLPHY},
215 	{MC_CMD_NVRAM_TYPE_MC_FW,		1, EFX_NVRAM_MC_FIRMWARE},
216 	{MC_CMD_NVRAM_TYPE_MC_FW,		2, EFX_NVRAM_MC_FIRMWARE},
217 	{MC_CMD_NVRAM_TYPE_MC_FW_BACKUP,	1, EFX_NVRAM_MC_GOLDEN},
218 	{MC_CMD_NVRAM_TYPE_MC_FW_BACKUP,	2, EFX_NVRAM_MC_GOLDEN},
219 	{MC_CMD_NVRAM_TYPE_EXP_ROM,		1, EFX_NVRAM_BOOTROM},
220 	{MC_CMD_NVRAM_TYPE_EXP_ROM,		2, EFX_NVRAM_BOOTROM},
221 	{MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT0,	1, EFX_NVRAM_BOOTROM_CFG},
222 	{MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT1,	2, EFX_NVRAM_BOOTROM_CFG},
223 	{MC_CMD_NVRAM_TYPE_PHY_PORT0,		1, EFX_NVRAM_PHY},
224 	{MC_CMD_NVRAM_TYPE_PHY_PORT1,		2, EFX_NVRAM_PHY},
225 	{MC_CMD_NVRAM_TYPE_FPGA,		1, EFX_NVRAM_FPGA},
226 	{MC_CMD_NVRAM_TYPE_FPGA,		2, EFX_NVRAM_FPGA},
227 	{MC_CMD_NVRAM_TYPE_FPGA_BACKUP,		1, EFX_NVRAM_FPGA_BACKUP},
228 	{MC_CMD_NVRAM_TYPE_FPGA_BACKUP,		2, EFX_NVRAM_FPGA_BACKUP},
229 	{MC_CMD_NVRAM_TYPE_FC_FW,		1, EFX_NVRAM_FCFW},
230 	{MC_CMD_NVRAM_TYPE_FC_FW,		2, EFX_NVRAM_FCFW},
231 	{MC_CMD_NVRAM_TYPE_CPLD,		1, EFX_NVRAM_CPLD},
232 	{MC_CMD_NVRAM_TYPE_CPLD,		2, EFX_NVRAM_CPLD},
233 };
234 
235 static	__checkReturn		siena_parttbl_entry_t *
236 siena_parttbl_entry(
237 	__in			efx_nic_t *enp,
238 	__in			efx_nvram_type_t type)
239 {
240 	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
241 	siena_parttbl_entry_t *entry;
242 	unsigned int i;
243 
244 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
245 
246 	for (i = 0; i < EFX_ARRAY_SIZE(siena_parttbl); i++) {
247 		entry = &siena_parttbl[i];
248 
249 		if (entry->port == emip->emi_port && entry->nvtype == type)
250 			return (entry);
251 	}
252 
253 	return (NULL);
254 }
255 
256 #if EFSYS_OPT_DIAG
257 
258 	__checkReturn		efx_rc_t
259 siena_nvram_test(
260 	__in			efx_nic_t *enp)
261 {
262 	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
263 	siena_parttbl_entry_t *entry;
264 	unsigned int i;
265 	efx_rc_t rc;
266 
267 	/*
268 	 * Iterate over the list of supported partition types
269 	 * applicable to *this* port
270 	 */
271 	for (i = 0; i < EFX_ARRAY_SIZE(siena_parttbl); i++) {
272 		entry = &siena_parttbl[i];
273 
274 		if (entry->port != emip->emi_port ||
275 		    !(enp->en_u.siena.enu_partn_mask & (1 << entry->partn)))
276 			continue;
277 
278 		if ((rc = efx_mcdi_nvram_test(enp, entry->partn)) != 0) {
279 			goto fail1;
280 		}
281 	}
282 
283 	return (0);
284 
285 fail1:
286 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
287 
288 	return (rc);
289 }
290 
291 #endif	/* EFSYS_OPT_DIAG */
292 
293 	__checkReturn		efx_rc_t
294 siena_nvram_size(
295 	__in			efx_nic_t *enp,
296 	__in			efx_nvram_type_t type,
297 	__out			size_t *sizep)
298 {
299 	siena_parttbl_entry_t *entry;
300 	efx_rc_t rc;
301 
302 	if ((entry = siena_parttbl_entry(enp, type)) == NULL) {
303 		rc = ENOTSUP;
304 		goto fail1;
305 	}
306 
307 	if ((rc = siena_nvram_partn_size(enp, entry->partn, sizep)) != 0)
308 		goto fail2;
309 
310 	return (0);
311 
312 fail2:
313 	EFSYS_PROBE(fail2);
314 fail1:
315 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
316 
317 	*sizep = 0;
318 
319 	return (rc);
320 }
321 
322 #define	SIENA_DYNAMIC_CFG_SIZE(_nitems)					\
323 	(sizeof (siena_mc_dynamic_config_hdr_t) + ((_nitems) *		\
324 	sizeof (((siena_mc_dynamic_config_hdr_t *)NULL)->fw_version[0])))
325 
326 	__checkReturn		efx_rc_t
327 siena_nvram_get_dynamic_cfg(
328 	__in			efx_nic_t *enp,
329 	__in			unsigned int partn,
330 	__in			boolean_t vpd,
331 	__out			siena_mc_dynamic_config_hdr_t **dcfgp,
332 	__out			size_t *sizep)
333 {
334 	siena_mc_dynamic_config_hdr_t *dcfg = NULL;
335 	size_t size;
336 	uint8_t cksum;
337 	unsigned int vpd_offset;
338 	unsigned int vpd_length;
339 	unsigned int hdr_length;
340 	unsigned int nversions;
341 	unsigned int pos;
342 	unsigned int region;
343 	efx_rc_t rc;
344 
345 	EFSYS_ASSERT(partn == MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 ||
346 		    partn == MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1);
347 
348 	/*
349 	 * Allocate sufficient memory for the entire dynamiccfg area, even
350 	 * if we're not actually going to read in the VPD.
351 	 */
352 	if ((rc = siena_nvram_partn_size(enp, partn, &size)) != 0)
353 		goto fail1;
354 
355 	EFSYS_KMEM_ALLOC(enp->en_esip, size, dcfg);
356 	if (dcfg == NULL) {
357 		rc = ENOMEM;
358 		goto fail2;
359 	}
360 
361 	if ((rc = siena_nvram_partn_read(enp, partn, 0,
362 	    (caddr_t)dcfg, SIENA_NVRAM_CHUNK)) != 0)
363 		goto fail3;
364 
365 	/* Verify the magic */
366 	if (EFX_DWORD_FIELD(dcfg->magic, EFX_DWORD_0)
367 	    != SIENA_MC_DYNAMIC_CONFIG_MAGIC)
368 		goto invalid1;
369 
370 	/* All future versions of the structure must be backwards compatable */
371 	EFX_STATIC_ASSERT(SIENA_MC_DYNAMIC_CONFIG_VERSION == 0);
372 
373 	hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0);
374 	nversions = EFX_DWORD_FIELD(dcfg->num_fw_version_items, EFX_DWORD_0);
375 	vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0);
376 	vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0);
377 
378 	/* Verify the hdr doesn't overflow the partn size */
379 	if (hdr_length > size || vpd_offset > size || vpd_length > size ||
380 	    vpd_length + vpd_offset > size)
381 		goto invalid2;
382 
383 	/* Verify the header has room for all it's versions */
384 	if (hdr_length < SIENA_DYNAMIC_CFG_SIZE(0) ||
385 	    hdr_length < SIENA_DYNAMIC_CFG_SIZE(nversions))
386 		goto invalid3;
387 
388 	/*
389 	 * Read the remaining portion of the dcfg, either including
390 	 * the whole of VPD (there is no vpd length in this structure,
391 	 * so we have to parse each tag), or just the dcfg header itself
392 	 */
393 	region = vpd ? vpd_offset + vpd_length : hdr_length;
394 	if (region > SIENA_NVRAM_CHUNK) {
395 		if ((rc = siena_nvram_partn_read(enp, partn, SIENA_NVRAM_CHUNK,
396 		    (caddr_t)dcfg + SIENA_NVRAM_CHUNK,
397 		    region - SIENA_NVRAM_CHUNK)) != 0)
398 			goto fail4;
399 	}
400 
401 	/* Verify checksum */
402 	cksum = 0;
403 	for (pos = 0; pos < hdr_length; pos++)
404 		cksum += ((uint8_t *)dcfg)[pos];
405 	if (cksum != 0)
406 		goto invalid4;
407 
408 	goto done;
409 
410 invalid4:
411 	EFSYS_PROBE(invalid4);
412 invalid3:
413 	EFSYS_PROBE(invalid3);
414 invalid2:
415 	EFSYS_PROBE(invalid2);
416 invalid1:
417 	EFSYS_PROBE(invalid1);
418 
419 	/*
420 	 * Construct a new "null" dcfg, with an empty version vector,
421 	 * and an empty VPD chunk trailing. This has the neat side effect
422 	 * of testing the exception paths in the write path.
423 	 */
424 	EFX_POPULATE_DWORD_1(dcfg->magic,
425 			    EFX_DWORD_0, SIENA_MC_DYNAMIC_CONFIG_MAGIC);
426 	EFX_POPULATE_WORD_1(dcfg->length, EFX_WORD_0, sizeof (*dcfg));
427 	EFX_POPULATE_BYTE_1(dcfg->version, EFX_BYTE_0,
428 			    SIENA_MC_DYNAMIC_CONFIG_VERSION);
429 	EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset,
430 			    EFX_DWORD_0, sizeof (*dcfg));
431 	EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_length, EFX_DWORD_0, 0);
432 	EFX_POPULATE_DWORD_1(dcfg->num_fw_version_items, EFX_DWORD_0, 0);
433 
434 done:
435 	*dcfgp = dcfg;
436 	*sizep = size;
437 
438 	return (0);
439 
440 fail4:
441 	EFSYS_PROBE(fail4);
442 fail3:
443 	EFSYS_PROBE(fail3);
444 
445 	EFSYS_KMEM_FREE(enp->en_esip, size, dcfg);
446 
447 fail2:
448 	EFSYS_PROBE(fail2);
449 fail1:
450 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
451 
452 	return (rc);
453 }
454 
455 	__checkReturn		efx_rc_t
456 siena_nvram_get_subtype(
457 	__in			efx_nic_t *enp,
458 	__in			unsigned int partn,
459 	__out			uint32_t *subtypep)
460 {
461 	efx_mcdi_req_t req;
462 	uint8_t payload[MAX(MC_CMD_GET_BOARD_CFG_IN_LEN,
463 			    MC_CMD_GET_BOARD_CFG_OUT_LENMAX)];
464 	efx_word_t *fw_list;
465 	efx_rc_t rc;
466 
467 	(void) memset(payload, 0, sizeof (payload));
468 	req.emr_cmd = MC_CMD_GET_BOARD_CFG;
469 	req.emr_in_buf = payload;
470 	req.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN;
471 	req.emr_out_buf = payload;
472 	req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMAX;
473 
474 	efx_mcdi_execute(enp, &req);
475 
476 	if (req.emr_rc != 0) {
477 		rc = req.emr_rc;
478 		goto fail1;
479 	}
480 
481 	if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) {
482 		rc = EMSGSIZE;
483 		goto fail2;
484 	}
485 
486 	if (req.emr_out_length_used <
487 	    MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_OFST +
488 	    (partn + 1) * sizeof (efx_word_t)) {
489 		rc = ENOENT;
490 		goto fail3;
491 	}
492 
493 	fw_list = MCDI_OUT2(req, efx_word_t,
494 			    GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST);
495 	*subtypep = EFX_WORD_FIELD(fw_list[partn], EFX_WORD_0);
496 
497 	return (0);
498 
499 fail3:
500 	EFSYS_PROBE(fail3);
501 fail2:
502 	EFSYS_PROBE(fail2);
503 fail1:
504 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
505 
506 	return (rc);
507 }
508 
509 	__checkReturn		efx_rc_t
510 siena_nvram_get_version(
511 	__in			efx_nic_t *enp,
512 	__in			efx_nvram_type_t type,
513 	__out			uint32_t *subtypep,
514 	__out_ecount(4)		uint16_t version[4])
515 {
516 	siena_mc_dynamic_config_hdr_t *dcfg;
517 	siena_parttbl_entry_t *entry;
518 	unsigned int dcfg_partn;
519 	unsigned int partn;
520 	unsigned int i;
521 	efx_rc_t rc;
522 
523 	if ((entry = siena_parttbl_entry(enp, type)) == NULL) {
524 		rc = ENOTSUP;
525 		goto fail1;
526 	}
527 	partn = entry->partn;
528 
529 	if ((1 << partn) & ~enp->en_u.siena.enu_partn_mask) {
530 		rc = ENOTSUP;
531 		goto fail2;
532 	}
533 
534 	if ((rc = siena_nvram_get_subtype(enp, partn, subtypep)) != 0)
535 		goto fail3;
536 
537 	/*
538 	 * Some partitions are accessible from both ports (for instance BOOTROM)
539 	 * Find the highest version reported by all dcfg structures on ports
540 	 * that have access to this partition.
541 	 */
542 	version[0] = version[1] = version[2] = version[3] = 0;
543 	for (i = 0; i < EFX_ARRAY_SIZE(siena_parttbl); i++) {
544 		unsigned int nitems;
545 		uint16_t temp[4];
546 		size_t length;
547 
548 		entry = &siena_parttbl[i];
549 		if (entry->partn != partn)
550 			continue;
551 
552 		dcfg_partn = (entry->port == 1)
553 			? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
554 			: MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
555 		/*
556 		 * Ingore missing partitions on port 2, assuming they're due
557 		 * to to running on a single port part.
558 		 */
559 		if ((1 << dcfg_partn) &  ~enp->en_u.siena.enu_partn_mask) {
560 			if (entry->port == 2)
561 				continue;
562 		}
563 
564 		if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
565 		    B_FALSE, &dcfg, &length)) != 0)
566 			goto fail4;
567 
568 		nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items,
569 			    EFX_DWORD_0);
570 		if (nitems < entry->partn)
571 			goto done;
572 
573 		temp[0] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_w,
574 			    EFX_WORD_0);
575 		temp[1] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_x,
576 			    EFX_WORD_0);
577 		temp[2] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_y,
578 			    EFX_WORD_0);
579 		temp[3] = EFX_WORD_FIELD(dcfg->fw_version[partn].version_z,
580 			    EFX_WORD_0);
581 		if (memcmp(version, temp, sizeof (temp)) < 0)
582 			memcpy(version, temp, sizeof (temp));
583 
584 	done:
585 		EFSYS_KMEM_FREE(enp->en_esip, length, dcfg);
586 	}
587 
588 	return (0);
589 
590 fail4:
591 	EFSYS_PROBE(fail4);
592 fail3:
593 	EFSYS_PROBE(fail3);
594 fail2:
595 	EFSYS_PROBE(fail2);
596 fail1:
597 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
598 
599 	return (rc);
600 }
601 
602 	__checkReturn		efx_rc_t
603 siena_nvram_rw_start(
604 	__in			efx_nic_t *enp,
605 	__in			efx_nvram_type_t type,
606 	__out			size_t *chunk_sizep)
607 {
608 	siena_parttbl_entry_t *entry;
609 	efx_rc_t rc;
610 
611 	if ((entry = siena_parttbl_entry(enp, type)) == NULL) {
612 		rc = ENOTSUP;
613 		goto fail1;
614 	}
615 
616 	if ((rc = siena_nvram_partn_lock(enp, entry->partn)) != 0)
617 		goto fail2;
618 
619 	if (chunk_sizep != NULL)
620 		*chunk_sizep = SIENA_NVRAM_CHUNK;
621 
622 	return (0);
623 
624 fail2:
625 	EFSYS_PROBE(fail2);
626 fail1:
627 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
628 
629 	return (rc);
630 }
631 
632 	__checkReturn		efx_rc_t
633 siena_nvram_read_chunk(
634 	__in			efx_nic_t *enp,
635 	__in			efx_nvram_type_t type,
636 	__in			unsigned int offset,
637 	__out_bcount(size)	caddr_t data,
638 	__in			size_t size)
639 {
640 	siena_parttbl_entry_t *entry;
641 	efx_rc_t rc;
642 
643 	if ((entry = siena_parttbl_entry(enp, type)) == NULL) {
644 		rc = ENOTSUP;
645 		goto fail1;
646 	}
647 
648 	if ((rc = siena_nvram_partn_read(enp, entry->partn,
649 	    offset, data, size)) != 0)
650 		goto fail2;
651 
652 	return (0);
653 
654 fail2:
655 	EFSYS_PROBE(fail2);
656 fail1:
657 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
658 
659 	return (rc);
660 }
661 
662 	__checkReturn		efx_rc_t
663 siena_nvram_erase(
664 	__in			efx_nic_t *enp,
665 	__in			efx_nvram_type_t type)
666 {
667 	siena_parttbl_entry_t *entry;
668 	size_t size;
669 	efx_rc_t rc;
670 
671 	if ((entry = siena_parttbl_entry(enp, type)) == NULL) {
672 		rc = ENOTSUP;
673 		goto fail1;
674 	}
675 
676 	if ((rc = siena_nvram_partn_size(enp, entry->partn, &size)) != 0)
677 		goto fail2;
678 
679 	if ((rc = siena_nvram_partn_erase(enp, entry->partn, 0, size)) != 0)
680 		goto fail3;
681 
682 	return (0);
683 
684 fail3:
685 	EFSYS_PROBE(fail3);
686 fail2:
687 	EFSYS_PROBE(fail2);
688 fail1:
689 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
690 
691 	return (rc);
692 }
693 
694 	__checkReturn		efx_rc_t
695 siena_nvram_write_chunk(
696 	__in			efx_nic_t *enp,
697 	__in			efx_nvram_type_t type,
698 	__in			unsigned int offset,
699 	__in_bcount(size)	caddr_t data,
700 	__in			size_t size)
701 {
702 	siena_parttbl_entry_t *entry;
703 	efx_rc_t rc;
704 
705 	if ((entry = siena_parttbl_entry(enp, type)) == NULL) {
706 		rc = ENOTSUP;
707 		goto fail1;
708 	}
709 
710 	if ((rc = siena_nvram_partn_write(enp, entry->partn,
711 	    offset, data, size)) != 0)
712 		goto fail2;
713 
714 	return (0);
715 
716 fail2:
717 	EFSYS_PROBE(fail2);
718 fail1:
719 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
720 
721 	return (rc);
722 }
723 
724 				void
725 siena_nvram_rw_finish(
726 	__in			efx_nic_t *enp,
727 	__in			efx_nvram_type_t type)
728 {
729 	siena_parttbl_entry_t *entry;
730 
731 	if ((entry = siena_parttbl_entry(enp, type)) != NULL)
732 		siena_nvram_partn_unlock(enp, entry->partn);
733 }
734 
735 	__checkReturn		efx_rc_t
736 siena_nvram_set_version(
737 	__in			efx_nic_t *enp,
738 	__in			efx_nvram_type_t type,
739 	__in_ecount(4)		uint16_t version[4])
740 {
741 	siena_mc_dynamic_config_hdr_t *dcfg = NULL;
742 	siena_parttbl_entry_t *entry;
743 	unsigned int dcfg_partn;
744 	size_t partn_size;
745 	unsigned int hdr_length;
746 	unsigned int vpd_length;
747 	unsigned int vpd_offset;
748 	unsigned int nitems;
749 	unsigned int required_hdr_length;
750 	unsigned int pos;
751 	uint8_t cksum;
752 	uint32_t subtype;
753 	size_t length;
754 	efx_rc_t rc;
755 
756 	if ((entry = siena_parttbl_entry(enp, type)) == NULL) {
757 		rc = ENOTSUP;
758 		goto fail1;
759 	}
760 
761 	dcfg_partn = (entry->port == 1)
762 		? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
763 		: MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
764 
765 	if ((rc = siena_nvram_partn_size(enp, dcfg_partn, &partn_size)) != 0)
766 		goto fail2;
767 
768 	if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0)
769 		goto fail2;
770 
771 	if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
772 	    B_TRUE, &dcfg, &length)) != 0)
773 		goto fail3;
774 
775 	hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0);
776 	nitems = EFX_DWORD_FIELD(dcfg->num_fw_version_items, EFX_DWORD_0);
777 	vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0);
778 	vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0);
779 
780 	/*
781 	 * NOTE: This function will blatt any fields trailing the version
782 	 * vector, or the VPD chunk.
783 	 */
784 	required_hdr_length = SIENA_DYNAMIC_CFG_SIZE(entry->partn + 1);
785 	if (required_hdr_length + vpd_length > length) {
786 		rc = ENOSPC;
787 		goto fail4;
788 	}
789 
790 	if (vpd_offset < required_hdr_length) {
791 		(void) memmove((caddr_t)dcfg + required_hdr_length,
792 			(caddr_t)dcfg + vpd_offset, vpd_length);
793 		vpd_offset = required_hdr_length;
794 		EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset,
795 				    EFX_DWORD_0, vpd_offset);
796 	}
797 
798 	if (hdr_length < required_hdr_length) {
799 		(void) memset((caddr_t)dcfg + hdr_length, 0,
800 			required_hdr_length - hdr_length);
801 		hdr_length = required_hdr_length;
802 		EFX_POPULATE_WORD_1(dcfg->length,
803 				    EFX_WORD_0, hdr_length);
804 	}
805 
806 	/* Get the subtype to insert into the fw_subtype array */
807 	if ((rc = siena_nvram_get_subtype(enp, entry->partn, &subtype)) != 0)
808 		goto fail5;
809 
810 	/* Fill out the new version */
811 	EFX_POPULATE_DWORD_1(dcfg->fw_version[entry->partn].fw_subtype,
812 			    EFX_DWORD_0, subtype);
813 	EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_w,
814 			    EFX_WORD_0, version[0]);
815 	EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_x,
816 			    EFX_WORD_0, version[1]);
817 	EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_y,
818 			    EFX_WORD_0, version[2]);
819 	EFX_POPULATE_WORD_1(dcfg->fw_version[entry->partn].version_z,
820 			    EFX_WORD_0, version[3]);
821 
822 	/* Update the version count */
823 	if (nitems < entry->partn + 1) {
824 		nitems = entry->partn + 1;
825 		EFX_POPULATE_DWORD_1(dcfg->num_fw_version_items,
826 				    EFX_DWORD_0, nitems);
827 	}
828 
829 	/* Update the checksum */
830 	cksum = 0;
831 	for (pos = 0; pos < hdr_length; pos++)
832 		cksum += ((uint8_t *)dcfg)[pos];
833 	dcfg->csum.eb_u8[0] -= cksum;
834 
835 	/* Erase and write the new partition */
836 	if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, partn_size)) != 0)
837 		goto fail6;
838 
839 	/* Write out the new structure to nvram */
840 	if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0,
841 	    (caddr_t)dcfg, vpd_offset + vpd_length)) != 0)
842 		goto fail7;
843 
844 	EFSYS_KMEM_FREE(enp->en_esip, length, dcfg);
845 
846 	siena_nvram_partn_unlock(enp, dcfg_partn);
847 
848 	return (0);
849 
850 fail7:
851 	EFSYS_PROBE(fail7);
852 fail6:
853 	EFSYS_PROBE(fail6);
854 fail5:
855 	EFSYS_PROBE(fail5);
856 fail4:
857 	EFSYS_PROBE(fail4);
858 
859 	EFSYS_KMEM_FREE(enp->en_esip, length, dcfg);
860 fail3:
861 	EFSYS_PROBE(fail3);
862 fail2:
863 	EFSYS_PROBE(fail2);
864 fail1:
865 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
866 
867 	return (rc);
868 }
869 
870 #endif	/* EFSYS_OPT_NVRAM */
871 
872 #endif	/* EFSYS_OPT_SIENA */
873