1 /* SPDX-License-Identifier: BSD-3-Clause
3 * Copyright (c) 2009-2018 Solarflare Communications Inc.
13 * Maximum size of BOOTCFG block across all nics as understood by SFCgPXE.
14 * NOTE: This is larger than the Medford per-PF bootcfg sector.
16 #define BOOTCFG_MAX_SIZE 0x1000
18 /* Medford per-PF bootcfg sector */
19 #define BOOTCFG_PER_PF 0x800
20 #define BOOTCFG_PF_COUNT 16
22 #define DHCP_OPT_HAS_VALUE(opt) \
23 (((opt) > EFX_DHCP_PAD) && ((opt) < EFX_DHCP_END))
25 #define DHCP_MAX_VALUE 255
27 #define DHCP_ENCAPSULATOR(encap_opt) ((encap_opt) >> 8)
28 #define DHCP_ENCAPSULATED(encap_opt) ((encap_opt) & 0xff)
29 #define DHCP_IS_ENCAP_OPT(opt) DHCP_OPT_HAS_VALUE(DHCP_ENCAPSULATOR(opt))
31 typedef struct efx_dhcp_tag_hdr_s
{
37 * Length calculations for tags with value field. PAD and END
38 * have a fixed length of 1, with no length or value field.
40 #define DHCP_FULL_TAG_LENGTH(hdr) \
41 (sizeof (efx_dhcp_tag_hdr_t) + (hdr)->length)
43 #define DHCP_NEXT_TAG(hdr) \
44 ((efx_dhcp_tag_hdr_t *)(((uint8_t *)(hdr)) + \
45 DHCP_FULL_TAG_LENGTH((hdr))))
47 #define DHCP_CALC_TAG_LENGTH(payload_len) \
48 ((payload_len) + sizeof (efx_dhcp_tag_hdr_t))
51 /* Report the layout of bootcfg sectors in NVRAM partition. */
52 __checkReturn efx_rc_t
53 efx_bootcfg_sector_info(
56 __out_opt
uint32_t *sector_countp
,
57 __out
size_t *offsetp
,
58 __out
size_t *max_sizep
)
65 switch (enp
->en_family
) {
67 case EFX_FAMILY_SIENA
:
68 max_size
= BOOTCFG_MAX_SIZE
;
72 #endif /* EFSYS_OPT_SIENA */
74 #if EFSYS_OPT_HUNTINGTON
75 case EFX_FAMILY_HUNTINGTON
:
76 max_size
= BOOTCFG_MAX_SIZE
;
80 #endif /* EFSYS_OPT_HUNTINGTON */
83 case EFX_FAMILY_MEDFORD
: {
84 /* Shared partition (array indexed by PF) */
85 max_size
= BOOTCFG_PER_PF
;
86 count
= BOOTCFG_PF_COUNT
;
91 offset
= max_size
* pf
;
94 #endif /* EFSYS_OPT_MEDFORD */
96 #if EFSYS_OPT_MEDFORD2
97 case EFX_FAMILY_MEDFORD2
: {
98 /* Shared partition (array indexed by PF) */
99 max_size
= BOOTCFG_PER_PF
;
100 count
= BOOTCFG_PF_COUNT
;
105 offset
= max_size
* pf
;
108 #endif /* EFSYS_OPT_MEDFORD2 */
115 EFSYS_ASSERT3U(max_size
, <=, BOOTCFG_MAX_SIZE
);
117 if (sector_countp
!= NULL
)
118 *sector_countp
= count
;
120 *max_sizep
= max_size
;
124 #if EFSYS_OPT_MEDFORD2
128 #if EFSYS_OPT_MEDFORD
133 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
138 __checkReturn
uint8_t
140 __in_bcount(size
) uint8_t const *data
,
144 uint8_t checksum
= 0;
146 for (pos
= 0; pos
< size
; pos
++)
147 checksum
+= data
[pos
];
151 __checkReturn efx_rc_t
153 __in_bcount(size
) uint8_t const *data
,
155 __out_opt
size_t *usedp
)
161 /* Start parsing tags immediately after the checksum */
162 for (offset
= 1; offset
< size
; ) {
168 if (tag
== EFX_DHCP_END
) {
173 if (tag
== EFX_DHCP_PAD
) {
179 if (offset
+ 1 >= size
) {
183 length
= data
[offset
+ 1];
185 /* Consume *length */
186 if (offset
+ 1 + length
>= size
) {
191 offset
+= 2 + length
;
195 /* Checksum the entire sector, including bytes after any EFX_DHCP_END */
196 if (efx_dhcp_csum(data
, size
) != 0) {
211 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
217 * Walk the entire tag set looking for option. The sought option may be
218 * encapsulated. ENOENT indicates the walk completed without finding the
219 * option. If we run out of buffer during the walk the function will return
224 __deref_inout
uint8_t **tagpp
,
225 __inout
size_t *buffer_sizep
,
229 boolean_t is_encap
= B_FALSE
;
231 if (DHCP_IS_ENCAP_OPT(opt
)) {
233 * Look for the encapsulator and, if found, limit ourselves
234 * to its payload. If it's not found then the entire tag
235 * cannot be found, so the encapsulated opt search is
238 rc
= efx_dhcp_walk_tags(tagpp
, buffer_sizep
,
239 DHCP_ENCAPSULATOR(opt
));
241 *buffer_sizep
= ((efx_dhcp_tag_hdr_t
*)*tagpp
)->length
;
242 (*tagpp
) += sizeof (efx_dhcp_tag_hdr_t
);
244 opt
= DHCP_ENCAPSULATED(opt
);
248 EFSYS_ASSERT(!DHCP_IS_ENCAP_OPT(opt
));
253 if (*buffer_sizep
== 0) {
258 if (DHCP_ENCAPSULATED(**tagpp
) == opt
)
261 if ((**tagpp
) == EFX_DHCP_END
) {
264 } else if ((**tagpp
) == EFX_DHCP_PAD
) {
267 if (*buffer_sizep
< sizeof (efx_dhcp_tag_hdr_t
)) {
273 DHCP_FULL_TAG_LENGTH((efx_dhcp_tag_hdr_t
*)*tagpp
);
276 if (size
> *buffer_sizep
) {
282 (*buffer_sizep
) -= size
;
284 if ((*buffer_sizep
== 0) && is_encap
) {
285 /* Search within encapulator tag finished */
292 * Returns 0 if found otherwise ENOENT indicating search finished
302 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
308 * Locate value buffer for option in the given buffer.
309 * Returns 0 if found, ENOENT indicating search finished
310 * correctly, otherwise search failed before completion.
312 __checkReturn efx_rc_t
314 __in_bcount(buffer_length
) uint8_t *bufferp
,
315 __in
size_t buffer_length
,
317 __deref_out
uint8_t **valuepp
,
318 __out
size_t *value_lengthp
)
321 uint8_t *tagp
= bufferp
;
322 size_t len
= buffer_length
;
324 rc
= efx_dhcp_walk_tags(&tagp
, &len
, opt
);
326 efx_dhcp_tag_hdr_t
*hdrp
;
328 hdrp
= (efx_dhcp_tag_hdr_t
*)tagp
;
329 *valuepp
= (uint8_t *)(&hdrp
[1]);
330 *value_lengthp
= hdrp
->length
;
331 } else if (rc
!= ENOENT
) {
338 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
344 * Locate the end tag in the given buffer.
345 * Returns 0 if found, ENOENT indicating search finished
346 * correctly but end tag was not found; otherwise search
347 * failed before completion.
349 __checkReturn efx_rc_t
351 __in_bcount(buffer_length
) uint8_t *bufferp
,
352 __in
size_t buffer_length
,
353 __deref_out
uint8_t **endpp
)
356 uint8_t *endp
= bufferp
;
357 size_t len
= buffer_length
;
359 rc
= efx_dhcp_walk_tags(&endp
, &len
, EFX_DHCP_END
);
362 else if (rc
!= ENOENT
)
368 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
375 * Delete the given tag from anywhere in the buffer. Copes with
376 * encapsulated tags, and updates or deletes the encapsulating opt as
379 __checkReturn efx_rc_t
381 __inout_bcount(buffer_length
) uint8_t *bufferp
,
382 __in
size_t buffer_length
,
386 efx_dhcp_tag_hdr_t
*hdrp
;
394 if (!DHCP_OPT_HAS_VALUE(DHCP_ENCAPSULATED(opt
))) {
399 rc
= efx_dhcp_walk_tags(&startp
, &len
, opt
);
403 hdrp
= (efx_dhcp_tag_hdr_t
*)startp
;
405 if (DHCP_IS_ENCAP_OPT(opt
)) {
406 uint8_t tag_length
= DHCP_FULL_TAG_LENGTH(hdrp
);
407 uint8_t *encapp
= bufferp
;
408 efx_dhcp_tag_hdr_t
*encap_hdrp
;
411 rc
= efx_dhcp_walk_tags(&encapp
, &len
,
412 DHCP_ENCAPSULATOR(opt
));
416 encap_hdrp
= (efx_dhcp_tag_hdr_t
*)encapp
;
417 if (encap_hdrp
->length
> tag_length
) {
418 encap_hdrp
->length
= (uint8_t)(
419 (size_t)encap_hdrp
->length
- tag_length
);
421 /* delete the encapsulating tag */
426 startp
= (uint8_t *)hdrp
;
427 endp
= (uint8_t *)DHCP_NEXT_TAG(hdrp
);
429 if (startp
< bufferp
) {
434 if (endp
> &bufferp
[buffer_length
]) {
439 memmove(startp
, endp
,
440 buffer_length
- (endp
- bufferp
));
451 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
457 * Write the tag header into write_pointp and optionally copies the payload
458 * into the space following.
462 __in
uint8_t *write_pointp
,
464 __in_bcount_opt(value_length
)
466 __in
size_t value_length
)
468 efx_dhcp_tag_hdr_t
*hdrp
= (efx_dhcp_tag_hdr_t
*)write_pointp
;
469 hdrp
->tag
= DHCP_ENCAPSULATED(opt
);
470 hdrp
->length
= (uint8_t)value_length
;
471 if ((value_length
> 0) && (valuep
!= NULL
))
472 memcpy(&hdrp
[1], valuep
, value_length
);
476 * Add the given tag to the end of the buffer. Copes with creating an
477 * encapsulated tag, and updates or creates the encapsulating opt as
480 __checkReturn efx_rc_t
482 __inout_bcount(buffer_length
) uint8_t *bufferp
,
483 __in
size_t buffer_length
,
485 __in_bcount_opt(value_length
) uint8_t *valuep
,
486 __in
size_t value_length
)
489 efx_dhcp_tag_hdr_t
*encap_hdrp
= NULL
;
490 uint8_t *insert_pointp
= NULL
;
492 size_t available_space
;
497 if (!DHCP_OPT_HAS_VALUE(DHCP_ENCAPSULATED(opt
))) {
502 if (value_length
> DHCP_MAX_VALUE
) {
507 if ((value_length
> 0) && (valuep
== NULL
)) {
513 available_space
= buffer_length
;
514 rc
= efx_dhcp_walk_tags(&endp
, &available_space
, EFX_DHCP_END
);
519 search_size
= buffer_length
;
520 if (DHCP_IS_ENCAP_OPT(opt
)) {
521 rc
= efx_dhcp_walk_tags(&searchp
, &search_size
,
522 DHCP_ENCAPSULATOR(opt
));
524 encap_hdrp
= (efx_dhcp_tag_hdr_t
*)searchp
;
526 /* Check encapsulated tag is not present */
527 search_size
= encap_hdrp
->length
;
528 rc
= efx_dhcp_walk_tags(&searchp
, &search_size
,
535 /* Check encapsulator will not overflow */
536 if (((size_t)encap_hdrp
->length
+
537 DHCP_CALC_TAG_LENGTH(value_length
)) >
543 /* Insert at start of existing encapsulator */
544 insert_pointp
= (uint8_t *)&encap_hdrp
[1];
545 opt
= DHCP_ENCAPSULATED(opt
);
546 } else if (rc
== ENOENT
) {
552 /* Check unencapsulated tag is not present */
553 rc
= efx_dhcp_walk_tags(&searchp
, &search_size
,
561 if (insert_pointp
== NULL
) {
562 /* Insert at end of existing tags */
563 insert_pointp
= endp
;
566 /* Includes the new encapsulator tag hdr if required */
567 added_length
= DHCP_CALC_TAG_LENGTH(value_length
) +
568 (DHCP_IS_ENCAP_OPT(opt
) ? sizeof (efx_dhcp_tag_hdr_t
) : 0);
570 if (available_space
<= added_length
) {
575 memmove(insert_pointp
+ added_length
, insert_pointp
,
576 available_space
- added_length
);
578 if (DHCP_IS_ENCAP_OPT(opt
)) {
579 /* Create new encapsulator header */
580 added_length
-= sizeof (efx_dhcp_tag_hdr_t
);
581 efx_dhcp_write_tag(insert_pointp
,
582 DHCP_ENCAPSULATOR(opt
), NULL
, added_length
);
583 insert_pointp
+= sizeof (efx_dhcp_tag_hdr_t
);
584 } else if (encap_hdrp
)
585 /* Modify existing encapsulator header */
586 encap_hdrp
->length
+=
587 ((uint8_t)DHCP_CALC_TAG_LENGTH(value_length
));
589 efx_dhcp_write_tag(insert_pointp
, opt
, valuep
, value_length
);
610 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
616 * Update an existing tag to the new value. Copes with encapsulated
617 * tags, and updates the encapsulating opt as necessary.
619 __checkReturn efx_rc_t
621 __inout_bcount(buffer_length
) uint8_t *bufferp
,
622 __in
size_t buffer_length
,
624 __in
uint8_t *value_locationp
,
625 __in_bcount_opt(value_length
) uint8_t *valuep
,
626 __in
size_t value_length
)
629 uint8_t *write_pointp
= value_locationp
- sizeof (efx_dhcp_tag_hdr_t
);
630 efx_dhcp_tag_hdr_t
*hdrp
= (efx_dhcp_tag_hdr_t
*)write_pointp
;
631 efx_dhcp_tag_hdr_t
*encap_hdrp
= NULL
;
634 if (!DHCP_OPT_HAS_VALUE(DHCP_ENCAPSULATED(opt
))) {
639 if (value_length
> DHCP_MAX_VALUE
) {
644 if ((value_length
> 0) && (valuep
== NULL
)) {
649 old_length
= hdrp
->length
;
651 if (old_length
< value_length
) {
652 uint8_t *endp
= bufferp
;
653 size_t available_space
= buffer_length
;
655 rc
= efx_dhcp_walk_tags(&endp
, &available_space
,
660 if (available_space
< (value_length
- old_length
)) {
666 if (DHCP_IS_ENCAP_OPT(opt
)) {
667 uint8_t *encapp
= bufferp
;
668 size_t following_encap
= buffer_length
;
671 rc
= efx_dhcp_walk_tags(&encapp
, &following_encap
,
672 DHCP_ENCAPSULATOR(opt
));
676 encap_hdrp
= (efx_dhcp_tag_hdr_t
*)encapp
;
678 new_length
= ((size_t)encap_hdrp
->length
+
679 value_length
- old_length
);
680 /* Check encapsulator will not overflow */
681 if (new_length
> DHCP_MAX_VALUE
) {
686 encap_hdrp
->length
= (uint8_t)new_length
;
690 * Move the following data up/down to accomodate the new payload
693 if (old_length
!= value_length
) {
694 uint8_t *destp
= (uint8_t *)DHCP_NEXT_TAG(hdrp
) +
695 value_length
- old_length
;
696 size_t count
= &bufferp
[buffer_length
] -
697 (uint8_t *)DHCP_NEXT_TAG(hdrp
);
699 memmove(destp
, DHCP_NEXT_TAG(hdrp
), count
);
702 EFSYS_ASSERT(hdrp
->tag
== DHCP_ENCAPSULATED(opt
));
703 efx_dhcp_write_tag(write_pointp
, opt
, valuep
, value_length
);
720 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
727 * Copy bootcfg sector data to a target buffer which may differ in size.
728 * Optionally corrects format errors in source buffer.
731 efx_bootcfg_copy_sector(
733 __inout_bcount(sector_length
)
735 __in
size_t sector_length
,
736 __out_bcount(data_size
) uint8_t *data
,
737 __in
size_t data_size
,
738 __in boolean_t handle_format_errors
)
740 _NOTE(ARGUNUSED(enp
))
745 /* Minimum buffer is checksum byte and EFX_DHCP_END terminator */
751 /* Verify that the area is correctly formatted and checksummed */
752 rc
= efx_dhcp_verify(sector
, sector_length
,
755 if (!handle_format_errors
) {
759 if ((used_bytes
< 2) ||
760 (sector
[used_bytes
- 1] != EFX_DHCP_END
)) {
761 /* Block too short, or EFX_DHCP_END missing */
767 /* Synthesize empty format on verification failure */
768 if (rc
!= 0 || used_bytes
== 0) {
770 sector
[1] = EFX_DHCP_END
;
773 EFSYS_ASSERT(used_bytes
>= 2); /* checksum and EFX_DHCP_END */
774 EFSYS_ASSERT(used_bytes
<= sector_length
);
775 EFSYS_ASSERT(sector_length
>= 2);
778 * Legacy bootcfg sectors don't terminate with an EFX_DHCP_END
779 * character. Modify the returned payload so it does.
780 * Reinitialise the sector if there isn't room for the character.
782 if (sector
[used_bytes
- 1] != EFX_DHCP_END
) {
783 if (used_bytes
>= sector_length
) {
787 sector
[used_bytes
] = EFX_DHCP_END
;
792 * Verify that the target buffer is large enough for the
793 * entire used bootcfg area, then copy into the target buffer.
795 if (used_bytes
> data_size
) {
800 data
[0] = 0; /* checksum, updated below */
802 /* Copy all after the checksum to the target buffer */
803 memcpy(data
+ 1, sector
+ 1, used_bytes
- 1);
805 /* Zero out the unused portion of the target buffer */
806 if (used_bytes
< data_size
)
807 (void) memset(data
+ used_bytes
, 0, data_size
- used_bytes
);
810 * The checksum includes trailing data after any EFX_DHCP_END
811 * character, which we've just modified (by truncation or appending
814 data
[0] -= efx_dhcp_csum(data
, data_size
);
825 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
833 __out_bcount(size
) uint8_t *data
,
836 uint8_t *payload
= NULL
;
839 size_t sector_length
;
840 size_t sector_offset
;
842 uint32_t sector_number
;
844 /* Minimum buffer is checksum byte and EFX_DHCP_END terminator */
851 sector_number
= enp
->en_nic_cfg
.enc_pf
;
855 rc
= efx_nvram_size(enp
, EFX_NVRAM_BOOTROM_CFG
, &partn_length
);
859 /* The bootcfg sector may be stored in a (larger) shared partition */
860 rc
= efx_bootcfg_sector_info(enp
, sector_number
,
861 NULL
, §or_offset
, §or_length
);
865 if (sector_length
< 2) {
870 if (sector_length
> BOOTCFG_MAX_SIZE
)
871 sector_length
= BOOTCFG_MAX_SIZE
;
873 if (sector_offset
+ sector_length
> partn_length
) {
874 /* Partition is too small */
880 * We need to read the entire BOOTCFG sector to ensure we read all
881 * tags, because legacy bootcfg sectors are not guaranteed to end
882 * with an EFX_DHCP_END character. If the user hasn't supplied a
883 * sufficiently large buffer then use our own buffer.
885 if (sector_length
> size
) {
886 EFSYS_KMEM_ALLOC(enp
->en_esip
, sector_length
, payload
);
887 if (payload
== NULL
) {
892 payload
= (uint8_t *)data
;
894 if ((rc
= efx_nvram_rw_start(enp
, EFX_NVRAM_BOOTROM_CFG
, NULL
)) != 0)
897 if ((rc
= efx_nvram_read_chunk(enp
, EFX_NVRAM_BOOTROM_CFG
,
898 sector_offset
, (caddr_t
)payload
, sector_length
)) != 0) {
899 (void) efx_nvram_rw_finish(enp
, EFX_NVRAM_BOOTROM_CFG
, NULL
);
903 if ((rc
= efx_nvram_rw_finish(enp
, EFX_NVRAM_BOOTROM_CFG
, NULL
)) != 0)
906 /* Verify that the area is correctly formatted and checksummed */
907 rc
= efx_dhcp_verify(payload
, sector_length
,
909 if (rc
!= 0 || used_bytes
== 0) {
911 payload
[1] = EFX_DHCP_END
;
915 EFSYS_ASSERT(used_bytes
>= 2); /* checksum and EFX_DHCP_END */
916 EFSYS_ASSERT(used_bytes
<= sector_length
);
919 * Legacy bootcfg sectors don't terminate with an EFX_DHCP_END
920 * character. Modify the returned payload so it does.
921 * BOOTCFG_MAX_SIZE is by definition large enough for any valid
922 * (per-port) bootcfg sector, so reinitialise the sector if there
923 * isn't room for the character.
925 if (payload
[used_bytes
- 1] != EFX_DHCP_END
) {
926 if (used_bytes
>= sector_length
)
929 payload
[used_bytes
] = EFX_DHCP_END
;
934 * Verify that the user supplied buffer is large enough for the
935 * entire used bootcfg area, then copy into the user supplied buffer.
937 if (used_bytes
> size
) {
942 data
[0] = 0; /* checksum, updated below */
944 if (sector_length
> size
) {
945 /* Copy all after the checksum to the target buffer */
946 memcpy(data
+ 1, payload
+ 1, used_bytes
- 1);
947 EFSYS_KMEM_FREE(enp
->en_esip
, sector_length
, payload
);
950 /* Zero out the unused portion of the user buffer */
951 if (used_bytes
< size
)
952 (void) memset(data
+ used_bytes
, 0, size
- used_bytes
);
955 * The checksum includes trailing data after any EFX_DHCP_END character,
956 * which we've just modified (by truncation or appending EFX_DHCP_END).
958 data
[0] -= efx_dhcp_csum(data
, size
);
970 if (sector_length
> size
)
971 EFSYS_KMEM_FREE(enp
->en_esip
, sector_length
, payload
);
983 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
991 __in_bcount(size
) uint8_t *data
,
997 size_t sector_length
;
998 size_t sector_offset
;
1001 uint32_t sector_number
;
1004 sector_number
= enp
->en_nic_cfg
.enc_pf
;
1009 rc
= efx_nvram_size(enp
, EFX_NVRAM_BOOTROM_CFG
, &partn_length
);
1013 /* The bootcfg sector may be stored in a (larger) shared partition */
1014 rc
= efx_bootcfg_sector_info(enp
, sector_number
,
1015 NULL
, §or_offset
, §or_length
);
1019 if (sector_length
> BOOTCFG_MAX_SIZE
)
1020 sector_length
= BOOTCFG_MAX_SIZE
;
1022 if (sector_offset
+ sector_length
> partn_length
) {
1023 /* Partition is too small */
1028 if ((rc
= efx_dhcp_verify(data
, size
, &used_bytes
)) != 0)
1032 * The caller *must* terminate their block with a EFX_DHCP_END
1035 if ((used_bytes
< 2) || ((uint8_t)data
[used_bytes
- 1] !=
1037 /* Block too short or EFX_DHCP_END missing */
1042 /* Check that the hardware has support for this much data */
1043 if (used_bytes
> MIN(sector_length
, BOOTCFG_MAX_SIZE
)) {
1049 * If the BOOTCFG sector is stored in a shared partition, then we must
1050 * read the whole partition and insert the updated bootcfg sector at the
1053 EFSYS_KMEM_ALLOC(enp
->en_esip
, partn_length
, partn_data
);
1054 if (partn_data
== NULL
) {
1059 rc
= efx_nvram_rw_start(enp
, EFX_NVRAM_BOOTROM_CFG
, NULL
);
1063 /* Read the entire partition */
1064 rc
= efx_nvram_read_chunk(enp
, EFX_NVRAM_BOOTROM_CFG
, 0,
1065 (caddr_t
)partn_data
, partn_length
);
1070 * Insert the BOOTCFG sector into the partition, Zero out all data
1071 * after the EFX_DHCP_END tag, and adjust the checksum.
1073 (void) memset(partn_data
+ sector_offset
, 0x0, sector_length
);
1074 (void) memcpy(partn_data
+ sector_offset
, data
, used_bytes
);
1076 checksum
= efx_dhcp_csum(data
, used_bytes
);
1077 partn_data
[sector_offset
] -= checksum
;
1079 if ((rc
= efx_nvram_erase(enp
, EFX_NVRAM_BOOTROM_CFG
)) != 0)
1082 if ((rc
= efx_nvram_write_chunk(enp
, EFX_NVRAM_BOOTROM_CFG
,
1083 0, (caddr_t
)partn_data
, partn_length
)) != 0)
1086 if ((rc
= efx_nvram_rw_finish(enp
, EFX_NVRAM_BOOTROM_CFG
, NULL
)) != 0)
1089 EFSYS_KMEM_FREE(enp
->en_esip
, partn_length
, partn_data
);
1094 EFSYS_PROBE(fail12
);
1096 EFSYS_PROBE(fail11
);
1098 EFSYS_PROBE(fail10
);
1102 (void) efx_nvram_rw_finish(enp
, EFX_NVRAM_BOOTROM_CFG
, NULL
);
1106 EFSYS_KMEM_FREE(enp
->en_esip
, partn_length
, partn_data
);
1120 EFSYS_PROBE1(fail1
, efx_rc_t
, rc
);
1125 #endif /* EFSYS_OPT_BOOTCFG */