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