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