xref: /titanic_41/usr/src/lib/libfru/libfru/PayloadReader.cc (revision 34e5f34ea2684ba8edcac4d3985bf6ea664830f4)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
23*34e5f34eSkmohan  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*34e5f34eSkmohan  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <string.h>
307c478bd9Sstevel@tonic-gate #include <stdlib.h>
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include "PayloadReader.h"
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #define	ITER_CONT_BYTE_LEN 4
357c478bd9Sstevel@tonic-gate #define	IS_ITERATED(pathDef) \
367c478bd9Sstevel@tonic-gate (pathDef->def->iterationType != FRU_NOT_ITERATED)
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate // functions to place bit data properly.
397c478bd9Sstevel@tonic-gate static fru_errno_t
407c478bd9Sstevel@tonic-gate writeBits(uint64_t bitData, size_t bitLength,
417c478bd9Sstevel@tonic-gate 	uint8_t *data, size_t dataLength, size_t bitOffset)
427c478bd9Sstevel@tonic-gate {
437c478bd9Sstevel@tonic-gate 	if ((bitLength > 64) &&
447c478bd9Sstevel@tonic-gate 		(bitOffset > 64) &&
457c478bd9Sstevel@tonic-gate 		(dataLength > 8) &&
467c478bd9Sstevel@tonic-gate 		(bitOffset > (dataLength * 8)))
477c478bd9Sstevel@tonic-gate 		return (FRU_FAILURE);
487c478bd9Sstevel@tonic-gate 	// move the bit data into place
497c478bd9Sstevel@tonic-gate 	bitData = (bitData << (64-bitLength));
507c478bd9Sstevel@tonic-gate 	bitData = (bitData >> bitOffset);
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate 	// create a mask to clear the old data.
537c478bd9Sstevel@tonic-gate 	uint64_t mask = 0;
547c478bd9Sstevel@tonic-gate 	for (size_t i = 0; i < bitLength; i++) {
557c478bd9Sstevel@tonic-gate 		mask = ((mask << 1) + 1);
567c478bd9Sstevel@tonic-gate 	}
577c478bd9Sstevel@tonic-gate 	mask = (mask << (64-bitLength));
587c478bd9Sstevel@tonic-gate 	mask = (mask >> bitOffset);
59*34e5f34eSkmohan 	mask = (mask ^ 0xFFFFFFFFFFFFFFFFULL);
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate 	// get the data out of the byte array.
627c478bd9Sstevel@tonic-gate 	uint64_t rd = 0;
637c478bd9Sstevel@tonic-gate 	memcpy((void *)&rd, (void *)data, dataLength);
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate 	// clear the old data
667c478bd9Sstevel@tonic-gate 	rd = (rd & mask);
677c478bd9Sstevel@tonic-gate 	// put in the new data.
687c478bd9Sstevel@tonic-gate 	rd = (rd | bitData);
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate 	// write the data back to the buffer.
717c478bd9Sstevel@tonic-gate 	memcpy((void *)data, (void *)&rd, dataLength);
727c478bd9Sstevel@tonic-gate 	return (FRU_SUCCESS);
737c478bd9Sstevel@tonic-gate }
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate static fru_errno_t
767c478bd9Sstevel@tonic-gate readBits(size_t bitLength, uint8_t *data,
777c478bd9Sstevel@tonic-gate 	size_t dataLength, int bitOffset, uint64_t *ret)
787c478bd9Sstevel@tonic-gate {
797c478bd9Sstevel@tonic-gate 	if ((bitLength > 64) ||
807c478bd9Sstevel@tonic-gate 		(bitLength < 0) ||
817c478bd9Sstevel@tonic-gate 		(bitOffset > 64) ||
827c478bd9Sstevel@tonic-gate 		(dataLength > 8) ||
837c478bd9Sstevel@tonic-gate 		(bitOffset > (dataLength * 8)))
847c478bd9Sstevel@tonic-gate 		return (FRU_FAILURE);
857c478bd9Sstevel@tonic-gate 	// get the data out of the byte array.
867c478bd9Sstevel@tonic-gate 	uint64_t rc = 0;
877c478bd9Sstevel@tonic-gate 	memcpy((void *)&rc, (void *)data, dataLength);
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 	rc = (rc << bitOffset);
907c478bd9Sstevel@tonic-gate 	rc = (rc >> (64 - bitLength));
917c478bd9Sstevel@tonic-gate 	*ret = rc;
927c478bd9Sstevel@tonic-gate 	return (FRU_SUCCESS);
937c478bd9Sstevel@tonic-gate }
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate // ===========================================================================
967c478bd9Sstevel@tonic-gate // caller is to be sure elemDef is contained by recDef.
977c478bd9Sstevel@tonic-gate int
987c478bd9Sstevel@tonic-gate PayloadReader::getOffsetIntoRecord(fru_regdef_t *recDef,
997c478bd9Sstevel@tonic-gate 				fru_regdef_t *elemDef)
1007c478bd9Sstevel@tonic-gate {
1017c478bd9Sstevel@tonic-gate 	int rc = 0;
1027c478bd9Sstevel@tonic-gate 	for (int i = 0; i < recDef->enumCount; i++) {
1037c478bd9Sstevel@tonic-gate 		if (strcmp(recDef->enumTable[i].text, elemDef->name) == 0)
1047c478bd9Sstevel@tonic-gate 			return (rc);
1057c478bd9Sstevel@tonic-gate 		const fru_regdef_t *tmpDef = fru_reg_lookup_def_by_name(
1067c478bd9Sstevel@tonic-gate 					(char *)recDef->enumTable[i].text);
1077c478bd9Sstevel@tonic-gate 		rc += tmpDef->payloadLen;
1087c478bd9Sstevel@tonic-gate 	}
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate }
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate // ===========================================================================
1137c478bd9Sstevel@tonic-gate // return -1 on error.
1147c478bd9Sstevel@tonic-gate int
1157c478bd9Sstevel@tonic-gate PayloadReader::calcOffset(int iterType,
1167c478bd9Sstevel@tonic-gate 			uint8_t head, uint8_t tail,
1177c478bd9Sstevel@tonic-gate 			uint8_t iterThere, uint8_t iterPoss,
1187c478bd9Sstevel@tonic-gate 			size_t length, int index,
1197c478bd9Sstevel@tonic-gate 			fru_errno_t *err)
1207c478bd9Sstevel@tonic-gate {
1217c478bd9Sstevel@tonic-gate 	*err = FRU_SUCCESS;
1227c478bd9Sstevel@tonic-gate 	switch (iterType) {
1237c478bd9Sstevel@tonic-gate 		case FRU_FIFO:
1247c478bd9Sstevel@tonic-gate 		case FRU_Linear:
1257c478bd9Sstevel@tonic-gate 		{
1267c478bd9Sstevel@tonic-gate 			if (index == PathDef::lastIteration)
1277c478bd9Sstevel@tonic-gate 				return (length * tail);
1287c478bd9Sstevel@tonic-gate 			return (length * index);
1297c478bd9Sstevel@tonic-gate 		break;
1307c478bd9Sstevel@tonic-gate 		}
1317c478bd9Sstevel@tonic-gate 		case FRU_Circular:
1327c478bd9Sstevel@tonic-gate 		case FRU_LIFO:
1337c478bd9Sstevel@tonic-gate 		{
1347c478bd9Sstevel@tonic-gate 			if (index == PathDef::lastIteration) {
1357c478bd9Sstevel@tonic-gate 				if (iterType == FRU_LIFO)
1367c478bd9Sstevel@tonic-gate 					return (length * head);
1377c478bd9Sstevel@tonic-gate 				return (length * tail);
1387c478bd9Sstevel@tonic-gate 			}
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 			// For reading they are oposite.
1417c478bd9Sstevel@tonic-gate 			if (iterType == FRU_Circular) {
1427c478bd9Sstevel@tonic-gate 				return (length * ((head + index) % iterPoss));
1437c478bd9Sstevel@tonic-gate 			} else {
1447c478bd9Sstevel@tonic-gate 				int abs = tail - index;
1457c478bd9Sstevel@tonic-gate 				if (abs < 0)
1467c478bd9Sstevel@tonic-gate 					// abs is negative here
1477c478bd9Sstevel@tonic-gate 					abs = iterPoss + abs;
1487c478bd9Sstevel@tonic-gate 				return (length * abs);
1497c478bd9Sstevel@tonic-gate 			}
1507c478bd9Sstevel@tonic-gate 		break;
1517c478bd9Sstevel@tonic-gate 		}
1527c478bd9Sstevel@tonic-gate 	}
1537c478bd9Sstevel@tonic-gate 	*err = FRU_FAILURE;
1547c478bd9Sstevel@tonic-gate 	return (-1);
1557c478bd9Sstevel@tonic-gate }
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate // ===========================================================================
1587c478bd9Sstevel@tonic-gate // return -1 on error.
1597c478bd9Sstevel@tonic-gate int
1607c478bd9Sstevel@tonic-gate PayloadReader::getIterationOffset(uint8_t *iter, int iterLen,
1617c478bd9Sstevel@tonic-gate 				PathDef *path, int *rcIterThere,
1627c478bd9Sstevel@tonic-gate 				fru_errno_t *err,
1637c478bd9Sstevel@tonic-gate 				int onlyFindingIterThereFlag)
1647c478bd9Sstevel@tonic-gate {
1657c478bd9Sstevel@tonic-gate 	int rc = 0;
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	// read the iteration control bytes first because we may ONLY need
1687c478bd9Sstevel@tonic-gate 	// them.
1697c478bd9Sstevel@tonic-gate 	uint8_t head = iter[0];
1707c478bd9Sstevel@tonic-gate 	uint8_t tail = iter[1];
1717c478bd9Sstevel@tonic-gate 	uint8_t iterThere = iter[2];
1727c478bd9Sstevel@tonic-gate 	uint8_t iterPoss = iter[3];
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	// the '+' symbol on anything is an error here
1757c478bd9Sstevel@tonic-gate 	if (path->iterIndex == PathDef::addIteration) {
1767c478bd9Sstevel@tonic-gate 		*err = FRU_INVALPATH;
1777c478bd9Sstevel@tonic-gate 		return (-1);
1787c478bd9Sstevel@tonic-gate 	}
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	// check assumptions for next calls.
1817c478bd9Sstevel@tonic-gate 	if (iterPoss != path->def->iterationCount) {
1827c478bd9Sstevel@tonic-gate 		*err = FRU_DATACORRUPT;
1837c478bd9Sstevel@tonic-gate 		return (-1);
1847c478bd9Sstevel@tonic-gate 	}
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	if (onlyFindingIterThereFlag == ITER_THERE_ONLY) {
1877c478bd9Sstevel@tonic-gate 		if (rcIterThere != NULL) {
1887c478bd9Sstevel@tonic-gate 			*rcIterThere = iterThere;
1897c478bd9Sstevel@tonic-gate 		}
1907c478bd9Sstevel@tonic-gate 		*err = FRU_SUCCESS;
1917c478bd9Sstevel@tonic-gate 		return (ITER_CONT_BYTE_LEN);
1927c478bd9Sstevel@tonic-gate 	}
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	if ((path->iterIndex != PathDef::addIteration) &&
1957c478bd9Sstevel@tonic-gate 		(path->iterIndex != PathDef::lastIteration) &&
1967c478bd9Sstevel@tonic-gate 		(path->iterIndex >= iterThere)) {
1977c478bd9Sstevel@tonic-gate 		*err = FRU_DATANOTFOUND;
1987c478bd9Sstevel@tonic-gate 		return (-1);
1997c478bd9Sstevel@tonic-gate 	}
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	// don't forget to skip the iteration control bytes!!!
2027c478bd9Sstevel@tonic-gate 	int length = ((path->def->payloadLen - ITER_CONT_BYTE_LEN)
2037c478bd9Sstevel@tonic-gate 			/path->def->iterationCount);
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	rc = calcOffset(path->def->iterationType,
2067c478bd9Sstevel@tonic-gate 			head, tail, iterThere, iterPoss,
2077c478bd9Sstevel@tonic-gate 			length, path->iterIndex, err);
2087c478bd9Sstevel@tonic-gate 	if (rc == -1) {
2097c478bd9Sstevel@tonic-gate 		// error set by calcOffset
2107c478bd9Sstevel@tonic-gate 		return (-1);
2117c478bd9Sstevel@tonic-gate 	}
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 	*err = FRU_SUCCESS;
2147c478bd9Sstevel@tonic-gate 	return (ITER_CONT_BYTE_LEN + rc);
2157c478bd9Sstevel@tonic-gate }
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate // ===========================================================================
2187c478bd9Sstevel@tonic-gate // Iff onlyFindingIterThereFlag is set data is ignored and dataLen will be set
2197c478bd9Sstevel@tonic-gate // to the number of iterations which are actually in the seeprom.
2207c478bd9Sstevel@tonic-gate fru_errno_t
2217c478bd9Sstevel@tonic-gate PayloadReader::readRecurse(PathDef *path,
2227c478bd9Sstevel@tonic-gate 			uint8_t *cur, size_t curLen,
2237c478bd9Sstevel@tonic-gate 			void **data, size_t *dataLen,
2247c478bd9Sstevel@tonic-gate 			int onlyFindingIterThereFlag)
2257c478bd9Sstevel@tonic-gate {
2267c478bd9Sstevel@tonic-gate 	fru_errno_t rc = FRU_SUCCESS;
2277c478bd9Sstevel@tonic-gate 	size_t calc_data_len = 0;
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	if (path->next == NULL) {
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 		// alway go ahead and do the iterated thing.  If we are not a
2327c478bd9Sstevel@tonic-gate 		// field then the onlyFindingIterThereFlag should be set.
2337c478bd9Sstevel@tonic-gate 		// Check this afterward.
2347c478bd9Sstevel@tonic-gate 		int offset = 0;
2357c478bd9Sstevel@tonic-gate 		int iterThere = 0;
2367c478bd9Sstevel@tonic-gate 		// zzz altering the length things again...
2377c478bd9Sstevel@tonic-gate 		if (IS_ITERATED(path)) {
2387c478bd9Sstevel@tonic-gate 			// we are iterated.
2397c478bd9Sstevel@tonic-gate 			calc_data_len = (path->def->payloadLen
2407c478bd9Sstevel@tonic-gate 						-ITER_CONT_BYTE_LEN)/
2417c478bd9Sstevel@tonic-gate 					path->def->iterationCount;
2427c478bd9Sstevel@tonic-gate // zzz still have to figure out the bit offsets for bit iterations...
2437c478bd9Sstevel@tonic-gate 			offset = getIterationOffset(cur, curLen, path,
2447c478bd9Sstevel@tonic-gate 				&iterThere, &rc,
2457c478bd9Sstevel@tonic-gate 				onlyFindingIterThereFlag);
2467c478bd9Sstevel@tonic-gate 			if (offset == -1)
2477c478bd9Sstevel@tonic-gate 				return (rc);
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 			// done
2507c478bd9Sstevel@tonic-gate 			if (onlyFindingIterThereFlag) {
2517c478bd9Sstevel@tonic-gate 				*dataLen = iterThere;
2527c478bd9Sstevel@tonic-gate 				return (FRU_SUCCESS);
2537c478bd9Sstevel@tonic-gate 			}
2547c478bd9Sstevel@tonic-gate 		} else {
2557c478bd9Sstevel@tonic-gate 			// done but this thing was not an iteration!!!
2567c478bd9Sstevel@tonic-gate 			if (onlyFindingIterThereFlag) {
2577c478bd9Sstevel@tonic-gate 				return (FRU_INVALPATH);
2587c478bd9Sstevel@tonic-gate 			}
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 			calc_data_len = path->def->payloadLen;
2617c478bd9Sstevel@tonic-gate 			offset = 0;
2627c478bd9Sstevel@tonic-gate 		}
2637c478bd9Sstevel@tonic-gate 		// end zzz
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 		// now make sure we have a field.
2667c478bd9Sstevel@tonic-gate 		if (path->def->dataType == FDTYPE_Record) {
2677c478bd9Sstevel@tonic-gate 			return (FRU_NOTFIELD);
2687c478bd9Sstevel@tonic-gate 		}
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 		// allocate and copy.
2717c478bd9Sstevel@tonic-gate 		if (path->def->dataType == FDTYPE_Binary) {
2727c478bd9Sstevel@tonic-gate 			uint64_t *eData = (uint64_t *)malloc(sizeof (*eData));
2737c478bd9Sstevel@tonic-gate 			if (eData == NULL) {
2747c478bd9Sstevel@tonic-gate 				return (FRU_FAILURE);
2757c478bd9Sstevel@tonic-gate 			}
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 			int bitLength = path->def->dataLength;
2787c478bd9Sstevel@tonic-gate 			// iterated bit field adjust acordingly.
2797c478bd9Sstevel@tonic-gate 			if (IS_ITERATED(path)) {
2807c478bd9Sstevel@tonic-gate 				bitLength = (bitLength-(ITER_CONT_BYTE_LEN*8))/
2817c478bd9Sstevel@tonic-gate 					path->def->iterationCount;
2827c478bd9Sstevel@tonic-gate 			}
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 			rc = readBits(bitLength, &(cur[offset]),
2857c478bd9Sstevel@tonic-gate 					calc_data_len, 0, eData);
2867c478bd9Sstevel@tonic-gate 			if (rc != FRU_SUCCESS) {
2877c478bd9Sstevel@tonic-gate 				free(eData);
2887c478bd9Sstevel@tonic-gate 				return (rc);
2897c478bd9Sstevel@tonic-gate 			}
2907c478bd9Sstevel@tonic-gate 			*data = (void *)eData;
2917c478bd9Sstevel@tonic-gate 			*dataLen = sizeof (*eData);
2927c478bd9Sstevel@tonic-gate 		} else if (path->def->dataType == FDTYPE_Enumeration) {
2937c478bd9Sstevel@tonic-gate 			unsigned char *eData
2947c478bd9Sstevel@tonic-gate 				= (unsigned char *)malloc(sizeof (uint64_t));
2957c478bd9Sstevel@tonic-gate 			if (eData == NULL) {
2967c478bd9Sstevel@tonic-gate 				return (FRU_FAILURE);
2977c478bd9Sstevel@tonic-gate 			}
2987c478bd9Sstevel@tonic-gate 			/* copy the correct number of bytes to eData */
2997c478bd9Sstevel@tonic-gate 			memset(eData, 0x00, sizeof (uint64_t));
3007c478bd9Sstevel@tonic-gate 			memcpy(&(eData[(sizeof (uint64_t) - (calc_data_len))]),
3017c478bd9Sstevel@tonic-gate 				&(cur[offset]),
3027c478bd9Sstevel@tonic-gate 				(calc_data_len));
3037c478bd9Sstevel@tonic-gate 			*data = (void*)eData;
3047c478bd9Sstevel@tonic-gate 			*dataLen = sizeof (uint64_t);
3057c478bd9Sstevel@tonic-gate 		} else {
3067c478bd9Sstevel@tonic-gate 			void *rc_data = malloc(calc_data_len);
3077c478bd9Sstevel@tonic-gate 			if (rc_data == NULL) {
3087c478bd9Sstevel@tonic-gate 				return (FRU_FAILURE);
3097c478bd9Sstevel@tonic-gate 			}
3107c478bd9Sstevel@tonic-gate 			memcpy(rc_data, &(cur[offset]), calc_data_len);
3117c478bd9Sstevel@tonic-gate 			*data = rc_data;
3127c478bd9Sstevel@tonic-gate 			*dataLen = calc_data_len;
3137c478bd9Sstevel@tonic-gate 		}
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 		return (FRU_SUCCESS);
3167c478bd9Sstevel@tonic-gate 	}
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	// At this point we know the entry is some sort of record.
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	int newOffset = 0, newLength = 0;
3217c478bd9Sstevel@tonic-gate 	if (IS_ITERATED(path)) {
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate // zzz still have to figure out the bit offsets for bit iterations...
3247c478bd9Sstevel@tonic-gate 		newOffset = getIterationOffset(cur, curLen,
3257c478bd9Sstevel@tonic-gate 				path, NULL, &rc, NORMAL_READ);
3267c478bd9Sstevel@tonic-gate 		if (newOffset == -1)
3277c478bd9Sstevel@tonic-gate 			return (rc);
3287c478bd9Sstevel@tonic-gate 	}
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	newOffset += getOffsetIntoRecord(path->def, path->next->def);
3317c478bd9Sstevel@tonic-gate 	newLength = path->next->def->payloadLen;
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	return (readRecurse(path->next, &(cur[newOffset]), newLength,
3347c478bd9Sstevel@tonic-gate 		data, dataLen, onlyFindingIterThereFlag));
3357c478bd9Sstevel@tonic-gate }
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate // ===========================================================================
3387c478bd9Sstevel@tonic-gate // will send the data back in (data,dataLen)
3397c478bd9Sstevel@tonic-gate fru_errno_t
3407c478bd9Sstevel@tonic-gate PayloadReader::readData(PathDef *path, Ancestor *curDef,
3417c478bd9Sstevel@tonic-gate 			int instWICur,
3427c478bd9Sstevel@tonic-gate 			uint8_t *payload, size_t payloadLen,
3437c478bd9Sstevel@tonic-gate 			void **data, size_t *dataLen)
3447c478bd9Sstevel@tonic-gate {
3457c478bd9Sstevel@tonic-gate 	int offset = curDef->getInstOffset(instWICur);
3467c478bd9Sstevel@tonic-gate 	return (readRecurse(path, &(payload[offset]), payloadLen-offset,
3477c478bd9Sstevel@tonic-gate 		data, dataLen, NORMAL_READ));
3487c478bd9Sstevel@tonic-gate }
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate // ===========================================================================
3517c478bd9Sstevel@tonic-gate fru_errno_t
3527c478bd9Sstevel@tonic-gate PayloadReader::findIterThere(PathDef *path, Ancestor *curDef,
3537c478bd9Sstevel@tonic-gate 				int instWICur,
3547c478bd9Sstevel@tonic-gate 				uint8_t *payload, size_t payloadLen,
3557c478bd9Sstevel@tonic-gate 				int *numThere)
3567c478bd9Sstevel@tonic-gate {
3577c478bd9Sstevel@tonic-gate 	int offset = curDef->getInstOffset(instWICur);
3587c478bd9Sstevel@tonic-gate 	size_t tmp_num = 0;
3597c478bd9Sstevel@tonic-gate 	fru_errno_t err = readRecurse(path, &(payload[offset]),
3607c478bd9Sstevel@tonic-gate 		payloadLen-offset, NULL, &tmp_num, ITER_THERE_ONLY);
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	if (err == FRU_SUCCESS) {
3637c478bd9Sstevel@tonic-gate 		int tmp_num_there = (int)tmp_num;
3647c478bd9Sstevel@tonic-gate 		if (tmp_num_there != tmp_num) {
3657c478bd9Sstevel@tonic-gate 			return (FRU_FAILURE);
3667c478bd9Sstevel@tonic-gate 		}
3677c478bd9Sstevel@tonic-gate 		*numThere = tmp_num_there;
3687c478bd9Sstevel@tonic-gate 	}
3697c478bd9Sstevel@tonic-gate 	return (err);
3707c478bd9Sstevel@tonic-gate }
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate static fru_errno_t
3737c478bd9Sstevel@tonic-gate update_iter_cont_bytes(PathDef *path, uint8_t *cur, size_t curLen)
3747c478bd9Sstevel@tonic-gate {
3757c478bd9Sstevel@tonic-gate 	// update the iteration control information
3767c478bd9Sstevel@tonic-gate 	uint8_t *head = &(cur[0]);
3777c478bd9Sstevel@tonic-gate 	uint8_t *tail = &(cur[1]);
3787c478bd9Sstevel@tonic-gate 	uint8_t *numThere = &(cur[2]);
3797c478bd9Sstevel@tonic-gate 	// This never changes.
3807c478bd9Sstevel@tonic-gate 	uint8_t numPoss = cur[3];
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	if (numPoss != path->def->iterationCount) {
3837c478bd9Sstevel@tonic-gate 		return (FRU_DATACORRUPT);
3847c478bd9Sstevel@tonic-gate 	}
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	// Remember that when the iteration is added the head and the tail both
3877c478bd9Sstevel@tonic-gate 	// equal 0 (ie point to 0).  So if we are empty when we are updating
3887c478bd9Sstevel@tonic-gate 	// then we don't have to alter the head or tail values.  We simply add
3897c478bd9Sstevel@tonic-gate 	// one to the numThere.
3907c478bd9Sstevel@tonic-gate 	if (*numThere != 0) {
3917c478bd9Sstevel@tonic-gate 		switch (path->def->iterationType) {
3927c478bd9Sstevel@tonic-gate 			case FRU_Linear:
3937c478bd9Sstevel@tonic-gate 				// this will flag an error when Linear can't
3947c478bd9Sstevel@tonic-gate 				// hold anymore.
3957c478bd9Sstevel@tonic-gate 				if ((*tail + 1) == numPoss)
3967c478bd9Sstevel@tonic-gate 					return (FRU_ITERFULL);
3977c478bd9Sstevel@tonic-gate 			/* Fall through */
3987c478bd9Sstevel@tonic-gate 			case FRU_FIFO:
3997c478bd9Sstevel@tonic-gate 				// if we are not at the end move the tail.
4007c478bd9Sstevel@tonic-gate 				if (*tail != (numPoss-1))
4017c478bd9Sstevel@tonic-gate 					*tail = *tail+1;
4027c478bd9Sstevel@tonic-gate 			break;
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 			case FRU_Circular:
4057c478bd9Sstevel@tonic-gate 			case FRU_LIFO:
4067c478bd9Sstevel@tonic-gate 				// this is the same except LIFO is read
4077c478bd9Sstevel@tonic-gate 				// BACKWARDS
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 				// move the tail.
4107c478bd9Sstevel@tonic-gate 				*tail = *tail + 1;
4117c478bd9Sstevel@tonic-gate 				// if the tail hits the end wrap around.
4127c478bd9Sstevel@tonic-gate 				if (*tail == numPoss)
4137c478bd9Sstevel@tonic-gate 					*tail = 0;
4147c478bd9Sstevel@tonic-gate 				// if tail catches head move the head.
4157c478bd9Sstevel@tonic-gate 				if (*tail == *head) {
4167c478bd9Sstevel@tonic-gate 					// if head hits the end wrap around.
4177c478bd9Sstevel@tonic-gate 					if (++(*head) == numPoss)
4187c478bd9Sstevel@tonic-gate 						*head = 0;
4197c478bd9Sstevel@tonic-gate 				}
4207c478bd9Sstevel@tonic-gate 			break;
4217c478bd9Sstevel@tonic-gate 		}
4227c478bd9Sstevel@tonic-gate 	}
4237c478bd9Sstevel@tonic-gate 	if ((*numThere) < numPoss) {
4247c478bd9Sstevel@tonic-gate 		// add one IFF we are not full
4257c478bd9Sstevel@tonic-gate 		*numThere = *numThere + 1;
4267c478bd9Sstevel@tonic-gate 	}
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	return (FRU_SUCCESS);
4297c478bd9Sstevel@tonic-gate }
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate // ===========================================================================
4327c478bd9Sstevel@tonic-gate fru_errno_t
4337c478bd9Sstevel@tonic-gate PayloadReader::updateRecurse(PathDef *path,
4347c478bd9Sstevel@tonic-gate 				uint8_t *cur, size_t curLen,
4357c478bd9Sstevel@tonic-gate 				void *data, size_t dataLen)
4367c478bd9Sstevel@tonic-gate {
4377c478bd9Sstevel@tonic-gate 	fru_errno_t rc = FRU_SUCCESS;
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	if (path->next == NULL) {
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 		// Delay checking for Records until after this which will
4427c478bd9Sstevel@tonic-gate 		// allow for [+] notation for Iterated Records.
4437c478bd9Sstevel@tonic-gate 		// if this is updating an iteration AND we are adding one...
4447c478bd9Sstevel@tonic-gate 		if (IS_ITERATED(path) &&
4457c478bd9Sstevel@tonic-gate 			(path->iterIndex == PathDef::addIteration)) {
4467c478bd9Sstevel@tonic-gate 			return (update_iter_cont_bytes(path, cur, curLen));
4477c478bd9Sstevel@tonic-gate 		}
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 		if (path->def->dataType == FDTYPE_Record) {
4507c478bd9Sstevel@tonic-gate 			return (FRU_NOTFIELD);
4517c478bd9Sstevel@tonic-gate 		}
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 		int offset = 0;
4547c478bd9Sstevel@tonic-gate 		int calcLen = 0;
4557c478bd9Sstevel@tonic-gate 		int dummy = 0;
4567c478bd9Sstevel@tonic-gate 		// zzz altering the length things again...
4577c478bd9Sstevel@tonic-gate 		if (IS_ITERATED(path)) {
4587c478bd9Sstevel@tonic-gate 			// we are iterated.
4597c478bd9Sstevel@tonic-gate 			calcLen = (path->def->payloadLen-ITER_CONT_BYTE_LEN)/
4607c478bd9Sstevel@tonic-gate 				path->def->iterationCount;
4617c478bd9Sstevel@tonic-gate // zzz still have to figure out the bit offsets
4627c478bd9Sstevel@tonic-gate 			offset = getIterationOffset(cur, curLen,
4637c478bd9Sstevel@tonic-gate 				path, &dummy, &rc, NORMAL_READ);
4647c478bd9Sstevel@tonic-gate 			if (offset == -1)
4657c478bd9Sstevel@tonic-gate 				return (rc);
4667c478bd9Sstevel@tonic-gate 		} else {
4677c478bd9Sstevel@tonic-gate 			calcLen = path->def->payloadLen;
4687c478bd9Sstevel@tonic-gate 			offset = 0;
4697c478bd9Sstevel@tonic-gate 		}
4707c478bd9Sstevel@tonic-gate 		// end zzz
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 		// once again convert enums for the user again.
4737c478bd9Sstevel@tonic-gate 		if (path->def->dataType == FDTYPE_Binary) {
4747c478bd9Sstevel@tonic-gate 			int bitLength = path->def->dataLength;
4757c478bd9Sstevel@tonic-gate 			// iterated bit field adjust acordingly.
4767c478bd9Sstevel@tonic-gate 			if (path->def->iterationType != FRU_NOT_ITERATED) {
4777c478bd9Sstevel@tonic-gate 				bitLength = (bitLength - 32)/
4787c478bd9Sstevel@tonic-gate 					path->def->iterationCount;
4797c478bd9Sstevel@tonic-gate 			}
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 			rc = writeBits (*(uint64_t *)data, bitLength,
4827c478bd9Sstevel@tonic-gate 					&(cur[offset]), calcLen, 0);
4837c478bd9Sstevel@tonic-gate 			if (rc != FRU_SUCCESS)
4847c478bd9Sstevel@tonic-gate 				return (rc);
4857c478bd9Sstevel@tonic-gate 		} else if (path->def->dataType == FDTYPE_Enumeration) {
4867c478bd9Sstevel@tonic-gate 			unsigned char *tmp = (unsigned char *)data;
4877c478bd9Sstevel@tonic-gate 			memcpy(&(cur[offset]),
4887c478bd9Sstevel@tonic-gate 				&(tmp[(sizeof (uint64_t) - (calcLen))]),
4897c478bd9Sstevel@tonic-gate 				calcLen);
4907c478bd9Sstevel@tonic-gate 		} else {
4917c478bd9Sstevel@tonic-gate 			// copy into and return.
4927c478bd9Sstevel@tonic-gate 			memcpy(&(cur[offset]), data, dataLen);
4937c478bd9Sstevel@tonic-gate 		}
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 		return (FRU_SUCCESS);
4967c478bd9Sstevel@tonic-gate 	}
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 	int newOffset = 0, newLength = 0;
4997c478bd9Sstevel@tonic-gate 	int dummy = 0;
5007c478bd9Sstevel@tonic-gate 	if (path->def->iterationType != FRU_NOT_ITERATED) {
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate // zzz still have to figure out the bit offsets
5037c478bd9Sstevel@tonic-gate 		newOffset = getIterationOffset(cur, curLen, path,
5047c478bd9Sstevel@tonic-gate 					&dummy, &rc, NORMAL_READ);
5057c478bd9Sstevel@tonic-gate 		if (newOffset == -1)
5067c478bd9Sstevel@tonic-gate 			return (rc);
5077c478bd9Sstevel@tonic-gate 	}
5087c478bd9Sstevel@tonic-gate 	newOffset += getOffsetIntoRecord(path->def, path->next->def);
5097c478bd9Sstevel@tonic-gate 	newLength = path->next->def->payloadLen;
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 	return (updateRecurse(path->next, &(cur[newOffset]), newLength,
5127c478bd9Sstevel@tonic-gate 		data, dataLen));
5137c478bd9Sstevel@tonic-gate }
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate // ===========================================================================
5167c478bd9Sstevel@tonic-gate // will update the data in payload which can then be written back.
5177c478bd9Sstevel@tonic-gate fru_errno_t
5187c478bd9Sstevel@tonic-gate PayloadReader::updateData(PathDef *path, Ancestor *ancestorDef,
5197c478bd9Sstevel@tonic-gate 			int instWICur,
5207c478bd9Sstevel@tonic-gate 			uint8_t *payload, size_t payloadLen,
5217c478bd9Sstevel@tonic-gate 			void *data, size_t dataLen)
5227c478bd9Sstevel@tonic-gate {
5237c478bd9Sstevel@tonic-gate 	// verify the user data first before doing any major work.
5247c478bd9Sstevel@tonic-gate 	int calcLen = 0;
5257c478bd9Sstevel@tonic-gate 	PathDef *prev = path;
5267c478bd9Sstevel@tonic-gate 	PathDef *cur = path;
5277c478bd9Sstevel@tonic-gate 	while (cur != NULL) {
5287c478bd9Sstevel@tonic-gate 		prev = cur;
5297c478bd9Sstevel@tonic-gate 		cur = cur->next;
5307c478bd9Sstevel@tonic-gate 	}
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	// unless we are updateing with [+] symbol
5337c478bd9Sstevel@tonic-gate 	// (which means we don't have any data length at all.)
5347c478bd9Sstevel@tonic-gate 	if (prev->iterIndex != PathDef::addIteration) {
5357c478bd9Sstevel@tonic-gate 		if (IS_ITERATED(prev)) {
5367c478bd9Sstevel@tonic-gate 			calcLen = (prev->def->payloadLen-ITER_CONT_BYTE_LEN)/
5377c478bd9Sstevel@tonic-gate 				prev->def->iterationCount;
5387c478bd9Sstevel@tonic-gate 		} else {
5397c478bd9Sstevel@tonic-gate 				calcLen = prev->def->payloadLen;
5407c478bd9Sstevel@tonic-gate 		}
5417c478bd9Sstevel@tonic-gate 		// the sizeof the data for Binary or Enumeration MUST
5427c478bd9Sstevel@tonic-gate 		// be uint64_t
5437c478bd9Sstevel@tonic-gate 		if ((prev->def->dataType == FDTYPE_Enumeration) ||
5447c478bd9Sstevel@tonic-gate 			(prev->def->dataType == FDTYPE_Binary)) {
5457c478bd9Sstevel@tonic-gate 			if (dataLen != sizeof (uint64_t))
5467c478bd9Sstevel@tonic-gate 				return (FRU_INVALDATASIZE);
5477c478bd9Sstevel@tonic-gate 		// all others must be shorter than the space available.
5487c478bd9Sstevel@tonic-gate 		} else {
5497c478bd9Sstevel@tonic-gate 			if (dataLen > calcLen)
5507c478bd9Sstevel@tonic-gate 				return (FRU_INVALDATASIZE);
5517c478bd9Sstevel@tonic-gate 		}
5527c478bd9Sstevel@tonic-gate 	}
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 	int offset = ancestorDef->getInstOffset(instWICur);
5557c478bd9Sstevel@tonic-gate 	return (updateRecurse(path, &(payload[offset]), payloadLen-offset,
5567c478bd9Sstevel@tonic-gate 		data, dataLen));
5577c478bd9Sstevel@tonic-gate }
558