From owner-svn-src-stable-10@freebsd.org Thu Jan 14 14:14:05 2016 Return-Path: Delivered-To: svn-src-stable-10@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 426C9A82376; Thu, 14 Jan 2016 14:14:05 +0000 (UTC) (envelope-from arybchik@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 8713B17B7; Thu, 14 Jan 2016 14:14:02 +0000 (UTC) (envelope-from arybchik@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u0EEE0dC019394; Thu, 14 Jan 2016 14:14:00 GMT (envelope-from arybchik@FreeBSD.org) Received: (from arybchik@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u0EEE0m3019391; Thu, 14 Jan 2016 14:14:00 GMT (envelope-from arybchik@FreeBSD.org) Message-Id: <201601141414.u0EEE0m3019391@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: arybchik set sender to arybchik@FreeBSD.org using -f From: Andrew Rybchenko Date: Thu, 14 Jan 2016 14:14:00 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r293925 - stable/10/sys/dev/sfxge/common X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable-10@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: SVN commit messages for only the 10-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 14 Jan 2016 14:14:05 -0000 Author: arybchik Date: Thu Jan 14 14:14:00 2016 New Revision: 293925 URL: https://svnweb.freebsd.org/changeset/base/293925 Log: MFC r291432 sfxge: modify nvram update functions for uio platform to support RFID-selectable presets Dynamic config partitions on boards that support RFID are divided into a number of segments, each formatted like a partition, with header, trailer and end tags. The first segment is the current active configuration. The segments are initialised by manftest and each contain a different configuration e.g. firmware variant. The firmware can be instructed via RFID to copy a segment over the first segment, hence changing the active configuration. This allows ops to change the configuration of a board prior to shipment using RFID. Changes to the dynamic config may need to be written to all segments (in particular firmware versions written by manftest) or just the first segment (changes to the active configuration). See SF-111324-SW. If only the first segment is written the code still needs to be aware of the possible presence of subsequent segments as writing to a segment may cause its size to increase, which would overwrite the subsequent segments and invalidate them. Boards that do not support RFID will only have one segment in their dynamic config partition. Submitted by: Paul Fox Sponsored by: Solarflare Communications, Inc. Modified: stable/10/sys/dev/sfxge/common/hunt_impl.h stable/10/sys/dev/sfxge/common/hunt_nvram.c stable/10/sys/dev/sfxge/common/hunt_vpd.c Directory Properties: stable/10/ (props changed) Modified: stable/10/sys/dev/sfxge/common/hunt_impl.h ============================================================================== --- stable/10/sys/dev/sfxge/common/hunt_impl.h Thu Jan 14 14:13:13 2016 (r293924) +++ stable/10/sys/dev/sfxge/common/hunt_impl.h Thu Jan 14 14:14:00 2016 (r293925) @@ -295,8 +295,8 @@ hunt_mcdi_macaddr_change_supported( extern __checkReturn int hunt_nvram_buf_read_tlv( __in efx_nic_t *enp, - __in_bcount(partn_size) caddr_t partn_data, - __in size_t partn_size, + __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); @@ -327,6 +327,15 @@ hunt_nvram_partn_write_tlv( __in size_t size); extern __checkReturn int +hunt_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); + +extern __checkReturn int hunt_nvram_partn_size( __in efx_nic_t *enp, __in unsigned int partn, Modified: stable/10/sys/dev/sfxge/common/hunt_nvram.c ============================================================================== --- stable/10/sys/dev/sfxge/common/hunt_nvram.c Thu Jan 14 14:13:13 2016 (r293924) +++ stable/10/sys/dev/sfxge/common/hunt_nvram.c Thu Jan 14 14:14:00 2016 (r293925) @@ -571,13 +571,19 @@ fail1: return (rc); } -/* Read and validate an entire TLV formatted partition */ -static __checkReturn int -hunt_nvram_read_tlv_partition( - __in efx_nic_t *enp, - __in uint32_t partn, - __in_bcount(partn_size) caddr_t partn_data, - __in size_t partn_size) +/* + * Read and validate a segment from a partition. A segment is a complete + * tlv chain between PARTITION_HEADER and PARTITION_END tags. There may + * be multiple segments in a partition, so seg_offset allows segments + * beyond the first to be read. + */ +static __checkReturn int +hunt_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) { tlv_cursor_t cursor; struct tlv_partition_header *header; @@ -589,20 +595,20 @@ hunt_nvram_read_tlv_partition( EFX_STATIC_ASSERT(sizeof (*header) <= HUNTINGTON_NVRAM_CHUNK); - if ((partn_data == NULL) || (partn_size == 0)) { + if ((seg_data == NULL) || (max_seg_size == 0)) { rc = EINVAL; goto fail1; } - /* Read initial chunk of partition */ - if ((rc = hunt_nvram_partn_read(enp, partn, 0, partn_data, + /* Read initial chunk of the segment, starting at offset */ + if ((rc = hunt_nvram_partn_read(enp, partn, seg_offset, seg_data, HUNTINGTON_NVRAM_CHUNK)) != 0) { goto fail2; } - /* The partition header must be the first item (at offset zero) */ - if ((rc = tlv_init_cursor_from_size(&cursor, partn_data, - partn_size)) != 0) { + /* A PARTITION_HEADER tag must be the first item at the given offset */ + if ((rc = tlv_init_cursor_from_size(&cursor, seg_data, + max_seg_size)) != 0) { rc = EFAULT; goto fail3; } @@ -612,23 +618,23 @@ hunt_nvram_read_tlv_partition( } header = (struct tlv_partition_header *)tlv_item(&cursor); - /* Check TLV partition length (includes the END tag) */ + /* Check TLV segment length (includes the END tag) */ total_length = __LE_TO_CPU_32(header->total_length); - if (total_length > partn_size) { + if (total_length > max_seg_size) { rc = EFBIG; goto fail5; } - /* Read the remaining partition content */ + /* Read the remaining segment content */ if (total_length > HUNTINGTON_NVRAM_CHUNK) { if ((rc = hunt_nvram_partn_read(enp, partn, - HUNTINGTON_NVRAM_CHUNK, - partn_data + HUNTINGTON_NVRAM_CHUNK, + seg_offset + HUNTINGTON_NVRAM_CHUNK, + seg_data + HUNTINGTON_NVRAM_CHUNK, total_length - HUNTINGTON_NVRAM_CHUNK)) != 0) goto fail6; } - /* Check partition ends with PARTITION_TRAILER and END tags */ + /* Check segment ends with PARTITION_TRAILER and END tags */ if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { rc = EINVAL; goto fail7; @@ -644,7 +650,7 @@ hunt_nvram_read_tlv_partition( goto fail9; } - /* Check data read from partition is consistent */ + /* Check data read from segment is consistent */ if (trailer->generation != header->generation) { /* * The partition data may have been modified between successive @@ -656,10 +662,10 @@ hunt_nvram_read_tlv_partition( goto fail10; } - /* Verify partition checksum */ + /* Verify segment checksum */ cksum = 0; for (pos = 0; (size_t)pos < total_length; pos += sizeof (uint32_t)) { - cksum += *((uint32_t *)(partn_data + pos)); + cksum += *((uint32_t *)(seg_data + pos)); } if (cksum != 0) { rc = EINVAL; @@ -696,13 +702,13 @@ fail1: /* * Read a single TLV item from a host memory - * buffer containing a TLV formatted partition. + * buffer containing a TLV formatted segment. */ __checkReturn int hunt_nvram_buf_read_tlv( __in efx_nic_t *enp, - __in_bcount(partn_size) caddr_t partn_data, - __in size_t partn_size, + __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) @@ -713,14 +719,14 @@ hunt_nvram_buf_read_tlv( caddr_t value; int rc; - if ((partn_data == NULL) || (partn_size == 0)) { + if ((seg_data == NULL) || (max_seg_size == 0)) { rc = EINVAL; goto fail1; } - /* Find requested TLV tag in partition data */ - if ((rc = tlv_init_cursor_from_size(&cursor, partn_data, - partn_size)) != 0) { + /* Find requested TLV tag in segment data */ + if ((rc = tlv_init_cursor_from_size(&cursor, seg_data, + max_seg_size)) != 0) { rc = EFAULT; goto fail2; } @@ -760,18 +766,16 @@ fail1: return (rc); } - - -/* Read a single TLV item from a TLV formatted partition */ +/* Read a single TLV item from the first segment in a TLV formatted partition */ __checkReturn int hunt_nvram_partn_read_tlv( - __in efx_nic_t *enp, - __in uint32_t partn, - __in uint32_t tag, - __deref_out_bcount_opt(*sizep) caddr_t *datap, - __out size_t *sizep) + __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) { - caddr_t partn_data = NULL; + caddr_t seg_data = NULL; size_t partn_size = 0; size_t length; caddr_t data; @@ -787,39 +791,39 @@ hunt_nvram_partn_read_tlv( goto fail2; } - EFSYS_KMEM_ALLOC(enp->en_esip, partn_size, partn_data); - if (partn_data == NULL) { + EFSYS_KMEM_ALLOC(enp->en_esip, partn_size, seg_data); + if (seg_data == NULL) { rc = ENOMEM; goto fail3; } /* - * Read the entire TLV partition. Retry until consistent partition - * contents are returned. Inconsistent data may be read if: - * a) the partition contents are invalid + * Read the first segment in a TLV partition. Retry until consistent + * segment contents are returned. Inconsistent data may be read if: + * a) the segment contents are invalid * b) the MC has rebooted while we were reading the partition * c) the partition has been modified while we were reading it * Limit retry attempts to ensure forward progress. */ retry = 10; do { - rc = hunt_nvram_read_tlv_partition(enp, partn, - partn_data, partn_size); + rc = hunt_nvram_read_tlv_segment(enp, partn, 0, + seg_data, partn_size); } while ((rc == EAGAIN) && (--retry > 0)); if (rc != 0) { - /* Failed to obtain consistent partition data */ + /* Failed to obtain consistent segment data */ goto fail4; } - if ((rc = hunt_nvram_buf_read_tlv(enp, partn_data, partn_size, + if ((rc = hunt_nvram_buf_read_tlv(enp, seg_data, partn_size, tag, &data, &length)) != 0) goto fail5; - EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data); + EFSYS_KMEM_FREE(enp->en_esip, partn_size, seg_data); - *datap = data; - *sizep = length; + *seg_datap = data; + *seg_sizep = length; return (0); @@ -828,7 +832,137 @@ fail5: fail4: EFSYS_PROBE(fail4); - EFSYS_KMEM_FREE(enp->en_esip, partn_size, partn_data); + EFSYS_KMEM_FREE(enp->en_esip, partn_size, seg_data); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, int, rc); + + return (rc); +} + +/* Compute the size of a segment. */ + static __checkReturn int +hunt_nvram_buf_segment_size( + __in caddr_t seg_data, + __in size_t max_seg_size, + __out size_t *seg_sizep) +{ + int rc; + tlv_cursor_t cursor; + struct tlv_partition_header *header; + struct tlv_partition_trailer *trailer; + uint32_t cksum; + int pos; + uint32_t *end_tag_position; + uint32_t segment_length; + + /* A PARTITION_HEADER tag must be the first item at the given offset */ + if ((rc = tlv_init_cursor_from_size(&cursor, seg_data, + max_seg_size)) != 0) { + rc = EFAULT; + goto fail1; + } + if (tlv_tag(&cursor) != TLV_TAG_PARTITION_HEADER) { + rc = EINVAL; + goto fail2; + } + header = (struct tlv_partition_header *)tlv_item(&cursor); + + /* Check TLV segment length (includes the END tag) */ + *seg_sizep = __LE_TO_CPU_32(header->total_length); + if (*seg_sizep > max_seg_size) { + rc = EFBIG; + goto fail3; + } + + /* Check segment ends with PARTITION_TRAILER and END tags */ + if ((rc = tlv_find(&cursor, TLV_TAG_PARTITION_TRAILER)) != 0) { + rc = EINVAL; + goto fail4; + } + trailer = (struct tlv_partition_trailer *)tlv_item(&cursor); + + if ((rc = tlv_advance(&cursor)) != 0) { + rc = EINVAL; + goto fail5; + } + if (tlv_tag(&cursor) != TLV_TAG_END) { + rc = EINVAL; + goto fail6; + } + end_tag_position = cursor.current; + + /* Verify segment checksum */ + cksum = 0; + for (pos = 0; (size_t)pos < *seg_sizep; pos += sizeof (uint32_t)) { + cksum += *((uint32_t *)(seg_data + pos)); + } + if (cksum != 0) { + rc = EINVAL; + goto fail7; + } + + /* + * Calculate total length from HEADER to END tags and compare to + * max_seg_size and the total_length field in the HEADER tag. + */ + segment_length = tlv_block_length_used(&cursor); + + if (segment_length > max_seg_size) { + rc = EINVAL; + goto fail8; + } + + if (segment_length != *seg_sizep) { + rc = EINVAL; + goto fail9; + } + + /* Skip over the first HEADER tag. */ + rc = tlv_rewind(&cursor); + rc = tlv_advance(&cursor); + + while (rc == 0) { + if (tlv_tag(&cursor) == TLV_TAG_END) { + /* Check that the END tag is the one found earlier. */ + if (cursor.current != end_tag_position) + goto fail10; + break; + } + /* Check for duplicate HEADER tags before the END tag. */ + if (tlv_tag(&cursor) == TLV_TAG_PARTITION_HEADER) { + rc = EINVAL; + goto fail11; + } + + rc = tlv_advance(&cursor); + } + if (rc != 0) + goto fail12; + + return (0); + +fail12: + EFSYS_PROBE(fail12); +fail11: + EFSYS_PROBE(fail11); +fail10: + EFSYS_PROBE(fail10); +fail9: + EFSYS_PROBE(fail9); +fail8: + EFSYS_PROBE(fail8); +fail7: + EFSYS_PROBE(fail7); +fail6: + EFSYS_PROBE(fail6); +fail5: + EFSYS_PROBE(fail5); +fail4: + EFSYS_PROBE(fail4); fail3: EFSYS_PROBE(fail3); fail2: @@ -841,12 +975,12 @@ fail1: /* * Add or update a single TLV item in a host memory buffer containing a TLV - * formatted partition. + * formatted segment. Historically partitions consisted of only one segment. */ - __checkReturn int + __checkReturn int hunt_nvram_buf_write_tlv( - __inout_bcount(partn_size) caddr_t partn_data, - __in size_t partn_size, + __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, @@ -860,9 +994,9 @@ hunt_nvram_buf_write_tlv( int pos; int rc; - /* The partition header must be the first item (at offset zero) */ - if ((rc = tlv_init_cursor_from_size(&cursor, partn_data, - partn_size)) != 0) { + /* A PARTITION_HEADER tag must be the first item (at offset zero) */ + if ((rc = tlv_init_cursor_from_size(&cursor, seg_data, + max_seg_size)) != 0) { rc = EFAULT; goto fail1; } @@ -901,7 +1035,10 @@ hunt_nvram_buf_write_tlv( /* Update PARTITION_HEADER and PARTITION_TRAILER fields */ *total_lengthp = tlv_block_length_used(&cursor); - EFSYS_ASSERT3U(*total_lengthp, <=, partn_size); + if (*total_lengthp > max_seg_size) { + rc = ENOSPC; + goto fail7; + } generation = __LE_TO_CPU_32(header->generation) + 1; header->total_length = __CPU_TO_LE_32(*total_lengthp); @@ -912,12 +1049,14 @@ hunt_nvram_buf_write_tlv( trailer->checksum = 0; cksum = 0; for (pos = 0; (size_t)pos < *total_lengthp; pos += sizeof (uint32_t)) { - cksum += *((uint32_t *)(partn_data + pos)); + cksum += *((uint32_t *)(seg_data + pos)); } trailer->checksum = ~cksum + 1; return (0); +fail7: + EFSYS_PROBE(fail7); fail6: EFSYS_PROBE(fail6); fail5: @@ -934,7 +1073,11 @@ fail1: return (rc); } -/* Add or update a single TLV item in a TLV formatted partition */ +/* + * Add or update a single TLV item in the first segment of a TLV formatted + * dynamic config partition. The first segment is the current active + * configuration. + */ __checkReturn int hunt_nvram_partn_write_tlv( __in efx_nic_t *enp, @@ -943,10 +1086,114 @@ hunt_nvram_partn_write_tlv( __in_bcount(size) caddr_t data, __in size_t size) { - size_t partn_size; + return hunt_nvram_partn_write_segment_tlv(enp, partn, tag, data, + size, B_FALSE); +} + +/* + * Read a segment from nvram at the given offset into a buffer (segment_data) + * and optionally write a new tag to it. + */ + static __checkReturn int +hunt_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) +{ + int rc; + int status; + size_t original_segment_size; + size_t modified_segment_size; + + /* + * Read the segment from NVRAM into the segment_data buffer and validate + * it, returning if it does not validate. This is not a failure unless + * this is the first segment in a partition. In this case the caller + * must propogate the error. + */ + status = hunt_nvram_read_tlv_segment(enp, partn, *partn_offsetp, + *seg_datap, *src_remain_lenp); + if (status != 0) + return (EINVAL); + + status = hunt_nvram_buf_segment_size(*seg_datap, + *src_remain_lenp, &original_segment_size); + if (status != 0) + return (EINVAL); + + if (write) { + /* Update the contents of the segment in the buffer */ + if ((rc = hunt_nvram_buf_write_tlv(*seg_datap, + *dest_remain_lenp, tag, data, size, + &modified_segment_size)) != 0) + goto fail1; + *dest_remain_lenp -= modified_segment_size; + *seg_datap += modified_segment_size; + } else { + /* + * We won't modify this segment, but still need to update the + * remaining lengths and pointers. + */ + *dest_remain_lenp -= original_segment_size; + *seg_datap += original_segment_size; + } + + *partn_offsetp += original_segment_size; + *src_remain_lenp -= original_segment_size; + + return (0); + +fail1: + EFSYS_PROBE1(fail1, int, rc); + + return (rc); +} + +/* + * Add or update a single TLV item in either the first segment or in all + * segments in a TLV formatted dynamic config partition. Dynamic config + * partitions on boards that support RFID are divided into a number of segments, + * each formatted like a partition, with header, trailer and end tags. The first + * segment is the current active configuration. + * + * The segments are initialised by manftest and each contain a different + * configuration e.g. firmware variant. The firmware can be instructed + * via RFID to copy a segment to replace the first segment, hence changing the + * active configuration. This allows ops to change the configuration of a board + * prior to shipment using RFID. + * + * Changes to the dynamic config may need to be written to all segments (e.g. + * firmware versions) or just the first segment (changes to the active + * configuration). See SF-111324-SW "The use of RFID in Solarflare Products". + * If only the first segment is written the code still needs to be aware of the + * possible presence of subsequent segments as writing to a segment may cause + * its size to increase, which would overwrite the subsequent segments and + * invalidate them. + */ + __checkReturn int +hunt_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) +{ + size_t partn_size = 0; caddr_t partn_data; - size_t total_length; + size_t total_length = 0; int rc; + size_t current_offset = 0; + size_t remaining_original_length; + size_t remaining_modified_length; + caddr_t segment_data; EFSYS_ASSERT3U(partn, ==, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG); @@ -960,27 +1207,49 @@ hunt_nvram_partn_write_tlv( goto fail2; } + remaining_original_length = partn_size; + remaining_modified_length = partn_size; + segment_data = partn_data; + /* Lock the partition */ if ((rc = hunt_nvram_partn_lock(enp, partn)) != 0) goto fail3; - /* Read the partition contents (no need to retry when locked). */ - if ((rc = hunt_nvram_read_tlv_partition(enp, partn, - partn_data, partn_size)) != 0) { - /* Failed to obtain consistent partition data */ - goto fail4; - } + /* Iterate over each (potential) segment to update it. */ + do { + boolean_t write = all_segments || current_offset == 0; - /* Update the contents in memory */ - if ((rc = hunt_nvram_buf_write_tlv(partn_data, partn_size, - tag, data, size, &total_length)) != 0) + rc = hunt_nvram_segment_write_tlv(enp, partn, tag, data, size, + &segment_data, ¤t_offset, &remaining_original_length, + &remaining_modified_length, write); + if (rc != 0) { + if (current_offset == 0) { + /* + * If no data has been read then the first + * segment is invalid, which is an error. + */ + goto fail4; + } + break; + } + } while (current_offset < partn_size); + + total_length = segment_data - partn_data; + + /* + * We've run out of space. This should actually be dealt with by + * hunt_nvram_buf_write_tlv returning ENOSPC. + */ + if (total_length > partn_size) { + rc = ENOSPC; goto fail5; + } - /* Erase the whole partition */ + /* Erase the whole partition in NVRAM */ if ((rc = hunt_nvram_partn_erase(enp, partn, 0, partn_size)) != 0) goto fail6; - /* Write new partition contents to NVRAM */ + /* Write new partition contents from the buffer to NVRAM */ if ((rc = hunt_nvram_partn_write(enp, partn, 0, partn_data, total_length)) != 0) goto fail7; @@ -1014,6 +1283,10 @@ fail1: return (rc); } +/* + * Get the size of a NVRAM partition. This is the total size allocated in nvram, + * not the data used by the segments in the partition. + */ __checkReturn int hunt_nvram_partn_size( __in efx_nic_t *enp, @@ -1171,10 +1444,11 @@ hunt_nvram_partn_set_version( size = sizeof (partn_version) - (2 * sizeof (uint32_t)); - if ((rc = hunt_nvram_partn_write_tlv(enp, + /* Write the version number to all segments in the partition */ + if ((rc = hunt_nvram_partn_write_segment_tlv(enp, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, TLV_TAG_PARTITION_VERSION(partn), - (caddr_t)&partn_version.version_w, size)) != 0) + (caddr_t)&partn_version.version_w, size, B_TRUE)) != 0) goto fail1; return (0); Modified: stable/10/sys/dev/sfxge/common/hunt_vpd.c ============================================================================== --- stable/10/sys/dev/sfxge/common/hunt_vpd.c Thu Jan 14 14:13:13 2016 (r293924) +++ stable/10/sys/dev/sfxge/common/hunt_vpd.c Thu Jan 14 14:14:00 2016 (r293925) @@ -396,11 +396,11 @@ hunt_vpd_write( if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0) goto fail1; - /* Store new dynamic VPD in DYNAMIC_CONFIG partition */ - if ((rc = hunt_nvram_partn_write_tlv(enp, + /* Store new dynamic VPD in all segments in DYNAMIC_CONFIG partition */ + if ((rc = hunt_nvram_partn_write_segment_tlv(enp, NVRAM_PARTITION_TYPE_DYNAMIC_CONFIG, TLV_TAG_PF_DYNAMIC_VPD(pci_pf), - data, vpd_length)) != 0) { + data, vpd_length, B_TRUE)) != 0) { goto fail2; }