svn commit: r293925 - stable/10/sys/dev/sfxge/common

Andrew Rybchenko arybchik at FreeBSD.org
Thu Jan 14 14:14:05 UTC 2016


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 <pfox at solarflare.com>
  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, &current_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;
 	}
 


More information about the svn-src-all mailing list