]> git.proxmox.com Git - ceph.git/blame - ceph/src/spdk/dpdk/drivers/net/sfc/base/efx_vpd.c
import 15.2.0 Octopus source
[ceph.git] / ceph / src / spdk / dpdk / drivers / net / sfc / base / efx_vpd.c
CommitLineData
11fdf7f2
TL
1/* SPDX-License-Identifier: BSD-3-Clause
2 *
3 * Copyright (c) 2009-2018 Solarflare Communications Inc.
4 * All rights reserved.
5 */
6
7#include "efx.h"
8#include "efx_impl.h"
9
10#if EFSYS_OPT_VPD
11
12#define TAG_TYPE_LBN 7
13#define TAG_TYPE_WIDTH 1
14#define TAG_TYPE_LARGE_ITEM_DECODE 1
15#define TAG_TYPE_SMALL_ITEM_DECODE 0
16
17#define TAG_SMALL_ITEM_NAME_LBN 3
18#define TAG_SMALL_ITEM_NAME_WIDTH 4
19#define TAG_SMALL_ITEM_SIZE_LBN 0
20#define TAG_SMALL_ITEM_SIZE_WIDTH 3
21
22#define TAG_LARGE_ITEM_NAME_LBN 0
23#define TAG_LARGE_ITEM_NAME_WIDTH 7
24
25#define TAG_NAME_END_DECODE 0x0f
26#define TAG_NAME_ID_STRING_DECODE 0x02
27#define TAG_NAME_VPD_R_DECODE 0x10
28#define TAG_NAME_VPD_W_DECODE 0x11
29
30#if EFSYS_OPT_SIENA
31
32static const efx_vpd_ops_t __efx_vpd_siena_ops = {
33 siena_vpd_init, /* evpdo_init */
34 siena_vpd_size, /* evpdo_size */
35 siena_vpd_read, /* evpdo_read */
36 siena_vpd_verify, /* evpdo_verify */
37 siena_vpd_reinit, /* evpdo_reinit */
38 siena_vpd_get, /* evpdo_get */
39 siena_vpd_set, /* evpdo_set */
40 siena_vpd_next, /* evpdo_next */
41 siena_vpd_write, /* evpdo_write */
42 siena_vpd_fini, /* evpdo_fini */
43};
44
45#endif /* EFSYS_OPT_SIENA */
46
9f95a23c 47#if EFX_OPTS_EF10()
11fdf7f2
TL
48
49static const efx_vpd_ops_t __efx_vpd_ef10_ops = {
50 ef10_vpd_init, /* evpdo_init */
51 ef10_vpd_size, /* evpdo_size */
52 ef10_vpd_read, /* evpdo_read */
53 ef10_vpd_verify, /* evpdo_verify */
54 ef10_vpd_reinit, /* evpdo_reinit */
55 ef10_vpd_get, /* evpdo_get */
56 ef10_vpd_set, /* evpdo_set */
57 ef10_vpd_next, /* evpdo_next */
58 ef10_vpd_write, /* evpdo_write */
59 ef10_vpd_fini, /* evpdo_fini */
60};
61
9f95a23c 62#endif /* EFX_OPTS_EF10() */
11fdf7f2
TL
63
64 __checkReturn efx_rc_t
65efx_vpd_init(
66 __in efx_nic_t *enp)
67{
68 const efx_vpd_ops_t *evpdop;
69 efx_rc_t rc;
70
71 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
72 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
73 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_VPD));
74
75 switch (enp->en_family) {
76#if EFSYS_OPT_SIENA
77 case EFX_FAMILY_SIENA:
78 evpdop = &__efx_vpd_siena_ops;
79 break;
80#endif /* EFSYS_OPT_SIENA */
81
82#if EFSYS_OPT_HUNTINGTON
83 case EFX_FAMILY_HUNTINGTON:
84 evpdop = &__efx_vpd_ef10_ops;
85 break;
86#endif /* EFSYS_OPT_HUNTINGTON */
87
88#if EFSYS_OPT_MEDFORD
89 case EFX_FAMILY_MEDFORD:
90 evpdop = &__efx_vpd_ef10_ops;
91 break;
92#endif /* EFSYS_OPT_MEDFORD */
93
94#if EFSYS_OPT_MEDFORD2
95 case EFX_FAMILY_MEDFORD2:
96 evpdop = &__efx_vpd_ef10_ops;
97 break;
98#endif /* EFSYS_OPT_MEDFORD2 */
99
100 default:
101 EFSYS_ASSERT(0);
102 rc = ENOTSUP;
103 goto fail1;
104 }
105
106 if (evpdop->evpdo_init != NULL) {
107 if ((rc = evpdop->evpdo_init(enp)) != 0)
108 goto fail2;
109 }
110
111 enp->en_evpdop = evpdop;
112 enp->en_mod_flags |= EFX_MOD_VPD;
113
114 return (0);
115
116fail2:
117 EFSYS_PROBE(fail2);
118fail1:
119 EFSYS_PROBE1(fail1, efx_rc_t, rc);
120
121 return (rc);
122}
123
124 __checkReturn efx_rc_t
125efx_vpd_size(
126 __in efx_nic_t *enp,
127 __out size_t *sizep)
128{
129 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
130 efx_rc_t rc;
131
132 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
133 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
134
135 if ((rc = evpdop->evpdo_size(enp, sizep)) != 0)
136 goto fail1;
137
138 return (0);
139
140fail1:
141 EFSYS_PROBE1(fail1, efx_rc_t, rc);
142
143 return (rc);
144}
145
146 __checkReturn efx_rc_t
147efx_vpd_read(
148 __in efx_nic_t *enp,
149 __out_bcount(size) caddr_t data,
150 __in size_t size)
151{
152 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
153 efx_rc_t rc;
154
155 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
156 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
157
158 if ((rc = evpdop->evpdo_read(enp, data, size)) != 0)
159 goto fail1;
160
161 return (0);
162
163fail1:
164 EFSYS_PROBE1(fail1, efx_rc_t, rc);
165
166 return (rc);
167}
168
169 __checkReturn efx_rc_t
170efx_vpd_verify(
171 __in efx_nic_t *enp,
172 __in_bcount(size) caddr_t data,
173 __in size_t size)
174{
175 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
176 efx_rc_t rc;
177
178 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
179 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
180
181 if ((rc = evpdop->evpdo_verify(enp, data, size)) != 0)
182 goto fail1;
183
184 return (0);
185
186fail1:
187 EFSYS_PROBE1(fail1, efx_rc_t, rc);
188
189 return (rc);
190}
191
192 __checkReturn efx_rc_t
193efx_vpd_reinit(
194 __in efx_nic_t *enp,
195 __in_bcount(size) caddr_t data,
196 __in size_t size)
197{
198 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
199 efx_rc_t rc;
200
201 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
202 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
203
204 if (evpdop->evpdo_reinit == NULL) {
205 rc = ENOTSUP;
206 goto fail1;
207 }
208
209 if ((rc = evpdop->evpdo_reinit(enp, data, size)) != 0)
210 goto fail2;
211
212 return (0);
213
214fail2:
215 EFSYS_PROBE(fail2);
216fail1:
217 EFSYS_PROBE1(fail1, efx_rc_t, rc);
218
219 return (rc);
220}
221
222 __checkReturn efx_rc_t
223efx_vpd_get(
224 __in efx_nic_t *enp,
225 __in_bcount(size) caddr_t data,
226 __in size_t size,
227 __inout efx_vpd_value_t *evvp)
228{
229 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
230 efx_rc_t rc;
231
232 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
233 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
234
235 if ((rc = evpdop->evpdo_get(enp, data, size, evvp)) != 0) {
236 if (rc == ENOENT)
237 return (rc);
238
239 goto fail1;
240 }
241
242 return (0);
243
244fail1:
245 EFSYS_PROBE1(fail1, efx_rc_t, rc);
246
247 return (rc);
248}
249
250 __checkReturn efx_rc_t
251efx_vpd_set(
252 __in efx_nic_t *enp,
253 __inout_bcount(size) caddr_t data,
254 __in size_t size,
255 __in efx_vpd_value_t *evvp)
256{
257 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
258 efx_rc_t rc;
259
260 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
261 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
262
263 if ((rc = evpdop->evpdo_set(enp, data, size, evvp)) != 0)
264 goto fail1;
265
266 return (0);
267
268fail1:
269 EFSYS_PROBE1(fail1, efx_rc_t, rc);
270
271 return (rc);
272}
273
274 __checkReturn efx_rc_t
275efx_vpd_next(
276 __in efx_nic_t *enp,
277 __inout_bcount(size) caddr_t data,
278 __in size_t size,
279 __out efx_vpd_value_t *evvp,
280 __inout unsigned int *contp)
281{
282 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
283 efx_rc_t rc;
284
285 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
286 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
287
288 if ((rc = evpdop->evpdo_next(enp, data, size, evvp, contp)) != 0)
289 goto fail1;
290
291 return (0);
292
293fail1:
294 EFSYS_PROBE1(fail1, efx_rc_t, rc);
295
296 return (rc);
297}
298
299 __checkReturn efx_rc_t
300efx_vpd_write(
301 __in efx_nic_t *enp,
302 __in_bcount(size) caddr_t data,
303 __in size_t size)
304{
305 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
306 efx_rc_t rc;
307
308 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
309 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
310
311 if ((rc = evpdop->evpdo_write(enp, data, size)) != 0)
312 goto fail1;
313
314 return (0);
315
316fail1:
317 EFSYS_PROBE1(fail1, efx_rc_t, rc);
318
319 return (rc);
320}
321
322static __checkReturn efx_rc_t
323efx_vpd_next_tag(
324 __in caddr_t data,
325 __in size_t size,
326 __inout unsigned int *offsetp,
327 __out efx_vpd_tag_t *tagp,
328 __out uint16_t *lengthp)
329{
330 efx_byte_t byte;
331 efx_word_t word;
332 uint8_t name;
333 uint16_t length;
334 size_t headlen;
335 efx_rc_t rc;
336
337 if (*offsetp >= size) {
338 rc = EFAULT;
339 goto fail1;
340 }
341
342 EFX_POPULATE_BYTE_1(byte, EFX_BYTE_0, data[*offsetp]);
343
344 switch (EFX_BYTE_FIELD(byte, TAG_TYPE)) {
345 case TAG_TYPE_SMALL_ITEM_DECODE:
346 headlen = 1;
347
348 name = EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_NAME);
349 length = (uint16_t)EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_SIZE);
350
351 break;
352
353 case TAG_TYPE_LARGE_ITEM_DECODE:
354 headlen = 3;
355
356 if (*offsetp + headlen > size) {
357 rc = EFAULT;
358 goto fail2;
359 }
360
361 name = EFX_BYTE_FIELD(byte, TAG_LARGE_ITEM_NAME);
362 EFX_POPULATE_WORD_2(word,
363 EFX_BYTE_0, data[*offsetp + 1],
364 EFX_BYTE_1, data[*offsetp + 2]);
365 length = EFX_WORD_FIELD(word, EFX_WORD_0);
366
367 break;
368
369 default:
370 rc = EFAULT;
371 goto fail2;
372 }
373
374 if (*offsetp + headlen + length > size) {
375 rc = EFAULT;
376 goto fail3;
377 }
378
379 EFX_STATIC_ASSERT(TAG_NAME_END_DECODE == EFX_VPD_END);
380 EFX_STATIC_ASSERT(TAG_NAME_ID_STRING_DECODE == EFX_VPD_ID);
381 EFX_STATIC_ASSERT(TAG_NAME_VPD_R_DECODE == EFX_VPD_RO);
382 EFX_STATIC_ASSERT(TAG_NAME_VPD_W_DECODE == EFX_VPD_RW);
383 if (name != EFX_VPD_END && name != EFX_VPD_ID &&
384 name != EFX_VPD_RO) {
385 rc = EFAULT;
386 goto fail4;
387 }
388
389 *tagp = name;
390 *lengthp = length;
391 *offsetp += headlen;
392
393 return (0);
394
395fail4:
396 EFSYS_PROBE(fail4);
397fail3:
398 EFSYS_PROBE(fail3);
399fail2:
400 EFSYS_PROBE(fail2);
401fail1:
402 EFSYS_PROBE1(fail1, efx_rc_t, rc);
403
404 return (rc);
405}
406
407static __checkReturn efx_rc_t
408efx_vpd_next_keyword(
409 __in_bcount(size) caddr_t tag,
410 __in size_t size,
411 __in unsigned int pos,
412 __out efx_vpd_keyword_t *keywordp,
413 __out uint8_t *lengthp)
414{
415 efx_vpd_keyword_t keyword;
416 uint8_t length;
417 efx_rc_t rc;
418
419 if (pos + 3U > size) {
420 rc = EFAULT;
421 goto fail1;
422 }
423
424 keyword = EFX_VPD_KEYWORD(tag[pos], tag[pos + 1]);
425 length = tag[pos + 2];
426
427 if (length == 0 || pos + 3U + length > size) {
428 rc = EFAULT;
429 goto fail2;
430 }
431
432 *keywordp = keyword;
433 *lengthp = length;
434
435 return (0);
436
437fail2:
438 EFSYS_PROBE(fail2);
439fail1:
440 EFSYS_PROBE1(fail1, efx_rc_t, rc);
441
442 return (rc);
443}
444
445 __checkReturn efx_rc_t
446efx_vpd_hunk_length(
447 __in_bcount(size) caddr_t data,
448 __in size_t size,
449 __out size_t *lengthp)
450{
451 efx_vpd_tag_t tag;
452 unsigned int offset;
453 uint16_t taglen;
454 efx_rc_t rc;
455
456 offset = 0;
457 _NOTE(CONSTANTCONDITION)
458 while (1) {
459 if ((rc = efx_vpd_next_tag(data, size, &offset,
460 &tag, &taglen)) != 0)
461 goto fail1;
462 offset += taglen;
463 if (tag == EFX_VPD_END)
464 break;
465 }
466
467 *lengthp = offset;
468
469 return (0);
470
471fail1:
472 EFSYS_PROBE1(fail1, efx_rc_t, rc);
473
474 return (rc);
475}
476
477 __checkReturn efx_rc_t
478efx_vpd_hunk_verify(
479 __in_bcount(size) caddr_t data,
480 __in size_t size,
481 __out_opt boolean_t *cksummedp)
482{
483 efx_vpd_tag_t tag;
484 efx_vpd_keyword_t keyword;
485 unsigned int offset;
486 unsigned int pos;
487 unsigned int i;
488 uint16_t taglen;
489 uint8_t keylen;
490 uint8_t cksum;
491 boolean_t cksummed = B_FALSE;
492 efx_rc_t rc;
493
494 /*
495 * Parse every tag,keyword in the existing VPD. If the csum is present,
496 * the assert it is correct, and is the final keyword in the RO block.
497 */
498 offset = 0;
499 _NOTE(CONSTANTCONDITION)
500 while (1) {
501 if ((rc = efx_vpd_next_tag(data, size, &offset,
502 &tag, &taglen)) != 0)
503 goto fail1;
504 if (tag == EFX_VPD_END)
505 break;
506 else if (tag == EFX_VPD_ID)
507 goto done;
508
509 for (pos = 0; pos != taglen; pos += 3 + keylen) {
510 /* RV keyword must be the last in the block */
511 if (cksummed) {
512 rc = EFAULT;
513 goto fail2;
514 }
515
516 if ((rc = efx_vpd_next_keyword(data + offset,
517 taglen, pos, &keyword, &keylen)) != 0)
518 goto fail3;
519
520 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
521 cksum = 0;
522 for (i = 0; i < offset + pos + 4; i++)
523 cksum += data[i];
524
525 if (cksum != 0) {
526 rc = EFAULT;
527 goto fail4;
528 }
529
530 cksummed = B_TRUE;
531 }
532 }
533
534 done:
535 offset += taglen;
536 }
537
538 if (!cksummed) {
539 rc = EFAULT;
540 goto fail5;
541 }
542
543 if (cksummedp != NULL)
544 *cksummedp = cksummed;
545
546 return (0);
547
548fail5:
549 EFSYS_PROBE(fail5);
550fail4:
551 EFSYS_PROBE(fail4);
552fail3:
553 EFSYS_PROBE(fail3);
554fail2:
555 EFSYS_PROBE(fail2);
556fail1:
557 EFSYS_PROBE1(fail1, efx_rc_t, rc);
558
559 return (rc);
560}
561
562static uint8_t __efx_vpd_blank_pid[] = {
563 /* Large resource type ID length 1 */
564 0x82, 0x01, 0x00,
565 /* Product name ' ' */
566 0x32,
567};
568
569static uint8_t __efx_vpd_blank_r[] = {
570 /* Large resource type VPD-R length 4 */
571 0x90, 0x04, 0x00,
572 /* RV keyword length 1 */
573 'R', 'V', 0x01,
574 /* RV payload checksum */
575 0x00,
576};
577
578 __checkReturn efx_rc_t
579efx_vpd_hunk_reinit(
580 __in_bcount(size) caddr_t data,
581 __in size_t size,
582 __in boolean_t wantpid)
583{
584 unsigned int offset = 0;
585 unsigned int pos;
586 efx_byte_t byte;
587 uint8_t cksum;
588 efx_rc_t rc;
589
590 if (size < 0x100) {
591 rc = ENOSPC;
592 goto fail1;
593 }
594
595 if (wantpid) {
596 memcpy(data + offset, __efx_vpd_blank_pid,
597 sizeof (__efx_vpd_blank_pid));
598 offset += sizeof (__efx_vpd_blank_pid);
599 }
600
601 memcpy(data + offset, __efx_vpd_blank_r, sizeof (__efx_vpd_blank_r));
602 offset += sizeof (__efx_vpd_blank_r);
603
604 /* Update checksum */
605 cksum = 0;
606 for (pos = 0; pos < offset; pos++)
607 cksum += data[pos];
608 data[offset - 1] -= cksum;
609
610 /* Append trailing tag */
611 EFX_POPULATE_BYTE_3(byte,
612 TAG_TYPE, TAG_TYPE_SMALL_ITEM_DECODE,
613 TAG_SMALL_ITEM_NAME, TAG_NAME_END_DECODE,
614 TAG_SMALL_ITEM_SIZE, 0);
615 data[offset] = EFX_BYTE_FIELD(byte, EFX_BYTE_0);
616 offset++;
617
618 return (0);
619
620fail1:
621 EFSYS_PROBE1(fail1, efx_rc_t, rc);
622
623 return (rc);
624}
625
626 __checkReturn efx_rc_t
627efx_vpd_hunk_next(
628 __in_bcount(size) caddr_t data,
629 __in size_t size,
630 __out efx_vpd_tag_t *tagp,
631 __out efx_vpd_keyword_t *keywordp,
632 __out_opt unsigned int *payloadp,
633 __out_opt uint8_t *paylenp,
634 __inout unsigned int *contp)
635{
636 efx_vpd_tag_t tag;
637 efx_vpd_keyword_t keyword = 0;
638 unsigned int offset;
639 unsigned int pos;
640 unsigned int index;
641 uint16_t taglen;
642 uint8_t keylen;
643 uint8_t paylen;
644 efx_rc_t rc;
645
646 offset = index = 0;
647 _NOTE(CONSTANTCONDITION)
648 while (1) {
649 if ((rc = efx_vpd_next_tag(data, size, &offset,
650 &tag, &taglen)) != 0)
651 goto fail1;
652
653 if (tag == EFX_VPD_END) {
654 keyword = 0;
655 paylen = 0;
656 index = 0;
657 break;
658 }
659
660 if (tag == EFX_VPD_ID) {
661 if (index++ == *contp) {
662 EFSYS_ASSERT3U(taglen, <, 0x100);
663 keyword = 0;
664 paylen = (uint8_t)MIN(taglen, 0xff);
665
666 goto done;
667 }
668 } else {
669 for (pos = 0; pos != taglen; pos += 3 + keylen) {
670 if ((rc = efx_vpd_next_keyword(data + offset,
671 taglen, pos, &keyword, &keylen)) != 0)
672 goto fail2;
673
674 if (index++ == *contp) {
675 offset += pos + 3;
676 paylen = keylen;
677
678 goto done;
679 }
680 }
681 }
682
683 offset += taglen;
684 }
685
686done:
687 *tagp = tag;
688 *keywordp = keyword;
689 if (payloadp != NULL)
690 *payloadp = offset;
691 if (paylenp != NULL)
692 *paylenp = paylen;
693
694 *contp = index;
695 return (0);
696
697fail2:
698 EFSYS_PROBE(fail2);
699fail1:
700 EFSYS_PROBE1(fail1, efx_rc_t, rc);
701
702 return (rc);
703}
704
705 __checkReturn efx_rc_t
706efx_vpd_hunk_get(
707 __in_bcount(size) caddr_t data,
708 __in size_t size,
709 __in efx_vpd_tag_t tag,
710 __in efx_vpd_keyword_t keyword,
711 __out unsigned int *payloadp,
712 __out uint8_t *paylenp)
713{
714 efx_vpd_tag_t itag;
715 efx_vpd_keyword_t ikeyword;
716 unsigned int offset;
717 unsigned int pos;
718 uint16_t taglen;
719 uint8_t keylen;
720 efx_rc_t rc;
721
722 offset = 0;
723 _NOTE(CONSTANTCONDITION)
724 while (1) {
725 if ((rc = efx_vpd_next_tag(data, size, &offset,
726 &itag, &taglen)) != 0)
727 goto fail1;
728 if (itag == EFX_VPD_END)
729 break;
730
731 if (itag == tag) {
732 if (itag == EFX_VPD_ID) {
733 EFSYS_ASSERT3U(taglen, <, 0x100);
734
735 *paylenp = (uint8_t)MIN(taglen, 0xff);
736 *payloadp = offset;
737 return (0);
738 }
739
740 for (pos = 0; pos != taglen; pos += 3 + keylen) {
741 if ((rc = efx_vpd_next_keyword(data + offset,
742 taglen, pos, &ikeyword, &keylen)) != 0)
743 goto fail2;
744
745 if (ikeyword == keyword) {
746 *paylenp = keylen;
747 *payloadp = offset + pos + 3;
748 return (0);
749 }
750 }
751 }
752
753 offset += taglen;
754 }
755
756 /* Not an error */
757 return (ENOENT);
758
759fail2:
760 EFSYS_PROBE(fail2);
761fail1:
762 EFSYS_PROBE1(fail1, efx_rc_t, rc);
763
764 return (rc);
765}
766
767 __checkReturn efx_rc_t
768efx_vpd_hunk_set(
769 __in_bcount(size) caddr_t data,
770 __in size_t size,
771 __in efx_vpd_value_t *evvp)
772{
773 efx_word_t word;
774 efx_vpd_tag_t tag;
775 efx_vpd_keyword_t keyword;
776 unsigned int offset;
777 unsigned int pos;
778 unsigned int taghead;
779 unsigned int source;
780 unsigned int dest;
781 unsigned int i;
782 uint16_t taglen;
783 uint8_t keylen;
784 uint8_t cksum;
785 size_t used;
786 efx_rc_t rc;
787
788 switch (evvp->evv_tag) {
789 case EFX_VPD_ID:
790 if (evvp->evv_keyword != 0) {
791 rc = EINVAL;
792 goto fail1;
793 }
794
795 /* Can't delete the ID keyword */
796 if (evvp->evv_length == 0) {
797 rc = EINVAL;
798 goto fail1;
799 }
800 break;
801
802 case EFX_VPD_RO:
803 if (evvp->evv_keyword == EFX_VPD_KEYWORD('R', 'V')) {
804 rc = EINVAL;
805 goto fail1;
806 }
807 break;
808
809 default:
810 rc = EINVAL;
811 goto fail1;
812 }
813
814 /* Determine total size of all current tags */
815 if ((rc = efx_vpd_hunk_length(data, size, &used)) != 0)
816 goto fail2;
817
818 offset = 0;
819 _NOTE(CONSTANTCONDITION)
820 while (1) {
821 taghead = offset;
822 if ((rc = efx_vpd_next_tag(data, size, &offset,
823 &tag, &taglen)) != 0)
824 goto fail3;
825 if (tag == EFX_VPD_END)
826 break;
827 else if (tag != evvp->evv_tag) {
828 offset += taglen;
829 continue;
830 }
831
832 /* We only support modifying large resource tags */
833 if (offset - taghead != 3) {
834 rc = EINVAL;
835 goto fail4;
836 }
837
838 /*
839 * Work out the offset of the byte immediately after the
840 * old (=source) and new (=dest) new keyword/tag
841 */
842 pos = 0;
843 if (tag == EFX_VPD_ID) {
844 source = offset + taglen;
845 dest = offset + evvp->evv_length;
846 goto check_space;
847 }
848
849 EFSYS_ASSERT3U(tag, ==, EFX_VPD_RO);
850 source = dest = 0;
851 for (pos = 0; pos != taglen; pos += 3 + keylen) {
852 if ((rc = efx_vpd_next_keyword(data + offset,
853 taglen, pos, &keyword, &keylen)) != 0)
854 goto fail5;
855
856 if (keyword == evvp->evv_keyword &&
857 evvp->evv_length == 0) {
858 /* Deleting this keyword */
859 source = offset + pos + 3 + keylen;
860 dest = offset + pos;
861 break;
862
863 } else if (keyword == evvp->evv_keyword) {
864 /* Adjusting this keyword */
865 source = offset + pos + 3 + keylen;
866 dest = offset + pos + 3 + evvp->evv_length;
867 break;
868
869 } else if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
870 /* The RV keyword must be at the end */
871 EFSYS_ASSERT3U(pos + 3 + keylen, ==, taglen);
872
873 /*
874 * The keyword doesn't already exist. If the
875 * user deleting a non-existant keyword then
876 * this is a no-op.
877 */
878 if (evvp->evv_length == 0)
879 return (0);
880
881 /* Insert this keyword before the RV keyword */
882 source = offset + pos;
883 dest = offset + pos + 3 + evvp->evv_length;
884 break;
885 }
886 }
887
888 check_space:
889 if (used + dest > size + source) {
890 rc = ENOSPC;
891 goto fail6;
892 }
893
894 /* Move trailing data */
895 (void) memmove(data + dest, data + source, used - source);
896
897 /* Copy contents */
898 memcpy(data + dest - evvp->evv_length, evvp->evv_value,
899 evvp->evv_length);
900
901 /* Insert new keyword header if required */
902 if (tag != EFX_VPD_ID && evvp->evv_length > 0) {
903 EFX_POPULATE_WORD_1(word, EFX_WORD_0,
904 evvp->evv_keyword);
905 data[offset + pos + 0] =
906 EFX_WORD_FIELD(word, EFX_BYTE_0);
907 data[offset + pos + 1] =
908 EFX_WORD_FIELD(word, EFX_BYTE_1);
909 data[offset + pos + 2] = evvp->evv_length;
910 }
911
912 /* Modify tag length (large resource type) */
913 taglen += (uint16_t)(dest - source);
914 EFX_POPULATE_WORD_1(word, EFX_WORD_0, taglen);
915 data[offset - 2] = EFX_WORD_FIELD(word, EFX_BYTE_0);
916 data[offset - 1] = EFX_WORD_FIELD(word, EFX_BYTE_1);
917
918 goto checksum;
919 }
920
921 /* Unable to find the matching tag */
922 rc = ENOENT;
923 goto fail7;
924
925checksum:
926 /* Find the RV tag, and update the checksum */
927 offset = 0;
928 _NOTE(CONSTANTCONDITION)
929 while (1) {
930 if ((rc = efx_vpd_next_tag(data, size, &offset,
931 &tag, &taglen)) != 0)
932 goto fail8;
933 if (tag == EFX_VPD_END)
934 break;
935 if (tag == EFX_VPD_RO) {
936 for (pos = 0; pos != taglen; pos += 3 + keylen) {
937 if ((rc = efx_vpd_next_keyword(data + offset,
938 taglen, pos, &keyword, &keylen)) != 0)
939 goto fail9;
940
941 if (keyword == EFX_VPD_KEYWORD('R', 'V')) {
942 cksum = 0;
943 for (i = 0; i < offset + pos + 3; i++)
944 cksum += data[i];
945 data[i] = -cksum;
946 break;
947 }
948 }
949 }
950
951 offset += taglen;
952 }
953
954 /* Zero out the unused portion */
955 (void) memset(data + offset + taglen, 0xff, size - offset - taglen);
956
957 return (0);
958
959fail9:
960 EFSYS_PROBE(fail9);
961fail8:
962 EFSYS_PROBE(fail8);
963fail7:
964 EFSYS_PROBE(fail7);
965fail6:
966 EFSYS_PROBE(fail6);
967fail5:
968 EFSYS_PROBE(fail5);
969fail4:
970 EFSYS_PROBE(fail4);
971fail3:
972 EFSYS_PROBE(fail3);
973fail2:
974 EFSYS_PROBE(fail2);
975fail1:
976 EFSYS_PROBE1(fail1, efx_rc_t, rc);
977
978 return (rc);
979}
980
981 void
982efx_vpd_fini(
983 __in efx_nic_t *enp)
984{
985 const efx_vpd_ops_t *evpdop = enp->en_evpdop;
986
987 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
988 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
989 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD);
990
991 if (evpdop->evpdo_fini != NULL)
992 evpdop->evpdo_fini(enp);
993
994 enp->en_evpdop = NULL;
995 enp->en_mod_flags &= ~EFX_MOD_VPD;
996}
997
998#endif /* EFSYS_OPT_VPD */