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