xref: /dpdk/drivers/common/sfc_efx/base/ef10_nvram.c (revision 672386c1e9e1f64f7aa3b1360ad22dc737ea8d72)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2019-2021 Xilinx, Inc.
4  * Copyright(c) 2012-2019 Solarflare Communications Inc.
5  */
6 
7 #include "efx.h"
8 #include "efx_impl.h"
9 
10 #if EFX_OPTS_EF10()
11 
12 #if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
13 
14 #include "ef10_tlv_layout.h"
15 
16 /* Cursor for TLV partition format */
17 typedef struct tlv_cursor_s {
18 	uint32_t	*block;			/* Base of data block */
19 	uint32_t	*current;		/* Cursor position */
20 	uint32_t	*end;			/* End tag position */
21 	uint32_t	*limit;			/* Last dword of data block */
22 } tlv_cursor_t;
23 
24 typedef struct nvram_partition_s {
25 	uint16_t type;
26 	uint8_t chip_select;
27 	uint8_t flags;
28 	/*
29 	 * The full length of the NVRAM partition.
30 	 * This is different from tlv_partition_header.total_length,
31 	 *  which can be smaller.
32 	 */
33 	uint32_t length;
34 	uint32_t erase_size;
35 	uint32_t *data;
36 	tlv_cursor_t tlv_cursor;
37 } nvram_partition_t;
38 
39 
40 static	__checkReturn		efx_rc_t
41 tlv_validate_state(
42 	__inout			tlv_cursor_t *cursor);
43 
44 
45 static				void
tlv_init_block(__out uint32_t * block)46 tlv_init_block(
47 	__out	uint32_t	*block)
48 {
49 	*block = __CPU_TO_LE_32(TLV_TAG_END);
50 }
51 
52 static				uint32_t
tlv_tag(__in tlv_cursor_t * cursor)53 tlv_tag(
54 	__in	tlv_cursor_t	*cursor)
55 {
56 	uint32_t dword, tag;
57 
58 	dword = cursor->current[0];
59 	tag = __LE_TO_CPU_32(dword);
60 
61 	return (tag);
62 }
63 
64 static				size_t
tlv_length(__in tlv_cursor_t * cursor)65 tlv_length(
66 	__in	tlv_cursor_t	*cursor)
67 {
68 	uint32_t dword, length;
69 
70 	if (tlv_tag(cursor) == TLV_TAG_END)
71 		return (0);
72 
73 	dword = cursor->current[1];
74 	length = __LE_TO_CPU_32(dword);
75 
76 	return ((size_t)length);
77 }
78 
79 static				uint8_t *
tlv_value(__in tlv_cursor_t * cursor)80 tlv_value(
81 	__in	tlv_cursor_t	*cursor)
82 {
83 	if (tlv_tag(cursor) == TLV_TAG_END)
84 		return (NULL);
85 
86 	return ((uint8_t *)(&cursor->current[2]));
87 }
88 
89 static				uint8_t *
tlv_item(__in tlv_cursor_t * cursor)90 tlv_item(
91 	__in	tlv_cursor_t	*cursor)
92 {
93 	if (tlv_tag(cursor) == TLV_TAG_END)
94 		return (NULL);
95 
96 	return ((uint8_t *)cursor->current);
97 }
98 
99 /*
100  * TLV item DWORD length is tag + length + value (rounded up to DWORD)
101  * equivalent to tlv_n_words_for_len in mc-comms tlv.c
102  */
103 #define	TLV_DWORD_COUNT(length) \
104 	(1 + 1 + (((length) + sizeof (uint32_t) - 1) / sizeof (uint32_t)))
105 
106 
107 static				uint32_t *
tlv_next_item_ptr(__in tlv_cursor_t * cursor)108 tlv_next_item_ptr(
109 	__in	tlv_cursor_t	*cursor)
110 {
111 	uint32_t length;
112 
113 	length = tlv_length(cursor);
114 
115 	return (cursor->current + TLV_DWORD_COUNT(length));
116 }
117 
118 static	__checkReturn		efx_rc_t
tlv_advance(__inout tlv_cursor_t * cursor)119 tlv_advance(
120 	__inout	tlv_cursor_t	*cursor)
121 {
122 	efx_rc_t rc;
123 
124 	if ((rc = tlv_validate_state(cursor)) != 0)
125 		goto fail1;
126 
127 	if (cursor->current == cursor->end) {
128 		/* No more tags after END tag */
129 		cursor->current = NULL;
130 		rc = ENOENT;
131 		goto fail2;
132 	}
133 
134 	/* Advance to next item and validate */
135 	cursor->current = tlv_next_item_ptr(cursor);
136 
137 	if ((rc = tlv_validate_state(cursor)) != 0)
138 		goto fail3;
139 
140 	return (0);
141 
142 fail3:
143 	EFSYS_PROBE(fail3);
144 fail2:
145 	EFSYS_PROBE(fail2);
146 fail1:
147 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
148 
149 	return (rc);
150 }
151 
152 static				efx_rc_t
tlv_rewind(__in tlv_cursor_t * cursor)153 tlv_rewind(
154 	__in	tlv_cursor_t	*cursor)
155 {
156 	efx_rc_t rc;
157 
158 	cursor->current = cursor->block;
159 
160 	if ((rc = tlv_validate_state(cursor)) != 0)
161 		goto fail1;
162 
163 	return (0);
164 
165 fail1:
166 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
167 
168 	return (rc);
169 }
170 
171 static				efx_rc_t
tlv_find(__inout tlv_cursor_t * cursor,__in uint32_t tag)172 tlv_find(
173 	__inout	tlv_cursor_t	*cursor,
174 	__in	uint32_t	tag)
175 {
176 	efx_rc_t rc;
177 
178 	rc = tlv_rewind(cursor);
179 	while (rc == 0) {
180 		if (tlv_tag(cursor) == tag)
181 			break;
182 
183 		rc = tlv_advance(cursor);
184 	}
185 	return (rc);
186 }
187 
188 static	__checkReturn		efx_rc_t
tlv_validate_state(__inout tlv_cursor_t * cursor)189 tlv_validate_state(
190 	__inout	tlv_cursor_t	*cursor)
191 {
192 	efx_rc_t rc;
193 
194 	/* Check cursor position */
195 	if (cursor->current < cursor->block) {
196 		rc = EINVAL;
197 		goto fail1;
198 	}
199 	if (cursor->current > cursor->limit) {
200 		rc = EINVAL;
201 		goto fail2;
202 	}
203 
204 	if (tlv_tag(cursor) != TLV_TAG_END) {
205 		/* Check current item has space for tag and length */
206 		if (cursor->current > (cursor->limit - 1)) {
207 			cursor->current = NULL;
208 			rc = EFAULT;
209 			goto fail3;
210 		}
211 
212 		/* Check we have value data for current item and an END tag */
213 		if (tlv_next_item_ptr(cursor) > cursor->limit) {
214 			cursor->current = NULL;
215 			rc = EFAULT;
216 			goto fail4;
217 		}
218 	}
219 
220 	return (0);
221 
222 fail4:
223 	EFSYS_PROBE(fail4);
224 fail3:
225 	EFSYS_PROBE(fail3);
226 fail2:
227 	EFSYS_PROBE(fail2);
228 fail1:
229 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
230 
231 	return (rc);
232 }
233 
234 static				efx_rc_t
tlv_init_cursor(__out tlv_cursor_t * cursor,__in uint32_t * block,__in uint32_t * limit,__in uint32_t * current)235 tlv_init_cursor(
236 	__out	tlv_cursor_t	*cursor,
237 	__in	uint32_t	*block,
238 	__in	uint32_t	*limit,
239 	__in	uint32_t	*current)
240 {
241 	cursor->block	= block;
242 	cursor->limit	= limit;
243 
244 	cursor->current	= current;
245 	cursor->end	= NULL;
246 
247 	return (tlv_validate_state(cursor));
248 }
249 
250 static	__checkReturn		efx_rc_t
tlv_init_cursor_from_size(__out tlv_cursor_t * cursor,__in_bcount (size)uint8_t * block,__in size_t size)251 tlv_init_cursor_from_size(
252 	__out	tlv_cursor_t	*cursor,
253 	__in_bcount(size)
254 		uint8_t		*block,
255 	__in	size_t		size)
256 {
257 	uint32_t *limit;
258 	limit = (uint32_t *)(block + size - sizeof (uint32_t));
259 	return (tlv_init_cursor(cursor, (uint32_t *)block,
260 		limit, (uint32_t *)block));
261 }
262 
263 static	__checkReturn		efx_rc_t
tlv_init_cursor_at_offset(__out tlv_cursor_t * cursor,__in_bcount (size)uint8_t * block,__in size_t size,__in size_t offset)264 tlv_init_cursor_at_offset(
265 	__out	tlv_cursor_t	*cursor,
266 	__in_bcount(size)
267 		uint8_t		*block,
268 	__in	size_t		size,
269 	__in	size_t		offset)
270 {
271 	uint32_t *limit;
272 	uint32_t *current;
273 	limit = (uint32_t *)(block + size - sizeof (uint32_t));
274 	current = (uint32_t *)(block + offset);
275 	return (tlv_init_cursor(cursor, (uint32_t *)block, limit, current));
276 }
277 
278 static	__checkReturn		efx_rc_t
tlv_require_end(__inout tlv_cursor_t * cursor)279 tlv_require_end(
280 	__inout	tlv_cursor_t	*cursor)
281 {
282 	uint32_t *pos;
283 	efx_rc_t rc;
284 
285 	if (cursor->end == NULL) {
286 		pos = cursor->current;
287 		if ((rc = tlv_find(cursor, TLV_TAG_END)) != 0)
288 			goto fail1;
289 
290 		cursor->end = cursor->current;
291 		cursor->current = pos;
292 	}
293 
294 	return (0);
295 
296 fail1:
297 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
298 
299 	return (rc);
300 }
301 
302 static				size_t
tlv_block_length_used(__inout tlv_cursor_t * cursor)303 tlv_block_length_used(
304 	__inout	tlv_cursor_t	*cursor)
305 {
306 	efx_rc_t rc;
307 
308 	if ((rc = tlv_validate_state(cursor)) != 0)
309 		goto fail1;
310 
311 	if ((rc = tlv_require_end(cursor)) != 0)
312 		goto fail2;
313 
314 	/* Return space used (including the END tag) */
315 	return (cursor->end + 1 - cursor->block) * sizeof (uint32_t);
316 
317 fail2:
318 	EFSYS_PROBE(fail2);
319 fail1:
320 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
321 
322 	return (0);
323 }
324 
325 static		uint32_t *
tlv_last_segment_end(__in tlv_cursor_t * cursor)326 tlv_last_segment_end(
327 	__in	tlv_cursor_t *cursor)
328 {
329 	tlv_cursor_t segment_cursor;
330 	uint32_t *last_segment_end = cursor->block;
331 	uint32_t *segment_start = cursor->block;
332 
333 	/*
334 	 * Go through each segment and check that it has an end tag. If there
335 	 * is no end tag then the previous segment was the last valid one,
336 	 * so return the pointer to its end tag.
337 	 */
338 	for (;;) {
339 		if (tlv_init_cursor(&segment_cursor, segment_start,
340 		    cursor->limit, segment_start) != 0)
341 			break;
342 		if (tlv_require_end(&segment_cursor) != 0)
343 			break;
344 		last_segment_end = segment_cursor.end;
345 		segment_start = segment_cursor.end + 1;
346 	}
347 
348 	return (last_segment_end);
349 }
350 
351 
352 static				uint32_t *
tlv_write(__in tlv_cursor_t * cursor,__in uint32_t tag,__in_bcount (size)uint8_t * data,__in size_t size)353 tlv_write(
354 	__in			tlv_cursor_t *cursor,
355 	__in			uint32_t tag,
356 	__in_bcount(size)	uint8_t *data,
357 	__in			size_t size)
358 {
359 	uint32_t len = size;
360 	uint32_t *ptr;
361 
362 	ptr = cursor->current;
363 
364 	*ptr++ = __CPU_TO_LE_32(tag);
365 	*ptr++ = __CPU_TO_LE_32(len);
366 
367 	if (len > 0) {
368 		ptr[(len - 1) / sizeof (uint32_t)] = 0;
369 		memcpy(ptr, data, len);
370 		ptr += EFX_P2ROUNDUP(uint32_t, len,
371 		    sizeof (uint32_t)) / sizeof (*ptr);
372 	}
373 
374 	return (ptr);
375 }
376 
377 static	__checkReturn		efx_rc_t
tlv_insert(__inout tlv_cursor_t * cursor,__in uint32_t tag,__in_bcount (size)uint8_t * data,__in size_t size)378 tlv_insert(
379 	__inout	tlv_cursor_t	*cursor,
380 	__in	uint32_t	tag,
381 	__in_bcount(size)
382 		uint8_t		*data,
383 	__in	size_t		size)
384 {
385 	unsigned int delta;
386 	uint32_t *last_segment_end;
387 	efx_rc_t rc;
388 
389 	if ((rc = tlv_validate_state(cursor)) != 0)
390 		goto fail1;
391 
392 	if ((rc = tlv_require_end(cursor)) != 0)
393 		goto fail2;
394 
395 	if (tag == TLV_TAG_END) {
396 		rc = EINVAL;
397 		goto fail3;
398 	}
399 
400 	last_segment_end = tlv_last_segment_end(cursor);
401 
402 	delta = TLV_DWORD_COUNT(size);
403 	if (last_segment_end + 1 + delta > cursor->limit) {
404 		rc = ENOSPC;
405 		goto fail4;
406 	}
407 
408 	/* Move data up: new space at cursor->current */
409 	memmove(cursor->current + delta, cursor->current,
410 	    (last_segment_end + 1 - cursor->current) * sizeof (uint32_t));
411 
412 	/* Adjust the end pointer */
413 	cursor->end += delta;
414 
415 	/* Write new TLV item */
416 	tlv_write(cursor, tag, data, size);
417 
418 	return (0);
419 
420 fail4:
421 	EFSYS_PROBE(fail4);
422 fail3:
423 	EFSYS_PROBE(fail3);
424 fail2:
425 	EFSYS_PROBE(fail2);
426 fail1:
427 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
428 
429 	return (rc);
430 }
431 
432 static	__checkReturn		efx_rc_t
tlv_delete(__inout tlv_cursor_t * cursor)433 tlv_delete(
434 	__inout	tlv_cursor_t	*cursor)
435 {
436 	unsigned int delta;
437 	uint32_t *last_segment_end;
438 	efx_rc_t rc;
439 
440 	if ((rc = tlv_validate_state(cursor)) != 0)
441 		goto fail1;
442 
443 	if (tlv_tag(cursor) == TLV_TAG_END) {
444 		rc = EINVAL;
445 		goto fail2;
446 	}
447 
448 	delta = TLV_DWORD_COUNT(tlv_length(cursor));
449 
450 	if ((rc = tlv_require_end(cursor)) != 0)
451 		goto fail3;
452 
453 	last_segment_end = tlv_last_segment_end(cursor);
454 
455 	/* Shuffle things down, destroying the item at cursor->current */
456 	memmove(cursor->current, cursor->current + delta,
457 	    (last_segment_end + 1 - cursor->current) * sizeof (uint32_t));
458 	/* Zero the new space at the end of the TLV chain */
459 	memset(last_segment_end + 1 - delta, 0, delta * sizeof (uint32_t));
460 	/* Adjust the end pointer */
461 	cursor->end -= delta;
462 
463 	return (0);
464 
465 fail3:
466 	EFSYS_PROBE(fail3);
467 fail2:
468 	EFSYS_PROBE(fail2);
469 fail1:
470 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
471 
472 	return (rc);
473 }
474 
475 static	__checkReturn		efx_rc_t
tlv_modify(__inout tlv_cursor_t * cursor,__in uint32_t tag,__in_bcount (size)uint8_t * data,__in size_t size)476 tlv_modify(
477 	__inout	tlv_cursor_t	*cursor,
478 	__in	uint32_t	tag,
479 	__in_bcount(size)
480 		uint8_t		*data,
481 	__in	size_t		size)
482 {
483 	uint32_t *pos;
484 	unsigned int old_ndwords;
485 	unsigned int new_ndwords;
486 	unsigned int delta;
487 	uint32_t *last_segment_end;
488 	efx_rc_t rc;
489 
490 	if ((rc = tlv_validate_state(cursor)) != 0)
491 		goto fail1;
492 
493 	if (tlv_tag(cursor) == TLV_TAG_END) {
494 		rc = EINVAL;
495 		goto fail2;
496 	}
497 	if (tlv_tag(cursor) != tag) {
498 		rc = EINVAL;
499 		goto fail3;
500 	}
501 
502 	old_ndwords = TLV_DWORD_COUNT(tlv_length(cursor));
503 	new_ndwords = TLV_DWORD_COUNT(size);
504 
505 	if ((rc = tlv_require_end(cursor)) != 0)
506 		goto fail4;
507 
508 	last_segment_end = tlv_last_segment_end(cursor);
509 
510 	if (new_ndwords > old_ndwords) {
511 		/* Expand space used for TLV item */
512 		delta = new_ndwords - old_ndwords;
513 		pos = cursor->current + old_ndwords;
514 
515 		if (last_segment_end + 1 + delta > cursor->limit) {
516 			rc = ENOSPC;
517 			goto fail5;
518 		}
519 
520 		/* Move up: new space at (cursor->current + old_ndwords) */
521 		memmove(pos + delta, pos,
522 		    (last_segment_end + 1 - pos) * sizeof (uint32_t));
523 
524 		/* Adjust the end pointer */
525 		cursor->end += delta;
526 
527 	} else if (new_ndwords < old_ndwords) {
528 		/* Shrink space used for TLV item */
529 		delta = old_ndwords - new_ndwords;
530 		pos = cursor->current + new_ndwords;
531 
532 		/* Move down: remove words at (cursor->current + new_ndwords) */
533 		memmove(pos, pos + delta,
534 		    (last_segment_end + 1 - pos) * sizeof (uint32_t));
535 
536 		/* Zero the new space at the end of the TLV chain */
537 		memset(last_segment_end + 1 - delta, 0,
538 		    delta * sizeof (uint32_t));
539 
540 		/* Adjust the end pointer */
541 		cursor->end -= delta;
542 	}
543 
544 	/* Write new data */
545 	tlv_write(cursor, tag, data, size);
546 
547 	return (0);
548 
549 fail5:
550 	EFSYS_PROBE(fail5);
551 fail4:
552 	EFSYS_PROBE(fail4);
553 fail3:
554 	EFSYS_PROBE(fail3);
555 fail2:
556 	EFSYS_PROBE(fail2);
557 fail1:
558 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
559 
560 	return (rc);
561 }
562 
checksum_tlv_partition(__in nvram_partition_t * partition)563 static uint32_t checksum_tlv_partition(
564 	__in	nvram_partition_t *partition)
565 {
566 	tlv_cursor_t *cursor;
567 	uint32_t *ptr;
568 	uint32_t *end;
569 	uint32_t csum;
570 	size_t len;
571 
572 	cursor = &partition->tlv_cursor;
573 	len = tlv_block_length_used(cursor);
574 	EFSYS_ASSERT3U((len & 3), ==, 0);
575 
576 	csum = 0;
577 	ptr = partition->data;
578 	end = &ptr[len >> 2];
579 
580 	while (ptr < end)
581 		csum += __LE_TO_CPU_32(*ptr++);
582 
583 	return (csum);
584 }
585 
586 static	__checkReturn		efx_rc_t
tlv_update_partition_len_and_cks(__in tlv_cursor_t * cursor)587 tlv_update_partition_len_and_cks(
588 	__in	tlv_cursor_t *cursor)
589 {
590 	efx_rc_t rc;
591 	nvram_partition_t partition;
592 	struct tlv_partition_header *header;
593 	struct tlv_partition_trailer *trailer;
594 	size_t new_len;
595 
596 	/*
597 	 * We just modified the partition, so the total length may not be
598 	 * valid. Don't use tlv_find(), which performs some sanity checks
599 	 * that may fail here.
600 	 */
601 	partition.data = cursor->block;
602 	memcpy(&partition.tlv_cursor, cursor, sizeof (*cursor));
603 	header = (struct tlv_partition_header *)partition.data;
604 	/* Sanity check. */
605 	if (__LE_TO_CPU_32(header->tag) != TLV_TAG_PARTITION_HEADER) {
606 		rc = EFAULT;
607 		goto fail1;
608 	}
609 	new_len =  tlv_block_length_used(&partition.tlv_cursor);
610 	if (new_len == 0) {
611 		rc = EFAULT;
612 		goto fail2;
613 	}
614 	header->total_length = __CPU_TO_LE_32(new_len);
615 	/* Ensure the modified partition always has a new generation count. */
616 	header->generation = __CPU_TO_LE_32(
617 	    __LE_TO_CPU_32(header->generation) + 1);
618 
619 	trailer = (struct tlv_partition_trailer *)((uint8_t *)header +
620 	    new_len - sizeof (*trailer) - sizeof (uint32_t));
621 	trailer->generation = header->generation;
622 	trailer->checksum = __CPU_TO_LE_32(
623 	    __LE_TO_CPU_32(trailer->checksum) -
624 	    checksum_tlv_partition(&partition));
625 
626 	return (0);
627 
628 fail2:
629 	EFSYS_PROBE(fail2);
630 fail1:
631 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
632 
633 	return (rc);
634 }
635 
636 /* Validate buffer contents (before writing to flash) */
637 	__checkReturn		efx_rc_t
ef10_nvram_buffer_validate(__in uint32_t partn,__in_bcount (partn_size)caddr_t partn_data,__in size_t partn_size)638 ef10_nvram_buffer_validate(
639 	__in			uint32_t partn,
640 	__in_bcount(partn_size)	caddr_t partn_data,
641 	__in			size_t partn_size)
642 {
643 	tlv_cursor_t cursor;
644 	struct tlv_partition_header *header;
645 	struct tlv_partition_trailer *trailer;
646 	size_t total_length;
647 	uint32_t cksum;
648 	int pos;
649 	efx_rc_t rc;
650 
651 	EFX_STATIC_ASSERT(sizeof (*header) <= EF10_NVRAM_CHUNK);
652 
653 	if ((partn_data == NULL) || (partn_size == 0)) {
654 		rc = EINVAL;
655 		goto fail1;
656 	}
657 
658 	/* The partition header must be the first item (at offset zero) */
659 	if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)partn_data,
660 		    partn_size)) != 0) {
661 		rc = EFAULT;
662 		goto fail2;
663 	}
664 	if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {
665 		rc = EINVAL;
666 		goto fail3;
667 	}
668 	header = (struct tlv_partition_header *)tlv_item(&cursor);
669 
670 	/* Check TLV partition length (includes the END tag) */
671 	total_length = __LE_TO_CPU_32(header->total_length);
672 	if (total_length > partn_size) {
673 		rc = EFBIG;
674 		goto fail4;
675 	}
676 
677 	/* Check partition header matches partn */
678 	if (__LE_TO_CPU_16(header->type_id) != partn) {
679 		rc = EINVAL;
680 		goto fail5;
681 	}
682 
683 	/* Check partition ends with PARTITION_TRAILER and END tags */
684 	if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) {
685 		rc = EINVAL;
686 		goto fail6;
687 	}
688 	trailer = (struct tlv_partition_trailer *)tlv_item(&cursor);
689 
690 	if ((rc = tlv_advance(&cursor)) != 0) {
691 		rc = EINVAL;
692 		goto fail7;
693 	}
694 	if (tlv_tag(&cursor) != TLV_TAG_END) {
695 		rc = EINVAL;
696 		goto fail8;
697 	}
698 
699 	/* Check generation counts are consistent */
700 	if (trailer->generation != header->generation) {
701 		rc = EINVAL;
702 		goto fail9;
703 	}
704 
705 	/* Verify partition checksum */
706 	cksum = 0;
707 	for (pos = 0; (size_t)pos < total_length; pos += sizeof (uint32_t)) {
708 		cksum += *((uint32_t *)(partn_data + pos));
709 	}
710 	if (cksum != 0) {
711 		rc = EINVAL;
712 		goto fail10;
713 	}
714 
715 	return (0);
716 
717 fail10:
718 	EFSYS_PROBE(fail10);
719 fail9:
720 	EFSYS_PROBE(fail9);
721 fail8:
722 	EFSYS_PROBE(fail8);
723 fail7:
724 	EFSYS_PROBE(fail7);
725 fail6:
726 	EFSYS_PROBE(fail6);
727 fail5:
728 	EFSYS_PROBE(fail5);
729 fail4:
730 	EFSYS_PROBE(fail4);
731 fail3:
732 	EFSYS_PROBE(fail3);
733 fail2:
734 	EFSYS_PROBE(fail2);
735 fail1:
736 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
737 
738 	return (rc);
739 }
740 
741 			void
ef10_nvram_buffer_init(__out_bcount (buffer_size)caddr_t bufferp,__in size_t buffer_size)742 ef10_nvram_buffer_init(
743 	__out_bcount(buffer_size)
744 				caddr_t bufferp,
745 	__in			size_t buffer_size)
746 {
747 	uint32_t *buf = (uint32_t *)bufferp;
748 
749 	memset(buf, 0xff, buffer_size);
750 
751 	tlv_init_block(buf);
752 }
753 
754 	__checkReturn		efx_rc_t
ef10_nvram_buffer_create(__in uint32_t partn_type,__out_bcount (partn_size)caddr_t partn_data,__in size_t partn_size)755 ef10_nvram_buffer_create(
756 	__in			uint32_t partn_type,
757 	__out_bcount(partn_size)
758 				caddr_t partn_data,
759 	__in			size_t partn_size)
760 {
761 	uint32_t *buf = (uint32_t *)partn_data;
762 	efx_rc_t rc;
763 	tlv_cursor_t cursor;
764 	struct tlv_partition_header header;
765 	struct tlv_partition_trailer trailer;
766 
767 	unsigned int min_buf_size = sizeof (struct tlv_partition_header) +
768 	    sizeof (struct tlv_partition_trailer);
769 	if (partn_size < min_buf_size) {
770 		rc = EINVAL;
771 		goto fail1;
772 	}
773 
774 	ef10_nvram_buffer_init(partn_data, partn_size);
775 
776 	if ((rc = tlv_init_cursor(&cursor, buf,
777 	    (uint32_t *)((uint8_t *)buf + partn_size),
778 	    buf)) != 0) {
779 		goto fail2;
780 	}
781 
782 	header.tag = __CPU_TO_LE_32(TLV_TAG_PARTITION_HEADER);
783 	header.length = __CPU_TO_LE_32(sizeof (header) - 8);
784 	header.type_id = __CPU_TO_LE_16(partn_type);
785 	header.preset = 0;
786 	header.generation = __CPU_TO_LE_32(1);
787 	header.total_length = 0;  /* This will be fixed below. */
788 	if ((rc = tlv_insert(
789 	    &cursor, TLV_TAG_PARTITION_HEADER,
790 	    (uint8_t *)&header.type_id, sizeof (header) - 8)) != 0)
791 		goto fail3;
792 	if ((rc = tlv_advance(&cursor)) != 0)
793 		goto fail4;
794 
795 	trailer.tag = __CPU_TO_LE_32(TLV_TAG_PARTITION_TRAILER);
796 	trailer.length = __CPU_TO_LE_32(sizeof (trailer) - 8);
797 	trailer.generation = header.generation;
798 	trailer.checksum = 0;  /* This will be fixed below. */
799 	if ((rc = tlv_insert(&cursor, TLV_TAG_PARTITION_TRAILER,
800 	    (uint8_t *)&trailer.generation, sizeof (trailer) - 8)) != 0)
801 		goto fail5;
802 
803 	if ((rc = tlv_update_partition_len_and_cks(&cursor)) != 0)
804 		goto fail6;
805 
806 	/* Check that the partition is valid. */
807 	if ((rc = ef10_nvram_buffer_validate(partn_type,
808 	    partn_data, partn_size)) != 0)
809 		goto fail7;
810 
811 	return (0);
812 
813 fail7:
814 	EFSYS_PROBE(fail7);
815 fail6:
816 	EFSYS_PROBE(fail6);
817 fail5:
818 	EFSYS_PROBE(fail5);
819 fail4:
820 	EFSYS_PROBE(fail4);
821 fail3:
822 	EFSYS_PROBE(fail3);
823 fail2:
824 	EFSYS_PROBE(fail2);
825 fail1:
826 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
827 
828 	return (rc);
829 }
830 
831 static			uint32_t
byte_offset(__in uint32_t * position,__in uint32_t * base)832 byte_offset(
833 	__in		uint32_t *position,
834 	__in		uint32_t *base)
835 {
836 	return (uint32_t)((uint8_t *)position - (uint8_t *)base);
837 }
838 
839 	__checkReturn		efx_rc_t
ef10_nvram_buffer_find_item_start(__in_bcount (buffer_size)caddr_t bufferp,__in size_t buffer_size,__out uint32_t * startp)840 ef10_nvram_buffer_find_item_start(
841 	__in_bcount(buffer_size)
842 				caddr_t bufferp,
843 	__in			size_t buffer_size,
844 	__out			uint32_t *startp)
845 {
846 	/* Read past partition header to find start address of the first key */
847 	tlv_cursor_t cursor;
848 	efx_rc_t rc;
849 
850 	/* A PARTITION_HEADER tag must be the first item (at offset zero) */
851 	if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp,
852 			buffer_size)) != 0) {
853 		rc = EFAULT;
854 		goto fail1;
855 	}
856 	if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {
857 		rc = EINVAL;
858 		goto fail2;
859 	}
860 
861 	if ((rc = tlv_advance(&cursor)) != 0) {
862 		rc = EINVAL;
863 		goto fail3;
864 	}
865 	*startp = byte_offset(cursor.current, cursor.block);
866 
867 	if ((rc = tlv_require_end(&cursor)) != 0)
868 		goto fail4;
869 
870 	return (0);
871 
872 fail4:
873 	EFSYS_PROBE(fail4);
874 fail3:
875 	EFSYS_PROBE(fail3);
876 fail2:
877 	EFSYS_PROBE(fail2);
878 fail1:
879 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
880 
881 	return (rc);
882 }
883 
884 	__checkReturn		efx_rc_t
ef10_nvram_buffer_find_end(__in_bcount (buffer_size)caddr_t bufferp,__in size_t buffer_size,__in uint32_t offset,__out uint32_t * endp)885 ef10_nvram_buffer_find_end(
886 	__in_bcount(buffer_size)
887 				caddr_t bufferp,
888 	__in			size_t buffer_size,
889 	__in			uint32_t offset,
890 	__out			uint32_t *endp)
891 {
892 	/* Read to end of partition */
893 	tlv_cursor_t cursor;
894 	efx_rc_t rc;
895 	uint32_t *segment_used;
896 
897 	_NOTE(ARGUNUSED(offset))
898 
899 	if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp,
900 			buffer_size)) != 0) {
901 		rc = EFAULT;
902 		goto fail1;
903 	}
904 
905 	segment_used = cursor.block;
906 
907 	/*
908 	 * Go through each segment and check that it has an end tag. If there
909 	 * is no end tag then the previous segment was the last valid one,
910 	 * so return the used space including that end tag.
911 	 */
912 	while (tlv_tag(&cursor) == TLV_TAG_PARTITION_HEADER) {
913 		if (tlv_require_end(&cursor) != 0) {
914 			if (segment_used == cursor.block) {
915 				/*
916 				 * First segment is corrupt, so there is
917 				 * no valid data in partition.
918 				 */
919 				rc = EINVAL;
920 				goto fail2;
921 			}
922 			break;
923 		}
924 		segment_used = cursor.end + 1;
925 
926 		cursor.current = segment_used;
927 	}
928 	/* Return space used (including the END tag) */
929 	*endp = (segment_used - cursor.block) * sizeof (uint32_t);
930 
931 	return (0);
932 
933 fail2:
934 	EFSYS_PROBE(fail2);
935 fail1:
936 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
937 
938 	return (rc);
939 }
940 
941 	__checkReturn	__success(return != B_FALSE)	boolean_t
ef10_nvram_buffer_find_item(__in_bcount (buffer_size)caddr_t bufferp,__in size_t buffer_size,__in uint32_t offset,__out uint32_t * startp,__out uint32_t * lengthp)942 ef10_nvram_buffer_find_item(
943 	__in_bcount(buffer_size)
944 				caddr_t bufferp,
945 	__in			size_t buffer_size,
946 	__in			uint32_t offset,
947 	__out			uint32_t *startp,
948 	__out			uint32_t *lengthp)
949 {
950 	/* Find TLV at offset and return key start and length */
951 	tlv_cursor_t cursor;
952 	uint8_t *key;
953 	uint32_t tag;
954 
955 	if (tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp,
956 			buffer_size, offset) != 0) {
957 		return (B_FALSE);
958 	}
959 
960 	while ((key = tlv_item(&cursor)) != NULL) {
961 		tag = tlv_tag(&cursor);
962 		if (tag == TLV_TAG_PARTITION_HEADER ||
963 		    tag == TLV_TAG_PARTITION_TRAILER) {
964 			if (tlv_advance(&cursor) != 0) {
965 				break;
966 			}
967 			continue;
968 		}
969 		*startp = byte_offset(cursor.current, cursor.block);
970 		*lengthp = byte_offset(tlv_next_item_ptr(&cursor),
971 		    cursor.current);
972 		return (B_TRUE);
973 	}
974 
975 	return (B_FALSE);
976 }
977 
978 	__checkReturn		efx_rc_t
ef10_nvram_buffer_peek_item(__in_bcount (buffer_size)caddr_t bufferp,__in size_t buffer_size,__in uint32_t offset,__out uint32_t * tagp,__out uint32_t * lengthp,__out uint32_t * value_offsetp)979 ef10_nvram_buffer_peek_item(
980 	__in_bcount(buffer_size)
981 				caddr_t bufferp,
982 	__in			size_t buffer_size,
983 	__in			uint32_t offset,
984 	__out			uint32_t *tagp,
985 	__out			uint32_t *lengthp,
986 	__out			uint32_t *value_offsetp)
987 {
988 	efx_rc_t rc;
989 	tlv_cursor_t cursor;
990 	uint32_t tag;
991 
992 	if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp,
993 			buffer_size, offset)) != 0) {
994 		goto fail1;
995 	}
996 
997 	tag = tlv_tag(&cursor);
998 	*tagp = tag;
999 	if (tag == TLV_TAG_END) {
1000 		/*
1001 		 * To allow stepping over the END tag, report the full tag
1002 		 * length and a zero length value.
1003 		 */
1004 		*lengthp = sizeof (tag);
1005 		*value_offsetp = sizeof (tag);
1006 	} else {
1007 		*lengthp = byte_offset(tlv_next_item_ptr(&cursor),
1008 			    cursor.current);
1009 		*value_offsetp = byte_offset((uint32_t *)tlv_value(&cursor),
1010 			    cursor.current);
1011 	}
1012 	return (0);
1013 
1014 fail1:
1015 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1016 
1017 	return (rc);
1018 }
1019 
1020 	__checkReturn		efx_rc_t
ef10_nvram_buffer_get_item(__in_bcount (buffer_size)caddr_t bufferp,__in size_t buffer_size,__in uint32_t offset,__in uint32_t length,__out uint32_t * tagp,__out_bcount_part (value_max_size,* lengthp)caddr_t valuep,__in size_t value_max_size,__out uint32_t * lengthp)1021 ef10_nvram_buffer_get_item(
1022 	__in_bcount(buffer_size)
1023 				caddr_t bufferp,
1024 	__in			size_t buffer_size,
1025 	__in			uint32_t offset,
1026 	__in			uint32_t length,
1027 	__out			uint32_t *tagp,
1028 	__out_bcount_part(value_max_size, *lengthp)
1029 				caddr_t valuep,
1030 	__in			size_t value_max_size,
1031 	__out			uint32_t *lengthp)
1032 {
1033 	efx_rc_t rc;
1034 	tlv_cursor_t cursor;
1035 	uint32_t value_length;
1036 
1037 	if (buffer_size < (offset + length)) {
1038 		rc = ENOSPC;
1039 		goto fail1;
1040 	}
1041 
1042 	if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp,
1043 			buffer_size, offset)) != 0) {
1044 		goto fail2;
1045 	}
1046 
1047 	value_length = tlv_length(&cursor);
1048 	if (value_max_size < value_length) {
1049 		rc = ENOSPC;
1050 		goto fail3;
1051 	}
1052 	memcpy(valuep, tlv_value(&cursor), value_length);
1053 
1054 	*tagp = tlv_tag(&cursor);
1055 	*lengthp = value_length;
1056 
1057 	return (0);
1058 
1059 fail3:
1060 	EFSYS_PROBE(fail3);
1061 fail2:
1062 	EFSYS_PROBE(fail2);
1063 fail1:
1064 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1065 
1066 	return (rc);
1067 }
1068 
1069 	__checkReturn		efx_rc_t
ef10_nvram_buffer_insert_item(__in_bcount (buffer_size)caddr_t bufferp,__in size_t buffer_size,__in uint32_t offset,__in uint32_t tag,__in_bcount (length)caddr_t valuep,__in uint32_t length,__out uint32_t * lengthp)1070 ef10_nvram_buffer_insert_item(
1071 	__in_bcount(buffer_size)
1072 				caddr_t bufferp,
1073 	__in			size_t buffer_size,
1074 	__in			uint32_t offset,
1075 	__in			uint32_t tag,
1076 	__in_bcount(length)	caddr_t valuep,
1077 	__in			uint32_t length,
1078 	__out			uint32_t *lengthp)
1079 {
1080 	efx_rc_t rc;
1081 	tlv_cursor_t cursor;
1082 
1083 	if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp,
1084 			buffer_size, offset)) != 0) {
1085 		goto fail1;
1086 	}
1087 
1088 	rc = tlv_insert(&cursor, tag, (uint8_t *)valuep, length);
1089 
1090 	if (rc != 0)
1091 		goto fail2;
1092 
1093 	*lengthp = byte_offset(tlv_next_item_ptr(&cursor),
1094 		    cursor.current);
1095 
1096 	return (0);
1097 
1098 fail2:
1099 	EFSYS_PROBE(fail2);
1100 fail1:
1101 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1102 
1103 	return (rc);
1104 }
1105 
1106 	__checkReturn		efx_rc_t
ef10_nvram_buffer_modify_item(__in_bcount (buffer_size)caddr_t bufferp,__in size_t buffer_size,__in uint32_t offset,__in uint32_t tag,__in_bcount (length)caddr_t valuep,__in uint32_t length,__out uint32_t * lengthp)1107 ef10_nvram_buffer_modify_item(
1108 	__in_bcount(buffer_size)
1109 				caddr_t bufferp,
1110 	__in			size_t buffer_size,
1111 	__in			uint32_t offset,
1112 	__in			uint32_t tag,
1113 	__in_bcount(length)	caddr_t valuep,
1114 	__in			uint32_t length,
1115 	__out			uint32_t *lengthp)
1116 {
1117 	efx_rc_t rc;
1118 	tlv_cursor_t cursor;
1119 
1120 	if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp,
1121 			buffer_size, offset)) != 0) {
1122 		goto fail1;
1123 	}
1124 
1125 	rc = tlv_modify(&cursor, tag, (uint8_t *)valuep, length);
1126 
1127 	if (rc != 0) {
1128 		goto fail2;
1129 	}
1130 
1131 	*lengthp = byte_offset(tlv_next_item_ptr(&cursor),
1132 		    cursor.current);
1133 
1134 	return (0);
1135 
1136 fail2:
1137 	EFSYS_PROBE(fail2);
1138 fail1:
1139 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1140 
1141 	return (rc);
1142 }
1143 
1144 
1145 	__checkReturn		efx_rc_t
ef10_nvram_buffer_delete_item(__in_bcount (buffer_size)caddr_t bufferp,__in size_t buffer_size,__in uint32_t offset,__in uint32_t length,__in uint32_t end)1146 ef10_nvram_buffer_delete_item(
1147 	__in_bcount(buffer_size)
1148 				caddr_t bufferp,
1149 	__in			size_t buffer_size,
1150 	__in			uint32_t offset,
1151 	__in			uint32_t length,
1152 	__in			uint32_t end)
1153 {
1154 	efx_rc_t rc;
1155 	tlv_cursor_t cursor;
1156 
1157 	_NOTE(ARGUNUSED(length, end))
1158 
1159 	if ((rc = tlv_init_cursor_at_offset(&cursor, (uint8_t *)bufferp,
1160 			buffer_size, offset)) != 0) {
1161 		goto fail1;
1162 	}
1163 
1164 	if ((rc = tlv_delete(&cursor)) != 0)
1165 		goto fail2;
1166 
1167 	return (0);
1168 
1169 fail2:
1170 	EFSYS_PROBE(fail2);
1171 fail1:
1172 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1173 
1174 	return (rc);
1175 }
1176 
1177 	__checkReturn		efx_rc_t
ef10_nvram_buffer_finish(__in_bcount (buffer_size)caddr_t bufferp,__in size_t buffer_size)1178 ef10_nvram_buffer_finish(
1179 	__in_bcount(buffer_size)
1180 				caddr_t bufferp,
1181 	__in			size_t buffer_size)
1182 {
1183 	efx_rc_t rc;
1184 	tlv_cursor_t cursor;
1185 
1186 	if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)bufferp,
1187 			buffer_size)) != 0) {
1188 		rc = EFAULT;
1189 		goto fail1;
1190 	}
1191 
1192 	if ((rc = tlv_require_end(&cursor)) != 0)
1193 		goto fail2;
1194 
1195 	if ((rc = tlv_update_partition_len_and_cks(&cursor)) != 0)
1196 		goto fail3;
1197 
1198 	return (0);
1199 
1200 fail3:
1201 	EFSYS_PROBE(fail3);
1202 fail2:
1203 	EFSYS_PROBE(fail2);
1204 fail1:
1205 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1206 
1207 	return (rc);
1208 }
1209 
1210 
1211 
1212 /*
1213  * Read and validate a segment from a partition. A segment is a complete
1214  * tlv chain between PARTITION_HEADER and PARTITION_END tags. There may
1215  * be multiple segments in a partition, so seg_offset allows segments
1216  * beyond the first to be read.
1217  */
1218 static	__checkReturn			efx_rc_t
ef10_nvram_read_tlv_segment(__in efx_nic_t * enp,__in uint32_t partn,__in size_t seg_offset,__in_bcount (max_seg_size)caddr_t seg_data,__in size_t max_seg_size)1219 ef10_nvram_read_tlv_segment(
1220 	__in				efx_nic_t *enp,
1221 	__in				uint32_t partn,
1222 	__in				size_t seg_offset,
1223 	__in_bcount(max_seg_size)	caddr_t seg_data,
1224 	__in				size_t max_seg_size)
1225 {
1226 	tlv_cursor_t cursor;
1227 	struct tlv_partition_header *header;
1228 	struct tlv_partition_trailer *trailer;
1229 	size_t total_length;
1230 	uint32_t cksum;
1231 	int pos;
1232 	efx_rc_t rc;
1233 
1234 	EFX_STATIC_ASSERT(sizeof (*header) <= EF10_NVRAM_CHUNK);
1235 
1236 	if ((seg_data == NULL) || (max_seg_size == 0)) {
1237 		rc = EINVAL;
1238 		goto fail1;
1239 	}
1240 
1241 	/* Read initial chunk of the segment, starting at offset */
1242 	if ((rc = ef10_nvram_partn_read_mode(enp, partn, seg_offset, seg_data,
1243 		    EF10_NVRAM_CHUNK,
1244 		    MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT)) != 0) {
1245 		goto fail2;
1246 	}
1247 
1248 	/* A PARTITION_HEADER tag must be the first item at the given offset */
1249 	if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data,
1250 		    max_seg_size)) != 0) {
1251 		rc = EFAULT;
1252 		goto fail3;
1253 	}
1254 	if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {
1255 		rc = EINVAL;
1256 		goto fail4;
1257 	}
1258 	header = (struct tlv_partition_header *)tlv_item(&cursor);
1259 
1260 	/* Check TLV segment length (includes the END tag) */
1261 	total_length = __LE_TO_CPU_32(header->total_length);
1262 	if (total_length > max_seg_size) {
1263 		rc = EFBIG;
1264 		goto fail5;
1265 	}
1266 
1267 	/* Read the remaining segment content */
1268 	if (total_length > EF10_NVRAM_CHUNK) {
1269 		if ((rc = ef10_nvram_partn_read_mode(enp, partn,
1270 			    seg_offset + EF10_NVRAM_CHUNK,
1271 			    seg_data + EF10_NVRAM_CHUNK,
1272 			    total_length - EF10_NVRAM_CHUNK,
1273 			    MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT)) != 0)
1274 			goto fail6;
1275 	}
1276 
1277 	/* Check segment ends with PARTITION_TRAILER and END tags */
1278 	if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) {
1279 		rc = EINVAL;
1280 		goto fail7;
1281 	}
1282 	trailer = (struct tlv_partition_trailer *)tlv_item(&cursor);
1283 
1284 	if ((rc = tlv_advance(&cursor)) != 0) {
1285 		rc = EINVAL;
1286 		goto fail8;
1287 	}
1288 	if (tlv_tag(&cursor) != TLV_TAG_END) {
1289 		rc = EINVAL;
1290 		goto fail9;
1291 	}
1292 
1293 	/* Check data read from segment is consistent */
1294 	if (trailer->generation != header->generation) {
1295 		/*
1296 		 * The partition data may have been modified between successive
1297 		 * MCDI NVRAM_READ requests by the MC or another PCI function.
1298 		 *
1299 		 * The caller must retry to obtain consistent partition data.
1300 		 */
1301 		rc = EAGAIN;
1302 		goto fail10;
1303 	}
1304 
1305 	/* Verify segment checksum */
1306 	cksum = 0;
1307 	for (pos = 0; (size_t)pos < total_length; pos += sizeof (uint32_t)) {
1308 		cksum += *((uint32_t *)(seg_data + pos));
1309 	}
1310 	if (cksum != 0) {
1311 		rc = EINVAL;
1312 		goto fail11;
1313 	}
1314 
1315 	return (0);
1316 
1317 fail11:
1318 	EFSYS_PROBE(fail11);
1319 fail10:
1320 	EFSYS_PROBE(fail10);
1321 fail9:
1322 	EFSYS_PROBE(fail9);
1323 fail8:
1324 	EFSYS_PROBE(fail8);
1325 fail7:
1326 	EFSYS_PROBE(fail7);
1327 fail6:
1328 	EFSYS_PROBE(fail6);
1329 fail5:
1330 	EFSYS_PROBE(fail5);
1331 fail4:
1332 	EFSYS_PROBE(fail4);
1333 fail3:
1334 	EFSYS_PROBE(fail3);
1335 fail2:
1336 	EFSYS_PROBE(fail2);
1337 fail1:
1338 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1339 
1340 	return (rc);
1341 }
1342 
1343 /*
1344  * Read a single TLV item from a host memory
1345  * buffer containing a TLV formatted segment.
1346  */
1347 	__checkReturn		efx_rc_t
ef10_nvram_buf_read_tlv(__in efx_nic_t * enp,__in_bcount (max_seg_size)caddr_t seg_data,__in size_t max_seg_size,__in uint32_t tag,__deref_out_bcount_opt (* sizep)caddr_t * datap,__out size_t * sizep)1348 ef10_nvram_buf_read_tlv(
1349 	__in				efx_nic_t *enp,
1350 	__in_bcount(max_seg_size)	caddr_t seg_data,
1351 	__in				size_t max_seg_size,
1352 	__in				uint32_t tag,
1353 	__deref_out_bcount_opt(*sizep)	caddr_t *datap,
1354 	__out				size_t *sizep)
1355 {
1356 	tlv_cursor_t cursor;
1357 	caddr_t data;
1358 	size_t length;
1359 	caddr_t value;
1360 	efx_rc_t rc;
1361 
1362 	_NOTE(ARGUNUSED(enp))
1363 
1364 	if ((seg_data == NULL) || (max_seg_size == 0)) {
1365 		rc = EINVAL;
1366 		goto fail1;
1367 	}
1368 
1369 	/* Find requested TLV tag in segment data */
1370 	if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data,
1371 		    max_seg_size)) != 0) {
1372 		rc = EFAULT;
1373 		goto fail2;
1374 	}
1375 	if ((rc = tlv_find(&cursor, tag)) != 0) {
1376 		rc = ENOENT;
1377 		goto fail3;
1378 	}
1379 	value = (caddr_t)tlv_value(&cursor);
1380 	length = tlv_length(&cursor);
1381 
1382 	if (length == 0)
1383 		data = NULL;
1384 	else {
1385 		/* Copy out data from TLV item */
1386 		EFSYS_KMEM_ALLOC(enp->en_esip, length, data);
1387 		if (data == NULL) {
1388 			rc = ENOMEM;
1389 			goto fail4;
1390 		}
1391 		memcpy(data, value, length);
1392 	}
1393 
1394 	*datap = data;
1395 	*sizep = length;
1396 
1397 	return (0);
1398 
1399 fail4:
1400 	EFSYS_PROBE(fail4);
1401 fail3:
1402 	EFSYS_PROBE(fail3);
1403 fail2:
1404 	EFSYS_PROBE(fail2);
1405 fail1:
1406 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1407 
1408 	return (rc);
1409 }
1410 
1411 /* Read a single TLV item from the first segment in a TLV formatted partition */
1412 	__checkReturn		efx_rc_t
ef10_nvram_partn_read_tlv(__in efx_nic_t * enp,__in uint32_t partn,__in uint32_t tag,__deref_out_bcount_opt (* seg_sizep)caddr_t * seg_datap,__out size_t * seg_sizep)1413 ef10_nvram_partn_read_tlv(
1414 	__in					efx_nic_t *enp,
1415 	__in					uint32_t partn,
1416 	__in					uint32_t tag,
1417 	__deref_out_bcount_opt(*seg_sizep)	caddr_t *seg_datap,
1418 	__out					size_t *seg_sizep)
1419 {
1420 	caddr_t seg_data = NULL;
1421 	size_t partn_size = 0;
1422 	size_t length;
1423 	caddr_t data;
1424 	int retry;
1425 	efx_rc_t rc;
1426 
1427 	/* Allocate sufficient memory for the entire partition */
1428 	if ((rc = ef10_nvram_partn_size(enp, partn, &partn_size)) != 0)
1429 		goto fail1;
1430 
1431 	if (partn_size == 0) {
1432 		rc = ENOENT;
1433 		goto fail2;
1434 	}
1435 
1436 	EFSYS_KMEM_ALLOC(enp->en_esip, partn_size, seg_data);
1437 	if (seg_data == NULL) {
1438 		rc = ENOMEM;
1439 		goto fail3;
1440 	}
1441 
1442 	/*
1443 	 * Read the first segment in a TLV partition. Retry until consistent
1444 	 * segment contents are returned. Inconsistent data may be read if:
1445 	 *  a) the segment contents are invalid
1446 	 *  b) the MC has rebooted while we were reading the partition
1447 	 *  c) the partition has been modified while we were reading it
1448 	 * Limit retry attempts to ensure forward progress.
1449 	 */
1450 	retry = 10;
1451 	do {
1452 		if ((rc = ef10_nvram_read_tlv_segment(enp, partn, 0,
1453 		    seg_data, partn_size)) != 0)
1454 			--retry;
1455 	} while ((rc == EAGAIN) && (retry > 0));
1456 
1457 	if (rc != 0) {
1458 		/* Failed to obtain consistent segment data */
1459 		if (rc == EAGAIN)
1460 			rc = EIO;
1461 
1462 		goto fail4;
1463 	}
1464 
1465 	if ((rc = ef10_nvram_buf_read_tlv(enp, seg_data, partn_size,
1466 		    tag, &data, &length)) != 0)
1467 		goto fail5;
1468 
1469 	EFSYS_KMEM_FREE(enp->en_esip, partn_size, seg_data);
1470 
1471 	*seg_datap = data;
1472 	*seg_sizep = length;
1473 
1474 	return (0);
1475 
1476 fail5:
1477 	EFSYS_PROBE(fail5);
1478 fail4:
1479 	EFSYS_PROBE(fail4);
1480 
1481 	EFSYS_KMEM_FREE(enp->en_esip, partn_size, seg_data);
1482 fail3:
1483 	EFSYS_PROBE(fail3);
1484 fail2:
1485 	EFSYS_PROBE(fail2);
1486 fail1:
1487 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1488 
1489 	return (rc);
1490 }
1491 
1492 /* Compute the size of a segment. */
1493 	static	__checkReturn	efx_rc_t
ef10_nvram_buf_segment_size(__in caddr_t seg_data,__in size_t max_seg_size,__out size_t * seg_sizep)1494 ef10_nvram_buf_segment_size(
1495 	__in			caddr_t seg_data,
1496 	__in			size_t max_seg_size,
1497 	__out			size_t *seg_sizep)
1498 {
1499 	efx_rc_t rc;
1500 	tlv_cursor_t cursor;
1501 	struct tlv_partition_header *header;
1502 	uint32_t cksum;
1503 	int pos;
1504 	uint32_t *end_tag_position;
1505 	uint32_t segment_length;
1506 
1507 	/* A PARTITION_HEADER tag must be the first item at the given offset */
1508 	if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data,
1509 		    max_seg_size)) != 0) {
1510 		rc = EFAULT;
1511 		goto fail1;
1512 	}
1513 	if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {
1514 		rc = EINVAL;
1515 		goto fail2;
1516 	}
1517 	header = (struct tlv_partition_header *)tlv_item(&cursor);
1518 
1519 	/* Check TLV segment length (includes the END tag) */
1520 	*seg_sizep = __LE_TO_CPU_32(header->total_length);
1521 	if (*seg_sizep > max_seg_size) {
1522 		rc = EFBIG;
1523 		goto fail3;
1524 	}
1525 
1526 	/* Check segment ends with PARTITION_TRAILER and END tags */
1527 	if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) {
1528 		rc = EINVAL;
1529 		goto fail4;
1530 	}
1531 
1532 	if ((rc = tlv_advance(&cursor)) != 0) {
1533 		rc = EINVAL;
1534 		goto fail5;
1535 	}
1536 	if (tlv_tag(&cursor) != TLV_TAG_END) {
1537 		rc = EINVAL;
1538 		goto fail6;
1539 	}
1540 	end_tag_position = cursor.current;
1541 
1542 	/* Verify segment checksum */
1543 	cksum = 0;
1544 	for (pos = 0; (size_t)pos < *seg_sizep; pos += sizeof (uint32_t)) {
1545 		cksum += *((uint32_t *)(seg_data + pos));
1546 	}
1547 	if (cksum != 0) {
1548 		rc = EINVAL;
1549 		goto fail7;
1550 	}
1551 
1552 	/*
1553 	 * Calculate total length from HEADER to END tags and compare to
1554 	 * max_seg_size and the total_length field in the HEADER tag.
1555 	 */
1556 	segment_length = tlv_block_length_used(&cursor);
1557 
1558 	if (segment_length > max_seg_size) {
1559 		rc = EINVAL;
1560 		goto fail8;
1561 	}
1562 
1563 	if (segment_length != *seg_sizep) {
1564 		rc = EINVAL;
1565 		goto fail9;
1566 	}
1567 
1568 	/* Skip over the first HEADER tag. */
1569 	rc = tlv_rewind(&cursor);
1570 	rc = tlv_advance(&cursor);
1571 
1572 	while (rc == 0) {
1573 		if (tlv_tag(&cursor) == TLV_TAG_END) {
1574 			/* Check that the END tag is the one found earlier. */
1575 			if (cursor.current != end_tag_position)
1576 				goto fail10;
1577 			break;
1578 		}
1579 		/* Check for duplicate HEADER tags before the END tag. */
1580 		if (tlv_tag(&cursor) == TLV_TAG_PARTITION_HEADER) {
1581 			rc = EINVAL;
1582 			goto fail11;
1583 		}
1584 
1585 		rc = tlv_advance(&cursor);
1586 	}
1587 	if (rc != 0)
1588 		goto fail12;
1589 
1590 	return (0);
1591 
1592 fail12:
1593 	EFSYS_PROBE(fail12);
1594 fail11:
1595 	EFSYS_PROBE(fail11);
1596 fail10:
1597 	EFSYS_PROBE(fail10);
1598 fail9:
1599 	EFSYS_PROBE(fail9);
1600 fail8:
1601 	EFSYS_PROBE(fail8);
1602 fail7:
1603 	EFSYS_PROBE(fail7);
1604 fail6:
1605 	EFSYS_PROBE(fail6);
1606 fail5:
1607 	EFSYS_PROBE(fail5);
1608 fail4:
1609 	EFSYS_PROBE(fail4);
1610 fail3:
1611 	EFSYS_PROBE(fail3);
1612 fail2:
1613 	EFSYS_PROBE(fail2);
1614 fail1:
1615 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1616 
1617 	return (rc);
1618 }
1619 
1620 /*
1621  * Add or update a single TLV item in a host memory buffer containing a TLV
1622  * formatted segment. Historically partitions consisted of only one segment.
1623  */
1624 	__checkReturn			efx_rc_t
ef10_nvram_buf_write_tlv(__inout_bcount (max_seg_size)caddr_t seg_data,__in size_t max_seg_size,__in uint32_t tag,__in_bcount (tag_size)caddr_t tag_data,__in size_t tag_size,__out size_t * total_lengthp)1625 ef10_nvram_buf_write_tlv(
1626 	__inout_bcount(max_seg_size)	caddr_t seg_data,
1627 	__in				size_t max_seg_size,
1628 	__in				uint32_t tag,
1629 	__in_bcount(tag_size)		caddr_t tag_data,
1630 	__in				size_t tag_size,
1631 	__out				size_t *total_lengthp)
1632 {
1633 	tlv_cursor_t cursor;
1634 	struct tlv_partition_header *header;
1635 	struct tlv_partition_trailer *trailer;
1636 	uint32_t generation;
1637 	uint32_t cksum;
1638 	int pos;
1639 	efx_rc_t rc;
1640 
1641 	/* A PARTITION_HEADER tag must be the first item (at offset zero) */
1642 	if ((rc = tlv_init_cursor_from_size(&cursor, (uint8_t *)seg_data,
1643 			max_seg_size)) != 0) {
1644 		rc = EFAULT;
1645 		goto fail1;
1646 	}
1647 	if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {
1648 		rc = EINVAL;
1649 		goto fail2;
1650 	}
1651 	header = (struct tlv_partition_header *)tlv_item(&cursor);
1652 
1653 	/* Update the TLV chain to contain the new data */
1654 	if ((rc = tlv_find(&cursor, tag)) == 0) {
1655 		/* Modify existing TLV item */
1656 		if ((rc = tlv_modify(&cursor, tag,
1657 			    (uint8_t *)tag_data, tag_size)) != 0)
1658 			goto fail3;
1659 	} else {
1660 		/* Insert a new TLV item before the PARTITION_TRAILER */
1661 		rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER);
1662 		if (rc != 0) {
1663 			rc = EINVAL;
1664 			goto fail4;
1665 		}
1666 		if ((rc = tlv_insert(&cursor, tag,
1667 			    (uint8_t *)tag_data, tag_size)) != 0) {
1668 			rc = EINVAL;
1669 			goto fail5;
1670 		}
1671 	}
1672 
1673 	/* Find the trailer tag */
1674 	if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) {
1675 		rc = EINVAL;
1676 		goto fail6;
1677 	}
1678 	trailer = (struct tlv_partition_trailer *)tlv_item(&cursor);
1679 
1680 	/* Update PARTITION_HEADER and PARTITION_TRAILER fields */
1681 	*total_lengthp = tlv_block_length_used(&cursor);
1682 	if (*total_lengthp > max_seg_size) {
1683 		rc = ENOSPC;
1684 		goto fail7;
1685 	}
1686 	generation = __LE_TO_CPU_32(header->generation) + 1;
1687 
1688 	header->total_length	= __CPU_TO_LE_32(*total_lengthp);
1689 	header->generation	= __CPU_TO_LE_32(generation);
1690 	trailer->generation	= __CPU_TO_LE_32(generation);
1691 
1692 	/* Recompute PARTITION_TRAILER checksum */
1693 	trailer->checksum = 0;
1694 	cksum = 0;
1695 	for (pos = 0; (size_t)pos < *total_lengthp; pos += sizeof (uint32_t)) {
1696 		cksum += *((uint32_t *)(seg_data + pos));
1697 	}
1698 	trailer->checksum = ~cksum + 1;
1699 
1700 	return (0);
1701 
1702 fail7:
1703 	EFSYS_PROBE(fail7);
1704 fail6:
1705 	EFSYS_PROBE(fail6);
1706 fail5:
1707 	EFSYS_PROBE(fail5);
1708 fail4:
1709 	EFSYS_PROBE(fail4);
1710 fail3:
1711 	EFSYS_PROBE(fail3);
1712 fail2:
1713 	EFSYS_PROBE(fail2);
1714 fail1:
1715 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1716 
1717 	return (rc);
1718 }
1719 
1720 /*
1721  * Add or update a single TLV item in the first segment of a TLV formatted
1722  * dynamic config partition. The first segment is the current active
1723  * configuration.
1724  */
1725 	__checkReturn		efx_rc_t
ef10_nvram_partn_write_tlv(__in efx_nic_t * enp,__in uint32_t partn,__in uint32_t tag,__in_bcount (size)caddr_t data,__in size_t size)1726 ef10_nvram_partn_write_tlv(
1727 	__in			efx_nic_t *enp,
1728 	__in			uint32_t partn,
1729 	__in			uint32_t tag,
1730 	__in_bcount(size)	caddr_t data,
1731 	__in			size_t size)
1732 {
1733 	return ef10_nvram_partn_write_segment_tlv(enp, partn, tag, data,
1734 	    size, B_FALSE);
1735 }
1736 
1737 /*
1738  * Read a segment from nvram at the given offset into a buffer (segment_data)
1739  * and optionally write a new tag to it.
1740  */
1741 static	__checkReturn		efx_rc_t
ef10_nvram_segment_write_tlv(__in efx_nic_t * enp,__in uint32_t partn,__in uint32_t tag,__in_bcount (size)caddr_t data,__in size_t size,__inout caddr_t * seg_datap,__inout size_t * partn_offsetp,__inout size_t * src_remain_lenp,__inout size_t * dest_remain_lenp,__in boolean_t write)1742 ef10_nvram_segment_write_tlv(
1743 	__in			efx_nic_t *enp,
1744 	__in			uint32_t partn,
1745 	__in			uint32_t tag,
1746 	__in_bcount(size)	caddr_t data,
1747 	__in			size_t size,
1748 	__inout			caddr_t *seg_datap,
1749 	__inout			size_t *partn_offsetp,
1750 	__inout			size_t *src_remain_lenp,
1751 	__inout			size_t *dest_remain_lenp,
1752 	__in			boolean_t write)
1753 {
1754 	efx_rc_t rc;
1755 	efx_rc_t status;
1756 	size_t original_segment_size;
1757 	size_t modified_segment_size;
1758 
1759 	/*
1760 	 * Read the segment from NVRAM into the segment_data buffer and validate
1761 	 * it, returning if it does not validate. This is not a failure unless
1762 	 * this is the first segment in a partition. In this case the caller
1763 	 * must propagate the error.
1764 	 */
1765 	status = ef10_nvram_read_tlv_segment(enp, partn, *partn_offsetp,
1766 	    *seg_datap, *src_remain_lenp);
1767 	if (status != 0) {
1768 		rc = EINVAL;
1769 		goto fail1;
1770 	}
1771 
1772 	status = ef10_nvram_buf_segment_size(*seg_datap,
1773 	    *src_remain_lenp, &original_segment_size);
1774 	if (status != 0) {
1775 		rc = EINVAL;
1776 		goto fail2;
1777 	}
1778 
1779 	if (write) {
1780 		/* Update the contents of the segment in the buffer */
1781 		if ((rc = ef10_nvram_buf_write_tlv(*seg_datap,
1782 			*dest_remain_lenp, tag, data, size,
1783 			&modified_segment_size)) != 0) {
1784 			goto fail3;
1785 		}
1786 		*dest_remain_lenp -= modified_segment_size;
1787 		*seg_datap += modified_segment_size;
1788 	} else {
1789 		/*
1790 		 * We won't modify this segment, but still need to update the
1791 		 * remaining lengths and pointers.
1792 		 */
1793 		*dest_remain_lenp -= original_segment_size;
1794 		*seg_datap += original_segment_size;
1795 	}
1796 
1797 	*partn_offsetp += original_segment_size;
1798 	*src_remain_lenp -= original_segment_size;
1799 
1800 	return (0);
1801 
1802 fail3:
1803 	EFSYS_PROBE(fail3);
1804 fail2:
1805 	EFSYS_PROBE(fail2);
1806 fail1:
1807 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1808 
1809 	return (rc);
1810 }
1811 
1812 /*
1813  * Add or update a single TLV item in either the first segment or in all
1814  * segments in a TLV formatted dynamic config partition. Dynamic config
1815  * partitions on boards that support RFID are divided into a number of segments,
1816  * each formatted like a partition, with header, trailer and end tags. The first
1817  * segment is the current active configuration.
1818  *
1819  * The segments are initialised by manftest and each contain a different
1820  * configuration e.g. firmware variant. The firmware can be instructed
1821  * via RFID to copy a segment to replace the first segment, hence changing the
1822  * active configuration.  This allows ops to change the configuration of a board
1823  * prior to shipment using RFID.
1824  *
1825  * Changes to the dynamic config may need to be written to all segments (e.g.
1826  * firmware versions) or just the first segment (changes to the active
1827  * configuration). See SF-111324-SW "The use of RFID in Solarflare Products".
1828  * If only the first segment is written the code still needs to be aware of the
1829  * possible presence of subsequent segments as writing to a segment may cause
1830  * its size to increase, which would overwrite the subsequent segments and
1831  * invalidate them.
1832  */
1833 	__checkReturn		efx_rc_t
ef10_nvram_partn_write_segment_tlv(__in efx_nic_t * enp,__in uint32_t partn,__in uint32_t tag,__in_bcount (size)caddr_t data,__in size_t size,__in boolean_t all_segments)1834 ef10_nvram_partn_write_segment_tlv(
1835 	__in			efx_nic_t *enp,
1836 	__in			uint32_t partn,
1837 	__in			uint32_t tag,
1838 	__in_bcount(size)	caddr_t data,
1839 	__in			size_t size,
1840 	__in			boolean_t all_segments)
1841 {
1842 	size_t partn_size = 0;
1843 	caddr_t partn_data;
1844 	size_t total_length = 0;
1845 	efx_rc_t rc;
1846 	size_t current_offset = 0;
1847 	size_t remaining_original_length;
1848 	size_t remaining_modified_length;
1849 	caddr_t segment_data;
1850 
1851 	EFSYS_ASSERT3U(partn, ==, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG);
1852 
1853 	/* Allocate sufficient memory for the entire partition */
1854 	if ((rc = ef10_nvram_partn_size(enp, partn, &partn_size)) != 0)
1855 		goto fail1;
1856 
1857 	EFSYS_KMEM_ALLOC(enp->en_esip, partn_size, partn_data);
1858 	if (partn_data == NULL) {
1859 		rc = ENOMEM;
1860 		goto fail2;
1861 	}
1862 
1863 	remaining_original_length = partn_size;
1864 	remaining_modified_length = partn_size;
1865 	segment_data = partn_data;
1866 
1867 	/* Lock the partition */
1868 	if ((rc = ef10_nvram_partn_lock(enp, partn)) != 0)
1869 		goto fail3;
1870 
1871 	/* Iterate over each (potential) segment to update it. */
1872 	do {
1873 		boolean_t write = all_segments || current_offset == 0;
1874 
1875 		rc = ef10_nvram_segment_write_tlv(enp, partn, tag, data, size,
1876 		    &segment_data, &current_offset, &remaining_original_length,
1877 		    &remaining_modified_length, write);
1878 		if (rc != 0) {
1879 			if (current_offset == 0) {
1880 				/*
1881 				 * If no data has been read then the first
1882 				 * segment is invalid, which is an error.
1883 				 */
1884 				goto fail4;
1885 			}
1886 			break;
1887 		}
1888 	} while (current_offset < partn_size);
1889 
1890 	total_length = segment_data - partn_data;
1891 
1892 	/*
1893 	 * We've run out of space.  This should actually be dealt with by
1894 	 * ef10_nvram_buf_write_tlv returning ENOSPC.
1895 	 */
1896 	if (total_length > partn_size) {
1897 		rc = ENOSPC;
1898 		goto fail5;
1899 	}
1900 
1901 	/* Erase the whole partition in NVRAM */
1902 	if ((rc = ef10_nvram_partn_erase(enp, partn, 0, partn_size)) != 0)
1903 		goto fail6;
1904 
1905 	/* Write new partition contents from the buffer to NVRAM */
1906 	if ((rc = ef10_nvram_partn_write(enp, partn, 0, partn_data,
1907 		    total_length)) != 0)
1908 		goto fail7;
1909 
1910 	/* Unlock the partition */
1911 	(void) ef10_nvram_partn_unlock(enp, partn, NULL);
1912 
1913 	EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data);
1914 
1915 	return (0);
1916 
1917 fail7:
1918 	EFSYS_PROBE(fail7);
1919 fail6:
1920 	EFSYS_PROBE(fail6);
1921 fail5:
1922 	EFSYS_PROBE(fail5);
1923 fail4:
1924 	EFSYS_PROBE(fail4);
1925 
1926 	(void) ef10_nvram_partn_unlock(enp, partn, NULL);
1927 fail3:
1928 	EFSYS_PROBE(fail3);
1929 
1930 	EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data);
1931 fail2:
1932 	EFSYS_PROBE(fail2);
1933 fail1:
1934 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1935 
1936 	return (rc);
1937 }
1938 
1939 /*
1940  * Get the size of a NVRAM partition. This is the total size allocated in nvram,
1941  * not the data used by the segments in the partition.
1942  */
1943 	__checkReturn		efx_rc_t
ef10_nvram_partn_size(__in efx_nic_t * enp,__in uint32_t partn,__out size_t * sizep)1944 ef10_nvram_partn_size(
1945 	__in			efx_nic_t *enp,
1946 	__in			uint32_t partn,
1947 	__out			size_t *sizep)
1948 {
1949 	efx_rc_t rc;
1950 	efx_nvram_info_t eni = { 0 };
1951 
1952 	if ((rc = efx_mcdi_nvram_info(enp, partn, &eni)) != 0)
1953 		goto fail1;
1954 
1955 	*sizep = eni.eni_partn_size;
1956 
1957 	return (0);
1958 
1959 fail1:
1960 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1961 
1962 	return (rc);
1963 }
1964 
1965 	__checkReturn		efx_rc_t
ef10_nvram_partn_info(__in efx_nic_t * enp,__in uint32_t partn,__out efx_nvram_info_t * enip)1966 ef10_nvram_partn_info(
1967 	__in			efx_nic_t *enp,
1968 	__in			uint32_t partn,
1969 	__out			efx_nvram_info_t *enip)
1970 {
1971 	efx_rc_t rc;
1972 
1973 	if ((rc = efx_mcdi_nvram_info(enp, partn, enip)) != 0)
1974 		goto fail1;
1975 
1976 	if (enip->eni_write_size == 0)
1977 		enip->eni_write_size = EF10_NVRAM_CHUNK;
1978 
1979 	return (0);
1980 
1981 fail1:
1982 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1983 
1984 	return (rc);
1985 }
1986 
1987 
1988 	__checkReturn		efx_rc_t
ef10_nvram_partn_lock(__in efx_nic_t * enp,__in uint32_t partn)1989 ef10_nvram_partn_lock(
1990 	__in			efx_nic_t *enp,
1991 	__in			uint32_t partn)
1992 {
1993 	efx_rc_t rc;
1994 
1995 	if ((rc = efx_mcdi_nvram_update_start(enp, partn)) != 0)
1996 		goto fail1;
1997 
1998 	return (0);
1999 
2000 fail1:
2001 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2002 
2003 	return (rc);
2004 }
2005 
2006 	__checkReturn		efx_rc_t
ef10_nvram_partn_read_mode(__in efx_nic_t * enp,__in uint32_t partn,__in unsigned int offset,__out_bcount (size)caddr_t data,__in size_t size,__in uint32_t mode)2007 ef10_nvram_partn_read_mode(
2008 	__in			efx_nic_t *enp,
2009 	__in			uint32_t partn,
2010 	__in			unsigned int offset,
2011 	__out_bcount(size)	caddr_t data,
2012 	__in			size_t size,
2013 	__in			uint32_t mode)
2014 {
2015 	size_t chunk;
2016 	efx_rc_t rc;
2017 
2018 	while (size > 0) {
2019 		chunk = MIN(size, EF10_NVRAM_CHUNK);
2020 
2021 		if ((rc = efx_mcdi_nvram_read(enp, partn, offset,
2022 			    data, chunk, mode)) != 0) {
2023 			goto fail1;
2024 		}
2025 
2026 		size -= chunk;
2027 		data += chunk;
2028 		offset += chunk;
2029 	}
2030 
2031 	return (0);
2032 
2033 fail1:
2034 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2035 
2036 	return (rc);
2037 }
2038 
2039 	__checkReturn		efx_rc_t
ef10_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)2040 ef10_nvram_partn_read(
2041 	__in			efx_nic_t *enp,
2042 	__in			uint32_t partn,
2043 	__in			unsigned int offset,
2044 	__out_bcount(size)	caddr_t data,
2045 	__in			size_t size)
2046 {
2047 	/*
2048 	 * An A/B partition has two data stores (current and backup).
2049 	 * Read requests which come in through the EFX API expect to read the
2050 	 * current, active store of an A/B partition. For non A/B partitions,
2051 	 * there is only a single store and so the mode param is ignored.
2052 	 */
2053 	return ef10_nvram_partn_read_mode(enp, partn, offset, data, size,
2054 			    MC_CMD_NVRAM_READ_IN_V2_TARGET_CURRENT);
2055 }
2056 
2057 	__checkReturn		efx_rc_t
ef10_nvram_partn_read_backup(__in efx_nic_t * enp,__in uint32_t partn,__in unsigned int offset,__out_bcount (size)caddr_t data,__in size_t size)2058 ef10_nvram_partn_read_backup(
2059 	__in			efx_nic_t *enp,
2060 	__in			uint32_t partn,
2061 	__in			unsigned int offset,
2062 	__out_bcount(size)	caddr_t data,
2063 	__in			size_t size)
2064 {
2065 	/*
2066 	 * An A/B partition has two data stores (current and backup).
2067 	 * Read the backup store of an A/B partition (i.e. the store currently
2068 	 * being written to if the partition is locked).
2069 	 *
2070 	 * This is needed when comparing the existing partition content to avoid
2071 	 * unnecessary writes, or to read back what has been written to check
2072 	 * that the writes have succeeded.
2073 	 */
2074 	return ef10_nvram_partn_read_mode(enp, partn, offset, data, size,
2075 			    MC_CMD_NVRAM_READ_IN_V2_TARGET_BACKUP);
2076 }
2077 
2078 	__checkReturn		efx_rc_t
ef10_nvram_partn_erase(__in efx_nic_t * enp,__in uint32_t partn,__in unsigned int offset,__in size_t size)2079 ef10_nvram_partn_erase(
2080 	__in			efx_nic_t *enp,
2081 	__in			uint32_t partn,
2082 	__in			unsigned int offset,
2083 	__in			size_t size)
2084 {
2085 	efx_rc_t rc;
2086 	efx_nvram_info_t eni = { 0 };
2087 	uint32_t erase_size;
2088 
2089 	if ((rc = efx_mcdi_nvram_info(enp, partn, &eni)) != 0)
2090 		goto fail1;
2091 
2092 	erase_size = eni.eni_erase_size;
2093 
2094 	if (erase_size == 0) {
2095 		if ((rc = efx_mcdi_nvram_erase(enp, partn, offset, size)) != 0)
2096 			goto fail2;
2097 	} else {
2098 		if (size % erase_size != 0) {
2099 			rc = EINVAL;
2100 			goto fail3;
2101 		}
2102 		while (size > 0) {
2103 			if ((rc = efx_mcdi_nvram_erase(enp, partn, offset,
2104 			    erase_size)) != 0)
2105 				goto fail4;
2106 			offset += erase_size;
2107 			size -= erase_size;
2108 		}
2109 	}
2110 
2111 	return (0);
2112 
2113 fail4:
2114 	EFSYS_PROBE(fail4);
2115 fail3:
2116 	EFSYS_PROBE(fail3);
2117 fail2:
2118 	EFSYS_PROBE(fail2);
2119 fail1:
2120 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2121 
2122 	return (rc);
2123 }
2124 
2125 	__checkReturn		efx_rc_t
ef10_nvram_partn_write(__in efx_nic_t * enp,__in uint32_t partn,__in unsigned int offset,__in_bcount (size)caddr_t data,__in size_t size)2126 ef10_nvram_partn_write(
2127 	__in			efx_nic_t *enp,
2128 	__in			uint32_t partn,
2129 	__in			unsigned int offset,
2130 	__in_bcount(size)	caddr_t data,
2131 	__in			size_t size)
2132 {
2133 	size_t chunk;
2134 	efx_nvram_info_t eni = { 0 };
2135 	uint32_t write_size;
2136 	efx_rc_t rc;
2137 
2138 	if ((rc = efx_mcdi_nvram_info(enp, partn, &eni)) != 0)
2139 		goto fail1;
2140 
2141 	write_size = eni.eni_write_size;
2142 
2143 	if (write_size != 0) {
2144 		/*
2145 		 * Check that the size is a multiple of the write chunk size if
2146 		 * the write chunk size is available.
2147 		 */
2148 		if (size % write_size != 0) {
2149 			rc = EINVAL;
2150 			goto fail2;
2151 		}
2152 	} else {
2153 		write_size = EF10_NVRAM_CHUNK;
2154 	}
2155 
2156 	while (size > 0) {
2157 		chunk = MIN(size, write_size);
2158 
2159 		if ((rc = efx_mcdi_nvram_write(enp, partn, offset,
2160 			    data, chunk)) != 0) {
2161 			goto fail3;
2162 		}
2163 
2164 		size -= chunk;
2165 		data += chunk;
2166 		offset += chunk;
2167 	}
2168 
2169 	return (0);
2170 
2171 fail3:
2172 	EFSYS_PROBE(fail3);
2173 fail2:
2174 	EFSYS_PROBE(fail2);
2175 fail1:
2176 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2177 
2178 	return (rc);
2179 }
2180 
2181 #define	EF10_NVRAM_INITIAL_POLL_DELAY_US 10000
2182 #define	EF10_NVRAM_MAX_POLL_DELAY_US     1000000
2183 #define	EF10_NVRAM_POLL_RETRIES          100
2184 
2185 	__checkReturn		efx_rc_t
ef10_nvram_partn_unlock(__in efx_nic_t * enp,__in uint32_t partn,__out_opt uint32_t * verify_resultp)2186 ef10_nvram_partn_unlock(
2187 	__in			efx_nic_t *enp,
2188 	__in			uint32_t partn,
2189 	__out_opt		uint32_t *verify_resultp)
2190 {
2191 	boolean_t reboot = B_FALSE;
2192 	uint32_t poll_delay_us = EF10_NVRAM_INITIAL_POLL_DELAY_US;
2193 	uint32_t poll_retry = 0;
2194 	uint32_t verify_result = MC_CMD_NVRAM_VERIFY_RC_UNKNOWN;
2195 	efx_rc_t rc;
2196 
2197 	rc = efx_mcdi_nvram_update_finish(enp, partn, reboot,
2198 	    EFX_NVRAM_UPDATE_FLAGS_BACKGROUND, &verify_result);
2199 
2200 	/*
2201 	 * NVRAM updates can take a long time (e.g. up to 1 minute for bundle
2202 	 * images). Polling for NVRAM update completion ensures that other MCDI
2203 	 * commands can be issued before the background NVRAM update completes.
2204 	 *
2205 	 * Without polling, other MCDI commands can only be issued before the
2206 	 * NVRAM update completes if the MCDI transport and the firmware
2207 	 * support the Asynchronous MCDI protocol extensions in SF-116575-PS.
2208 	 *
2209 	 * The initial call either completes the update synchronously, or
2210 	 * returns RC_PENDING to indicate processing is continuing. In the
2211 	 * latter case, we poll for at least 1 minute, at increasing intervals
2212 	 * (10ms, 100ms, 1s).
2213 	 */
2214 	while (verify_result == MC_CMD_NVRAM_VERIFY_RC_PENDING) {
2215 
2216 		if (poll_retry > EF10_NVRAM_POLL_RETRIES) {
2217 			rc = ETIMEDOUT;
2218 			goto fail1;
2219 		}
2220 		poll_retry++;
2221 
2222 		EFSYS_SLEEP(poll_delay_us);
2223 		if (poll_delay_us < EF10_NVRAM_MAX_POLL_DELAY_US)
2224 			poll_delay_us *= 10;
2225 
2226 		/* Poll for completion of background NVRAM update. */
2227 		verify_result = MC_CMD_NVRAM_VERIFY_RC_UNKNOWN;
2228 
2229 		rc = efx_mcdi_nvram_update_finish(enp, partn, reboot,
2230 		    EFX_NVRAM_UPDATE_FLAGS_POLL, &verify_result);
2231 		if (rc != 0) {
2232 			/* Poll failed, so assume NVRAM update failed. */
2233 			goto fail2;
2234 		}
2235 	}
2236 
2237 	if (verify_resultp != NULL)
2238 		*verify_resultp = verify_result;
2239 
2240 	return (0);
2241 
2242 fail2:
2243 	EFSYS_PROBE(fail2);
2244 fail1:
2245 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2246 
2247 	return (rc);
2248 }
2249 
2250 	__checkReturn		efx_rc_t
2251 ef10_nvram_partn_set_version(
2252 	__in			efx_nic_t *enp,
2253 	__in			uint32_t partn,
2254 	__in_ecount(4)		uint16_t version[4])
2255 {
2256 	struct tlv_partition_version partn_version;
2257 	size_t size;
2258 	efx_rc_t rc;
2259 
2260 	/* Add or modify partition version TLV item */
2261 	partn_version.version_w = __CPU_TO_LE_16(version[0]);
2262 	partn_version.version_x = __CPU_TO_LE_16(version[1]);
2263 	partn_version.version_y = __CPU_TO_LE_16(version[2]);
2264 	partn_version.version_z = __CPU_TO_LE_16(version[3]);
2265 
2266 	size = sizeof (partn_version) - (2 * sizeof (uint32_t));
2267 
2268 	/* Write the version number to all segments in the partition */
2269 	if ((rc = ef10_nvram_partn_write_segment_tlv(enp,
2270 		    NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
2271 		    TLV_TAG_PARTITION_VERSION(partn),
2272 		    (caddr_t)&partn_version.version_w, size, B_TRUE)) != 0)
2273 		goto fail1;
2274 
2275 	return (0);
2276 
2277 fail1:
2278 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2279 
2280 	return (rc);
2281 }
2282 
2283 #endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */
2284 
2285 #if EFSYS_OPT_NVRAM
2286 
2287 typedef struct ef10_parttbl_entry_s {
2288 	unsigned int		partn;
2289 	unsigned int		port_mask;
2290 	efx_nvram_type_t	nvtype;
2291 } ef10_parttbl_entry_t;
2292 
2293 /* Port mask values */
2294 #define	PORT_1		(1u << 1)
2295 #define	PORT_2		(1u << 2)
2296 #define	PORT_3		(1u << 3)
2297 #define	PORT_4		(1u << 4)
2298 #define	PORT_ALL	(0xffffffffu)
2299 
2300 #define	PARTN_MAP_ENTRY(partn, port_mask, nvtype)	\
2301 { (NVRAM_PARTITION_TYPE_##partn), (PORT_##port_mask), (EFX_NVRAM_##nvtype) }
2302 
2303 /* Translate EFX NVRAM types to firmware partition types */
2304 static ef10_parttbl_entry_t hunt_parttbl[] = {
2305 	/*		partn			ports	nvtype */
2306 	PARTN_MAP_ENTRY(MC_FIRMWARE,		ALL,	MC_FIRMWARE),
2307 	PARTN_MAP_ENTRY(MC_FIRMWARE_BACKUP,	ALL,	MC_GOLDEN),
2308 	PARTN_MAP_ENTRY(EXPANSION_ROM,		ALL,	BOOTROM),
2309 	PARTN_MAP_ENTRY(EXPROM_CONFIG_PORT0,	1,	BOOTROM_CFG),
2310 	PARTN_MAP_ENTRY(EXPROM_CONFIG_PORT1,	2,	BOOTROM_CFG),
2311 	PARTN_MAP_ENTRY(EXPROM_CONFIG_PORT2,	3,	BOOTROM_CFG),
2312 	PARTN_MAP_ENTRY(EXPROM_CONFIG_PORT3,	4,	BOOTROM_CFG),
2313 	PARTN_MAP_ENTRY(DYNAMIC_CONFIG,		ALL,	DYNAMIC_CFG),
2314 	PARTN_MAP_ENTRY(FPGA,			ALL,	FPGA),
2315 	PARTN_MAP_ENTRY(FPGA_BACKUP,		ALL,	FPGA_BACKUP),
2316 	PARTN_MAP_ENTRY(LICENSE,		ALL,	LICENSE),
2317 };
2318 
2319 static ef10_parttbl_entry_t medford_parttbl[] = {
2320 	/*		partn			ports	nvtype */
2321 	PARTN_MAP_ENTRY(MC_FIRMWARE,		ALL,	MC_FIRMWARE),
2322 	PARTN_MAP_ENTRY(MC_FIRMWARE_BACKUP,	ALL,	MC_GOLDEN),
2323 	PARTN_MAP_ENTRY(EXPANSION_ROM,		ALL,	BOOTROM),
2324 	PARTN_MAP_ENTRY(EXPROM_CONFIG,		ALL,	BOOTROM_CFG),
2325 	PARTN_MAP_ENTRY(DYNAMIC_CONFIG,		ALL,	DYNAMIC_CFG),
2326 	PARTN_MAP_ENTRY(FPGA,			ALL,	FPGA),
2327 	PARTN_MAP_ENTRY(FPGA_BACKUP,		ALL,	FPGA_BACKUP),
2328 	PARTN_MAP_ENTRY(LICENSE,		ALL,	LICENSE),
2329 	PARTN_MAP_ENTRY(EXPANSION_UEFI,		ALL,	UEFIROM),
2330 	PARTN_MAP_ENTRY(MUM_FIRMWARE,		ALL,	MUM_FIRMWARE),
2331 };
2332 
2333 static ef10_parttbl_entry_t medford2_parttbl[] = {
2334 	/*		partn			ports	nvtype */
2335 	PARTN_MAP_ENTRY(MC_FIRMWARE,		ALL,	MC_FIRMWARE),
2336 	PARTN_MAP_ENTRY(MC_FIRMWARE_BACKUP,	ALL,	MC_GOLDEN),
2337 	PARTN_MAP_ENTRY(EXPANSION_ROM,		ALL,	BOOTROM),
2338 	PARTN_MAP_ENTRY(EXPROM_CONFIG,		ALL,	BOOTROM_CFG),
2339 	PARTN_MAP_ENTRY(DYNAMIC_CONFIG,		ALL,	DYNAMIC_CFG),
2340 	PARTN_MAP_ENTRY(FPGA,			ALL,	FPGA),
2341 	PARTN_MAP_ENTRY(FPGA_BACKUP,		ALL,	FPGA_BACKUP),
2342 	PARTN_MAP_ENTRY(LICENSE,		ALL,	LICENSE),
2343 	PARTN_MAP_ENTRY(EXPANSION_UEFI,		ALL,	UEFIROM),
2344 	PARTN_MAP_ENTRY(MUM_FIRMWARE,		ALL,	MUM_FIRMWARE),
2345 	PARTN_MAP_ENTRY(DYNCONFIG_DEFAULTS,	ALL,	DYNCONFIG_DEFAULTS),
2346 	PARTN_MAP_ENTRY(ROMCONFIG_DEFAULTS,	ALL,	ROMCONFIG_DEFAULTS),
2347 	PARTN_MAP_ENTRY(BUNDLE,			ALL,	BUNDLE),
2348 	PARTN_MAP_ENTRY(BUNDLE_METADATA,	ALL,	BUNDLE_METADATA),
2349 };
2350 
2351 static	__checkReturn		efx_rc_t
ef10_parttbl_get(__in efx_nic_t * enp,__out ef10_parttbl_entry_t ** parttblp,__out size_t * parttbl_rowsp)2352 ef10_parttbl_get(
2353 	__in			efx_nic_t *enp,
2354 	__out			ef10_parttbl_entry_t **parttblp,
2355 	__out			size_t *parttbl_rowsp)
2356 {
2357 	switch (enp->en_family) {
2358 	case EFX_FAMILY_HUNTINGTON:
2359 		*parttblp = hunt_parttbl;
2360 		*parttbl_rowsp = EFX_ARRAY_SIZE(hunt_parttbl);
2361 		break;
2362 
2363 	case EFX_FAMILY_MEDFORD:
2364 		*parttblp = medford_parttbl;
2365 		*parttbl_rowsp = EFX_ARRAY_SIZE(medford_parttbl);
2366 		break;
2367 
2368 	case EFX_FAMILY_MEDFORD2:
2369 		*parttblp = medford2_parttbl;
2370 		*parttbl_rowsp = EFX_ARRAY_SIZE(medford2_parttbl);
2371 		break;
2372 
2373 	default:
2374 		EFSYS_ASSERT(B_FALSE);
2375 		return (EINVAL);
2376 	}
2377 	return (0);
2378 }
2379 
2380 	__checkReturn		efx_rc_t
ef10_nvram_type_to_partn(__in efx_nic_t * enp,__in efx_nvram_type_t type,__out uint32_t * partnp)2381 ef10_nvram_type_to_partn(
2382 	__in			efx_nic_t *enp,
2383 	__in			efx_nvram_type_t type,
2384 	__out			uint32_t *partnp)
2385 {
2386 	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
2387 	ef10_parttbl_entry_t *parttbl = NULL;
2388 	size_t parttbl_rows = 0;
2389 	unsigned int i;
2390 
2391 	EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID);
2392 	EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
2393 	EFSYS_ASSERT(partnp != NULL);
2394 
2395 	if (ef10_parttbl_get(enp, &parttbl, &parttbl_rows) == 0) {
2396 		for (i = 0; i < parttbl_rows; i++) {
2397 			ef10_parttbl_entry_t *entry = &parttbl[i];
2398 
2399 			if ((entry->nvtype == type) &&
2400 			    (entry->port_mask & (1u << emip->emi_port))) {
2401 				*partnp = entry->partn;
2402 				return (0);
2403 			}
2404 		}
2405 	}
2406 
2407 	return (ENOTSUP);
2408 }
2409 
2410 #if EFSYS_OPT_DIAG
2411 
2412 static	__checkReturn		efx_rc_t
ef10_nvram_partn_to_type(__in efx_nic_t * enp,__in uint32_t partn,__out efx_nvram_type_t * typep)2413 ef10_nvram_partn_to_type(
2414 	__in			efx_nic_t *enp,
2415 	__in			uint32_t partn,
2416 	__out			efx_nvram_type_t *typep)
2417 {
2418 	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
2419 	ef10_parttbl_entry_t *parttbl = NULL;
2420 	size_t parttbl_rows = 0;
2421 	unsigned int i;
2422 
2423 	EFSYS_ASSERT(typep != NULL);
2424 
2425 	if (ef10_parttbl_get(enp, &parttbl, &parttbl_rows) == 0) {
2426 		for (i = 0; i < parttbl_rows; i++) {
2427 			ef10_parttbl_entry_t *entry = &parttbl[i];
2428 
2429 			if ((entry->partn == partn) &&
2430 			    (entry->port_mask & (1u << emip->emi_port))) {
2431 				*typep = entry->nvtype;
2432 				return (0);
2433 			}
2434 		}
2435 	}
2436 
2437 	return (ENOTSUP);
2438 }
2439 
2440 	__checkReturn		efx_rc_t
ef10_nvram_test(__in efx_nic_t * enp)2441 ef10_nvram_test(
2442 	__in			efx_nic_t *enp)
2443 {
2444 	efx_nvram_type_t type;
2445 	unsigned int npartns = 0;
2446 	uint32_t *partns = NULL;
2447 	size_t size;
2448 	unsigned int i;
2449 	efx_rc_t rc;
2450 
2451 	/* Read available partitions from NVRAM partition map */
2452 	size = MC_CMD_NVRAM_PARTITIONS_OUT_TYPE_ID_MAXNUM * sizeof (uint32_t);
2453 	EFSYS_KMEM_ALLOC(enp->en_esip, size, partns);
2454 	if (partns == NULL) {
2455 		rc = ENOMEM;
2456 		goto fail1;
2457 	}
2458 
2459 	if ((rc = efx_mcdi_nvram_partitions(enp, (caddr_t)partns, size,
2460 		    &npartns)) != 0) {
2461 		goto fail2;
2462 	}
2463 
2464 	for (i = 0; i < npartns; i++) {
2465 		/* Check if the partition is supported for this port */
2466 		if ((rc = ef10_nvram_partn_to_type(enp, partns[i], &type)) != 0)
2467 			continue;
2468 
2469 		if ((rc = efx_mcdi_nvram_test(enp, partns[i])) != 0)
2470 			goto fail3;
2471 	}
2472 
2473 	EFSYS_KMEM_FREE(enp->en_esip, size, partns);
2474 	return (0);
2475 
2476 fail3:
2477 	EFSYS_PROBE(fail3);
2478 fail2:
2479 	EFSYS_PROBE(fail2);
2480 	EFSYS_KMEM_FREE(enp->en_esip, size, partns);
2481 fail1:
2482 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2483 	return (rc);
2484 }
2485 
2486 #endif	/* EFSYS_OPT_DIAG */
2487 
2488 	__checkReturn		efx_rc_t
2489 ef10_nvram_partn_get_version(
2490 	__in			efx_nic_t *enp,
2491 	__in			uint32_t partn,
2492 	__out			uint32_t *subtypep,
2493 	__out_ecount(4)		uint16_t version[4])
2494 {
2495 	efx_rc_t rc;
2496 
2497 	/* FIXME: get highest partn version from all ports */
2498 	/* FIXME: return partn description if available */
2499 
2500 	if ((rc = efx_mcdi_nvram_metadata(enp, partn, subtypep,
2501 		    version, NULL, 0)) != 0)
2502 		goto fail1;
2503 
2504 	return (0);
2505 
2506 fail1:
2507 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2508 
2509 	return (rc);
2510 }
2511 
2512 	__checkReturn		efx_rc_t
ef10_nvram_partn_rw_start(__in efx_nic_t * enp,__in uint32_t partn,__out size_t * chunk_sizep)2513 ef10_nvram_partn_rw_start(
2514 	__in			efx_nic_t *enp,
2515 	__in			uint32_t partn,
2516 	__out			size_t *chunk_sizep)
2517 {
2518 	efx_nvram_info_t eni = { 0 };
2519 	efx_rc_t rc;
2520 
2521 	if ((rc = ef10_nvram_partn_info(enp, partn, &eni)) != 0)
2522 		goto fail1;
2523 
2524 	if ((rc = ef10_nvram_partn_lock(enp, partn)) != 0)
2525 		goto fail2;
2526 
2527 	if (chunk_sizep != NULL)
2528 		*chunk_sizep = eni.eni_write_size;
2529 
2530 	return (0);
2531 
2532 fail2:
2533 	EFSYS_PROBE(fail2);
2534 fail1:
2535 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2536 
2537 	return (rc);
2538 }
2539 
2540 	__checkReturn		efx_rc_t
ef10_nvram_partn_rw_finish(__in efx_nic_t * enp,__in uint32_t partn,__out_opt uint32_t * verify_resultp)2541 ef10_nvram_partn_rw_finish(
2542 	__in			efx_nic_t *enp,
2543 	__in			uint32_t partn,
2544 	__out_opt		uint32_t *verify_resultp)
2545 {
2546 	efx_rc_t rc;
2547 
2548 	if ((rc = ef10_nvram_partn_unlock(enp, partn, verify_resultp)) != 0)
2549 		goto fail1;
2550 
2551 	return (0);
2552 
2553 fail1:
2554 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
2555 
2556 	return (rc);
2557 }
2558 
2559 #endif	/* EFSYS_OPT_NVRAM */
2560 
2561 #endif	/* EFX_OPTS_EF10() */
2562