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