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