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