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