]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/dev/sfxge/common/hunt_nvram.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / dev / sfxge / common / hunt_nvram.c
1 /*-
2  * Copyright (c) 2012-2015 Solarflare Communications Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * The views and conclusions contained in the software and documentation are
27  * those of the authors and should not be interpreted as representing official
28  * policies, either expressed or implied, of the FreeBSD Project.
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include "efsys.h"
35 #include "efx.h"
36 #include "efx_types.h"
37 #include "efx_regs.h"
38 #include "efx_impl.h"
39
40 #if EFSYS_OPT_HUNTINGTON
41
42 #if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
43
44 #include "ef10_tlv_layout.h"
45
46 /* Cursor for TLV partition format */
47 typedef struct tlv_cursor_s {
48         uint32_t        *block;                 /* Base of data block */
49         uint32_t        *current;               /* Cursor position */
50         uint32_t        *end;                   /* End tag position */
51         uint32_t        *limit;                 /* Last dword of data block */
52 } tlv_cursor_t;
53
54 static  __checkReturn           int
55 tlv_validate_state(
56         __in                    tlv_cursor_t *cursor);
57
58
59 /*
60  * Operations on TLV formatted partition data.
61  */
62 static                          uint32_t
63 tlv_tag(
64         __in    tlv_cursor_t    *cursor)
65 {
66         uint32_t dword, tag;
67
68         dword = cursor->current[0];
69         tag = __LE_TO_CPU_32(dword);
70
71         return (tag);
72 }
73
74 static                          size_t
75 tlv_length(
76         __in    tlv_cursor_t    *cursor)
77 {
78         uint32_t dword, length;
79
80         if (tlv_tag(cursor) == TLV_TAG_END)
81                 return (0);
82
83         dword = cursor->current[1];
84         length = __LE_TO_CPU_32(dword);
85
86         return ((size_t)length);
87 }
88
89 static                          uint8_t *
90 tlv_value(
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[2]));
97 }
98
99 static                          uint8_t *
100 tlv_item(
101         __in    tlv_cursor_t    *cursor)
102 {
103         if (tlv_tag(cursor) == TLV_TAG_END)
104                 return (NULL);
105
106         return ((uint8_t *)cursor->current);
107 }
108
109 /*
110  * TLV item DWORD length is tag + length + value (rounded up to DWORD)
111  * equivalent to tlv_n_words_for_len in mc-comms tlv.c
112  */
113 #define TLV_DWORD_COUNT(length) \
114         (1 + 1 + (((length) + sizeof (uint32_t) - 1) / sizeof (uint32_t)))
115
116
117 static                          uint32_t *
118 tlv_next_item_ptr(
119         __in    tlv_cursor_t    *cursor)
120 {
121         uint32_t length;
122
123         length = tlv_length(cursor);
124
125         return (cursor->current + TLV_DWORD_COUNT(length));
126 }
127
128 static                          int
129 tlv_advance(
130         __in    tlv_cursor_t    *cursor)
131 {
132         int rc;
133
134         if ((rc = tlv_validate_state(cursor)) != 0)
135                 goto fail1;
136
137         if (cursor->current == cursor->end) {
138                 /* No more tags after END tag */
139                 cursor->current = NULL;
140                 rc = ENOENT;
141                 goto fail2;
142         }
143
144         /* Advance to next item and validate */
145         cursor->current = tlv_next_item_ptr(cursor);
146
147         if ((rc = tlv_validate_state(cursor)) != 0)
148                 goto fail3;
149
150         return (0);
151
152 fail3:
153         EFSYS_PROBE(fail3);
154 fail2:
155         EFSYS_PROBE(fail2);
156 fail1:
157         EFSYS_PROBE1(fail1, int, rc);
158
159         return (rc);
160 }
161
162 static                          int
163 tlv_rewind(
164         __in    tlv_cursor_t    *cursor)
165 {
166         int rc;
167
168         cursor->current = cursor->block;
169
170         if ((rc = tlv_validate_state(cursor)) != 0)
171                 goto fail1;
172
173         return (0);
174
175 fail1:
176         EFSYS_PROBE1(fail1, int, rc);
177
178         return (rc);
179 }
180
181 static                          int
182 tlv_find(
183         __in    tlv_cursor_t    *cursor,
184         __in    uint32_t        tag)
185 {
186         int rc;
187
188         rc = tlv_rewind(cursor);
189         while (rc == 0) {
190                 if (tlv_tag(cursor) == tag)
191                         break;
192
193                 rc = tlv_advance(cursor);
194         }
195         return (rc);
196 }
197
198 static  __checkReturn           int
199 tlv_validate_state(
200         __in    tlv_cursor_t    *cursor)
201 {
202         int rc;
203
204         /* Check cursor position */
205         if (cursor->current < cursor->block) {
206                 rc = EINVAL;
207                 goto fail1;
208         }
209         if (cursor->current > cursor->limit) {
210                 rc = EINVAL;
211                 goto fail2;
212         }
213
214         if (tlv_tag(cursor) != TLV_TAG_END) {
215                 /* Check current item has space for tag and length */
216                 if (cursor->current > (cursor->limit - 2)) {
217                         cursor->current = NULL;
218                         rc = EFAULT;
219                         goto fail3;
220                 }
221
222                 /* Check we have value data for current item and another tag */
223                 if (tlv_next_item_ptr(cursor) > (cursor->limit - 1)) {
224                         cursor->current = NULL;
225                         rc = EFAULT;
226                         goto fail4;
227                 }
228         }
229
230         return (0);
231
232 fail4:
233         EFSYS_PROBE(fail4);
234 fail3:
235         EFSYS_PROBE(fail3);
236 fail2:
237         EFSYS_PROBE(fail2);
238 fail1:
239         EFSYS_PROBE1(fail1, int, rc);
240
241         return (rc);
242 }
243
244 static                          int
245 tlv_init_cursor(
246         __in    tlv_cursor_t    *cursor,
247         __in    uint32_t        *block,
248         __in    uint32_t        *limit)
249 {
250         cursor->block   = block;
251         cursor->limit   = limit;
252
253         cursor->current = cursor->block;
254         cursor->end     = NULL;
255
256         return (tlv_validate_state(cursor));
257 }
258
259 static                          int
260 tlv_init_cursor_from_size(
261         __in    tlv_cursor_t    *cursor,
262         __in    uint8_t *block,
263         __in    size_t          size)
264 {
265         uint32_t *limit;
266         limit = (uint32_t *)(block + size - sizeof (uint32_t));
267         return (tlv_init_cursor(cursor, (uint32_t *)block, limit));
268 }
269
270 static                          int
271 tlv_require_end(
272         __in    tlv_cursor_t    *cursor)
273 {
274         uint32_t *pos;
275         int rc;
276
277         if (cursor->end == NULL) {
278                 pos = cursor->current;
279                 if ((rc = tlv_find(cursor, TLV_TAG_END)) != 0)
280                         goto fail1;
281
282                 cursor->end = cursor->current;
283                 cursor->current = pos;
284         }
285
286         return (0);
287
288 fail1:
289         EFSYS_PROBE1(fail1, int, rc);
290
291         return (rc);
292 }
293
294 static                          size_t
295 tlv_block_length_used(
296         __in    tlv_cursor_t    *cursor)
297 {
298         int rc;
299
300         if ((rc = tlv_validate_state(cursor)) != 0)
301                 goto fail1;
302
303         if ((rc = tlv_require_end(cursor)) != 0)
304                 goto fail2;
305
306         /* Return space used (including the END tag) */
307         return (cursor->end + 1 - cursor->block) * sizeof (uint32_t);
308
309 fail2:
310         EFSYS_PROBE(fail2);
311 fail1:
312         EFSYS_PROBE1(fail1, int, rc);
313
314         return (0);
315 }
316
317
318 static  __checkReturn           uint32_t *
319 tlv_write(
320         __in                    tlv_cursor_t *cursor,
321         __in                    uint32_t tag,
322         __in_bcount(size)       uint8_t *data,
323         __in                    size_t size)
324 {
325         uint32_t len = size;
326         uint32_t *ptr;
327
328         ptr = cursor->current;
329
330         *ptr++ = __CPU_TO_LE_32(tag);
331         *ptr++ = __CPU_TO_LE_32(len);
332
333         if (len > 0) {
334                 ptr[(len - 1) / sizeof (uint32_t)] = 0;
335                 memcpy(ptr, data, len);
336                 ptr += P2ROUNDUP(len, sizeof (uint32_t)) / sizeof (*ptr);
337         }
338
339         return (ptr);
340 }
341
342 static  __checkReturn           int
343 tlv_insert(
344         __in    tlv_cursor_t    *cursor,
345         __in    uint32_t        tag,
346         __in    uint8_t         *data,
347         __in    size_t          size)
348 {
349         unsigned int delta;
350         int rc;
351
352         if ((rc = tlv_validate_state(cursor)) != 0)
353                 goto fail1;
354
355         if ((rc = tlv_require_end(cursor)) != 0)
356                 goto fail2;
357
358         if (tag == TLV_TAG_END) {
359                 rc = EINVAL;
360                 goto fail3;
361         }
362
363         delta = TLV_DWORD_COUNT(size);
364         if (cursor->end + 1 + delta > cursor->limit) {
365                 rc = ENOSPC;
366                 goto fail4;
367         }
368
369         /* Move data up: new space at cursor->current */
370         memmove(cursor->current + delta, cursor->current,
371             (cursor->end + 1 - cursor->current) * sizeof (uint32_t));
372
373         /* Adjust the end pointer */
374         cursor->end += delta;
375
376         /* Write new TLV item */
377         tlv_write(cursor, tag, data, size);
378
379         return (0);
380
381 fail4:
382         EFSYS_PROBE(fail4);
383 fail3:
384         EFSYS_PROBE(fail3);
385 fail2:
386         EFSYS_PROBE(fail2);
387 fail1:
388         EFSYS_PROBE1(fail1, int, rc);
389
390         return (rc);
391 }
392
393 static  __checkReturn           int
394 tlv_modify(
395         __in    tlv_cursor_t    *cursor,
396         __in    uint32_t        tag,
397         __in    uint8_t         *data,
398         __in    size_t          size)
399 {
400         uint32_t *pos;
401         unsigned int old_ndwords;
402         unsigned int new_ndwords;
403         unsigned int delta;
404         int rc;
405
406         if ((rc = tlv_validate_state(cursor)) != 0)
407                 goto fail1;
408
409         if (tlv_tag(cursor) == TLV_TAG_END) {
410                 rc = EINVAL;
411                 goto fail2;
412         }
413         if (tlv_tag(cursor) != tag) {
414                 rc = EINVAL;
415                 goto fail3;
416         }
417
418         old_ndwords = TLV_DWORD_COUNT(tlv_length(cursor));
419         new_ndwords = TLV_DWORD_COUNT(size);
420
421         if ((rc = tlv_require_end(cursor)) != 0)
422                 goto fail4;
423
424         if (new_ndwords > old_ndwords) {
425                 /* Expand space used for TLV item */
426                 delta = new_ndwords - old_ndwords;
427                 pos = cursor->current + old_ndwords;
428
429                 if (cursor->end + 1 + delta > cursor->limit) {
430                         rc = ENOSPC;
431                         goto fail5;
432                 }
433
434                 /* Move up: new space at (cursor->current + old_ndwords) */
435                 memmove(pos + delta, pos,
436                     (cursor->end + 1 - pos) * sizeof (uint32_t));
437
438                 /* Adjust the end pointer */
439                 cursor->end += delta;
440
441         } else if (new_ndwords < old_ndwords) {
442                 /* Shrink space used for TLV item */
443                 delta = old_ndwords - new_ndwords;
444                 pos = cursor->current + new_ndwords;
445
446                 /* Move down: remove words at (cursor->current + new_ndwords) */
447                 memmove(pos, pos + delta,
448                     (cursor->end + 1 - pos) * sizeof (uint32_t));
449
450                 /* Zero the new space at the end of the TLV chain */
451                 memset(cursor->end + 1 - delta, 0, delta * sizeof (uint32_t));
452
453                 /* Adjust the end pointer */
454                 cursor->end -= delta;
455         }
456
457         /* Write new data */
458         tlv_write(cursor, tag, data, size);
459
460         return (0);
461
462 fail5:
463         EFSYS_PROBE(fail5);
464 fail4:
465         EFSYS_PROBE(fail4);
466 fail3:
467         EFSYS_PROBE(fail3);
468 fail2:
469         EFSYS_PROBE(fail2);
470 fail1:
471         EFSYS_PROBE1(fail1, int, rc);
472
473         return (rc);
474 }
475
476 /* Validate TLV formatted partition contents (before writing to flash) */
477         __checkReturn           int
478 efx_nvram_tlv_validate(
479         __in                    efx_nic_t *enp,
480         __in                    uint32_t partn,
481         __in_bcount(partn_size) caddr_t partn_data,
482         __in                    size_t partn_size)
483 {
484         tlv_cursor_t cursor;
485         struct tlv_partition_header *header;
486         struct tlv_partition_trailer *trailer;
487         size_t total_length;
488         uint32_t cksum;
489         int pos;
490         int rc;
491
492         EFX_STATIC_ASSERT(sizeof (*header) <= HUNTINGTON_NVRAM_CHUNK);
493
494         if ((partn_data == NULL) || (partn_size == 0)) {
495                 rc = EINVAL;
496                 goto fail1;
497         }
498
499         /* The partition header must be the first item (at offset zero) */
500         if ((rc = tlv_init_cursor_from_size(&cursor, partn_data,
501                     partn_size)) != 0) {
502                 rc = EFAULT;
503                 goto fail2;
504         }
505         if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {
506                 rc = EINVAL;
507                 goto fail3;
508         }
509         header = (struct tlv_partition_header *)tlv_item(&cursor);
510
511         /* Check TLV partition length (includes the END tag) */
512         total_length = __LE_TO_CPU_32(header->total_length);
513         if (total_length > partn_size) {
514                 rc = EFBIG;
515                 goto fail4;
516         }
517
518         /* Check partition ends with PARTITION_TRAILER and END tags */
519         if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) {
520                 rc = EINVAL;
521                 goto fail5;
522         }
523         trailer = (struct tlv_partition_trailer *)tlv_item(&cursor);
524
525         if ((rc = tlv_advance(&cursor)) != 0) {
526                 rc = EINVAL;
527                 goto fail6;
528         }
529         if (tlv_tag(&cursor) != TLV_TAG_END) {
530                 rc = EINVAL;
531                 goto fail7;
532         }
533
534         /* Check generation counts are consistent */
535         if (trailer->generation != header->generation) {
536                 rc = EINVAL;
537                 goto fail8;
538         }
539
540         /* Verify partition checksum */
541         cksum = 0;
542         for (pos = 0; (size_t)pos < total_length; pos += sizeof (uint32_t)) {
543                 cksum += *((uint32_t *)(partn_data + pos));
544         }
545         if (cksum != 0) {
546                 rc = EINVAL;
547                 goto fail9;
548         }
549
550         return (0);
551
552 fail9:
553         EFSYS_PROBE(fail9);
554 fail8:
555         EFSYS_PROBE(fail8);
556 fail7:
557         EFSYS_PROBE(fail7);
558 fail6:
559         EFSYS_PROBE(fail6);
560 fail5:
561         EFSYS_PROBE(fail5);
562 fail4:
563         EFSYS_PROBE(fail4);
564 fail3:
565         EFSYS_PROBE(fail3);
566 fail2:
567         EFSYS_PROBE(fail2);
568 fail1:
569         EFSYS_PROBE1(fail1, int, rc);
570
571         return (rc);
572 }
573
574 /* Read and validate an entire TLV formatted partition */
575 static  __checkReturn           int
576 hunt_nvram_read_tlv_partition(
577         __in                    efx_nic_t *enp,
578         __in                    uint32_t partn,
579         __in_bcount(partn_size) caddr_t partn_data,
580         __in                    size_t partn_size)
581 {
582         tlv_cursor_t cursor;
583         struct tlv_partition_header *header;
584         struct tlv_partition_trailer *trailer;
585         size_t total_length;
586         uint32_t cksum;
587         int pos;
588         int rc;
589
590         EFX_STATIC_ASSERT(sizeof (*header) <= HUNTINGTON_NVRAM_CHUNK);
591
592         if ((partn_data == NULL) || (partn_size == 0)) {
593                 rc = EINVAL;
594                 goto fail1;
595         }
596
597         /* Read initial chunk of partition */
598         if ((rc = hunt_nvram_partn_read(enp, partn, 0, partn_data,
599                     HUNTINGTON_NVRAM_CHUNK)) != 0) {
600                 goto fail2;
601         }
602
603         /* The partition header must be the first item (at offset zero) */
604         if ((rc = tlv_init_cursor_from_size(&cursor, partn_data,
605                     partn_size)) != 0) {
606                 rc = EFAULT;
607                 goto fail3;
608         }
609         if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {
610                 rc = EINVAL;
611                 goto fail4;
612         }
613         header = (struct tlv_partition_header *)tlv_item(&cursor);
614
615         /* Check TLV partition length (includes the END tag) */
616         total_length = __LE_TO_CPU_32(header->total_length);
617         if (total_length > partn_size) {
618                 rc = EFBIG;
619                 goto fail5;
620         }
621
622         /* Read the remaining partition content */
623         if (total_length > HUNTINGTON_NVRAM_CHUNK) {
624                 if ((rc = hunt_nvram_partn_read(enp, partn,
625                             HUNTINGTON_NVRAM_CHUNK,
626                             partn_data + HUNTINGTON_NVRAM_CHUNK,
627                             total_length - HUNTINGTON_NVRAM_CHUNK)) != 0)
628                         goto fail6;
629         }
630
631         /* Check partition ends with PARTITION_TRAILER and END tags */
632         if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) {
633                 rc = EINVAL;
634                 goto fail7;
635         }
636         trailer = (struct tlv_partition_trailer *)tlv_item(&cursor);
637
638         if ((rc = tlv_advance(&cursor)) != 0) {
639                 rc = EINVAL;
640                 goto fail8;
641         }
642         if (tlv_tag(&cursor) != TLV_TAG_END) {
643                 rc = EINVAL;
644                 goto fail9;
645         }
646
647         /* Check data read from partition is consistent */
648         if (trailer->generation != header->generation) {
649                 /*
650                  * The partition data may have been modified between successive
651                  * MCDI NVRAM_READ requests by the MC or another PCI function.
652                  *
653                  * The caller must retry to obtain consistent partition data.
654                  */
655                 rc = EAGAIN;
656                 goto fail10;
657         }
658
659         /* Verify partition checksum */
660         cksum = 0;
661         for (pos = 0; (size_t)pos < total_length; pos += sizeof (uint32_t)) {
662                 cksum += *((uint32_t *)(partn_data + pos));
663         }
664         if (cksum != 0) {
665                 rc = EINVAL;
666                 goto fail11;
667         }
668
669         return (0);
670
671 fail11:
672         EFSYS_PROBE(fail11);
673 fail10:
674         EFSYS_PROBE(fail10);
675 fail9:
676         EFSYS_PROBE(fail9);
677 fail8:
678         EFSYS_PROBE(fail8);
679 fail7:
680         EFSYS_PROBE(fail7);
681 fail6:
682         EFSYS_PROBE(fail6);
683 fail5:
684         EFSYS_PROBE(fail5);
685 fail4:
686         EFSYS_PROBE(fail4);
687 fail3:
688         EFSYS_PROBE(fail3);
689 fail2:
690         EFSYS_PROBE(fail2);
691 fail1:
692         EFSYS_PROBE1(fail1, int, rc);
693
694         return (rc);
695 }
696
697 /*
698  * Read a single TLV item from a host memory
699  * buffer containing a TLV formatted partition.
700  */
701         __checkReturn           int
702 hunt_nvram_buf_read_tlv(
703         __in                            efx_nic_t *enp,
704         __in_bcount(partn_size)         caddr_t partn_data,
705         __in                            size_t partn_size,
706         __in                            uint32_t tag,
707         __deref_out_bcount_opt(*sizep)  caddr_t *datap,
708         __out                           size_t *sizep)
709 {
710         tlv_cursor_t cursor;
711         caddr_t data;
712         size_t length;
713         caddr_t value;
714         int rc;
715
716         if ((partn_data == NULL) || (partn_size == 0)) {
717                 rc = EINVAL;
718                 goto fail1;
719         }
720
721         /* Find requested TLV tag in partition data */
722         if ((rc = tlv_init_cursor_from_size(&cursor, partn_data,
723                     partn_size)) != 0) {
724                 rc = EFAULT;
725                 goto fail2;
726         }
727         if ((rc = tlv_find(&cursor, tag)) != 0) {
728                 rc = ENOENT;
729                 goto fail3;
730         }
731         value = tlv_value(&cursor);
732         length = tlv_length(&cursor);
733
734         if (length == 0)
735                 data = NULL;
736         else {
737                 /* Copy out data from TLV item */
738                 EFSYS_KMEM_ALLOC(enp->en_esip, length, data);
739                 if (data == NULL) {
740                         rc = ENOMEM;
741                         goto fail4;
742                 }
743                 memcpy(data, value, length);
744         }
745
746         *datap = data;
747         *sizep = length;
748
749         return (0);
750
751 fail4:
752         EFSYS_PROBE(fail4);
753 fail3:
754         EFSYS_PROBE(fail3);
755 fail2:
756         EFSYS_PROBE(fail2);
757 fail1:
758         EFSYS_PROBE1(fail1, int, rc);
759
760         return (rc);
761 }
762
763
764
765 /* Read a single TLV item from a TLV formatted partition */
766         __checkReturn           int
767 hunt_nvram_partn_read_tlv(
768         __in                            efx_nic_t *enp,
769         __in                            uint32_t partn,
770         __in                            uint32_t tag,
771         __deref_out_bcount_opt(*sizep)  caddr_t *datap,
772         __out                           size_t *sizep)
773 {
774         caddr_t partn_data = NULL;
775         size_t partn_size = 0;
776         size_t length;
777         caddr_t data;
778         int retry;
779         int rc;
780
781         /* Allocate sufficient memory for the entire partition */
782         if ((rc = hunt_nvram_partn_size(enp, partn, &partn_size)) != 0)
783                 goto fail1;
784
785         if (partn_size == 0) {
786                 rc = ENOENT;
787                 goto fail2;
788         }
789
790         EFSYS_KMEM_ALLOC(enp->en_esip, partn_size, partn_data);
791         if (partn_data == NULL) {
792                 rc = ENOMEM;
793                 goto fail3;
794         }
795
796         /*
797          * Read the entire TLV partition. Retry until consistent partition
798          * contents are returned. Inconsistent data may be read if:
799          *  a) the partition contents are invalid
800          *  b) the MC has rebooted while we were reading the partition
801          *  c) the partition has been modified while we were reading it
802          * Limit retry attempts to ensure forward progress.
803          */
804         retry = 10;
805         do {
806                 rc = hunt_nvram_read_tlv_partition(enp, partn,
807                     partn_data, partn_size);
808         } while ((rc == EAGAIN) && (--retry > 0));
809
810         if (rc != 0) {
811                 /* Failed to obtain consistent partition data */
812                 goto fail4;
813         }
814
815         if ((rc = hunt_nvram_buf_read_tlv(enp, partn_data, partn_size,
816                     tag, &data, &length)) != 0)
817                 goto fail5;
818
819         EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data);
820
821         *datap = data;
822         *sizep = length;
823
824         return (0);
825
826 fail5:
827         EFSYS_PROBE(fail5);
828 fail4:
829         EFSYS_PROBE(fail4);
830
831         EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data);
832 fail3:
833         EFSYS_PROBE(fail3);
834 fail2:
835         EFSYS_PROBE(fail2);
836 fail1:
837         EFSYS_PROBE1(fail1, int, rc);
838
839         return (rc);
840 }
841
842 /*
843  * Add or update a single TLV item in a host memory buffer containing a TLV
844  * formatted partition.
845  */
846         __checkReturn           int
847 hunt_nvram_buf_write_tlv(
848         __inout_bcount(partn_size)      caddr_t partn_data,
849         __in                            size_t partn_size,
850         __in                            uint32_t tag,
851         __in_bcount(tag_size)           caddr_t tag_data,
852         __in                            size_t tag_size,
853         __out                           size_t *total_lengthp)
854 {
855         tlv_cursor_t cursor;
856         struct tlv_partition_header *header;
857         struct tlv_partition_trailer *trailer;
858         uint32_t generation;
859         uint32_t cksum;
860         int pos;
861         int rc;
862
863         /* The partition header must be the first item (at offset zero) */
864         if ((rc = tlv_init_cursor_from_size(&cursor, partn_data,
865                         partn_size)) != 0) {
866                 rc = EFAULT;
867                 goto fail1;
868         }
869         if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) {
870                 rc = EINVAL;
871                 goto fail2;
872         }
873         header = (struct tlv_partition_header *)tlv_item(&cursor);
874
875         /* Update the TLV chain to contain the new data */
876         if ((rc = tlv_find(&cursor, tag)) == 0) {
877                 /* Modify existing TLV item */
878                 if ((rc = tlv_modify(&cursor, tag,
879                             tag_data, tag_size)) != 0)
880                         goto fail3;
881         } else {
882                 /* Insert a new TLV item before the PARTITION_TRAILER */
883                 rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER);
884                 if (rc != 0) {
885                         rc = EINVAL;
886                         goto fail4;
887                 }
888                 if ((rc = tlv_insert(&cursor, tag,
889                             tag_data, tag_size)) != 0) {
890                         rc = EINVAL;
891                         goto fail5;
892                 }
893         }
894
895         /* Find the trailer tag */
896         if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) {
897                 rc = EINVAL;
898                 goto fail6;
899         }
900         trailer = (struct tlv_partition_trailer *)tlv_item(&cursor);
901
902         /* Update PARTITION_HEADER and PARTITION_TRAILER fields */
903         *total_lengthp = tlv_block_length_used(&cursor);
904         EFSYS_ASSERT3U(*total_lengthp, <=, partn_size);
905         generation = __LE_TO_CPU_32(header->generation) + 1;
906
907         header->total_length    = __CPU_TO_LE_32(*total_lengthp);
908         header->generation      = __CPU_TO_LE_32(generation);
909         trailer->generation     = __CPU_TO_LE_32(generation);
910
911         /* Recompute PARTITION_TRAILER checksum */
912         trailer->checksum = 0;
913         cksum = 0;
914         for (pos = 0; (size_t)pos < *total_lengthp; pos += sizeof (uint32_t)) {
915                 cksum += *((uint32_t *)(partn_data + pos));
916         }
917         trailer->checksum = ~cksum + 1;
918
919         return (0);
920
921 fail6:
922         EFSYS_PROBE(fail6);
923 fail5:
924         EFSYS_PROBE(fail5);
925 fail4:
926         EFSYS_PROBE(fail4);
927 fail3:
928         EFSYS_PROBE(fail3);
929 fail2:
930         EFSYS_PROBE(fail2);
931 fail1:
932         EFSYS_PROBE1(fail1, int, rc);
933
934         return (rc);
935 }
936
937 /* Add or update a single TLV item in a TLV formatted partition */
938         __checkReturn           int
939 hunt_nvram_partn_write_tlv(
940         __in                    efx_nic_t *enp,
941         __in                    uint32_t partn,
942         __in                    uint32_t tag,
943         __in_bcount(size)       caddr_t data,
944         __in                    size_t size)
945 {
946         size_t partn_size;
947         caddr_t partn_data;
948         size_t total_length;
949         int rc;
950
951         EFSYS_ASSERT3U(partn, ==, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG);
952
953         /* Allocate sufficient memory for the entire partition */
954         if ((rc = hunt_nvram_partn_size(enp, partn, &partn_size)) != 0)
955                 goto fail1;
956
957         EFSYS_KMEM_ALLOC(enp->en_esip, partn_size, partn_data);
958         if (partn_data == NULL) {
959                 rc = ENOMEM;
960                 goto fail2;
961         }
962
963         /* Lock the partition */
964         if ((rc = hunt_nvram_partn_lock(enp, partn)) != 0)
965                 goto fail3;
966
967         /* Read the partition contents (no need to retry when locked). */
968         if ((rc = hunt_nvram_read_tlv_partition(enp, partn,
969                     partn_data, partn_size)) != 0) {
970                 /* Failed to obtain consistent partition data */
971                 goto fail4;
972         }
973
974         /* Update the contents in memory */
975         if ((rc = hunt_nvram_buf_write_tlv(partn_data, partn_size,
976                     tag, data, size, &total_length)) != 0)
977                 goto fail5;
978
979         /* Erase the whole partition */
980         if ((rc = hunt_nvram_partn_erase(enp, partn, 0, partn_size)) != 0)
981                 goto fail6;
982
983         /* Write new partition contents to NVRAM */
984         if ((rc = hunt_nvram_partn_write(enp, partn, 0, partn_data,
985                     total_length)) != 0)
986                 goto fail7;
987
988         /* Unlock the partition */
989         hunt_nvram_partn_unlock(enp, partn);
990
991         EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data);
992
993         return (0);
994
995 fail7:
996         EFSYS_PROBE(fail7);
997 fail6:
998         EFSYS_PROBE(fail6);
999 fail5:
1000         EFSYS_PROBE(fail5);
1001 fail4:
1002         EFSYS_PROBE(fail4);
1003
1004         hunt_nvram_partn_unlock(enp, partn);
1005 fail3:
1006         EFSYS_PROBE(fail3);
1007
1008         EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data);
1009 fail2:
1010         EFSYS_PROBE(fail2);
1011 fail1:
1012         EFSYS_PROBE1(fail1, int, rc);
1013
1014         return (rc);
1015 }
1016
1017         __checkReturn           int
1018 hunt_nvram_partn_size(
1019         __in                    efx_nic_t *enp,
1020         __in                    unsigned int partn,
1021         __out                   size_t *sizep)
1022 {
1023         int rc;
1024
1025         if ((rc = efx_mcdi_nvram_info(enp, partn, sizep, NULL, NULL)) != 0)
1026                 goto fail1;
1027
1028         return (0);
1029
1030 fail1:
1031         EFSYS_PROBE1(fail1, int, rc);
1032
1033         return (rc);
1034 }
1035
1036         __checkReturn           int
1037 hunt_nvram_partn_lock(
1038         __in                    efx_nic_t *enp,
1039         __in                    unsigned int partn)
1040 {
1041         int rc;
1042
1043         if ((rc = efx_mcdi_nvram_update_start(enp, partn)) != 0)
1044                 goto fail1;
1045
1046         return (0);
1047
1048 fail1:
1049         EFSYS_PROBE1(fail1, int, rc);
1050
1051         return (rc);
1052 }
1053
1054         __checkReturn           int
1055 hunt_nvram_partn_read(
1056         __in                    efx_nic_t *enp,
1057         __in                    unsigned int partn,
1058         __in                    unsigned int offset,
1059         __out_bcount(size)      caddr_t data,
1060         __in                    size_t size)
1061 {
1062         size_t chunk;
1063         int rc;
1064
1065         while (size > 0) {
1066                 chunk = MIN(size, HUNTINGTON_NVRAM_CHUNK);
1067
1068                 if ((rc = efx_mcdi_nvram_read(enp, partn, offset,
1069                             data, chunk)) != 0) {
1070                         goto fail1;
1071                 }
1072
1073                 size -= chunk;
1074                 data += chunk;
1075                 offset += chunk;
1076         }
1077
1078         return (0);
1079
1080 fail1:
1081         EFSYS_PROBE1(fail1, int, rc);
1082
1083         return (rc);
1084 }
1085
1086         __checkReturn           int
1087 hunt_nvram_partn_erase(
1088         __in                    efx_nic_t *enp,
1089         __in                    unsigned int partn,
1090         __in                    unsigned int offset,
1091         __in                    size_t size)
1092 {
1093         int rc;
1094
1095         if ((rc = efx_mcdi_nvram_erase(enp, partn, offset, size)) != 0)
1096                 goto fail1;
1097
1098         return (0);
1099
1100 fail1:
1101         EFSYS_PROBE1(fail1, int, rc);
1102
1103         return (rc);
1104 }
1105
1106         __checkReturn           int
1107 hunt_nvram_partn_write(
1108         __in                    efx_nic_t *enp,
1109         __in                    unsigned int partn,
1110         __in                    unsigned int offset,
1111         __out_bcount(size)      caddr_t data,
1112         __in                    size_t size)
1113 {
1114         size_t chunk;
1115         int rc;
1116
1117         while (size > 0) {
1118                 chunk = MIN(size, HUNTINGTON_NVRAM_CHUNK);
1119
1120                 if ((rc = efx_mcdi_nvram_write(enp, partn, offset,
1121                             data, chunk)) != 0) {
1122                         goto fail1;
1123                 }
1124
1125                 size -= chunk;
1126                 data += chunk;
1127                 offset += chunk;
1128         }
1129
1130         return (0);
1131
1132 fail1:
1133         EFSYS_PROBE1(fail1, int, rc);
1134
1135         return (rc);
1136 }
1137
1138                                 void
1139 hunt_nvram_partn_unlock(
1140         __in                    efx_nic_t *enp,
1141         __in                    unsigned int partn)
1142 {
1143         boolean_t reboot;
1144         int rc;
1145
1146         reboot = B_FALSE;
1147         if ((rc = efx_mcdi_nvram_update_finish(enp, partn, reboot)) != 0)
1148                 goto fail1;
1149
1150         return;
1151
1152 fail1:
1153         EFSYS_PROBE1(fail1, int, rc);
1154 }
1155
1156         __checkReturn           int
1157 hunt_nvram_partn_set_version(
1158         __in                    efx_nic_t *enp,
1159         __in                    unsigned int partn,
1160         __in_ecount(4)          uint16_t version[4])
1161 {
1162         struct tlv_partition_version partn_version;
1163         size_t size;
1164         int rc;
1165
1166         /* Add or modify partition version TLV item */
1167         partn_version.version_w = __CPU_TO_LE_16(version[0]);
1168         partn_version.version_x = __CPU_TO_LE_16(version[1]);
1169         partn_version.version_y = __CPU_TO_LE_16(version[2]);
1170         partn_version.version_z = __CPU_TO_LE_16(version[3]);
1171
1172         size = sizeof (partn_version) - (2 * sizeof (uint32_t));
1173
1174         if ((rc = hunt_nvram_partn_write_tlv(enp,
1175                     NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,
1176                     TLV_TAG_PARTITION_VERSION(partn),
1177                     (caddr_t)&partn_version.version_w, size)) != 0)
1178                 goto fail1;
1179
1180         return (0);
1181
1182 fail1:
1183         EFSYS_PROBE1(fail1, int, rc);
1184
1185         return (rc);
1186 }
1187
1188 #endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */
1189
1190 #if EFSYS_OPT_NVRAM
1191
1192 typedef struct hunt_parttbl_entry_s {
1193         unsigned int            partn;
1194         unsigned int            port;
1195         efx_nvram_type_t        nvtype;
1196 } hunt_parttbl_entry_t;
1197
1198 /* Translate EFX NVRAM types to firmware partition types */
1199 static hunt_parttbl_entry_t hunt_parttbl[] = {
1200         {NVRAM_PARTITION_TYPE_MC_FIRMWARE,         1, EFX_NVRAM_MC_FIRMWARE},
1201         {NVRAM_PARTITION_TYPE_MC_FIRMWARE,         2, EFX_NVRAM_MC_FIRMWARE},
1202         {NVRAM_PARTITION_TYPE_MC_FIRMWARE,         3, EFX_NVRAM_MC_FIRMWARE},
1203         {NVRAM_PARTITION_TYPE_MC_FIRMWARE,         4, EFX_NVRAM_MC_FIRMWARE},
1204         {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP,  1, EFX_NVRAM_MC_GOLDEN},
1205         {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP,  2, EFX_NVRAM_MC_GOLDEN},
1206         {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP,  3, EFX_NVRAM_MC_GOLDEN},
1207         {NVRAM_PARTITION_TYPE_MC_FIRMWARE_BACKUP,  4, EFX_NVRAM_MC_GOLDEN},
1208         {NVRAM_PARTITION_TYPE_EXPANSION_ROM,       1, EFX_NVRAM_BOOTROM},
1209         {NVRAM_PARTITION_TYPE_EXPANSION_ROM,       2, EFX_NVRAM_BOOTROM},
1210         {NVRAM_PARTITION_TYPE_EXPANSION_ROM,       3, EFX_NVRAM_BOOTROM},
1211         {NVRAM_PARTITION_TYPE_EXPANSION_ROM,       4, EFX_NVRAM_BOOTROM},
1212         {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT0, 1, EFX_NVRAM_BOOTROM_CFG},
1213         {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT1, 2, EFX_NVRAM_BOOTROM_CFG},
1214         {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT2, 3, EFX_NVRAM_BOOTROM_CFG},
1215         {NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT3, 4, EFX_NVRAM_BOOTROM_CFG},
1216         {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,      1, EFX_NVRAM_DYNAMIC_CFG},
1217         {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,      2, EFX_NVRAM_DYNAMIC_CFG},
1218         {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,      3, EFX_NVRAM_DYNAMIC_CFG},
1219         {NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG,      4, EFX_NVRAM_DYNAMIC_CFG}
1220 };
1221
1222 static  __checkReturn           hunt_parttbl_entry_t *
1223 hunt_parttbl_entry(
1224         __in                    efx_nic_t *enp,
1225         __in                    efx_nvram_type_t type)
1226 {
1227         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
1228         hunt_parttbl_entry_t *entry;
1229         int i;
1230
1231         EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES);
1232
1233         for (i = 0; i < EFX_ARRAY_SIZE(hunt_parttbl); i++) {
1234                 entry = &hunt_parttbl[i];
1235
1236                 if (entry->port == emip->emi_port && entry->nvtype == type)
1237                         return (entry);
1238         }
1239
1240         return (NULL);
1241 }
1242
1243
1244 #if EFSYS_OPT_DIAG
1245
1246         __checkReturn           int
1247 hunt_nvram_test(
1248         __in                    efx_nic_t *enp)
1249 {
1250         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
1251         hunt_parttbl_entry_t *entry;
1252         unsigned int npartns = 0;
1253         uint32_t *partns = NULL;
1254         size_t size;
1255         int i;
1256         unsigned int j;
1257         int rc;
1258
1259         /* Find supported partitions */
1260         size = MC_CMD_NVRAM_PARTITIONS_OUT_TYPE_ID_MAXNUM * sizeof (uint32_t);
1261         EFSYS_KMEM_ALLOC(enp->en_esip, size, partns);
1262         if (partns == NULL) {
1263                 rc = ENOMEM;
1264                 goto fail1;
1265         }
1266
1267         if ((rc = efx_mcdi_nvram_partitions(enp, (caddr_t)partns, size,
1268                     &npartns)) != 0) {
1269                 goto fail2;
1270         }
1271
1272         /*
1273          * Iterate over the list of supported partition types
1274          * applicable to *this* port
1275          */
1276         for (i = 0; i < EFX_ARRAY_SIZE(hunt_parttbl); i++) {
1277                 entry = &hunt_parttbl[i];
1278
1279                 if (entry->port != emip->emi_port)
1280                         continue;
1281
1282                 for (j = 0; j < npartns; j++) {
1283                         if (entry->partn == partns[j]) {
1284                                 rc = efx_mcdi_nvram_test(enp, entry->partn);
1285                                 if (rc != 0)
1286                                         goto fail3;
1287                         }
1288                 }
1289         }
1290
1291         EFSYS_KMEM_FREE(enp->en_esip, size, partns);
1292         return (0);
1293
1294 fail3:
1295         EFSYS_PROBE(fail3);
1296 fail2:
1297         EFSYS_PROBE(fail2);
1298         EFSYS_KMEM_FREE(enp->en_esip, size, partns);
1299 fail1:
1300         EFSYS_PROBE1(fail1, int, rc);
1301         return (rc);
1302 }
1303
1304 #endif  /* EFSYS_OPT_DIAG */
1305
1306         __checkReturn           int
1307 hunt_nvram_size(
1308         __in                    efx_nic_t *enp,
1309         __in                    efx_nvram_type_t type,
1310         __out                   size_t *sizep)
1311 {
1312         hunt_parttbl_entry_t *entry;
1313         uint32_t partn;
1314         int rc;
1315
1316         if ((entry = hunt_parttbl_entry(enp, type)) == NULL) {
1317                 rc = ENOTSUP;
1318                 goto fail1;
1319         }
1320         partn = entry->partn;
1321
1322         if ((rc = hunt_nvram_partn_size(enp, partn, sizep)) != 0)
1323                 goto fail2;
1324
1325         return (0);
1326
1327 fail2:
1328         EFSYS_PROBE(fail2);
1329 fail1:
1330         EFSYS_PROBE1(fail1, int, rc);
1331
1332         *sizep = 0;
1333
1334         return (rc);
1335 }
1336
1337         __checkReturn           int
1338 hunt_nvram_get_version(
1339         __in                    efx_nic_t *enp,
1340         __in                    efx_nvram_type_t type,
1341         __out                   uint32_t *subtypep,
1342         __out_ecount(4)         uint16_t version[4])
1343 {
1344         hunt_parttbl_entry_t *entry;
1345         uint32_t partn;
1346         int rc;
1347
1348         if ((entry = hunt_parttbl_entry(enp, type)) == NULL) {
1349                 rc = ENOTSUP;
1350                 goto fail1;
1351         }
1352         partn = entry->partn;
1353
1354         /* FIXME: get highest partn version from all ports */
1355         /* FIXME: return partn description if available */
1356
1357         if ((rc = efx_mcdi_nvram_metadata(enp, partn, subtypep,
1358                     version, NULL, 0)) != 0)
1359                 goto fail2;
1360
1361         return (0);
1362
1363 fail2:
1364         EFSYS_PROBE(fail2);
1365 fail1:
1366         EFSYS_PROBE1(fail1, int, rc);
1367
1368         return (rc);
1369 }
1370
1371         __checkReturn           int
1372 hunt_nvram_rw_start(
1373         __in                    efx_nic_t *enp,
1374         __in                    efx_nvram_type_t type,
1375         __out                   size_t *chunk_sizep)
1376 {
1377         hunt_parttbl_entry_t *entry;
1378         uint32_t partn;
1379         int rc;
1380
1381         if ((entry = hunt_parttbl_entry(enp, type)) == NULL) {
1382                 rc = ENOTSUP;
1383                 goto fail1;
1384         }
1385         partn = entry->partn;
1386
1387         if ((rc = hunt_nvram_partn_lock(enp, partn)) != 0)
1388                 goto fail2;
1389
1390         if (chunk_sizep != NULL)
1391                 *chunk_sizep = HUNTINGTON_NVRAM_CHUNK;
1392
1393         return (0);
1394
1395 fail2:
1396         EFSYS_PROBE(fail2);
1397 fail1:
1398         EFSYS_PROBE1(fail1, int, rc);
1399
1400         return (rc);
1401 }
1402
1403         __checkReturn           int
1404 hunt_nvram_read_chunk(
1405         __in                    efx_nic_t *enp,
1406         __in                    efx_nvram_type_t type,
1407         __in                    unsigned int offset,
1408         __out_bcount(size)      caddr_t data,
1409         __in                    size_t size)
1410 {
1411         hunt_parttbl_entry_t *entry;
1412         int rc;
1413
1414         if ((entry = hunt_parttbl_entry(enp, type)) == NULL) {
1415                 rc = ENOTSUP;
1416                 goto fail1;
1417         }
1418
1419         if ((rc = hunt_nvram_partn_read(enp, entry->partn,
1420                     offset, data, size)) != 0)
1421                 goto fail2;
1422
1423         return (0);
1424
1425 fail2:
1426         EFSYS_PROBE(fail2);
1427 fail1:
1428         EFSYS_PROBE1(fail1, int, rc);
1429
1430         return (rc);
1431 }
1432
1433         __checkReturn           int
1434 hunt_nvram_erase(
1435         __in                    efx_nic_t *enp,
1436         __in                    efx_nvram_type_t type)
1437 {
1438         hunt_parttbl_entry_t *entry;
1439         size_t size;
1440         int rc;
1441
1442         if ((entry = hunt_parttbl_entry(enp, type)) == NULL) {
1443                 rc = ENOTSUP;
1444                 goto fail1;
1445         }
1446
1447         if ((rc = hunt_nvram_partn_size(enp, entry->partn, &size)) != 0)
1448                 goto fail2;
1449
1450         if ((rc = hunt_nvram_partn_erase(enp, entry->partn, 0, size)) != 0)
1451                 goto fail3;
1452
1453         return (0);
1454
1455 fail3:
1456         EFSYS_PROBE(fail3);
1457 fail2:
1458         EFSYS_PROBE(fail2);
1459 fail1:
1460         EFSYS_PROBE1(fail1, int, rc);
1461
1462         return (rc);
1463 }
1464
1465         __checkReturn           int
1466 hunt_nvram_write_chunk(
1467         __in                    efx_nic_t *enp,
1468         __in                    efx_nvram_type_t type,
1469         __in                    unsigned int offset,
1470         __in_bcount(size)       caddr_t data,
1471         __in                    size_t size)
1472 {
1473         hunt_parttbl_entry_t *entry;
1474         int rc;
1475
1476         if ((entry = hunt_parttbl_entry(enp, type)) == NULL) {
1477                 rc = ENOTSUP;
1478                 goto fail1;
1479         }
1480
1481         if ((rc = hunt_nvram_partn_write(enp, entry->partn,
1482                     offset, data, size)) != 0)
1483                 goto fail2;
1484
1485         return (0);
1486
1487 fail2:
1488         EFSYS_PROBE(fail2);
1489 fail1:
1490         EFSYS_PROBE1(fail1, int, rc);
1491
1492         return (rc);
1493 }
1494
1495                                 void
1496 hunt_nvram_rw_finish(
1497         __in                    efx_nic_t *enp,
1498         __in                    efx_nvram_type_t type)
1499 {
1500         hunt_parttbl_entry_t *entry;
1501
1502         if ((entry = hunt_parttbl_entry(enp, type)) != NULL)
1503                 hunt_nvram_partn_unlock(enp, entry->partn);
1504 }
1505
1506         __checkReturn           int
1507 hunt_nvram_set_version(
1508         __in                    efx_nic_t *enp,
1509         __in                    efx_nvram_type_t type,
1510         __in_ecount(4)          uint16_t version[4])
1511 {
1512         hunt_parttbl_entry_t *entry;
1513         unsigned int partn;
1514         int rc;
1515
1516         if ((entry = hunt_parttbl_entry(enp, type)) == NULL) {
1517                 rc = ENOTSUP;
1518                 goto fail1;
1519         }
1520         partn = entry->partn;
1521
1522         if ((rc = hunt_nvram_partn_set_version(enp, partn, version)) != 0)
1523                 goto fail2;
1524
1525         return (0);
1526
1527 fail2:
1528         EFSYS_PROBE(fail2);
1529
1530 fail1:
1531         EFSYS_PROBE1(fail1, int, rc);
1532
1533         return (rc);
1534 }
1535
1536 #endif  /* EFSYS_OPT_NVRAM */
1537
1538 #endif  /* EFSYS_OPT_HUNTINGTON */