xref: /openbmc/ipmitool/lib/ipmi_fru.c (revision c18ec02f)
1*c18ec02fSPetter Reinholdtsen /*
2*c18ec02fSPetter Reinholdtsen * Copyright (c) 2003 Sun Microsystems, Inc.  All Rights Reserved.
3*c18ec02fSPetter Reinholdtsen *
4*c18ec02fSPetter Reinholdtsen * Redistribution and use in source and binary forms, with or without
5*c18ec02fSPetter Reinholdtsen * modification, are permitted provided that the following conditions
6*c18ec02fSPetter Reinholdtsen * are met:
7*c18ec02fSPetter Reinholdtsen *
8*c18ec02fSPetter Reinholdtsen * Redistribution of source code must retain the above copyright
9*c18ec02fSPetter Reinholdtsen * notice, this list of conditions and the following disclaimer.
10*c18ec02fSPetter Reinholdtsen *
11*c18ec02fSPetter Reinholdtsen * Redistribution in binary form must reproduce the above copyright
12*c18ec02fSPetter Reinholdtsen * notice, this list of conditions and the following disclaimer in the
13*c18ec02fSPetter Reinholdtsen * documentation and/or other materials provided with the distribution.
14*c18ec02fSPetter Reinholdtsen *
15*c18ec02fSPetter Reinholdtsen * Neither the name of Sun Microsystems, Inc. or the names of
16*c18ec02fSPetter Reinholdtsen * contributors may be used to endorse or promote products derived
17*c18ec02fSPetter Reinholdtsen * from this software without specific prior written permission.
18*c18ec02fSPetter Reinholdtsen *
19*c18ec02fSPetter Reinholdtsen * This software is provided "AS IS," without a warranty of any kind.
20*c18ec02fSPetter Reinholdtsen * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21*c18ec02fSPetter Reinholdtsen * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22*c18ec02fSPetter Reinholdtsen * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
23*c18ec02fSPetter Reinholdtsen * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
24*c18ec02fSPetter Reinholdtsen * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
25*c18ec02fSPetter Reinholdtsen * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  IN NO EVENT WILL
26*c18ec02fSPetter Reinholdtsen * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
27*c18ec02fSPetter Reinholdtsen * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
28*c18ec02fSPetter Reinholdtsen * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
29*c18ec02fSPetter Reinholdtsen * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30*c18ec02fSPetter Reinholdtsen * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31*c18ec02fSPetter Reinholdtsen */
32*c18ec02fSPetter Reinholdtsen 
33*c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi.h>
34*c18ec02fSPetter Reinholdtsen #include <ipmitool/log.h>
35*c18ec02fSPetter Reinholdtsen #include <ipmitool/helper.h>
36*c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_intf.h>
37*c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_fru.h>
38*c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_mc.h>
39*c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_sdr.h>
40*c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_strings.h>  /* IANA id strings */
41*c18ec02fSPetter Reinholdtsen 
42*c18ec02fSPetter Reinholdtsen #include <stdlib.h>
43*c18ec02fSPetter Reinholdtsen #include <string.h>
44*c18ec02fSPetter Reinholdtsen #include <time.h>
45*c18ec02fSPetter Reinholdtsen #include <errno.h>
46*c18ec02fSPetter Reinholdtsen 
47*c18ec02fSPetter Reinholdtsen #if HAVE_CONFIG_H
48*c18ec02fSPetter Reinholdtsen # include <config.h>
49*c18ec02fSPetter Reinholdtsen #endif
50*c18ec02fSPetter Reinholdtsen 
51*c18ec02fSPetter Reinholdtsen #define FRU_MULTIREC_CHUNK_SIZE     (255 + sizeof(struct fru_multirec_header))
52*c18ec02fSPetter Reinholdtsen 
53*c18ec02fSPetter Reinholdtsen extern int verbose;
54*c18ec02fSPetter Reinholdtsen 
55*c18ec02fSPetter Reinholdtsen static void ipmi_fru_read_to_bin(struct ipmi_intf * intf, char * pFileName, uint8_t fruId);
56*c18ec02fSPetter Reinholdtsen static void ipmi_fru_write_from_bin(struct ipmi_intf * intf, char * pFileName, uint8_t fruId);
57*c18ec02fSPetter Reinholdtsen static int ipmi_fru_upg_ekeying(struct ipmi_intf * intf, char * pFileName, uint8_t fruId);
58*c18ec02fSPetter Reinholdtsen static int ipmi_fru_get_multirec_location_from_fru(struct ipmi_intf * intf, uint8_t fruId,
59*c18ec02fSPetter Reinholdtsen 							struct fru_info *pFruInfo, uint32_t * pRetLocation,
60*c18ec02fSPetter Reinholdtsen 							uint32_t * pRetSize);
61*c18ec02fSPetter Reinholdtsen static int ipmi_fru_get_multirec_from_file(char * pFileName, uint8_t * pBufArea,
62*c18ec02fSPetter Reinholdtsen 						uint32_t size, uint32_t offset);
63*c18ec02fSPetter Reinholdtsen static int ipmi_fru_get_multirec_size_from_file(char * pFileName, uint32_t * pSize, uint32_t * pOffset);
64*c18ec02fSPetter Reinholdtsen int ipmi_fru_get_adjust_size_from_buffer(uint8_t *pBufArea, uint32_t *pSize);
65*c18ec02fSPetter Reinholdtsen static void ipmi_fru_picmg_ext_print(uint8_t * fru_data, int off, int length);
66*c18ec02fSPetter Reinholdtsen 
67*c18ec02fSPetter Reinholdtsen static int ipmi_fru_set_field_string(struct ipmi_intf * intf, unsigned
68*c18ec02fSPetter Reinholdtsen 						char fruId, uint8_t f_type, uint8_t f_index, char *f_string);
69*c18ec02fSPetter Reinholdtsen static int
70*c18ec02fSPetter Reinholdtsen ipmi_fru_set_field_string_rebuild(struct ipmi_intf * intf, uint8_t fruId,
71*c18ec02fSPetter Reinholdtsen 											struct fru_info fru, struct fru_header header,
72*c18ec02fSPetter Reinholdtsen 											uint8_t f_type, uint8_t f_index, char *f_string);
73*c18ec02fSPetter Reinholdtsen 
74*c18ec02fSPetter Reinholdtsen static void
75*c18ec02fSPetter Reinholdtsen fru_area_print_multirec_bloc(struct ipmi_intf * intf, struct fru_info * fru,
76*c18ec02fSPetter Reinholdtsen 			uint8_t id, uint32_t offset);
77*c18ec02fSPetter Reinholdtsen int
78*c18ec02fSPetter Reinholdtsen read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
79*c18ec02fSPetter Reinholdtsen 			uint32_t offset, uint32_t length, uint8_t *frubuf);
80*c18ec02fSPetter Reinholdtsen void free_fru_bloc(t_ipmi_fru_bloc *bloc);
81*c18ec02fSPetter Reinholdtsen 
82*c18ec02fSPetter Reinholdtsen /* get_fru_area_str  -  Parse FRU area string from raw data
83*c18ec02fSPetter Reinholdtsen *
84*c18ec02fSPetter Reinholdtsen * @data:   raw FRU data
85*c18ec02fSPetter Reinholdtsen * @offset: offset into data for area
86*c18ec02fSPetter Reinholdtsen *
87*c18ec02fSPetter Reinholdtsen * returns pointer to FRU area string
88*c18ec02fSPetter Reinholdtsen */
89*c18ec02fSPetter Reinholdtsen char * get_fru_area_str(uint8_t * data, uint32_t * offset)
90*c18ec02fSPetter Reinholdtsen {
91*c18ec02fSPetter Reinholdtsen 	static const char bcd_plus[] = "0123456789 -.:,_";
92*c18ec02fSPetter Reinholdtsen 	char * str;
93*c18ec02fSPetter Reinholdtsen 	int len, off, size, i, j, k, typecode;
94*c18ec02fSPetter Reinholdtsen 	union {
95*c18ec02fSPetter Reinholdtsen 		uint32_t bits;
96*c18ec02fSPetter Reinholdtsen 		char chars[4];
97*c18ec02fSPetter Reinholdtsen 	} u;
98*c18ec02fSPetter Reinholdtsen 
99*c18ec02fSPetter Reinholdtsen 	size = 0;
100*c18ec02fSPetter Reinholdtsen 	off = *offset;
101*c18ec02fSPetter Reinholdtsen 
102*c18ec02fSPetter Reinholdtsen 	/* bits 6:7 contain format */
103*c18ec02fSPetter Reinholdtsen 	typecode = ((data[off] & 0xC0) >> 6);
104*c18ec02fSPetter Reinholdtsen 
105*c18ec02fSPetter Reinholdtsen 	// printf("Typecode:%i\n", typecode);
106*c18ec02fSPetter Reinholdtsen 	/* bits 0:5 contain length */
107*c18ec02fSPetter Reinholdtsen 	len = data[off++];
108*c18ec02fSPetter Reinholdtsen 	len &= 0x3f;
109*c18ec02fSPetter Reinholdtsen 
110*c18ec02fSPetter Reinholdtsen 	switch (typecode) {
111*c18ec02fSPetter Reinholdtsen 	case 0:           /* 00b: binary/unspecified */
112*c18ec02fSPetter Reinholdtsen 		/* hex dump -> 2x length */
113*c18ec02fSPetter Reinholdtsen 		size = (len*2);
114*c18ec02fSPetter Reinholdtsen 		break;
115*c18ec02fSPetter Reinholdtsen 	case 2:           /* 10b: 6-bit ASCII */
116*c18ec02fSPetter Reinholdtsen 		/* 4 chars per group of 1-3 bytes */
117*c18ec02fSPetter Reinholdtsen 		size = ((((len+2)*4)/3) & ~3);
118*c18ec02fSPetter Reinholdtsen 		break;
119*c18ec02fSPetter Reinholdtsen 	case 3:           /* 11b: 8-bit ASCII */
120*c18ec02fSPetter Reinholdtsen 	case 1:           /* 01b: BCD plus */
121*c18ec02fSPetter Reinholdtsen 		/* no length adjustment */
122*c18ec02fSPetter Reinholdtsen 		size = len;
123*c18ec02fSPetter Reinholdtsen 		break;
124*c18ec02fSPetter Reinholdtsen 	}
125*c18ec02fSPetter Reinholdtsen 
126*c18ec02fSPetter Reinholdtsen 	if (size < 1) {
127*c18ec02fSPetter Reinholdtsen 		*offset = off;
128*c18ec02fSPetter Reinholdtsen 		return NULL;
129*c18ec02fSPetter Reinholdtsen 	}
130*c18ec02fSPetter Reinholdtsen 	str = malloc(size+1);
131*c18ec02fSPetter Reinholdtsen 	if (str == NULL)
132*c18ec02fSPetter Reinholdtsen 		return NULL;
133*c18ec02fSPetter Reinholdtsen 	memset(str, 0, size+1);
134*c18ec02fSPetter Reinholdtsen 
135*c18ec02fSPetter Reinholdtsen 	if (len == 0) {
136*c18ec02fSPetter Reinholdtsen 		str[0] = '\0';
137*c18ec02fSPetter Reinholdtsen 		*offset = off;
138*c18ec02fSPetter Reinholdtsen 		return str;
139*c18ec02fSPetter Reinholdtsen 	}
140*c18ec02fSPetter Reinholdtsen 
141*c18ec02fSPetter Reinholdtsen 	switch (typecode) {
142*c18ec02fSPetter Reinholdtsen 	case 0:        /* Binary */
143*c18ec02fSPetter Reinholdtsen 		strncpy(str, buf2str(&data[off], len), len*2);
144*c18ec02fSPetter Reinholdtsen 		break;
145*c18ec02fSPetter Reinholdtsen 
146*c18ec02fSPetter Reinholdtsen 	case 1:        /* BCD plus */
147*c18ec02fSPetter Reinholdtsen 		for (k=0; k<len; k++)
148*c18ec02fSPetter Reinholdtsen 			str[k] = bcd_plus[(data[off+k] & 0x0f)];
149*c18ec02fSPetter Reinholdtsen 		str[k] = '\0';
150*c18ec02fSPetter Reinholdtsen 		break;
151*c18ec02fSPetter Reinholdtsen 
152*c18ec02fSPetter Reinholdtsen 	case 2:        /* 6-bit ASCII */
153*c18ec02fSPetter Reinholdtsen 		for (i=j=0; i<len; i+=3) {
154*c18ec02fSPetter Reinholdtsen 			u.bits = 0;
155*c18ec02fSPetter Reinholdtsen 			k = ((len-i) < 3 ? (len-i) : 3);
156*c18ec02fSPetter Reinholdtsen #if WORDS_BIGENDIAN
157*c18ec02fSPetter Reinholdtsen 			u.chars[3] = data[off+i];
158*c18ec02fSPetter Reinholdtsen 			u.chars[2] = (k > 1 ? data[off+i+1] : 0);
159*c18ec02fSPetter Reinholdtsen 			u.chars[1] = (k > 2 ? data[off+i+2] : 0);
160*c18ec02fSPetter Reinholdtsen #define CHAR_IDX 3
161*c18ec02fSPetter Reinholdtsen #else
162*c18ec02fSPetter Reinholdtsen 			memcpy((void *)&u.bits, &data[off+i], k);
163*c18ec02fSPetter Reinholdtsen #define CHAR_IDX 0
164*c18ec02fSPetter Reinholdtsen #endif
165*c18ec02fSPetter Reinholdtsen 			for (k=0; k<4; k++) {
166*c18ec02fSPetter Reinholdtsen 				str[j++] = ((u.chars[CHAR_IDX] & 0x3f) + 0x20);
167*c18ec02fSPetter Reinholdtsen 				u.bits >>= 6;
168*c18ec02fSPetter Reinholdtsen 			}
169*c18ec02fSPetter Reinholdtsen 		}
170*c18ec02fSPetter Reinholdtsen 		str[j] = '\0';
171*c18ec02fSPetter Reinholdtsen 		break;
172*c18ec02fSPetter Reinholdtsen 
173*c18ec02fSPetter Reinholdtsen 	case 3:
174*c18ec02fSPetter Reinholdtsen 		memcpy(str, &data[off], len);
175*c18ec02fSPetter Reinholdtsen 		str[len] = '\0';
176*c18ec02fSPetter Reinholdtsen 		break;
177*c18ec02fSPetter Reinholdtsen 	}
178*c18ec02fSPetter Reinholdtsen 
179*c18ec02fSPetter Reinholdtsen 	off += len;
180*c18ec02fSPetter Reinholdtsen 	*offset = off;
181*c18ec02fSPetter Reinholdtsen 
182*c18ec02fSPetter Reinholdtsen 	return str;
183*c18ec02fSPetter Reinholdtsen }
184*c18ec02fSPetter Reinholdtsen 
185*c18ec02fSPetter Reinholdtsen /* is_valid_filename - checks file/path supplied by user
186*c18ec02fSPetter Reinholdtsen  *
187*c18ec02fSPetter Reinholdtsen  * input_filename - user input string
188*c18ec02fSPetter Reinholdtsen  *
189*c18ec02fSPetter Reinholdtsen  * returns   0  if path is ok
190*c18ec02fSPetter Reinholdtsen  * returns (-1) if path is NULL
191*c18ec02fSPetter Reinholdtsen  * returns (-2) if path is too short
192*c18ec02fSPetter Reinholdtsen  * returns (-3) if path is too long
193*c18ec02fSPetter Reinholdtsen  */
194*c18ec02fSPetter Reinholdtsen int
195*c18ec02fSPetter Reinholdtsen is_valid_filename(const char *input_filename)
196*c18ec02fSPetter Reinholdtsen {
197*c18ec02fSPetter Reinholdtsen 	if (input_filename == NULL) {
198*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "ERROR: NULL pointer passed.");
199*c18ec02fSPetter Reinholdtsen 		return (-1);
200*c18ec02fSPetter Reinholdtsen 	}
201*c18ec02fSPetter Reinholdtsen 
202*c18ec02fSPetter Reinholdtsen 	if (strlen(input_filename) < 1) {
203*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "File/path is invalid.");
204*c18ec02fSPetter Reinholdtsen 		return (-2);
205*c18ec02fSPetter Reinholdtsen 	}
206*c18ec02fSPetter Reinholdtsen 
207*c18ec02fSPetter Reinholdtsen 	if (strlen(input_filename) >= 512) {
208*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "File/path must be shorter than 512 bytes.");
209*c18ec02fSPetter Reinholdtsen 		return (-3);
210*c18ec02fSPetter Reinholdtsen 	}
211*c18ec02fSPetter Reinholdtsen 
212*c18ec02fSPetter Reinholdtsen 	return 0;
213*c18ec02fSPetter Reinholdtsen } /* is_valid_filename() */
214*c18ec02fSPetter Reinholdtsen 
215*c18ec02fSPetter Reinholdtsen /* build_fru_bloc  -  build fru bloc for write protection
216*c18ec02fSPetter Reinholdtsen *
217*c18ec02fSPetter Reinholdtsen * @intf:     ipmi interface
218*c18ec02fSPetter Reinholdtsen * @fru_info: information about FRU device
219*c18ec02fSPetter Reinholdtsen * @id      : Fru id
220*c18ec02fSPetter Reinholdtsen * @soffset : Source offset      (from buffer)
221*c18ec02fSPetter Reinholdtsen * @doffset : Destination offset (in device)
222*c18ec02fSPetter Reinholdtsen * @length  : Size of data to write (in bytes)
223*c18ec02fSPetter Reinholdtsen * @pFrubuf : Pointer on data to write
224*c18ec02fSPetter Reinholdtsen *
225*c18ec02fSPetter Reinholdtsen * returns 0 on success
226*c18ec02fSPetter Reinholdtsen * returns -1 on error
227*c18ec02fSPetter Reinholdtsen */
228*c18ec02fSPetter Reinholdtsen #define FRU_NUM_BLOC_COMMON_HEADER  6
229*c18ec02fSPetter Reinholdtsen t_ipmi_fru_bloc *
230*c18ec02fSPetter Reinholdtsen build_fru_bloc(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id)
231*c18ec02fSPetter Reinholdtsen {
232*c18ec02fSPetter Reinholdtsen 	t_ipmi_fru_bloc * p_first, * p_bloc, * p_new;
233*c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
234*c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
235*c18ec02fSPetter Reinholdtsen 	struct fru_header header;
236*c18ec02fSPetter Reinholdtsen 	struct fru_multirec_header rec_hdr;
237*c18ec02fSPetter Reinholdtsen 	uint8_t msg_data[4];
238*c18ec02fSPetter Reinholdtsen 	uint32_t off;
239*c18ec02fSPetter Reinholdtsen 	uint16_t i;
240*c18ec02fSPetter Reinholdtsen 
241*c18ec02fSPetter Reinholdtsen 	/*
242*c18ec02fSPetter Reinholdtsen 	* get COMMON Header format
243*c18ec02fSPetter Reinholdtsen 	*/
244*c18ec02fSPetter Reinholdtsen 	msg_data[0] = id;
245*c18ec02fSPetter Reinholdtsen 	msg_data[1] = 0;
246*c18ec02fSPetter Reinholdtsen 	msg_data[2] = 0;
247*c18ec02fSPetter Reinholdtsen 	msg_data[3] = 8;
248*c18ec02fSPetter Reinholdtsen 
249*c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
250*c18ec02fSPetter Reinholdtsen 	req.msg.netfn = IPMI_NETFN_STORAGE;
251*c18ec02fSPetter Reinholdtsen 	req.msg.cmd = GET_FRU_DATA;
252*c18ec02fSPetter Reinholdtsen 	req.msg.data = msg_data;
253*c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 4;
254*c18ec02fSPetter Reinholdtsen 
255*c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
256*c18ec02fSPetter Reinholdtsen 
257*c18ec02fSPetter Reinholdtsen 	if (rsp == NULL) {
258*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, " Device not present (No Response)");
259*c18ec02fSPetter Reinholdtsen 		return NULL;
260*c18ec02fSPetter Reinholdtsen 	}
261*c18ec02fSPetter Reinholdtsen 
262*c18ec02fSPetter Reinholdtsen 	if (rsp->ccode > 0) {
263*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR," Device not present (%s)",
264*c18ec02fSPetter Reinholdtsen 				val2str(rsp->ccode, completion_code_vals));
265*c18ec02fSPetter Reinholdtsen 		return NULL;
266*c18ec02fSPetter Reinholdtsen 	}
267*c18ec02fSPetter Reinholdtsen 
268*c18ec02fSPetter Reinholdtsen 	if (verbose > 1) {
269*c18ec02fSPetter Reinholdtsen 		printbuf(rsp->data, rsp->data_len, "FRU DATA");
270*c18ec02fSPetter Reinholdtsen 	}
271*c18ec02fSPetter Reinholdtsen 
272*c18ec02fSPetter Reinholdtsen 	memcpy(&header, rsp->data + 1, 8);
273*c18ec02fSPetter Reinholdtsen 
274*c18ec02fSPetter Reinholdtsen 	/* verify header checksum */
275*c18ec02fSPetter Reinholdtsen 	if (ipmi_csum((uint8_t *)&header, 8)) {
276*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, " Bad header checksum");
277*c18ec02fSPetter Reinholdtsen 		return NULL;
278*c18ec02fSPetter Reinholdtsen 	}
279*c18ec02fSPetter Reinholdtsen 
280*c18ec02fSPetter Reinholdtsen 	if (header.version != 1) {
281*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, " Unknown FRU header version 0x%02x", header.version);
282*c18ec02fSPetter Reinholdtsen 		return NULL;
283*c18ec02fSPetter Reinholdtsen 	}
284*c18ec02fSPetter Reinholdtsen 
285*c18ec02fSPetter Reinholdtsen 	/******************************************
286*c18ec02fSPetter Reinholdtsen 		Malloc and fill up the bloc contents
287*c18ec02fSPetter Reinholdtsen 	*******************************************/
288*c18ec02fSPetter Reinholdtsen 
289*c18ec02fSPetter Reinholdtsen 	// Common header
290*c18ec02fSPetter Reinholdtsen 	p_first = malloc(sizeof(struct ipmi_fru_bloc));
291*c18ec02fSPetter Reinholdtsen 	if (!p_first) {
292*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "ipmitool: malloc failure");
293*c18ec02fSPetter Reinholdtsen 		return NULL;
294*c18ec02fSPetter Reinholdtsen 	}
295*c18ec02fSPetter Reinholdtsen 
296*c18ec02fSPetter Reinholdtsen 	p_bloc = p_first;
297*c18ec02fSPetter Reinholdtsen 	p_bloc->next = NULL;
298*c18ec02fSPetter Reinholdtsen 	p_bloc->start= 0;
299*c18ec02fSPetter Reinholdtsen 	p_bloc->size = fru->size;
300*c18ec02fSPetter Reinholdtsen 	strcpy((char *)p_bloc->blocId, "Common Header Section");
301*c18ec02fSPetter Reinholdtsen 
302*c18ec02fSPetter Reinholdtsen 	for (i = 0; i < 4; i++) {
303*c18ec02fSPetter Reinholdtsen 		if (header.offsets[i]) {
304*c18ec02fSPetter Reinholdtsen 			p_new = malloc(sizeof(struct ipmi_fru_bloc));
305*c18ec02fSPetter Reinholdtsen 			if (!p_new) {
306*c18ec02fSPetter Reinholdtsen 				lprintf(LOG_ERR, "ipmitool: malloc failure");
307*c18ec02fSPetter Reinholdtsen 				free_fru_bloc(p_first);
308*c18ec02fSPetter Reinholdtsen 				return NULL;
309*c18ec02fSPetter Reinholdtsen 			}
310*c18ec02fSPetter Reinholdtsen 
311*c18ec02fSPetter Reinholdtsen 			p_new->next = NULL;
312*c18ec02fSPetter Reinholdtsen 			p_new->start = header.offsets[i] * 8;
313*c18ec02fSPetter Reinholdtsen 			p_new->size = fru->size - p_new->start;
314*c18ec02fSPetter Reinholdtsen 
315*c18ec02fSPetter Reinholdtsen 			strncpy((char *)p_new->blocId, section_id[i], sizeof(p_new->blocId));
316*c18ec02fSPetter Reinholdtsen 			/* Make sure string is null terminated */
317*c18ec02fSPetter Reinholdtsen 			p_new->blocId[sizeof(p_new->blocId)-1] = 0;
318*c18ec02fSPetter Reinholdtsen 
319*c18ec02fSPetter Reinholdtsen 			p_bloc->next = p_new;
320*c18ec02fSPetter Reinholdtsen 			p_bloc->size = p_new->start - p_bloc->start;
321*c18ec02fSPetter Reinholdtsen 			p_bloc = p_new;
322*c18ec02fSPetter Reinholdtsen 		}
323*c18ec02fSPetter Reinholdtsen 	}
324*c18ec02fSPetter Reinholdtsen 
325*c18ec02fSPetter Reinholdtsen 	// Multi
326*c18ec02fSPetter Reinholdtsen 	if (header.offset.multi) {
327*c18ec02fSPetter Reinholdtsen 		off = header.offset.multi * 8;
328*c18ec02fSPetter Reinholdtsen 
329*c18ec02fSPetter Reinholdtsen 		do {
330*c18ec02fSPetter Reinholdtsen 			/*
331*c18ec02fSPetter Reinholdtsen 			 * check for odd offset for the case of fru devices
332*c18ec02fSPetter Reinholdtsen 			 * accessed by words
333*c18ec02fSPetter Reinholdtsen 			 */
334*c18ec02fSPetter Reinholdtsen 			if (fru->access && (off & 1)) {
335*c18ec02fSPetter Reinholdtsen 				lprintf(LOG_ERR, " Unaligned offset for a block: %d", off);
336*c18ec02fSPetter Reinholdtsen 				/* increment offset */
337*c18ec02fSPetter Reinholdtsen 				off++;
338*c18ec02fSPetter Reinholdtsen 				break;
339*c18ec02fSPetter Reinholdtsen 			}
340*c18ec02fSPetter Reinholdtsen 
341*c18ec02fSPetter Reinholdtsen 			if (read_fru_area(intf, fru, id, off, 5,
342*c18ec02fSPetter Reinholdtsen 					(uint8_t *) &rec_hdr) < 0) {
343*c18ec02fSPetter Reinholdtsen 				break;
344*c18ec02fSPetter Reinholdtsen 			}
345*c18ec02fSPetter Reinholdtsen 
346*c18ec02fSPetter Reinholdtsen 			p_new = malloc(sizeof(struct ipmi_fru_bloc));
347*c18ec02fSPetter Reinholdtsen 			if (!p_new) {
348*c18ec02fSPetter Reinholdtsen 				lprintf(LOG_ERR, "ipmitool: malloc failure");
349*c18ec02fSPetter Reinholdtsen 				free_fru_bloc(p_first);
350*c18ec02fSPetter Reinholdtsen 				return NULL;
351*c18ec02fSPetter Reinholdtsen 			}
352*c18ec02fSPetter Reinholdtsen 
353*c18ec02fSPetter Reinholdtsen 			p_new->next = NULL;
354*c18ec02fSPetter Reinholdtsen 			p_new->start = off;
355*c18ec02fSPetter Reinholdtsen 			p_new->size = fru->size - p_new->start;
356*c18ec02fSPetter Reinholdtsen 			sprintf((char *)p_new->blocId, "Multi-Rec Area: Type %i",
357*c18ec02fSPetter Reinholdtsen 					rec_hdr.type);
358*c18ec02fSPetter Reinholdtsen 
359*c18ec02fSPetter Reinholdtsen 			p_bloc->next = p_new;
360*c18ec02fSPetter Reinholdtsen 			p_bloc->size = p_new->start - p_bloc->start;
361*c18ec02fSPetter Reinholdtsen 			p_bloc = p_new;
362*c18ec02fSPetter Reinholdtsen 
363*c18ec02fSPetter Reinholdtsen 			off += rec_hdr.len + sizeof(struct fru_multirec_header);
364*c18ec02fSPetter Reinholdtsen 
365*c18ec02fSPetter Reinholdtsen 			/* verify record header */
366*c18ec02fSPetter Reinholdtsen 			if (ipmi_csum((uint8_t *)&rec_hdr,
367*c18ec02fSPetter Reinholdtsen 					sizeof(struct fru_multirec_header))) {
368*c18ec02fSPetter Reinholdtsen 				/* can't reliably judge for the rest space */
369*c18ec02fSPetter Reinholdtsen 				break;
370*c18ec02fSPetter Reinholdtsen 			}
371*c18ec02fSPetter Reinholdtsen 		} while (!(rec_hdr.format & 0x80) && (off < fru->size));
372*c18ec02fSPetter Reinholdtsen 
373*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_DEBUG,"Multi-Record area ends at: %i (%xh)", off, off);
374*c18ec02fSPetter Reinholdtsen 
375*c18ec02fSPetter Reinholdtsen 		if (fru->size > off) {
376*c18ec02fSPetter Reinholdtsen 			// Bloc for remaining space
377*c18ec02fSPetter Reinholdtsen 			p_new = malloc(sizeof(struct ipmi_fru_bloc));
378*c18ec02fSPetter Reinholdtsen 			if (!p_new) {
379*c18ec02fSPetter Reinholdtsen 				lprintf(LOG_ERR, "ipmitool: malloc failure");
380*c18ec02fSPetter Reinholdtsen 				free_fru_bloc(p_first);
381*c18ec02fSPetter Reinholdtsen 				return NULL;
382*c18ec02fSPetter Reinholdtsen 			}
383*c18ec02fSPetter Reinholdtsen 
384*c18ec02fSPetter Reinholdtsen 			p_new->next = NULL;
385*c18ec02fSPetter Reinholdtsen 			p_new->start = off;
386*c18ec02fSPetter Reinholdtsen 			p_new->size = fru->size - p_new->start;
387*c18ec02fSPetter Reinholdtsen 			strcpy((char *)p_new->blocId, "Unused space");
388*c18ec02fSPetter Reinholdtsen 
389*c18ec02fSPetter Reinholdtsen 			p_bloc->next = p_new;
390*c18ec02fSPetter Reinholdtsen 			p_bloc->size = p_new->start - p_bloc->start;
391*c18ec02fSPetter Reinholdtsen 		}
392*c18ec02fSPetter Reinholdtsen 	}
393*c18ec02fSPetter Reinholdtsen 
394*c18ec02fSPetter Reinholdtsen 	/* Dump blocs */
395*c18ec02fSPetter Reinholdtsen 	for(p_bloc = p_first, i = 0; p_bloc; p_bloc = p_bloc->next) {
396*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_DEBUG ,"Bloc Numb : %i", i++);
397*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_DEBUG ,"Bloc Id   : %s", p_bloc->blocId);
398*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_DEBUG ,"Bloc Start: %i", p_bloc->start);
399*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_DEBUG ,"Bloc Size : %i", p_bloc->size);
400*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_DEBUG ,"");
401*c18ec02fSPetter Reinholdtsen 	}
402*c18ec02fSPetter Reinholdtsen 
403*c18ec02fSPetter Reinholdtsen 	return p_first;
404*c18ec02fSPetter Reinholdtsen }
405*c18ec02fSPetter Reinholdtsen 
406*c18ec02fSPetter Reinholdtsen void
407*c18ec02fSPetter Reinholdtsen free_fru_bloc(t_ipmi_fru_bloc *bloc)
408*c18ec02fSPetter Reinholdtsen {
409*c18ec02fSPetter Reinholdtsen 	t_ipmi_fru_bloc * del;
410*c18ec02fSPetter Reinholdtsen 
411*c18ec02fSPetter Reinholdtsen 	while (bloc) {
412*c18ec02fSPetter Reinholdtsen 		del = bloc;
413*c18ec02fSPetter Reinholdtsen 		bloc = bloc->next;
414*c18ec02fSPetter Reinholdtsen 		free(del);
415*c18ec02fSPetter Reinholdtsen 		del = NULL;
416*c18ec02fSPetter Reinholdtsen 	}
417*c18ec02fSPetter Reinholdtsen }
418*c18ec02fSPetter Reinholdtsen 
419*c18ec02fSPetter Reinholdtsen /*
420*c18ec02fSPetter Reinholdtsen  * write FRU[doffset:length] from the pFrubuf[soffset:length]
421*c18ec02fSPetter Reinholdtsen  * rc=1 on success
422*c18ec02fSPetter Reinholdtsen **/
423*c18ec02fSPetter Reinholdtsen int
424*c18ec02fSPetter Reinholdtsen write_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
425*c18ec02fSPetter Reinholdtsen 					uint16_t soffset,  uint16_t doffset,
426*c18ec02fSPetter Reinholdtsen 					uint16_t length, uint8_t *pFrubuf)
427*c18ec02fSPetter Reinholdtsen {
428*c18ec02fSPetter Reinholdtsen 	uint16_t tmp, finish;
429*c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
430*c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
431*c18ec02fSPetter Reinholdtsen 	uint8_t msg_data[255+3];
432*c18ec02fSPetter Reinholdtsen 	uint16_t writeLength;
433*c18ec02fSPetter Reinholdtsen 	uint16_t found_bloc = 0;
434*c18ec02fSPetter Reinholdtsen 
435*c18ec02fSPetter Reinholdtsen 	finish = doffset + length;        /* destination offset */
436*c18ec02fSPetter Reinholdtsen 	if (finish > fru->size)
437*c18ec02fSPetter Reinholdtsen 	{
438*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERROR, "Return error");
439*c18ec02fSPetter Reinholdtsen 		return -1;
440*c18ec02fSPetter Reinholdtsen 	}
441*c18ec02fSPetter Reinholdtsen 
442*c18ec02fSPetter Reinholdtsen 	if (fru->access && ((doffset & 1) || (length & 1))) {
443*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERROR, "Odd offset or length specified");
444*c18ec02fSPetter Reinholdtsen 		return (-1);
445*c18ec02fSPetter Reinholdtsen 	}
446*c18ec02fSPetter Reinholdtsen 
447*c18ec02fSPetter Reinholdtsen 	t_ipmi_fru_bloc * fru_bloc = build_fru_bloc(intf, fru, id);
448*c18ec02fSPetter Reinholdtsen 	t_ipmi_fru_bloc * saved_fru_bloc = fru_bloc;
449*c18ec02fSPetter Reinholdtsen 
450*c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
451*c18ec02fSPetter Reinholdtsen 	req.msg.netfn = IPMI_NETFN_STORAGE;
452*c18ec02fSPetter Reinholdtsen 	req.msg.cmd = SET_FRU_DATA;
453*c18ec02fSPetter Reinholdtsen 	req.msg.data = msg_data;
454*c18ec02fSPetter Reinholdtsen 
455*c18ec02fSPetter Reinholdtsen 	/* initialize request size only once */
456*c18ec02fSPetter Reinholdtsen 	if (fru->max_write_size == 0) {
457*c18ec02fSPetter Reinholdtsen 		if (intf->channel_buf_size != 0) {
458*c18ec02fSPetter Reinholdtsen 			/* subtract 1 byte for FRU ID an 2 bytes for offset */
459*c18ec02fSPetter Reinholdtsen 			fru->max_write_size = intf->channel_buf_size - 3;
460*c18ec02fSPetter Reinholdtsen 		} else {
461*c18ec02fSPetter Reinholdtsen 			/* subtract 1 byte for FRU ID an 2 bytes for offset */
462*c18ec02fSPetter Reinholdtsen 			fru->max_write_size = 32 - 3;
463*c18ec02fSPetter Reinholdtsen 		}
464*c18ec02fSPetter Reinholdtsen 
465*c18ec02fSPetter Reinholdtsen 		/* check word access */
466*c18ec02fSPetter Reinholdtsen 		if (fru->access) {
467*c18ec02fSPetter Reinholdtsen 			fru->max_write_size &= ~1;
468*c18ec02fSPetter Reinholdtsen 		}
469*c18ec02fSPetter Reinholdtsen 	}
470*c18ec02fSPetter Reinholdtsen 
471*c18ec02fSPetter Reinholdtsen 	do {
472*c18ec02fSPetter Reinholdtsen 		uint16_t end_bloc;
473*c18ec02fSPetter Reinholdtsen 		uint8_t protected_bloc = 0;
474*c18ec02fSPetter Reinholdtsen 
475*c18ec02fSPetter Reinholdtsen 		/* Write per bloc, try to find the end of a bloc*/
476*c18ec02fSPetter Reinholdtsen 		while (fru_bloc && fru_bloc->start + fru_bloc->size <= doffset) {
477*c18ec02fSPetter Reinholdtsen 			fru_bloc = fru_bloc->next;
478*c18ec02fSPetter Reinholdtsen 			found_bloc++;
479*c18ec02fSPetter Reinholdtsen 		}
480*c18ec02fSPetter Reinholdtsen 
481*c18ec02fSPetter Reinholdtsen 		if (fru_bloc && fru_bloc->start + fru_bloc->size < finish) {
482*c18ec02fSPetter Reinholdtsen 			end_bloc = fru_bloc->start + fru_bloc->size;
483*c18ec02fSPetter Reinholdtsen 		} else {
484*c18ec02fSPetter Reinholdtsen 			end_bloc = finish;
485*c18ec02fSPetter Reinholdtsen 		}
486*c18ec02fSPetter Reinholdtsen 
487*c18ec02fSPetter Reinholdtsen 		/* calculate write length */
488*c18ec02fSPetter Reinholdtsen 		tmp = end_bloc - doffset;
489*c18ec02fSPetter Reinholdtsen 
490*c18ec02fSPetter Reinholdtsen 		/* check that write length is more than maximum request size */
491*c18ec02fSPetter Reinholdtsen 		if (tmp > fru->max_write_size) {
492*c18ec02fSPetter Reinholdtsen 			writeLength = fru->max_write_size;
493*c18ec02fSPetter Reinholdtsen 		} else {
494*c18ec02fSPetter Reinholdtsen 			writeLength = tmp;
495*c18ec02fSPetter Reinholdtsen 		}
496*c18ec02fSPetter Reinholdtsen 
497*c18ec02fSPetter Reinholdtsen 		/* copy fru data */
498*c18ec02fSPetter Reinholdtsen 		memcpy(&msg_data[3], pFrubuf + soffset, writeLength);
499*c18ec02fSPetter Reinholdtsen 
500*c18ec02fSPetter Reinholdtsen 		/* check word access */
501*c18ec02fSPetter Reinholdtsen 		if (fru->access) {
502*c18ec02fSPetter Reinholdtsen 			writeLength &= ~1;
503*c18ec02fSPetter Reinholdtsen 		}
504*c18ec02fSPetter Reinholdtsen 
505*c18ec02fSPetter Reinholdtsen 		tmp = doffset;
506*c18ec02fSPetter Reinholdtsen 		if (fru->access) {
507*c18ec02fSPetter Reinholdtsen 			tmp >>= 1;
508*c18ec02fSPetter Reinholdtsen 		}
509*c18ec02fSPetter Reinholdtsen 
510*c18ec02fSPetter Reinholdtsen 		msg_data[0] = id;
511*c18ec02fSPetter Reinholdtsen 		msg_data[1] = (uint8_t)tmp;
512*c18ec02fSPetter Reinholdtsen 		msg_data[2] = (uint8_t)(tmp >> 8);
513*c18ec02fSPetter Reinholdtsen 		req.msg.data_len = writeLength + 3;
514*c18ec02fSPetter Reinholdtsen 
515*c18ec02fSPetter Reinholdtsen 		if(fru_bloc) {
516*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_INFO,"Writing %d bytes (Bloc #%i: %s)",
517*c18ec02fSPetter Reinholdtsen 					writeLength, found_bloc, fru_bloc->blocId);
518*c18ec02fSPetter Reinholdtsen 		} else {
519*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_INFO,"Writing %d bytes", writeLength);
520*c18ec02fSPetter Reinholdtsen 		}
521*c18ec02fSPetter Reinholdtsen 
522*c18ec02fSPetter Reinholdtsen 		rsp = intf->sendrecv(intf, &req);
523*c18ec02fSPetter Reinholdtsen 		if (!rsp) {
524*c18ec02fSPetter Reinholdtsen 			break;
525*c18ec02fSPetter Reinholdtsen 		}
526*c18ec02fSPetter Reinholdtsen 
527*c18ec02fSPetter Reinholdtsen 		if (rsp->ccode == 0xc7 || rsp->ccode == 0xc8 || rsp->ccode == 0xca) {
528*c18ec02fSPetter Reinholdtsen 			if (fru->max_write_size > 8) {
529*c18ec02fSPetter Reinholdtsen 				fru->max_write_size -= 8;
530*c18ec02fSPetter Reinholdtsen 				lprintf(LOG_INFO, "Retrying FRU write with request size %d",
531*c18ec02fSPetter Reinholdtsen 						fru->max_write_size);
532*c18ec02fSPetter Reinholdtsen 				continue;
533*c18ec02fSPetter Reinholdtsen 			}
534*c18ec02fSPetter Reinholdtsen 		} else if(rsp->ccode == 0x80) {
535*c18ec02fSPetter Reinholdtsen 			rsp->ccode = 0;
536*c18ec02fSPetter Reinholdtsen 			// Write protected section
537*c18ec02fSPetter Reinholdtsen 			protected_bloc = 1;
538*c18ec02fSPetter Reinholdtsen 		}
539*c18ec02fSPetter Reinholdtsen 
540*c18ec02fSPetter Reinholdtsen 		if (rsp->ccode > 0)
541*c18ec02fSPetter Reinholdtsen 			break;
542*c18ec02fSPetter Reinholdtsen 
543*c18ec02fSPetter Reinholdtsen 		if (protected_bloc == 0) {
544*c18ec02fSPetter Reinholdtsen 			// Write OK, bloc not protected, continue
545*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_INFO,"Wrote %d bytes", writeLength);
546*c18ec02fSPetter Reinholdtsen 			doffset += writeLength;
547*c18ec02fSPetter Reinholdtsen 			soffset += writeLength;
548*c18ec02fSPetter Reinholdtsen 		} else {
549*c18ec02fSPetter Reinholdtsen 			if(fru_bloc) {
550*c18ec02fSPetter Reinholdtsen 				// Bloc protected, advise user and jump over protected bloc
551*c18ec02fSPetter Reinholdtsen 				lprintf(LOG_INFO,
552*c18ec02fSPetter Reinholdtsen 						"Bloc [%s] protected at offset: %i (size %i bytes)",
553*c18ec02fSPetter Reinholdtsen 						fru_bloc->blocId, fru_bloc->start, fru_bloc->size);
554*c18ec02fSPetter Reinholdtsen 				lprintf(LOG_INFO,"Jumping over this bloc");
555*c18ec02fSPetter Reinholdtsen 			} else {
556*c18ec02fSPetter Reinholdtsen 				lprintf(LOG_INFO,
557*c18ec02fSPetter Reinholdtsen 						"Remaining FRU is protected following offset: %i",
558*c18ec02fSPetter Reinholdtsen 						doffset);
559*c18ec02fSPetter Reinholdtsen 			}
560*c18ec02fSPetter Reinholdtsen 			soffset += end_bloc - doffset;
561*c18ec02fSPetter Reinholdtsen 			doffset = end_bloc;
562*c18ec02fSPetter Reinholdtsen 		}
563*c18ec02fSPetter Reinholdtsen 	} while (doffset < finish);
564*c18ec02fSPetter Reinholdtsen 
565*c18ec02fSPetter Reinholdtsen 	if (saved_fru_bloc) {
566*c18ec02fSPetter Reinholdtsen 		free_fru_bloc(saved_fru_bloc);
567*c18ec02fSPetter Reinholdtsen 	}
568*c18ec02fSPetter Reinholdtsen 
569*c18ec02fSPetter Reinholdtsen 	return doffset >= finish;
570*c18ec02fSPetter Reinholdtsen }
571*c18ec02fSPetter Reinholdtsen 
572*c18ec02fSPetter Reinholdtsen /* read_fru_area  -  fill in frubuf[offset:length] from the FRU[offset:length]
573*c18ec02fSPetter Reinholdtsen *
574*c18ec02fSPetter Reinholdtsen * @intf:   ipmi interface
575*c18ec02fSPetter Reinholdtsen * @fru: fru info
576*c18ec02fSPetter Reinholdtsen * @id:     fru id
577*c18ec02fSPetter Reinholdtsen * @offset: offset into buffer
578*c18ec02fSPetter Reinholdtsen * @length: how much to read
579*c18ec02fSPetter Reinholdtsen * @frubuf: buffer read into
580*c18ec02fSPetter Reinholdtsen *
581*c18ec02fSPetter Reinholdtsen * returns -1 on error
582*c18ec02fSPetter Reinholdtsen * returns 0 if successful
583*c18ec02fSPetter Reinholdtsen */
584*c18ec02fSPetter Reinholdtsen int
585*c18ec02fSPetter Reinholdtsen read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
586*c18ec02fSPetter Reinholdtsen 			uint32_t offset, uint32_t length, uint8_t *frubuf)
587*c18ec02fSPetter Reinholdtsen {
588*c18ec02fSPetter Reinholdtsen 	uint32_t off = offset, tmp, finish;
589*c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
590*c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
591*c18ec02fSPetter Reinholdtsen 	uint8_t msg_data[4];
592*c18ec02fSPetter Reinholdtsen 
593*c18ec02fSPetter Reinholdtsen 	if (offset > fru->size) {
594*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Read FRU Area offset incorrect: %d > %d",
595*c18ec02fSPetter Reinholdtsen 			offset, fru->size);
596*c18ec02fSPetter Reinholdtsen 		return -1;
597*c18ec02fSPetter Reinholdtsen 	}
598*c18ec02fSPetter Reinholdtsen 
599*c18ec02fSPetter Reinholdtsen 	finish = offset + length;
600*c18ec02fSPetter Reinholdtsen 	if (finish > fru->size) {
601*c18ec02fSPetter Reinholdtsen 		finish = fru->size;
602*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_NOTICE, "Read FRU Area length %d too large, "
603*c18ec02fSPetter Reinholdtsen 			"Adjusting to %d",
604*c18ec02fSPetter Reinholdtsen 			offset + length, finish - offset);
605*c18ec02fSPetter Reinholdtsen 	}
606*c18ec02fSPetter Reinholdtsen 
607*c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
608*c18ec02fSPetter Reinholdtsen 	req.msg.netfn = IPMI_NETFN_STORAGE;
609*c18ec02fSPetter Reinholdtsen 	req.msg.cmd = GET_FRU_DATA;
610*c18ec02fSPetter Reinholdtsen 	req.msg.data = msg_data;
611*c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 4;
612*c18ec02fSPetter Reinholdtsen 
613*c18ec02fSPetter Reinholdtsen 	if (fru->max_read_size == 0) {
614*c18ec02fSPetter Reinholdtsen 		/* subtract 1 byte for completion code and 1 for byte count */
615*c18ec02fSPetter Reinholdtsen 		fru->max_read_size = 32 - 2;
616*c18ec02fSPetter Reinholdtsen 
617*c18ec02fSPetter Reinholdtsen 		/* check word access */
618*c18ec02fSPetter Reinholdtsen 		if (fru->access) {
619*c18ec02fSPetter Reinholdtsen 			fru->max_read_size &= ~1;
620*c18ec02fSPetter Reinholdtsen 		}
621*c18ec02fSPetter Reinholdtsen 	}
622*c18ec02fSPetter Reinholdtsen 
623*c18ec02fSPetter Reinholdtsen 	do {
624*c18ec02fSPetter Reinholdtsen 		tmp = fru->access ? off >> 1 : off;
625*c18ec02fSPetter Reinholdtsen 		msg_data[0] = id;
626*c18ec02fSPetter Reinholdtsen 		msg_data[1] = (uint8_t)(tmp & 0xff);
627*c18ec02fSPetter Reinholdtsen 		msg_data[2] = (uint8_t)(tmp >> 8);
628*c18ec02fSPetter Reinholdtsen 		tmp = finish - off;
629*c18ec02fSPetter Reinholdtsen 		if (tmp > fru->max_read_size)
630*c18ec02fSPetter Reinholdtsen 			msg_data[3] = (uint8_t)fru->max_read_size;
631*c18ec02fSPetter Reinholdtsen 		else
632*c18ec02fSPetter Reinholdtsen 			msg_data[3] = (uint8_t)tmp;
633*c18ec02fSPetter Reinholdtsen 
634*c18ec02fSPetter Reinholdtsen 		rsp = intf->sendrecv(intf, &req);
635*c18ec02fSPetter Reinholdtsen 		if (rsp == NULL) {
636*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_NOTICE, "FRU Read failed");
637*c18ec02fSPetter Reinholdtsen 			break;
638*c18ec02fSPetter Reinholdtsen 		}
639*c18ec02fSPetter Reinholdtsen 		if (rsp->ccode > 0) {
640*c18ec02fSPetter Reinholdtsen 			/* if we get C8h or CAh completion code then we requested too
641*c18ec02fSPetter Reinholdtsen 			* many bytes at once so try again with smaller size */
642*c18ec02fSPetter Reinholdtsen 			if ((rsp->ccode == 0xc8 || rsp->ccode == 0xca)
643*c18ec02fSPetter Reinholdtsen 					&& fru->max_read_size > 8) {
644*c18ec02fSPetter Reinholdtsen 				if (fru->max_read_size > 32) {
645*c18ec02fSPetter Reinholdtsen 					/* subtract read length more aggressively */
646*c18ec02fSPetter Reinholdtsen 					fru->max_read_size -= 8;
647*c18ec02fSPetter Reinholdtsen 				} else {
648*c18ec02fSPetter Reinholdtsen 					/* subtract length less aggressively */
649*c18ec02fSPetter Reinholdtsen 					fru->max_read_size--;
650*c18ec02fSPetter Reinholdtsen 				}
651*c18ec02fSPetter Reinholdtsen 
652*c18ec02fSPetter Reinholdtsen 				lprintf(LOG_INFO, "Retrying FRU read with request size %d",
653*c18ec02fSPetter Reinholdtsen 						fru->max_read_size);
654*c18ec02fSPetter Reinholdtsen 				continue;
655*c18ec02fSPetter Reinholdtsen 			}
656*c18ec02fSPetter Reinholdtsen 
657*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_NOTICE, "FRU Read failed: %s",
658*c18ec02fSPetter Reinholdtsen 				val2str(rsp->ccode, completion_code_vals));
659*c18ec02fSPetter Reinholdtsen 			break;
660*c18ec02fSPetter Reinholdtsen 		}
661*c18ec02fSPetter Reinholdtsen 
662*c18ec02fSPetter Reinholdtsen 		tmp = fru->access ? rsp->data[0] << 1 : rsp->data[0];
663*c18ec02fSPetter Reinholdtsen 		memcpy(frubuf, rsp->data + 1, tmp);
664*c18ec02fSPetter Reinholdtsen 		off += tmp;
665*c18ec02fSPetter Reinholdtsen 		frubuf += tmp;
666*c18ec02fSPetter Reinholdtsen 		/* sometimes the size returned in the Info command
667*c18ec02fSPetter Reinholdtsen 		* is too large.  return 0 so higher level function
668*c18ec02fSPetter Reinholdtsen 		* still attempts to parse what was returned */
669*c18ec02fSPetter Reinholdtsen 		if (tmp == 0 && off < finish) {
670*c18ec02fSPetter Reinholdtsen 			return 0;
671*c18ec02fSPetter Reinholdtsen 		}
672*c18ec02fSPetter Reinholdtsen 	} while (off < finish);
673*c18ec02fSPetter Reinholdtsen 
674*c18ec02fSPetter Reinholdtsen 	if (off < finish) {
675*c18ec02fSPetter Reinholdtsen 		return -1;
676*c18ec02fSPetter Reinholdtsen 	}
677*c18ec02fSPetter Reinholdtsen 
678*c18ec02fSPetter Reinholdtsen 	return 0;
679*c18ec02fSPetter Reinholdtsen }
680*c18ec02fSPetter Reinholdtsen 
681*c18ec02fSPetter Reinholdtsen /* read_fru_area  -  fill in frubuf[offset:length] from the FRU[offset:length]
682*c18ec02fSPetter Reinholdtsen *
683*c18ec02fSPetter Reinholdtsen * @intf:   ipmi interface
684*c18ec02fSPetter Reinholdtsen * @fru: fru info
685*c18ec02fSPetter Reinholdtsen * @id:     fru id
686*c18ec02fSPetter Reinholdtsen * @offset: offset into buffer
687*c18ec02fSPetter Reinholdtsen * @length: how much to read
688*c18ec02fSPetter Reinholdtsen * @frubuf: buffer read into
689*c18ec02fSPetter Reinholdtsen *
690*c18ec02fSPetter Reinholdtsen * returns -1 on error
691*c18ec02fSPetter Reinholdtsen * returns 0 if successful
692*c18ec02fSPetter Reinholdtsen */
693*c18ec02fSPetter Reinholdtsen int
694*c18ec02fSPetter Reinholdtsen read_fru_area_section(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
695*c18ec02fSPetter Reinholdtsen 			uint32_t offset, uint32_t length, uint8_t *frubuf)
696*c18ec02fSPetter Reinholdtsen {
697*c18ec02fSPetter Reinholdtsen 	static uint32_t fru_data_rqst_size = 20;
698*c18ec02fSPetter Reinholdtsen 	uint32_t off = offset, tmp, finish;
699*c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
700*c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
701*c18ec02fSPetter Reinholdtsen 	uint8_t msg_data[4];
702*c18ec02fSPetter Reinholdtsen 
703*c18ec02fSPetter Reinholdtsen 	if (offset > fru->size) {
704*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Read FRU Area offset incorrect: %d > %d",
705*c18ec02fSPetter Reinholdtsen 			offset, fru->size);
706*c18ec02fSPetter Reinholdtsen 		return -1;
707*c18ec02fSPetter Reinholdtsen 	}
708*c18ec02fSPetter Reinholdtsen 
709*c18ec02fSPetter Reinholdtsen 	finish = offset + length;
710*c18ec02fSPetter Reinholdtsen 	if (finish > fru->size) {
711*c18ec02fSPetter Reinholdtsen 		finish = fru->size;
712*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_NOTICE, "Read FRU Area length %d too large, "
713*c18ec02fSPetter Reinholdtsen 			"Adjusting to %d",
714*c18ec02fSPetter Reinholdtsen 			offset + length, finish - offset);
715*c18ec02fSPetter Reinholdtsen 	}
716*c18ec02fSPetter Reinholdtsen 
717*c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
718*c18ec02fSPetter Reinholdtsen 	req.msg.netfn = IPMI_NETFN_STORAGE;
719*c18ec02fSPetter Reinholdtsen 	req.msg.cmd = GET_FRU_DATA;
720*c18ec02fSPetter Reinholdtsen 	req.msg.data = msg_data;
721*c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 4;
722*c18ec02fSPetter Reinholdtsen 
723*c18ec02fSPetter Reinholdtsen #ifdef LIMIT_ALL_REQUEST_SIZE
724*c18ec02fSPetter Reinholdtsen 	if (fru_data_rqst_size > 16)
725*c18ec02fSPetter Reinholdtsen #else
726*c18ec02fSPetter Reinholdtsen 	if (fru->access && fru_data_rqst_size > 16)
727*c18ec02fSPetter Reinholdtsen #endif
728*c18ec02fSPetter Reinholdtsen 		fru_data_rqst_size = 16;
729*c18ec02fSPetter Reinholdtsen 	do {
730*c18ec02fSPetter Reinholdtsen 		tmp = fru->access ? off >> 1 : off;
731*c18ec02fSPetter Reinholdtsen 		msg_data[0] = id;
732*c18ec02fSPetter Reinholdtsen 		msg_data[1] = (uint8_t)(tmp & 0xff);
733*c18ec02fSPetter Reinholdtsen 		msg_data[2] = (uint8_t)(tmp >> 8);
734*c18ec02fSPetter Reinholdtsen 		tmp = finish - off;
735*c18ec02fSPetter Reinholdtsen 		if (tmp > fru_data_rqst_size)
736*c18ec02fSPetter Reinholdtsen 			msg_data[3] = (uint8_t)fru_data_rqst_size;
737*c18ec02fSPetter Reinholdtsen 		else
738*c18ec02fSPetter Reinholdtsen 			msg_data[3] = (uint8_t)tmp;
739*c18ec02fSPetter Reinholdtsen 
740*c18ec02fSPetter Reinholdtsen 		rsp = intf->sendrecv(intf, &req);
741*c18ec02fSPetter Reinholdtsen 		if (rsp == NULL) {
742*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_NOTICE, "FRU Read failed");
743*c18ec02fSPetter Reinholdtsen 			break;
744*c18ec02fSPetter Reinholdtsen 		}
745*c18ec02fSPetter Reinholdtsen 		if (rsp->ccode > 0) {
746*c18ec02fSPetter Reinholdtsen 			/* if we get C7 or C8  or CA return code then we requested too
747*c18ec02fSPetter Reinholdtsen 			* many bytes at once so try again with smaller size */
748*c18ec02fSPetter Reinholdtsen 			if ((rsp->ccode == 0xc7 || rsp->ccode == 0xc8 || rsp->ccode == 0xca) &&
749*c18ec02fSPetter Reinholdtsen 				(--fru_data_rqst_size > 8)) {
750*c18ec02fSPetter Reinholdtsen 				lprintf(LOG_INFO, "Retrying FRU read with request size %d",
751*c18ec02fSPetter Reinholdtsen 					fru_data_rqst_size);
752*c18ec02fSPetter Reinholdtsen 				continue;
753*c18ec02fSPetter Reinholdtsen 			}
754*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_NOTICE, "FRU Read failed: %s",
755*c18ec02fSPetter Reinholdtsen 				val2str(rsp->ccode, completion_code_vals));
756*c18ec02fSPetter Reinholdtsen 			break;
757*c18ec02fSPetter Reinholdtsen 		}
758*c18ec02fSPetter Reinholdtsen 
759*c18ec02fSPetter Reinholdtsen 		tmp = fru->access ? rsp->data[0] << 1 : rsp->data[0];
760*c18ec02fSPetter Reinholdtsen 		memcpy((frubuf + off)-offset, rsp->data + 1, tmp);
761*c18ec02fSPetter Reinholdtsen 		off += tmp;
762*c18ec02fSPetter Reinholdtsen 
763*c18ec02fSPetter Reinholdtsen 		/* sometimes the size returned in the Info command
764*c18ec02fSPetter Reinholdtsen 		* is too large.  return 0 so higher level function
765*c18ec02fSPetter Reinholdtsen 		* still attempts to parse what was returned */
766*c18ec02fSPetter Reinholdtsen 		if (tmp == 0 && off < finish)
767*c18ec02fSPetter Reinholdtsen 			return 0;
768*c18ec02fSPetter Reinholdtsen 
769*c18ec02fSPetter Reinholdtsen 	} while (off < finish);
770*c18ec02fSPetter Reinholdtsen 
771*c18ec02fSPetter Reinholdtsen 	if (off < finish)
772*c18ec02fSPetter Reinholdtsen 		return -1;
773*c18ec02fSPetter Reinholdtsen 
774*c18ec02fSPetter Reinholdtsen 	return 0;
775*c18ec02fSPetter Reinholdtsen }
776*c18ec02fSPetter Reinholdtsen 
777*c18ec02fSPetter Reinholdtsen 
778*c18ec02fSPetter Reinholdtsen static void
779*c18ec02fSPetter Reinholdtsen fru_area_print_multirec_bloc(struct ipmi_intf * intf, struct fru_info * fru,
780*c18ec02fSPetter Reinholdtsen 			uint8_t id, uint32_t offset)
781*c18ec02fSPetter Reinholdtsen {
782*c18ec02fSPetter Reinholdtsen 	uint8_t * fru_data = NULL;
783*c18ec02fSPetter Reinholdtsen 	uint32_t fru_len, i;
784*c18ec02fSPetter Reinholdtsen 	struct fru_multirec_header * h;
785*c18ec02fSPetter Reinholdtsen 	uint32_t last_off, len;
786*c18ec02fSPetter Reinholdtsen 
787*c18ec02fSPetter Reinholdtsen 	i = last_off = offset;
788*c18ec02fSPetter Reinholdtsen 	fru_len = 0;
789*c18ec02fSPetter Reinholdtsen 
790*c18ec02fSPetter Reinholdtsen 	fru_data = malloc(fru->size + 1);
791*c18ec02fSPetter Reinholdtsen 	if (fru_data == NULL) {
792*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, " Out of memory!");
793*c18ec02fSPetter Reinholdtsen 		return;
794*c18ec02fSPetter Reinholdtsen 	}
795*c18ec02fSPetter Reinholdtsen 
796*c18ec02fSPetter Reinholdtsen 	memset(fru_data, 0, fru->size + 1);
797*c18ec02fSPetter Reinholdtsen 
798*c18ec02fSPetter Reinholdtsen 	do {
799*c18ec02fSPetter Reinholdtsen 		h = (struct fru_multirec_header *) (fru_data + i);
800*c18ec02fSPetter Reinholdtsen 
801*c18ec02fSPetter Reinholdtsen 		// read area in (at most) FRU_MULTIREC_CHUNK_SIZE bytes at a time
802*c18ec02fSPetter Reinholdtsen 		if ((last_off < (i + sizeof(*h))) || (last_off < (i + h->len)))
803*c18ec02fSPetter Reinholdtsen 		{
804*c18ec02fSPetter Reinholdtsen 			len = fru->size - last_off;
805*c18ec02fSPetter Reinholdtsen 			if (len > FRU_MULTIREC_CHUNK_SIZE)
806*c18ec02fSPetter Reinholdtsen 				len = FRU_MULTIREC_CHUNK_SIZE;
807*c18ec02fSPetter Reinholdtsen 
808*c18ec02fSPetter Reinholdtsen 			if (read_fru_area(intf, fru, id, last_off, len, fru_data) < 0)
809*c18ec02fSPetter Reinholdtsen 				break;
810*c18ec02fSPetter Reinholdtsen 
811*c18ec02fSPetter Reinholdtsen 			last_off += len;
812*c18ec02fSPetter Reinholdtsen 		}
813*c18ec02fSPetter Reinholdtsen 
814*c18ec02fSPetter Reinholdtsen 		//printf("Bloc Numb : %i\n", counter);
815*c18ec02fSPetter Reinholdtsen 		printf("Bloc Start: %i\n", i);
816*c18ec02fSPetter Reinholdtsen 		printf("Bloc Size : %i\n", h->len);
817*c18ec02fSPetter Reinholdtsen 		printf("\n");
818*c18ec02fSPetter Reinholdtsen 
819*c18ec02fSPetter Reinholdtsen 		i += h->len + sizeof (struct fru_multirec_header);
820*c18ec02fSPetter Reinholdtsen 	} while (!(h->format & 0x80));
821*c18ec02fSPetter Reinholdtsen 
822*c18ec02fSPetter Reinholdtsen 	i = offset;
823*c18ec02fSPetter Reinholdtsen 	do {
824*c18ec02fSPetter Reinholdtsen 		h = (struct fru_multirec_header *) (fru_data + i);
825*c18ec02fSPetter Reinholdtsen 
826*c18ec02fSPetter Reinholdtsen 		printf("Bloc Start: %i\n", i);
827*c18ec02fSPetter Reinholdtsen 		printf("Bloc Size : %i\n", h->len);
828*c18ec02fSPetter Reinholdtsen 		printf("\n");
829*c18ec02fSPetter Reinholdtsen 
830*c18ec02fSPetter Reinholdtsen 		i += h->len + sizeof (struct fru_multirec_header);
831*c18ec02fSPetter Reinholdtsen 	} while (!(h->format & 0x80));
832*c18ec02fSPetter Reinholdtsen 
833*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG ,"Multi-Record area ends at: %i (%xh)",i,i);
834*c18ec02fSPetter Reinholdtsen 
835*c18ec02fSPetter Reinholdtsen 	free(fru_data);
836*c18ec02fSPetter Reinholdtsen 	fru_data = NULL;
837*c18ec02fSPetter Reinholdtsen }
838*c18ec02fSPetter Reinholdtsen 
839*c18ec02fSPetter Reinholdtsen 
840*c18ec02fSPetter Reinholdtsen /* fru_area_print_chassis  -  Print FRU Chassis Area
841*c18ec02fSPetter Reinholdtsen *
842*c18ec02fSPetter Reinholdtsen * @intf:   ipmi interface
843*c18ec02fSPetter Reinholdtsen * @fru: fru info
844*c18ec02fSPetter Reinholdtsen * @id:  fru id
845*c18ec02fSPetter Reinholdtsen * @offset: offset pointer
846*c18ec02fSPetter Reinholdtsen */
847*c18ec02fSPetter Reinholdtsen static void
848*c18ec02fSPetter Reinholdtsen fru_area_print_chassis(struct ipmi_intf * intf, struct fru_info * fru,
849*c18ec02fSPetter Reinholdtsen 			uint8_t id, uint32_t offset)
850*c18ec02fSPetter Reinholdtsen {
851*c18ec02fSPetter Reinholdtsen 	char * fru_area;
852*c18ec02fSPetter Reinholdtsen 	uint8_t * fru_data;
853*c18ec02fSPetter Reinholdtsen 	uint32_t fru_len, i;
854*c18ec02fSPetter Reinholdtsen 	uint8_t tmp[2];
855*c18ec02fSPetter Reinholdtsen 
856*c18ec02fSPetter Reinholdtsen 	fru_len = 0;
857*c18ec02fSPetter Reinholdtsen 
858*c18ec02fSPetter Reinholdtsen 	/* read enough to check length field */
859*c18ec02fSPetter Reinholdtsen 	if (read_fru_area(intf, fru, id, offset, 2, tmp) == 0) {
860*c18ec02fSPetter Reinholdtsen 		fru_len = 8 * tmp[1];
861*c18ec02fSPetter Reinholdtsen 	}
862*c18ec02fSPetter Reinholdtsen 
863*c18ec02fSPetter Reinholdtsen 	if (fru_len == 0) {
864*c18ec02fSPetter Reinholdtsen 		return;
865*c18ec02fSPetter Reinholdtsen 	}
866*c18ec02fSPetter Reinholdtsen 
867*c18ec02fSPetter Reinholdtsen 	fru_data = malloc(fru_len);
868*c18ec02fSPetter Reinholdtsen 	if (fru_data == NULL) {
869*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "ipmitool: malloc failure");
870*c18ec02fSPetter Reinholdtsen 		return;
871*c18ec02fSPetter Reinholdtsen 	}
872*c18ec02fSPetter Reinholdtsen 
873*c18ec02fSPetter Reinholdtsen 	memset(fru_data, 0, fru_len);
874*c18ec02fSPetter Reinholdtsen 
875*c18ec02fSPetter Reinholdtsen 	/* read in the full fru */
876*c18ec02fSPetter Reinholdtsen 	if (read_fru_area(intf, fru, id, offset, fru_len, fru_data) < 0) {
877*c18ec02fSPetter Reinholdtsen 		free(fru_data);
878*c18ec02fSPetter Reinholdtsen 		fru_data = NULL;
879*c18ec02fSPetter Reinholdtsen 		return;
880*c18ec02fSPetter Reinholdtsen 	}
881*c18ec02fSPetter Reinholdtsen 
882*c18ec02fSPetter Reinholdtsen 	/*
883*c18ec02fSPetter Reinholdtsen 	 * skip first two bytes which specify
884*c18ec02fSPetter Reinholdtsen 	 * fru area version and fru area length
885*c18ec02fSPetter Reinholdtsen 	 */
886*c18ec02fSPetter Reinholdtsen 	i = 2;
887*c18ec02fSPetter Reinholdtsen 
888*c18ec02fSPetter Reinholdtsen 	printf(" Chassis Type          : %s\n",
889*c18ec02fSPetter Reinholdtsen  		chassis_type_desc[fru_data[i] >
890*c18ec02fSPetter Reinholdtsen  		(sizeof(chassis_type_desc)/sizeof(chassis_type_desc[0])) - 1 ?
891*c18ec02fSPetter Reinholdtsen  		2 : fru_data[i]]);
892*c18ec02fSPetter Reinholdtsen 
893*c18ec02fSPetter Reinholdtsen  	i++;
894*c18ec02fSPetter Reinholdtsen 
895*c18ec02fSPetter Reinholdtsen 	fru_area = get_fru_area_str(fru_data, &i);
896*c18ec02fSPetter Reinholdtsen 	if (fru_area != NULL) {
897*c18ec02fSPetter Reinholdtsen 		if (strlen(fru_area) > 0) {
898*c18ec02fSPetter Reinholdtsen 			printf(" Chassis Part Number   : %s\n", fru_area);
899*c18ec02fSPetter Reinholdtsen 		}
900*c18ec02fSPetter Reinholdtsen 		free(fru_area);
901*c18ec02fSPetter Reinholdtsen 		fru_area = NULL;
902*c18ec02fSPetter Reinholdtsen 	}
903*c18ec02fSPetter Reinholdtsen 
904*c18ec02fSPetter Reinholdtsen 	fru_area = get_fru_area_str(fru_data, &i);
905*c18ec02fSPetter Reinholdtsen 	if (fru_area != NULL) {
906*c18ec02fSPetter Reinholdtsen 		if (strlen(fru_area) > 0) {
907*c18ec02fSPetter Reinholdtsen 			printf(" Chassis Serial        : %s\n", fru_area);
908*c18ec02fSPetter Reinholdtsen 		}
909*c18ec02fSPetter Reinholdtsen 		free(fru_area);
910*c18ec02fSPetter Reinholdtsen 		fru_area = NULL;
911*c18ec02fSPetter Reinholdtsen 	}
912*c18ec02fSPetter Reinholdtsen 
913*c18ec02fSPetter Reinholdtsen 	/* read any extra fields */
914*c18ec02fSPetter Reinholdtsen 	while ((fru_data[i] != 0xc1) && (i < fru_len))
915*c18ec02fSPetter Reinholdtsen 	{
916*c18ec02fSPetter Reinholdtsen 		int j = i;
917*c18ec02fSPetter Reinholdtsen 		fru_area = get_fru_area_str(fru_data, &i);
918*c18ec02fSPetter Reinholdtsen 		if (fru_area != NULL) {
919*c18ec02fSPetter Reinholdtsen 			if (strlen(fru_area) > 0) {
920*c18ec02fSPetter Reinholdtsen 				printf(" Chassis Extra         : %s\n", fru_area);
921*c18ec02fSPetter Reinholdtsen 			}
922*c18ec02fSPetter Reinholdtsen 			free(fru_area);
923*c18ec02fSPetter Reinholdtsen 			fru_area = NULL;
924*c18ec02fSPetter Reinholdtsen 		}
925*c18ec02fSPetter Reinholdtsen 
926*c18ec02fSPetter Reinholdtsen 		if (i == j) {
927*c18ec02fSPetter Reinholdtsen 			break;
928*c18ec02fSPetter Reinholdtsen 		}
929*c18ec02fSPetter Reinholdtsen 	}
930*c18ec02fSPetter Reinholdtsen 
931*c18ec02fSPetter Reinholdtsen 	if (fru_area != NULL) {
932*c18ec02fSPetter Reinholdtsen 		free(fru_data);
933*c18ec02fSPetter Reinholdtsen 		fru_data = NULL;
934*c18ec02fSPetter Reinholdtsen 	}
935*c18ec02fSPetter Reinholdtsen }
936*c18ec02fSPetter Reinholdtsen 
937*c18ec02fSPetter Reinholdtsen /* fru_area_print_board  -  Print FRU Board Area
938*c18ec02fSPetter Reinholdtsen *
939*c18ec02fSPetter Reinholdtsen * @intf:   ipmi interface
940*c18ec02fSPetter Reinholdtsen * @fru: fru info
941*c18ec02fSPetter Reinholdtsen * @id:  fru id
942*c18ec02fSPetter Reinholdtsen * @offset: offset pointer
943*c18ec02fSPetter Reinholdtsen */
944*c18ec02fSPetter Reinholdtsen static void
945*c18ec02fSPetter Reinholdtsen fru_area_print_board(struct ipmi_intf * intf, struct fru_info * fru,
946*c18ec02fSPetter Reinholdtsen 			uint8_t id, uint32_t offset)
947*c18ec02fSPetter Reinholdtsen {
948*c18ec02fSPetter Reinholdtsen 	char * fru_area;
949*c18ec02fSPetter Reinholdtsen 	uint8_t * fru_data;
950*c18ec02fSPetter Reinholdtsen 	uint32_t fru_len;
951*c18ec02fSPetter Reinholdtsen 	uint32_t i;
952*c18ec02fSPetter Reinholdtsen 	time_t tval;
953*c18ec02fSPetter Reinholdtsen 	uint8_t tmp[2];
954*c18ec02fSPetter Reinholdtsen 
955*c18ec02fSPetter Reinholdtsen 	fru_len = 0;
956*c18ec02fSPetter Reinholdtsen 
957*c18ec02fSPetter Reinholdtsen 	/* read enough to check length field */
958*c18ec02fSPetter Reinholdtsen 	if (read_fru_area(intf, fru, id, offset, 2, tmp) == 0) {
959*c18ec02fSPetter Reinholdtsen 		fru_len = 8 * tmp[1];
960*c18ec02fSPetter Reinholdtsen 	}
961*c18ec02fSPetter Reinholdtsen 
962*c18ec02fSPetter Reinholdtsen 	if (fru_len <= 0) {
963*c18ec02fSPetter Reinholdtsen 		return;
964*c18ec02fSPetter Reinholdtsen 	}
965*c18ec02fSPetter Reinholdtsen 
966*c18ec02fSPetter Reinholdtsen 	fru_data = malloc(fru_len);
967*c18ec02fSPetter Reinholdtsen 	if (fru_data == NULL) {
968*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "ipmitool: malloc failure");
969*c18ec02fSPetter Reinholdtsen 		return;
970*c18ec02fSPetter Reinholdtsen 	}
971*c18ec02fSPetter Reinholdtsen 
972*c18ec02fSPetter Reinholdtsen 	memset(fru_data, 0, fru_len);
973*c18ec02fSPetter Reinholdtsen 
974*c18ec02fSPetter Reinholdtsen 	/* read in the full fru */
975*c18ec02fSPetter Reinholdtsen 	if (read_fru_area(intf, fru, id, offset, fru_len, fru_data) < 0) {
976*c18ec02fSPetter Reinholdtsen 		free(fru_data);
977*c18ec02fSPetter Reinholdtsen 		fru_data = NULL;
978*c18ec02fSPetter Reinholdtsen 		return;
979*c18ec02fSPetter Reinholdtsen 	}
980*c18ec02fSPetter Reinholdtsen 
981*c18ec02fSPetter Reinholdtsen 	/*
982*c18ec02fSPetter Reinholdtsen 	 * skip first three bytes which specify
983*c18ec02fSPetter Reinholdtsen 	 * fru area version, fru area length
984*c18ec02fSPetter Reinholdtsen 	 * and fru board language
985*c18ec02fSPetter Reinholdtsen 	 */
986*c18ec02fSPetter Reinholdtsen 	i = 3;
987*c18ec02fSPetter Reinholdtsen 
988*c18ec02fSPetter Reinholdtsen 	tval=((fru_data[i+2] << 16) + (fru_data[i+1] << 8) + (fru_data[i]));
989*c18ec02fSPetter Reinholdtsen 	tval=tval * 60;
990*c18ec02fSPetter Reinholdtsen 	tval=tval + secs_from_1970_1996;
991*c18ec02fSPetter Reinholdtsen 	printf(" Board Mfg Date        : %s", asctime(localtime(&tval)));
992*c18ec02fSPetter Reinholdtsen 	i += 3;  /* skip mfg. date time */
993*c18ec02fSPetter Reinholdtsen 
994*c18ec02fSPetter Reinholdtsen 	fru_area = get_fru_area_str(fru_data, &i);
995*c18ec02fSPetter Reinholdtsen 	if (fru_area != NULL) {
996*c18ec02fSPetter Reinholdtsen 		if (strlen(fru_area) > 0) {
997*c18ec02fSPetter Reinholdtsen 			printf(" Board Mfg             : %s\n", fru_area);
998*c18ec02fSPetter Reinholdtsen 		}
999*c18ec02fSPetter Reinholdtsen 		free(fru_area);
1000*c18ec02fSPetter Reinholdtsen 		fru_area = NULL;
1001*c18ec02fSPetter Reinholdtsen 	}
1002*c18ec02fSPetter Reinholdtsen 
1003*c18ec02fSPetter Reinholdtsen 	fru_area = get_fru_area_str(fru_data, &i);
1004*c18ec02fSPetter Reinholdtsen 	if (fru_area != NULL) {
1005*c18ec02fSPetter Reinholdtsen 		if (strlen(fru_area) > 0) {
1006*c18ec02fSPetter Reinholdtsen 			printf(" Board Product         : %s\n", fru_area);
1007*c18ec02fSPetter Reinholdtsen 		}
1008*c18ec02fSPetter Reinholdtsen 		free(fru_area);
1009*c18ec02fSPetter Reinholdtsen 		fru_area = NULL;
1010*c18ec02fSPetter Reinholdtsen 	}
1011*c18ec02fSPetter Reinholdtsen 
1012*c18ec02fSPetter Reinholdtsen 	fru_area = get_fru_area_str(fru_data, &i);
1013*c18ec02fSPetter Reinholdtsen 	if (fru_area != NULL) {
1014*c18ec02fSPetter Reinholdtsen 		if (strlen(fru_area) > 0) {
1015*c18ec02fSPetter Reinholdtsen 			printf(" Board Serial          : %s\n", fru_area);
1016*c18ec02fSPetter Reinholdtsen 		}
1017*c18ec02fSPetter Reinholdtsen 		free(fru_area);
1018*c18ec02fSPetter Reinholdtsen 		fru_area = NULL;
1019*c18ec02fSPetter Reinholdtsen 	}
1020*c18ec02fSPetter Reinholdtsen 
1021*c18ec02fSPetter Reinholdtsen 	fru_area = get_fru_area_str(fru_data, &i);
1022*c18ec02fSPetter Reinholdtsen 	if (fru_area != NULL) {
1023*c18ec02fSPetter Reinholdtsen 		if (strlen(fru_area) > 0) {
1024*c18ec02fSPetter Reinholdtsen 			printf(" Board Part Number     : %s\n", fru_area);
1025*c18ec02fSPetter Reinholdtsen 		}
1026*c18ec02fSPetter Reinholdtsen 		free(fru_area);
1027*c18ec02fSPetter Reinholdtsen 		fru_area = NULL;
1028*c18ec02fSPetter Reinholdtsen 	}
1029*c18ec02fSPetter Reinholdtsen 
1030*c18ec02fSPetter Reinholdtsen 	fru_area = get_fru_area_str(fru_data, &i);
1031*c18ec02fSPetter Reinholdtsen 	if (fru_area != NULL) {
1032*c18ec02fSPetter Reinholdtsen 		if (strlen(fru_area) > 0 && verbose > 0) {
1033*c18ec02fSPetter Reinholdtsen 			printf(" Board FRU ID          : %s\n", fru_area);
1034*c18ec02fSPetter Reinholdtsen 		}
1035*c18ec02fSPetter Reinholdtsen 		free(fru_area);
1036*c18ec02fSPetter Reinholdtsen 		fru_area = NULL;
1037*c18ec02fSPetter Reinholdtsen 	}
1038*c18ec02fSPetter Reinholdtsen 
1039*c18ec02fSPetter Reinholdtsen 	/* read any extra fields */
1040*c18ec02fSPetter Reinholdtsen 	while ((fru_data[i] != 0xc1) && (i < fru_len))
1041*c18ec02fSPetter Reinholdtsen 	{
1042*c18ec02fSPetter Reinholdtsen 		int j = i;
1043*c18ec02fSPetter Reinholdtsen 		fru_area = get_fru_area_str(fru_data, &i);
1044*c18ec02fSPetter Reinholdtsen 		if (fru_area != NULL) {
1045*c18ec02fSPetter Reinholdtsen 			if (strlen(fru_area) > 0) {
1046*c18ec02fSPetter Reinholdtsen 				printf(" Board Extra           : %s\n", fru_area);
1047*c18ec02fSPetter Reinholdtsen 			}
1048*c18ec02fSPetter Reinholdtsen 			free(fru_area);
1049*c18ec02fSPetter Reinholdtsen 			fru_area = NULL;
1050*c18ec02fSPetter Reinholdtsen 		}
1051*c18ec02fSPetter Reinholdtsen 		if (i == j)
1052*c18ec02fSPetter Reinholdtsen 			break;
1053*c18ec02fSPetter Reinholdtsen 	}
1054*c18ec02fSPetter Reinholdtsen 
1055*c18ec02fSPetter Reinholdtsen 	if (fru_area != NULL) {
1056*c18ec02fSPetter Reinholdtsen 		free(fru_data);
1057*c18ec02fSPetter Reinholdtsen 		fru_data = NULL;
1058*c18ec02fSPetter Reinholdtsen 	}
1059*c18ec02fSPetter Reinholdtsen }
1060*c18ec02fSPetter Reinholdtsen 
1061*c18ec02fSPetter Reinholdtsen /* fru_area_print_product  -  Print FRU Product Area
1062*c18ec02fSPetter Reinholdtsen *
1063*c18ec02fSPetter Reinholdtsen * @intf:   ipmi interface
1064*c18ec02fSPetter Reinholdtsen * @fru: fru info
1065*c18ec02fSPetter Reinholdtsen * @id:  fru id
1066*c18ec02fSPetter Reinholdtsen * @offset: offset pointer
1067*c18ec02fSPetter Reinholdtsen */
1068*c18ec02fSPetter Reinholdtsen static void
1069*c18ec02fSPetter Reinholdtsen fru_area_print_product(struct ipmi_intf * intf, struct fru_info * fru,
1070*c18ec02fSPetter Reinholdtsen 				uint8_t id, uint32_t offset)
1071*c18ec02fSPetter Reinholdtsen {
1072*c18ec02fSPetter Reinholdtsen 	char * fru_area;
1073*c18ec02fSPetter Reinholdtsen 	uint8_t * fru_data;
1074*c18ec02fSPetter Reinholdtsen 	uint32_t fru_len, i;
1075*c18ec02fSPetter Reinholdtsen 	uint8_t tmp[2];
1076*c18ec02fSPetter Reinholdtsen 
1077*c18ec02fSPetter Reinholdtsen 	fru_len = 0;
1078*c18ec02fSPetter Reinholdtsen 
1079*c18ec02fSPetter Reinholdtsen 	/* read enough to check length field */
1080*c18ec02fSPetter Reinholdtsen 	if (read_fru_area(intf, fru, id, offset, 2, tmp) == 0) {
1081*c18ec02fSPetter Reinholdtsen 		fru_len = 8 * tmp[1];
1082*c18ec02fSPetter Reinholdtsen 	}
1083*c18ec02fSPetter Reinholdtsen 
1084*c18ec02fSPetter Reinholdtsen 	if (fru_len == 0) {
1085*c18ec02fSPetter Reinholdtsen 		return;
1086*c18ec02fSPetter Reinholdtsen 	}
1087*c18ec02fSPetter Reinholdtsen 
1088*c18ec02fSPetter Reinholdtsen 	fru_data = malloc(fru_len);
1089*c18ec02fSPetter Reinholdtsen 	if (fru_data == NULL) {
1090*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "ipmitool: malloc failure");
1091*c18ec02fSPetter Reinholdtsen 		return;
1092*c18ec02fSPetter Reinholdtsen 	}
1093*c18ec02fSPetter Reinholdtsen 
1094*c18ec02fSPetter Reinholdtsen 	memset(fru_data, 0, fru_len);
1095*c18ec02fSPetter Reinholdtsen 
1096*c18ec02fSPetter Reinholdtsen 
1097*c18ec02fSPetter Reinholdtsen 	/* read in the full fru */
1098*c18ec02fSPetter Reinholdtsen 	if (read_fru_area(intf, fru, id, offset, fru_len, fru_data) < 0) {
1099*c18ec02fSPetter Reinholdtsen 		free(fru_data);
1100*c18ec02fSPetter Reinholdtsen 		fru_data = NULL;
1101*c18ec02fSPetter Reinholdtsen 		return;
1102*c18ec02fSPetter Reinholdtsen 	}
1103*c18ec02fSPetter Reinholdtsen 
1104*c18ec02fSPetter Reinholdtsen 	/*
1105*c18ec02fSPetter Reinholdtsen 	 * skip first three bytes which specify
1106*c18ec02fSPetter Reinholdtsen 	 * fru area version, fru area length
1107*c18ec02fSPetter Reinholdtsen 	 * and fru board language
1108*c18ec02fSPetter Reinholdtsen 	 */
1109*c18ec02fSPetter Reinholdtsen 	i = 3;
1110*c18ec02fSPetter Reinholdtsen 
1111*c18ec02fSPetter Reinholdtsen 	fru_area = get_fru_area_str(fru_data, &i);
1112*c18ec02fSPetter Reinholdtsen 	if (fru_area != NULL) {
1113*c18ec02fSPetter Reinholdtsen 		if (strlen(fru_area) > 0) {
1114*c18ec02fSPetter Reinholdtsen 			printf(" Product Manufacturer  : %s\n", fru_area);
1115*c18ec02fSPetter Reinholdtsen 		}
1116*c18ec02fSPetter Reinholdtsen 		free(fru_area);
1117*c18ec02fSPetter Reinholdtsen 		fru_area = NULL;
1118*c18ec02fSPetter Reinholdtsen 	}
1119*c18ec02fSPetter Reinholdtsen 
1120*c18ec02fSPetter Reinholdtsen 	fru_area = get_fru_area_str(fru_data, &i);
1121*c18ec02fSPetter Reinholdtsen 	if (fru_area != NULL) {
1122*c18ec02fSPetter Reinholdtsen 		if (strlen(fru_area) > 0) {
1123*c18ec02fSPetter Reinholdtsen 			printf(" Product Name          : %s\n", fru_area);
1124*c18ec02fSPetter Reinholdtsen 		}
1125*c18ec02fSPetter Reinholdtsen 		free(fru_area);
1126*c18ec02fSPetter Reinholdtsen 		fru_area = NULL;
1127*c18ec02fSPetter Reinholdtsen 	}
1128*c18ec02fSPetter Reinholdtsen 
1129*c18ec02fSPetter Reinholdtsen 	fru_area = get_fru_area_str(fru_data, &i);
1130*c18ec02fSPetter Reinholdtsen 	if (fru_area != NULL) {
1131*c18ec02fSPetter Reinholdtsen 		if (strlen(fru_area) > 0) {
1132*c18ec02fSPetter Reinholdtsen 			printf(" Product Part Number   : %s\n", fru_area);
1133*c18ec02fSPetter Reinholdtsen 		}
1134*c18ec02fSPetter Reinholdtsen 		free(fru_area);
1135*c18ec02fSPetter Reinholdtsen 		fru_area = NULL;
1136*c18ec02fSPetter Reinholdtsen 	}
1137*c18ec02fSPetter Reinholdtsen 
1138*c18ec02fSPetter Reinholdtsen 	fru_area = get_fru_area_str(fru_data, &i);
1139*c18ec02fSPetter Reinholdtsen 	if (fru_area != NULL) {
1140*c18ec02fSPetter Reinholdtsen 		if (strlen(fru_area) > 0) {
1141*c18ec02fSPetter Reinholdtsen 			printf(" Product Version       : %s\n", fru_area);
1142*c18ec02fSPetter Reinholdtsen 		}
1143*c18ec02fSPetter Reinholdtsen 		free(fru_area);
1144*c18ec02fSPetter Reinholdtsen 		fru_area = NULL;
1145*c18ec02fSPetter Reinholdtsen 	}
1146*c18ec02fSPetter Reinholdtsen 
1147*c18ec02fSPetter Reinholdtsen 	fru_area = get_fru_area_str(fru_data, &i);
1148*c18ec02fSPetter Reinholdtsen 	if (fru_area != NULL) {
1149*c18ec02fSPetter Reinholdtsen 		if (strlen(fru_area) > 0) {
1150*c18ec02fSPetter Reinholdtsen 			printf(" Product Serial        : %s\n", fru_area);
1151*c18ec02fSPetter Reinholdtsen 		}
1152*c18ec02fSPetter Reinholdtsen 		free(fru_area);
1153*c18ec02fSPetter Reinholdtsen 		fru_area = NULL;
1154*c18ec02fSPetter Reinholdtsen 	}
1155*c18ec02fSPetter Reinholdtsen 
1156*c18ec02fSPetter Reinholdtsen 	fru_area = get_fru_area_str(fru_data, &i);
1157*c18ec02fSPetter Reinholdtsen 	if (fru_area != NULL) {
1158*c18ec02fSPetter Reinholdtsen 		if (strlen(fru_area) > 0) {
1159*c18ec02fSPetter Reinholdtsen 			printf(" Product Asset Tag     : %s\n", fru_area);
1160*c18ec02fSPetter Reinholdtsen 		}
1161*c18ec02fSPetter Reinholdtsen 		free(fru_area);
1162*c18ec02fSPetter Reinholdtsen 		fru_area = NULL;
1163*c18ec02fSPetter Reinholdtsen 	}
1164*c18ec02fSPetter Reinholdtsen 
1165*c18ec02fSPetter Reinholdtsen 	fru_area = get_fru_area_str(fru_data, &i);
1166*c18ec02fSPetter Reinholdtsen 	if (fru_area != NULL) {
1167*c18ec02fSPetter Reinholdtsen 		if (strlen(fru_area) > 0 && verbose > 0) {
1168*c18ec02fSPetter Reinholdtsen 			printf(" Product FRU ID        : %s\n", fru_area);
1169*c18ec02fSPetter Reinholdtsen 		}
1170*c18ec02fSPetter Reinholdtsen 		free(fru_area);
1171*c18ec02fSPetter Reinholdtsen 		fru_area = NULL;
1172*c18ec02fSPetter Reinholdtsen 	}
1173*c18ec02fSPetter Reinholdtsen 
1174*c18ec02fSPetter Reinholdtsen 	/* read any extra fields */
1175*c18ec02fSPetter Reinholdtsen 	while ((fru_data[i] != 0xc1) && (i < fru_len))
1176*c18ec02fSPetter Reinholdtsen 	{
1177*c18ec02fSPetter Reinholdtsen 		int j = i;
1178*c18ec02fSPetter Reinholdtsen 		fru_area = get_fru_area_str(fru_data, &i);
1179*c18ec02fSPetter Reinholdtsen 		if (fru_area != NULL) {
1180*c18ec02fSPetter Reinholdtsen 			if (strlen(fru_area) > 0) {
1181*c18ec02fSPetter Reinholdtsen 				printf(" Product Extra         : %s\n", fru_area);
1182*c18ec02fSPetter Reinholdtsen 			}
1183*c18ec02fSPetter Reinholdtsen 			free(fru_area);
1184*c18ec02fSPetter Reinholdtsen 			fru_area = NULL;
1185*c18ec02fSPetter Reinholdtsen 		}
1186*c18ec02fSPetter Reinholdtsen 		if (i == j)
1187*c18ec02fSPetter Reinholdtsen 			break;
1188*c18ec02fSPetter Reinholdtsen 	}
1189*c18ec02fSPetter Reinholdtsen 
1190*c18ec02fSPetter Reinholdtsen 	if (fru_area != NULL) {
1191*c18ec02fSPetter Reinholdtsen 		free(fru_data);
1192*c18ec02fSPetter Reinholdtsen 		fru_data = NULL;
1193*c18ec02fSPetter Reinholdtsen 	}
1194*c18ec02fSPetter Reinholdtsen }
1195*c18ec02fSPetter Reinholdtsen 
1196*c18ec02fSPetter Reinholdtsen /* fru_area_print_multirec  -  Print FRU Multi Record Area
1197*c18ec02fSPetter Reinholdtsen *
1198*c18ec02fSPetter Reinholdtsen * @intf:   ipmi interface
1199*c18ec02fSPetter Reinholdtsen * @fru: fru info
1200*c18ec02fSPetter Reinholdtsen * @id:  fru id
1201*c18ec02fSPetter Reinholdtsen * @offset: offset pointer
1202*c18ec02fSPetter Reinholdtsen */
1203*c18ec02fSPetter Reinholdtsen static void
1204*c18ec02fSPetter Reinholdtsen fru_area_print_multirec(struct ipmi_intf * intf, struct fru_info * fru,
1205*c18ec02fSPetter Reinholdtsen 			uint8_t id, uint32_t offset)
1206*c18ec02fSPetter Reinholdtsen {
1207*c18ec02fSPetter Reinholdtsen 	uint8_t * fru_data;
1208*c18ec02fSPetter Reinholdtsen 	struct fru_multirec_header * h;
1209*c18ec02fSPetter Reinholdtsen 	struct fru_multirec_powersupply * ps;
1210*c18ec02fSPetter Reinholdtsen 	struct fru_multirec_dcoutput * dc;
1211*c18ec02fSPetter Reinholdtsen 	struct fru_multirec_dcload * dl;
1212*c18ec02fSPetter Reinholdtsen 	uint16_t peak_capacity;
1213*c18ec02fSPetter Reinholdtsen 	uint8_t peak_hold_up_time;
1214*c18ec02fSPetter Reinholdtsen 	uint32_t last_off;
1215*c18ec02fSPetter Reinholdtsen 
1216*c18ec02fSPetter Reinholdtsen 	last_off = offset;
1217*c18ec02fSPetter Reinholdtsen 
1218*c18ec02fSPetter Reinholdtsen 	fru_data = malloc(FRU_MULTIREC_CHUNK_SIZE);
1219*c18ec02fSPetter Reinholdtsen 	if (fru_data == NULL) {
1220*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "ipmitool: malloc failure");
1221*c18ec02fSPetter Reinholdtsen 		return;
1222*c18ec02fSPetter Reinholdtsen 	}
1223*c18ec02fSPetter Reinholdtsen 
1224*c18ec02fSPetter Reinholdtsen 	memset(fru_data, 0, FRU_MULTIREC_CHUNK_SIZE);
1225*c18ec02fSPetter Reinholdtsen 
1226*c18ec02fSPetter Reinholdtsen 	h = (struct fru_multirec_header *) (fru_data);
1227*c18ec02fSPetter Reinholdtsen 
1228*c18ec02fSPetter Reinholdtsen 	do {
1229*c18ec02fSPetter Reinholdtsen 		if (read_fru_area(intf, fru, id, last_off, sizeof(*h), fru_data) < 0) {
1230*c18ec02fSPetter Reinholdtsen 			break;
1231*c18ec02fSPetter Reinholdtsen 		}
1232*c18ec02fSPetter Reinholdtsen 
1233*c18ec02fSPetter Reinholdtsen 		if (h->len && read_fru_area(intf, fru, id,
1234*c18ec02fSPetter Reinholdtsen 				last_off + sizeof(*h), h->len, fru_data + sizeof(*h)) < 0) {
1235*c18ec02fSPetter Reinholdtsen 			break;
1236*c18ec02fSPetter Reinholdtsen 		}
1237*c18ec02fSPetter Reinholdtsen 
1238*c18ec02fSPetter Reinholdtsen 		last_off += h->len + sizeof(*h);
1239*c18ec02fSPetter Reinholdtsen 
1240*c18ec02fSPetter Reinholdtsen 		switch (h->type) {
1241*c18ec02fSPetter Reinholdtsen 		case FRU_RECORD_TYPE_POWER_SUPPLY_INFORMATION:
1242*c18ec02fSPetter Reinholdtsen 			ps = (struct fru_multirec_powersupply *)
1243*c18ec02fSPetter Reinholdtsen 				(fru_data + sizeof(struct fru_multirec_header));
1244*c18ec02fSPetter Reinholdtsen 
1245*c18ec02fSPetter Reinholdtsen #if WORDS_BIGENDIAN
1246*c18ec02fSPetter Reinholdtsen 			ps->capacity      = BSWAP_16(ps->capacity);
1247*c18ec02fSPetter Reinholdtsen 			ps->peak_va    = BSWAP_16(ps->peak_va);
1248*c18ec02fSPetter Reinholdtsen 			ps->lowend_input1 = BSWAP_16(ps->lowend_input1);
1249*c18ec02fSPetter Reinholdtsen 			ps->highend_input1   = BSWAP_16(ps->highend_input1);
1250*c18ec02fSPetter Reinholdtsen 			ps->lowend_input2 = BSWAP_16(ps->lowend_input2);
1251*c18ec02fSPetter Reinholdtsen 			ps->highend_input2   = BSWAP_16(ps->highend_input2);
1252*c18ec02fSPetter Reinholdtsen 			ps->combined_capacity   = BSWAP_16(ps->combined_capacity);
1253*c18ec02fSPetter Reinholdtsen 			ps->peak_cap_ht      = BSWAP_16(ps->peak_cap_ht);
1254*c18ec02fSPetter Reinholdtsen #endif
1255*c18ec02fSPetter Reinholdtsen 			peak_hold_up_time = (ps->peak_cap_ht & 0xf000) >> 12;
1256*c18ec02fSPetter Reinholdtsen 			peak_capacity     = ps->peak_cap_ht & 0x0fff;
1257*c18ec02fSPetter Reinholdtsen 
1258*c18ec02fSPetter Reinholdtsen 			printf (" Power Supply Record\n");
1259*c18ec02fSPetter Reinholdtsen 			printf ("  Capacity                   : %d W\n",
1260*c18ec02fSPetter Reinholdtsen 				ps->capacity);
1261*c18ec02fSPetter Reinholdtsen 			printf ("  Peak VA                    : %d VA\n",
1262*c18ec02fSPetter Reinholdtsen 				ps->peak_va);
1263*c18ec02fSPetter Reinholdtsen 			printf ("  Inrush Current             : %d A\n",
1264*c18ec02fSPetter Reinholdtsen 				ps->inrush_current);
1265*c18ec02fSPetter Reinholdtsen 			printf ("  Inrush Interval            : %d ms\n",
1266*c18ec02fSPetter Reinholdtsen 				ps->inrush_interval);
1267*c18ec02fSPetter Reinholdtsen 			printf ("  Input Voltage Range 1      : %d-%d V\n",
1268*c18ec02fSPetter Reinholdtsen 				ps->lowend_input1 / 100, ps->highend_input1 / 100);
1269*c18ec02fSPetter Reinholdtsen 			printf ("  Input Voltage Range 2      : %d-%d V\n",
1270*c18ec02fSPetter Reinholdtsen 				ps->lowend_input2 / 100, ps->highend_input2 / 100);
1271*c18ec02fSPetter Reinholdtsen 			printf ("  Input Frequency Range      : %d-%d Hz\n",
1272*c18ec02fSPetter Reinholdtsen 				ps->lowend_freq, ps->highend_freq);
1273*c18ec02fSPetter Reinholdtsen 			printf ("  A/C Dropout Tolerance      : %d ms\n",
1274*c18ec02fSPetter Reinholdtsen 				ps->dropout_tolerance);
1275*c18ec02fSPetter Reinholdtsen 			printf ("  Flags                      : %s%s%s%s%s\n",
1276*c18ec02fSPetter Reinholdtsen 				ps->predictive_fail ? "'Predictive fail' " : "",
1277*c18ec02fSPetter Reinholdtsen 				ps->pfc ? "'Power factor correction' " : "",
1278*c18ec02fSPetter Reinholdtsen 				ps->autoswitch ? "'Autoswitch voltage' " : "",
1279*c18ec02fSPetter Reinholdtsen 				ps->hotswap ? "'Hot swap' " : "",
1280*c18ec02fSPetter Reinholdtsen 				ps->predictive_fail ? ps->rps_threshold ?
1281*c18ec02fSPetter Reinholdtsen 				ps->tach ? "'Two pulses per rotation'" : "'One pulse per rotation'" :
1282*c18ec02fSPetter Reinholdtsen 				ps->tach ? "'Failure on pin de-assertion'" : "'Failure on pin assertion'" : "");
1283*c18ec02fSPetter Reinholdtsen 			printf ("  Peak capacity              : %d W\n",
1284*c18ec02fSPetter Reinholdtsen 				peak_capacity);
1285*c18ec02fSPetter Reinholdtsen 			printf ("  Peak capacity holdup       : %d s\n",
1286*c18ec02fSPetter Reinholdtsen 				peak_hold_up_time);
1287*c18ec02fSPetter Reinholdtsen 			if (ps->combined_capacity == 0)
1288*c18ec02fSPetter Reinholdtsen 				printf ("  Combined capacity          : not specified\n");
1289*c18ec02fSPetter Reinholdtsen 			else
1290*c18ec02fSPetter Reinholdtsen 				printf ("  Combined capacity          : %d W (%s and %s)\n",
1291*c18ec02fSPetter Reinholdtsen 					ps->combined_capacity,
1292*c18ec02fSPetter Reinholdtsen 					combined_voltage_desc [ps->combined_voltage1],
1293*c18ec02fSPetter Reinholdtsen 					combined_voltage_desc [ps->combined_voltage2]);
1294*c18ec02fSPetter Reinholdtsen 			if (ps->predictive_fail)
1295*c18ec02fSPetter Reinholdtsen 				printf ("  Fan lower threshold        : %d RPS\n",
1296*c18ec02fSPetter Reinholdtsen 					ps->rps_threshold);
1297*c18ec02fSPetter Reinholdtsen 			break;
1298*c18ec02fSPetter Reinholdtsen 
1299*c18ec02fSPetter Reinholdtsen 		case FRU_RECORD_TYPE_DC_OUTPUT:
1300*c18ec02fSPetter Reinholdtsen 			dc = (struct fru_multirec_dcoutput *)
1301*c18ec02fSPetter Reinholdtsen 				(fru_data + sizeof(struct fru_multirec_header));
1302*c18ec02fSPetter Reinholdtsen 
1303*c18ec02fSPetter Reinholdtsen #if WORDS_BIGENDIAN
1304*c18ec02fSPetter Reinholdtsen 			dc->nominal_voltage  = BSWAP_16(dc->nominal_voltage);
1305*c18ec02fSPetter Reinholdtsen 			dc->max_neg_dev      = BSWAP_16(dc->max_neg_dev);
1306*c18ec02fSPetter Reinholdtsen 			dc->max_pos_dev      = BSWAP_16(dc->max_pos_dev);
1307*c18ec02fSPetter Reinholdtsen 			dc->ripple_and_noise = BSWAP_16(dc->ripple_and_noise);
1308*c18ec02fSPetter Reinholdtsen 			dc->min_current      = BSWAP_16(dc->min_current);
1309*c18ec02fSPetter Reinholdtsen 			dc->max_current      = BSWAP_16(dc->max_current);
1310*c18ec02fSPetter Reinholdtsen #endif
1311*c18ec02fSPetter Reinholdtsen 
1312*c18ec02fSPetter Reinholdtsen 			printf (" DC Output Record\n");
1313*c18ec02fSPetter Reinholdtsen 			printf ("  Output Number              : %d\n",
1314*c18ec02fSPetter Reinholdtsen 				dc->output_number);
1315*c18ec02fSPetter Reinholdtsen 			printf ("  Standby power              : %s\n",
1316*c18ec02fSPetter Reinholdtsen 				dc->standby ? "Yes" : "No");
1317*c18ec02fSPetter Reinholdtsen 			printf ("  Nominal voltage            : %.2f V\n",
1318*c18ec02fSPetter Reinholdtsen 				(double) dc->nominal_voltage / 100);
1319*c18ec02fSPetter Reinholdtsen 			printf ("  Max negative deviation     : %.2f V\n",
1320*c18ec02fSPetter Reinholdtsen 				(double) dc->max_neg_dev / 100);
1321*c18ec02fSPetter Reinholdtsen 			printf ("  Max positive deviation     : %.2f V\n",
1322*c18ec02fSPetter Reinholdtsen 				(double) dc->max_pos_dev / 100);
1323*c18ec02fSPetter Reinholdtsen 			printf ("  Ripple and noise pk-pk     : %d mV\n",
1324*c18ec02fSPetter Reinholdtsen 				dc->ripple_and_noise);
1325*c18ec02fSPetter Reinholdtsen 			printf ("  Minimum current draw       : %.3f A\n",
1326*c18ec02fSPetter Reinholdtsen 				(double) dc->min_current / 1000);
1327*c18ec02fSPetter Reinholdtsen 			printf ("  Maximum current draw       : %.3f A\n",
1328*c18ec02fSPetter Reinholdtsen 				(double) dc->max_current / 1000);
1329*c18ec02fSPetter Reinholdtsen 			break;
1330*c18ec02fSPetter Reinholdtsen 
1331*c18ec02fSPetter Reinholdtsen 		case FRU_RECORD_TYPE_DC_LOAD:
1332*c18ec02fSPetter Reinholdtsen 			dl = (struct fru_multirec_dcload *)
1333*c18ec02fSPetter Reinholdtsen 				(fru_data + sizeof(struct fru_multirec_header));
1334*c18ec02fSPetter Reinholdtsen 
1335*c18ec02fSPetter Reinholdtsen #if WORDS_BIGENDIAN
1336*c18ec02fSPetter Reinholdtsen 			dl->nominal_voltage  = BSWAP_16(dl->nominal_voltage);
1337*c18ec02fSPetter Reinholdtsen 			dl->min_voltage      = BSWAP_16(dl->min_voltage);
1338*c18ec02fSPetter Reinholdtsen 			dl->max_voltage      = BSWAP_16(dl->max_voltage);
1339*c18ec02fSPetter Reinholdtsen 			dl->ripple_and_noise = BSWAP_16(dl->ripple_and_noise);
1340*c18ec02fSPetter Reinholdtsen 			dl->min_current      = BSWAP_16(dl->min_current);
1341*c18ec02fSPetter Reinholdtsen 			dl->max_current      = BSWAP_16(dl->max_current);
1342*c18ec02fSPetter Reinholdtsen #endif
1343*c18ec02fSPetter Reinholdtsen 
1344*c18ec02fSPetter Reinholdtsen 			printf (" DC Load Record\n");
1345*c18ec02fSPetter Reinholdtsen 			printf ("  Output Number              : %d\n",
1346*c18ec02fSPetter Reinholdtsen 				dl->output_number);
1347*c18ec02fSPetter Reinholdtsen 			printf ("  Nominal voltage            : %.2f V\n",
1348*c18ec02fSPetter Reinholdtsen 				(double) dl->nominal_voltage / 100);
1349*c18ec02fSPetter Reinholdtsen 			printf ("  Min voltage allowed        : %.2f V\n",
1350*c18ec02fSPetter Reinholdtsen 				(double) dl->min_voltage / 100);
1351*c18ec02fSPetter Reinholdtsen 			printf ("  Max voltage allowed        : %.2f V\n",
1352*c18ec02fSPetter Reinholdtsen 				(double) dl->max_voltage / 100);
1353*c18ec02fSPetter Reinholdtsen 			printf ("  Ripple and noise pk-pk     : %d mV\n",
1354*c18ec02fSPetter Reinholdtsen 				dl->ripple_and_noise);
1355*c18ec02fSPetter Reinholdtsen 			printf ("  Minimum current load       : %.3f A\n",
1356*c18ec02fSPetter Reinholdtsen 				(double) dl->min_current / 1000);
1357*c18ec02fSPetter Reinholdtsen 			printf ("  Maximum current load       : %.3f A\n",
1358*c18ec02fSPetter Reinholdtsen 				(double) dl->max_current / 1000);
1359*c18ec02fSPetter Reinholdtsen 			break;
1360*c18ec02fSPetter Reinholdtsen 		case FRU_RECORD_TYPE_OEM_EXTENSION:
1361*c18ec02fSPetter Reinholdtsen 			{
1362*c18ec02fSPetter Reinholdtsen 				struct fru_multirec_oem_header *oh=(struct fru_multirec_oem_header *)
1363*c18ec02fSPetter Reinholdtsen 										&fru_data[sizeof(struct fru_multirec_header)];
1364*c18ec02fSPetter Reinholdtsen 				uint32_t iana = oh->mfg_id[0] | oh->mfg_id[1]<<8 | oh->mfg_id[2]<<16;
1365*c18ec02fSPetter Reinholdtsen 
1366*c18ec02fSPetter Reinholdtsen 				/* Now makes sure this is really PICMG record */
1367*c18ec02fSPetter Reinholdtsen 
1368*c18ec02fSPetter Reinholdtsen 				if( iana == IPMI_OEM_PICMG ){
1369*c18ec02fSPetter Reinholdtsen 					printf("  PICMG Extension Record\n");
1370*c18ec02fSPetter Reinholdtsen 					ipmi_fru_picmg_ext_print(fru_data,
1371*c18ec02fSPetter Reinholdtsen 													sizeof(struct fru_multirec_header),
1372*c18ec02fSPetter Reinholdtsen 													h->len);
1373*c18ec02fSPetter Reinholdtsen 				}
1374*c18ec02fSPetter Reinholdtsen 				/* FIXME: Add OEM record support here */
1375*c18ec02fSPetter Reinholdtsen 				else{
1376*c18ec02fSPetter Reinholdtsen 					printf("  OEM (%s) Record\n", val2str( iana, ipmi_oem_info));
1377*c18ec02fSPetter Reinholdtsen 				}
1378*c18ec02fSPetter Reinholdtsen 			}
1379*c18ec02fSPetter Reinholdtsen 			break;
1380*c18ec02fSPetter Reinholdtsen 		}
1381*c18ec02fSPetter Reinholdtsen 	} while (!(h->format & 0x80));
1382*c18ec02fSPetter Reinholdtsen 
1383*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG ,"Multi-Record area ends at: %i (%xh)", last_off, last_off);
1384*c18ec02fSPetter Reinholdtsen 
1385*c18ec02fSPetter Reinholdtsen 	free(fru_data);
1386*c18ec02fSPetter Reinholdtsen }
1387*c18ec02fSPetter Reinholdtsen 
1388*c18ec02fSPetter Reinholdtsen /* ipmi_fru_query_new_value  -  Query new values to replace original FRU content
1389*c18ec02fSPetter Reinholdtsen *
1390*c18ec02fSPetter Reinholdtsen * @data:   FRU data
1391*c18ec02fSPetter Reinholdtsen * @offset: offset of the bytes to be modified in data
1392*c18ec02fSPetter Reinholdtsen * @len:    size of the modified data
1393*c18ec02fSPetter Reinholdtsen *
1394*c18ec02fSPetter Reinholdtsen * returns : TRUE if data changed
1395*c18ec02fSPetter Reinholdtsen * returns : FALSE if data not changed
1396*c18ec02fSPetter Reinholdtsen */
1397*c18ec02fSPetter Reinholdtsen int ipmi_fru_query_new_value(uint8_t *data,int offset, size_t len)
1398*c18ec02fSPetter Reinholdtsen {
1399*c18ec02fSPetter Reinholdtsen 	int status=FALSE;
1400*c18ec02fSPetter Reinholdtsen 	int ret;
1401*c18ec02fSPetter Reinholdtsen 	char answer;
1402*c18ec02fSPetter Reinholdtsen 
1403*c18ec02fSPetter Reinholdtsen 	printf("Would you like to change this value <y/n> ? ");
1404*c18ec02fSPetter Reinholdtsen 	ret = scanf("%c", &answer);
1405*c18ec02fSPetter Reinholdtsen 	if (ret != 1) {
1406*c18ec02fSPetter Reinholdtsen 		return FALSE;
1407*c18ec02fSPetter Reinholdtsen 	}
1408*c18ec02fSPetter Reinholdtsen 
1409*c18ec02fSPetter Reinholdtsen 	if( answer == 'y' || answer == 'Y' ){
1410*c18ec02fSPetter Reinholdtsen 		int i;
1411*c18ec02fSPetter Reinholdtsen 		unsigned int *holder;
1412*c18ec02fSPetter Reinholdtsen 
1413*c18ec02fSPetter Reinholdtsen 		holder = malloc(len);
1414*c18ec02fSPetter Reinholdtsen 		printf(
1415*c18ec02fSPetter Reinholdtsen 		 "Enter hex values for each of the %d entries (lsb first), "
1416*c18ec02fSPetter Reinholdtsen 		 "hit <enter> between entries\n", (int)len);
1417*c18ec02fSPetter Reinholdtsen 
1418*c18ec02fSPetter Reinholdtsen 		/* I can't assign scanf' %x into a single char */
1419*c18ec02fSPetter Reinholdtsen 		for( i=0;i<len;i++ ){
1420*c18ec02fSPetter Reinholdtsen 			ret = scanf("%x", holder+i);
1421*c18ec02fSPetter Reinholdtsen 			if (ret != 1) {
1422*c18ec02fSPetter Reinholdtsen 				free(holder);
1423*c18ec02fSPetter Reinholdtsen 				return FALSE;
1424*c18ec02fSPetter Reinholdtsen 			}
1425*c18ec02fSPetter Reinholdtsen 		}
1426*c18ec02fSPetter Reinholdtsen 		for( i=0;i<len;i++ ){
1427*c18ec02fSPetter Reinholdtsen 			data[offset++] = (unsigned char) *(holder+i);
1428*c18ec02fSPetter Reinholdtsen 		}
1429*c18ec02fSPetter Reinholdtsen 		/* &data[offset++] */
1430*c18ec02fSPetter Reinholdtsen 		free(holder);
1431*c18ec02fSPetter Reinholdtsen 		holder = NULL;
1432*c18ec02fSPetter Reinholdtsen 		status = TRUE;
1433*c18ec02fSPetter Reinholdtsen 	}
1434*c18ec02fSPetter Reinholdtsen 	else{
1435*c18ec02fSPetter Reinholdtsen 		printf("Entered %c\n",answer);
1436*c18ec02fSPetter Reinholdtsen 	}
1437*c18ec02fSPetter Reinholdtsen 
1438*c18ec02fSPetter Reinholdtsen 	return status;
1439*c18ec02fSPetter Reinholdtsen }
1440*c18ec02fSPetter Reinholdtsen 
1441*c18ec02fSPetter Reinholdtsen /* ipmi_fru_oemkontron_edit  -
1442*c18ec02fSPetter Reinholdtsen *  Query new values to replace original FRU content
1443*c18ec02fSPetter Reinholdtsen *  This is a generic enough to support any type of 'OEM' record
1444*c18ec02fSPetter Reinholdtsen *  because the user supplies 'IANA number' , 'record Id' and 'record' version'
1445*c18ec02fSPetter Reinholdtsen *
1446*c18ec02fSPetter Reinholdtsen * However, the parser must have 'apriori' knowledge of the record format
1447*c18ec02fSPetter Reinholdtsen * The currently supported record is :
1448*c18ec02fSPetter Reinholdtsen *
1449*c18ec02fSPetter Reinholdtsen *    IANA          : 15000  (Kontron)
1450*c18ec02fSPetter Reinholdtsen *    RECORD ID     : 3
1451*c18ec02fSPetter Reinholdtsen *    RECORD VERSION: 0 (or 1)
1452*c18ec02fSPetter Reinholdtsen *
1453*c18ec02fSPetter Reinholdtsen * I would have like to put that stuff in an OEM specific file, but apart for
1454*c18ec02fSPetter Reinholdtsen * the record format information, all commands are really standard 'FRU' command
1455*c18ec02fSPetter Reinholdtsen *
1456*c18ec02fSPetter Reinholdtsen *
1457*c18ec02fSPetter Reinholdtsen * @data:   FRU data
1458*c18ec02fSPetter Reinholdtsen * @offset: start of the current multi record (start of header)
1459*c18ec02fSPetter Reinholdtsen * @len:    len of the current record (excluding header)
1460*c18ec02fSPetter Reinholdtsen * @h:      pointer to record header
1461*c18ec02fSPetter Reinholdtsen * @oh:     pointer to OEM /PICMG header
1462*c18ec02fSPetter Reinholdtsen *
1463*c18ec02fSPetter Reinholdtsen * returns: TRUE if data changed
1464*c18ec02fSPetter Reinholdtsen * returns: FALSE if data not changed
1465*c18ec02fSPetter Reinholdtsen */
1466*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_INFORMATION_RECORD 3
1467*c18ec02fSPetter Reinholdtsen 
1468*c18ec02fSPetter Reinholdtsen #define EDIT_OEM_KONTRON_COMPLETE_ARG_COUNT    12
1469*c18ec02fSPetter Reinholdtsen #define GET_OEM_KONTRON_COMPLETE_ARG_COUNT     5
1470*c18ec02fSPetter Reinholdtsen /*
1471*c18ec02fSPetter Reinholdtsen ./src/ipmitool  fru edit 0
1472*c18ec02fSPetter Reinholdtsen oem 15000 3 0 name instance FIELD1 FIELD2 FIELD3 crc32
1473*c18ec02fSPetter Reinholdtsen */
1474*c18ec02fSPetter Reinholdtsen 
1475*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_SUBCOMMAND_ARG_POS   2
1476*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_IANA_ARG_POS         3
1477*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_RECORDID_ARG_POS     4
1478*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_FORMAT_ARG_POS       5
1479*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_NAME_ARG_POS         6
1480*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_INSTANCE_ARG_POS     7
1481*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_VERSION_ARG_POS      8
1482*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_BUILDDATE_ARG_POS    9
1483*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_UPDATEDATE_ARG_POS   10
1484*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_CRC32_ARG_POS        11
1485*c18ec02fSPetter Reinholdtsen 
1486*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_FIELD_SIZE          8
1487*c18ec02fSPetter Reinholdtsen #define OEM_KONTRON_VERSION_FIELD_SIZE 10
1488*c18ec02fSPetter Reinholdtsen 
1489*c18ec02fSPetter Reinholdtsen #ifdef HAVE_PRAGMA_PACK
1490*c18ec02fSPetter Reinholdtsen #pragma pack(1)
1491*c18ec02fSPetter Reinholdtsen #endif
1492*c18ec02fSPetter Reinholdtsen typedef struct OemKontronInformationRecordV0{
1493*c18ec02fSPetter Reinholdtsen 	uint8_t field1TypeLength;
1494*c18ec02fSPetter Reinholdtsen 	uint8_t field1[OEM_KONTRON_FIELD_SIZE];
1495*c18ec02fSPetter Reinholdtsen 	uint8_t field2TypeLength;
1496*c18ec02fSPetter Reinholdtsen 	uint8_t field2[OEM_KONTRON_FIELD_SIZE];
1497*c18ec02fSPetter Reinholdtsen 	uint8_t field3TypeLength;
1498*c18ec02fSPetter Reinholdtsen 	uint8_t field3[OEM_KONTRON_FIELD_SIZE];
1499*c18ec02fSPetter Reinholdtsen 	uint8_t crcTypeLength;
1500*c18ec02fSPetter Reinholdtsen 	uint8_t crc32[OEM_KONTRON_FIELD_SIZE];
1501*c18ec02fSPetter Reinholdtsen }tOemKontronInformationRecordV0;
1502*c18ec02fSPetter Reinholdtsen #ifdef HAVE_PRAGMA_PACK
1503*c18ec02fSPetter Reinholdtsen #pragma pack(0)
1504*c18ec02fSPetter Reinholdtsen #endif
1505*c18ec02fSPetter Reinholdtsen 
1506*c18ec02fSPetter Reinholdtsen 
1507*c18ec02fSPetter Reinholdtsen #ifdef HAVE_PRAGMA_PACK
1508*c18ec02fSPetter Reinholdtsen #pragma pack(1)
1509*c18ec02fSPetter Reinholdtsen #endif
1510*c18ec02fSPetter Reinholdtsen typedef struct OemKontronInformationRecordV1{
1511*c18ec02fSPetter Reinholdtsen 	uint8_t field1TypeLength;
1512*c18ec02fSPetter Reinholdtsen 	uint8_t field1[OEM_KONTRON_VERSION_FIELD_SIZE];
1513*c18ec02fSPetter Reinholdtsen 	uint8_t field2TypeLength;
1514*c18ec02fSPetter Reinholdtsen 	uint8_t field2[OEM_KONTRON_FIELD_SIZE];
1515*c18ec02fSPetter Reinholdtsen 	uint8_t field3TypeLength;
1516*c18ec02fSPetter Reinholdtsen 	uint8_t field3[OEM_KONTRON_FIELD_SIZE];
1517*c18ec02fSPetter Reinholdtsen 	uint8_t crcTypeLength;
1518*c18ec02fSPetter Reinholdtsen 	uint8_t crc32[OEM_KONTRON_FIELD_SIZE];
1519*c18ec02fSPetter Reinholdtsen }tOemKontronInformationRecordV1;
1520*c18ec02fSPetter Reinholdtsen #ifdef HAVE_PRAGMA_PACK
1521*c18ec02fSPetter Reinholdtsen #pragma pack(0)
1522*c18ec02fSPetter Reinholdtsen #endif
1523*c18ec02fSPetter Reinholdtsen 
1524*c18ec02fSPetter Reinholdtsen /*
1525*c18ec02fSPetter Reinholdtsen ./src/ipmitool  fru get 0 oem iana 3
1526*c18ec02fSPetter Reinholdtsen 
1527*c18ec02fSPetter Reinholdtsen */
1528*c18ec02fSPetter Reinholdtsen 
1529*c18ec02fSPetter Reinholdtsen static void ipmi_fru_oemkontron_get( int argc, char ** argv,uint8_t * fru_data,
1530*c18ec02fSPetter Reinholdtsen 												int off,int len,
1531*c18ec02fSPetter Reinholdtsen 												struct fru_multirec_header *h,
1532*c18ec02fSPetter Reinholdtsen 												struct fru_multirec_oem_header *oh)
1533*c18ec02fSPetter Reinholdtsen {
1534*c18ec02fSPetter Reinholdtsen 	static int badParams=FALSE;
1535*c18ec02fSPetter Reinholdtsen 	int start = off;
1536*c18ec02fSPetter Reinholdtsen 	int offset = start;
1537*c18ec02fSPetter Reinholdtsen 	int length = len;
1538*c18ec02fSPetter Reinholdtsen 	int i;
1539*c18ec02fSPetter Reinholdtsen 	offset += sizeof(struct fru_multirec_oem_header);
1540*c18ec02fSPetter Reinholdtsen 
1541*c18ec02fSPetter Reinholdtsen 	if(!badParams){
1542*c18ec02fSPetter Reinholdtsen 		/* the 'OEM' field is already checked in caller */
1543*c18ec02fSPetter Reinholdtsen 		if( argc > OEM_KONTRON_SUBCOMMAND_ARG_POS ){
1544*c18ec02fSPetter Reinholdtsen 			if(strncmp("oem", argv[OEM_KONTRON_SUBCOMMAND_ARG_POS],3)){
1545*c18ec02fSPetter Reinholdtsen 				printf("usage: fru get <id> <oem>\n");
1546*c18ec02fSPetter Reinholdtsen 				badParams = TRUE;
1547*c18ec02fSPetter Reinholdtsen 				return;
1548*c18ec02fSPetter Reinholdtsen 			}
1549*c18ec02fSPetter Reinholdtsen 		}
1550*c18ec02fSPetter Reinholdtsen 		if( argc<GET_OEM_KONTRON_COMPLETE_ARG_COUNT ){
1551*c18ec02fSPetter Reinholdtsen 			printf("usage: oem <iana> <recordid>\n");
1552*c18ec02fSPetter Reinholdtsen 			printf("usage: oem 15000 3\n");
1553*c18ec02fSPetter Reinholdtsen 			badParams = TRUE;
1554*c18ec02fSPetter Reinholdtsen 			return;
1555*c18ec02fSPetter Reinholdtsen 		}
1556*c18ec02fSPetter Reinholdtsen 	}
1557*c18ec02fSPetter Reinholdtsen 
1558*c18ec02fSPetter Reinholdtsen 	if(!badParams){
1559*c18ec02fSPetter Reinholdtsen 
1560*c18ec02fSPetter Reinholdtsen 		if(oh->record_id == OEM_KONTRON_INFORMATION_RECORD ) {
1561*c18ec02fSPetter Reinholdtsen 
1562*c18ec02fSPetter Reinholdtsen 			uint8_t version;
1563*c18ec02fSPetter Reinholdtsen 
1564*c18ec02fSPetter Reinholdtsen 			printf("Kontron OEM Information Record\n");
1565*c18ec02fSPetter Reinholdtsen 			version = oh->record_version;
1566*c18ec02fSPetter Reinholdtsen 
1567*c18ec02fSPetter Reinholdtsen 			int blockstart;
1568*c18ec02fSPetter Reinholdtsen 			uint8_t blockCount;
1569*c18ec02fSPetter Reinholdtsen 			uint8_t blockIndex=0;
1570*c18ec02fSPetter Reinholdtsen 
1571*c18ec02fSPetter Reinholdtsen 			unsigned int matchInstance = 0;
1572*c18ec02fSPetter Reinholdtsen 			uint8_t instance = 0;
1573*c18ec02fSPetter Reinholdtsen 
1574*c18ec02fSPetter Reinholdtsen 			if (str2uchar(argv[OEM_KONTRON_INSTANCE_ARG_POS], &instance) != 0) {
1575*c18ec02fSPetter Reinholdtsen 				lprintf(LOG_ERR,
1576*c18ec02fSPetter Reinholdtsen 						"Instance argument '%s' is either invalid or out of range.",
1577*c18ec02fSPetter Reinholdtsen 						argv[OEM_KONTRON_INSTANCE_ARG_POS]);
1578*c18ec02fSPetter Reinholdtsen 				badParams = TRUE;
1579*c18ec02fSPetter Reinholdtsen 				return;
1580*c18ec02fSPetter Reinholdtsen 			}
1581*c18ec02fSPetter Reinholdtsen 
1582*c18ec02fSPetter Reinholdtsen 			blockCount = fru_data[offset++];
1583*c18ec02fSPetter Reinholdtsen 
1584*c18ec02fSPetter Reinholdtsen 			for(blockIndex=0;blockIndex<blockCount;blockIndex++){
1585*c18ec02fSPetter Reinholdtsen 				void * pRecordData;
1586*c18ec02fSPetter Reinholdtsen 				uint8_t nameLen;
1587*c18ec02fSPetter Reinholdtsen 
1588*c18ec02fSPetter Reinholdtsen 				blockstart = offset;
1589*c18ec02fSPetter Reinholdtsen 				nameLen = ( fru_data[offset++] &= 0x3F );
1590*c18ec02fSPetter Reinholdtsen 				printf("  Name: %*.*s\n",nameLen, nameLen, (const char *)(fru_data+offset));
1591*c18ec02fSPetter Reinholdtsen 
1592*c18ec02fSPetter Reinholdtsen 				offset+=nameLen;
1593*c18ec02fSPetter Reinholdtsen 
1594*c18ec02fSPetter Reinholdtsen 				pRecordData = &fru_data[offset];
1595*c18ec02fSPetter Reinholdtsen 
1596*c18ec02fSPetter Reinholdtsen 				printf("  Record Version: %d\n", version);
1597*c18ec02fSPetter Reinholdtsen 				if( version == 0 )
1598*c18ec02fSPetter Reinholdtsen 				{
1599*c18ec02fSPetter Reinholdtsen 					printf("  Version: %*.*s\n",
1600*c18ec02fSPetter Reinholdtsen 						OEM_KONTRON_FIELD_SIZE,
1601*c18ec02fSPetter Reinholdtsen 						OEM_KONTRON_FIELD_SIZE,
1602*c18ec02fSPetter Reinholdtsen 						((tOemKontronInformationRecordV0 *) pRecordData)->field1);
1603*c18ec02fSPetter Reinholdtsen 					printf("  Build Date: %*.*s\n",
1604*c18ec02fSPetter Reinholdtsen 						OEM_KONTRON_FIELD_SIZE,
1605*c18ec02fSPetter Reinholdtsen 						OEM_KONTRON_FIELD_SIZE,
1606*c18ec02fSPetter Reinholdtsen 						((tOemKontronInformationRecordV0 *) pRecordData)->field2);
1607*c18ec02fSPetter Reinholdtsen 					printf("  Update Date: %*.*s\n",
1608*c18ec02fSPetter Reinholdtsen 						OEM_KONTRON_FIELD_SIZE,
1609*c18ec02fSPetter Reinholdtsen 						OEM_KONTRON_FIELD_SIZE,
1610*c18ec02fSPetter Reinholdtsen 						((tOemKontronInformationRecordV0 *) pRecordData)->field3);
1611*c18ec02fSPetter Reinholdtsen 					printf("  Checksum: %*.*s\n\n",
1612*c18ec02fSPetter Reinholdtsen 						OEM_KONTRON_FIELD_SIZE,
1613*c18ec02fSPetter Reinholdtsen 						OEM_KONTRON_FIELD_SIZE,
1614*c18ec02fSPetter Reinholdtsen 						((tOemKontronInformationRecordV0 *) pRecordData)->crc32);
1615*c18ec02fSPetter Reinholdtsen 					matchInstance++;
1616*c18ec02fSPetter Reinholdtsen 					offset+= sizeof(tOemKontronInformationRecordV0);
1617*c18ec02fSPetter Reinholdtsen 					offset++;
1618*c18ec02fSPetter Reinholdtsen 				}
1619*c18ec02fSPetter Reinholdtsen 				else if ( version == 1 )
1620*c18ec02fSPetter Reinholdtsen 				{
1621*c18ec02fSPetter Reinholdtsen 					printf("  Version: %*.*s\n",
1622*c18ec02fSPetter Reinholdtsen 						OEM_KONTRON_VERSION_FIELD_SIZE,
1623*c18ec02fSPetter Reinholdtsen 						OEM_KONTRON_VERSION_FIELD_SIZE,
1624*c18ec02fSPetter Reinholdtsen 						((tOemKontronInformationRecordV1 *) pRecordData)->field1);
1625*c18ec02fSPetter Reinholdtsen 					printf("  Build Date: %*.*s\n",
1626*c18ec02fSPetter Reinholdtsen 						OEM_KONTRON_FIELD_SIZE,
1627*c18ec02fSPetter Reinholdtsen 						OEM_KONTRON_FIELD_SIZE,
1628*c18ec02fSPetter Reinholdtsen 						((tOemKontronInformationRecordV1 *) pRecordData)->field2);
1629*c18ec02fSPetter Reinholdtsen 					printf("  Update Date: %*.*s\n",
1630*c18ec02fSPetter Reinholdtsen 						OEM_KONTRON_FIELD_SIZE,
1631*c18ec02fSPetter Reinholdtsen 						OEM_KONTRON_FIELD_SIZE,
1632*c18ec02fSPetter Reinholdtsen 						((tOemKontronInformationRecordV1 *) pRecordData)->field3);
1633*c18ec02fSPetter Reinholdtsen 					printf("  Checksum: %*.*s\n\n",
1634*c18ec02fSPetter Reinholdtsen 						OEM_KONTRON_FIELD_SIZE,
1635*c18ec02fSPetter Reinholdtsen 						OEM_KONTRON_FIELD_SIZE,
1636*c18ec02fSPetter Reinholdtsen 						((tOemKontronInformationRecordV1 *) pRecordData)->crc32);
1637*c18ec02fSPetter Reinholdtsen 					matchInstance++;
1638*c18ec02fSPetter Reinholdtsen 					offset+= sizeof(tOemKontronInformationRecordV1);
1639*c18ec02fSPetter Reinholdtsen 					offset++;
1640*c18ec02fSPetter Reinholdtsen 				}
1641*c18ec02fSPetter Reinholdtsen 				else
1642*c18ec02fSPetter Reinholdtsen 				{
1643*c18ec02fSPetter Reinholdtsen 					printf ("  Unsupported version %d\n",version);
1644*c18ec02fSPetter Reinholdtsen 				}
1645*c18ec02fSPetter Reinholdtsen 			}
1646*c18ec02fSPetter Reinholdtsen 		}
1647*c18ec02fSPetter Reinholdtsen 	}
1648*c18ec02fSPetter Reinholdtsen }
1649*c18ec02fSPetter Reinholdtsen 
1650*c18ec02fSPetter Reinholdtsen static int ipmi_fru_oemkontron_edit( int argc, char ** argv,uint8_t * fru_data,
1651*c18ec02fSPetter Reinholdtsen 												int off,int len,
1652*c18ec02fSPetter Reinholdtsen 												struct fru_multirec_header *h,
1653*c18ec02fSPetter Reinholdtsen 												struct fru_multirec_oem_header *oh)
1654*c18ec02fSPetter Reinholdtsen {
1655*c18ec02fSPetter Reinholdtsen 	static int badParams=FALSE;
1656*c18ec02fSPetter Reinholdtsen 	int hasChanged = FALSE;
1657*c18ec02fSPetter Reinholdtsen 	int start = off;
1658*c18ec02fSPetter Reinholdtsen 	int offset = start;
1659*c18ec02fSPetter Reinholdtsen 	int length = len;
1660*c18ec02fSPetter Reinholdtsen 	int i;
1661*c18ec02fSPetter Reinholdtsen 	uint8_t record_id = 0;
1662*c18ec02fSPetter Reinholdtsen 	offset += sizeof(struct fru_multirec_oem_header);
1663*c18ec02fSPetter Reinholdtsen 
1664*c18ec02fSPetter Reinholdtsen 	if(!badParams){
1665*c18ec02fSPetter Reinholdtsen 		/* the 'OEM' field is already checked in caller */
1666*c18ec02fSPetter Reinholdtsen 		if( argc > OEM_KONTRON_SUBCOMMAND_ARG_POS ){
1667*c18ec02fSPetter Reinholdtsen 			if(strncmp("oem", argv[OEM_KONTRON_SUBCOMMAND_ARG_POS],3)){
1668*c18ec02fSPetter Reinholdtsen 				printf("usage: fru edit <id> <oem> <args...>\n");
1669*c18ec02fSPetter Reinholdtsen 				badParams = TRUE;
1670*c18ec02fSPetter Reinholdtsen 				return hasChanged;
1671*c18ec02fSPetter Reinholdtsen 			}
1672*c18ec02fSPetter Reinholdtsen 		}
1673*c18ec02fSPetter Reinholdtsen 		if( argc<EDIT_OEM_KONTRON_COMPLETE_ARG_COUNT ){
1674*c18ec02fSPetter Reinholdtsen 			printf("usage: oem <iana> <recordid> <format> <args...>\n");
1675*c18ec02fSPetter Reinholdtsen 			printf("usage: oem 15000 3 0 <name> <instance> <field1>"\
1676*c18ec02fSPetter Reinholdtsen 					" <field2> <field3> <crc32>\n");
1677*c18ec02fSPetter Reinholdtsen 			badParams = TRUE;
1678*c18ec02fSPetter Reinholdtsen 			return hasChanged;
1679*c18ec02fSPetter Reinholdtsen 		}
1680*c18ec02fSPetter Reinholdtsen 		if (str2uchar(argv[OEM_KONTRON_RECORDID_ARG_POS], &record_id) != 0) {
1681*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR,
1682*c18ec02fSPetter Reinholdtsen 					"Record ID argument '%s' is either invalid or out of range.",
1683*c18ec02fSPetter Reinholdtsen 					argv[OEM_KONTRON_RECORDID_ARG_POS]);
1684*c18ec02fSPetter Reinholdtsen 			badParams = TRUE;
1685*c18ec02fSPetter Reinholdtsen 			return hasChanged;
1686*c18ec02fSPetter Reinholdtsen 		}
1687*c18ec02fSPetter Reinholdtsen 		if (record_id == OEM_KONTRON_INFORMATION_RECORD) {
1688*c18ec02fSPetter Reinholdtsen 			for(i=OEM_KONTRON_VERSION_ARG_POS;i<=OEM_KONTRON_CRC32_ARG_POS;i++){
1689*c18ec02fSPetter Reinholdtsen 				if( (strlen(argv[i]) != OEM_KONTRON_FIELD_SIZE) &&
1690*c18ec02fSPetter Reinholdtsen 					(strlen(argv[i]) != OEM_KONTRON_VERSION_FIELD_SIZE)) {
1691*c18ec02fSPetter Reinholdtsen 					printf("error: version fields must have %d characters\n",
1692*c18ec02fSPetter Reinholdtsen 										OEM_KONTRON_FIELD_SIZE);
1693*c18ec02fSPetter Reinholdtsen 					badParams = TRUE;
1694*c18ec02fSPetter Reinholdtsen 					return hasChanged;
1695*c18ec02fSPetter Reinholdtsen 				}
1696*c18ec02fSPetter Reinholdtsen 			}
1697*c18ec02fSPetter Reinholdtsen 		}
1698*c18ec02fSPetter Reinholdtsen 	}
1699*c18ec02fSPetter Reinholdtsen 
1700*c18ec02fSPetter Reinholdtsen 	if(!badParams){
1701*c18ec02fSPetter Reinholdtsen 
1702*c18ec02fSPetter Reinholdtsen 		if(oh->record_id == OEM_KONTRON_INFORMATION_RECORD ) {
1703*c18ec02fSPetter Reinholdtsen 			uint8_t formatVersion = 0;
1704*c18ec02fSPetter Reinholdtsen 			uint8_t version;
1705*c18ec02fSPetter Reinholdtsen 
1706*c18ec02fSPetter Reinholdtsen 			if (str2uchar(argv[OEM_KONTRON_FORMAT_ARG_POS], &formatVersion) != 0) {
1707*c18ec02fSPetter Reinholdtsen 				lprintf(LOG_ERR,
1708*c18ec02fSPetter Reinholdtsen 						"Format argument '%s' is either invalid or out of range.",
1709*c18ec02fSPetter Reinholdtsen 						argv[OEM_KONTRON_FORMAT_ARG_POS]);
1710*c18ec02fSPetter Reinholdtsen 				badParams = TRUE;
1711*c18ec02fSPetter Reinholdtsen 				return hasChanged;
1712*c18ec02fSPetter Reinholdtsen 			}
1713*c18ec02fSPetter Reinholdtsen 
1714*c18ec02fSPetter Reinholdtsen 			printf("   Kontron OEM Information Record\n");
1715*c18ec02fSPetter Reinholdtsen 			version = oh->record_version;
1716*c18ec02fSPetter Reinholdtsen 
1717*c18ec02fSPetter Reinholdtsen 			if( version == formatVersion  ){
1718*c18ec02fSPetter Reinholdtsen 				int blockstart;
1719*c18ec02fSPetter Reinholdtsen 				uint8_t blockCount;
1720*c18ec02fSPetter Reinholdtsen 				uint8_t blockIndex=0;
1721*c18ec02fSPetter Reinholdtsen 
1722*c18ec02fSPetter Reinholdtsen 				uint8_t matchInstance = 0;
1723*c18ec02fSPetter Reinholdtsen 				uint8_t instance = 0;
1724*c18ec02fSPetter Reinholdtsen 
1725*c18ec02fSPetter Reinholdtsen 				if (str2uchar(argv[OEM_KONTRON_INSTANCE_ARG_POS], &instance) != 0) {
1726*c18ec02fSPetter Reinholdtsen 					lprintf(LOG_ERR,
1727*c18ec02fSPetter Reinholdtsen 							"Instance argument '%s' is either invalid or out of range.",
1728*c18ec02fSPetter Reinholdtsen 							argv[OEM_KONTRON_INSTANCE_ARG_POS]);
1729*c18ec02fSPetter Reinholdtsen 					badParams = TRUE;
1730*c18ec02fSPetter Reinholdtsen 					return hasChanged;
1731*c18ec02fSPetter Reinholdtsen 				}
1732*c18ec02fSPetter Reinholdtsen 
1733*c18ec02fSPetter Reinholdtsen 				blockCount = fru_data[offset++];
1734*c18ec02fSPetter Reinholdtsen 				printf("   blockCount: %d\n",blockCount);
1735*c18ec02fSPetter Reinholdtsen 
1736*c18ec02fSPetter Reinholdtsen 				for(blockIndex=0;blockIndex<blockCount;blockIndex++){
1737*c18ec02fSPetter Reinholdtsen 					void * pRecordData;
1738*c18ec02fSPetter Reinholdtsen 					uint8_t nameLen;
1739*c18ec02fSPetter Reinholdtsen 
1740*c18ec02fSPetter Reinholdtsen 					blockstart = offset;
1741*c18ec02fSPetter Reinholdtsen 
1742*c18ec02fSPetter Reinholdtsen 					nameLen = ( fru_data[offset++] & 0x3F );
1743*c18ec02fSPetter Reinholdtsen 
1744*c18ec02fSPetter Reinholdtsen 					if( version == 0 || version == 1 )
1745*c18ec02fSPetter Reinholdtsen 					{
1746*c18ec02fSPetter Reinholdtsen 						if(!strncmp((char *)argv[OEM_KONTRON_NAME_ARG_POS],
1747*c18ec02fSPetter Reinholdtsen 						(const char *)(fru_data+offset),nameLen)&& (matchInstance == instance)){
1748*c18ec02fSPetter Reinholdtsen 
1749*c18ec02fSPetter Reinholdtsen 							printf ("Found : %s\n",argv[OEM_KONTRON_NAME_ARG_POS]);
1750*c18ec02fSPetter Reinholdtsen 							offset+=nameLen;
1751*c18ec02fSPetter Reinholdtsen 
1752*c18ec02fSPetter Reinholdtsen 							pRecordData =  &fru_data[offset];
1753*c18ec02fSPetter Reinholdtsen 
1754*c18ec02fSPetter Reinholdtsen 							if( version == 0 )
1755*c18ec02fSPetter Reinholdtsen 							{
1756*c18ec02fSPetter Reinholdtsen 								memcpy( ((tOemKontronInformationRecordV0 *)
1757*c18ec02fSPetter Reinholdtsen 															pRecordData)->field1 ,
1758*c18ec02fSPetter Reinholdtsen 								argv[OEM_KONTRON_VERSION_ARG_POS] ,
1759*c18ec02fSPetter Reinholdtsen 								OEM_KONTRON_FIELD_SIZE);
1760*c18ec02fSPetter Reinholdtsen 								memcpy( ((tOemKontronInformationRecordV0 *)
1761*c18ec02fSPetter Reinholdtsen 															pRecordData)->field2 ,
1762*c18ec02fSPetter Reinholdtsen 								argv[OEM_KONTRON_BUILDDATE_ARG_POS],
1763*c18ec02fSPetter Reinholdtsen 								OEM_KONTRON_FIELD_SIZE);
1764*c18ec02fSPetter Reinholdtsen 								memcpy( ((tOemKontronInformationRecordV0 *)
1765*c18ec02fSPetter Reinholdtsen 															pRecordData)->field3 ,
1766*c18ec02fSPetter Reinholdtsen 								argv[OEM_KONTRON_UPDATEDATE_ARG_POS],
1767*c18ec02fSPetter Reinholdtsen 								OEM_KONTRON_FIELD_SIZE);
1768*c18ec02fSPetter Reinholdtsen 								memcpy( ((tOemKontronInformationRecordV0 *)
1769*c18ec02fSPetter Reinholdtsen 															pRecordData)->crc32 ,
1770*c18ec02fSPetter Reinholdtsen 							argv[OEM_KONTRON_CRC32_ARG_POS] ,
1771*c18ec02fSPetter Reinholdtsen 							OEM_KONTRON_FIELD_SIZE);
1772*c18ec02fSPetter Reinholdtsen 							}
1773*c18ec02fSPetter Reinholdtsen 							else
1774*c18ec02fSPetter Reinholdtsen 							{
1775*c18ec02fSPetter Reinholdtsen 								memcpy( ((tOemKontronInformationRecordV1 *)
1776*c18ec02fSPetter Reinholdtsen 															pRecordData)->field1 ,
1777*c18ec02fSPetter Reinholdtsen 								argv[OEM_KONTRON_VERSION_ARG_POS] ,
1778*c18ec02fSPetter Reinholdtsen 								OEM_KONTRON_VERSION_FIELD_SIZE);
1779*c18ec02fSPetter Reinholdtsen 								memcpy( ((tOemKontronInformationRecordV1 *)
1780*c18ec02fSPetter Reinholdtsen 															pRecordData)->field2 ,
1781*c18ec02fSPetter Reinholdtsen 								argv[OEM_KONTRON_BUILDDATE_ARG_POS],
1782*c18ec02fSPetter Reinholdtsen 								OEM_KONTRON_FIELD_SIZE);
1783*c18ec02fSPetter Reinholdtsen 								memcpy( ((tOemKontronInformationRecordV1 *)
1784*c18ec02fSPetter Reinholdtsen 															pRecordData)->field3 ,
1785*c18ec02fSPetter Reinholdtsen 								argv[OEM_KONTRON_UPDATEDATE_ARG_POS],
1786*c18ec02fSPetter Reinholdtsen 								OEM_KONTRON_FIELD_SIZE);
1787*c18ec02fSPetter Reinholdtsen 								memcpy( ((tOemKontronInformationRecordV1 *)
1788*c18ec02fSPetter Reinholdtsen 															pRecordData)->crc32 ,
1789*c18ec02fSPetter Reinholdtsen 							argv[OEM_KONTRON_CRC32_ARG_POS] ,
1790*c18ec02fSPetter Reinholdtsen 							OEM_KONTRON_FIELD_SIZE);
1791*c18ec02fSPetter Reinholdtsen 							}
1792*c18ec02fSPetter Reinholdtsen 
1793*c18ec02fSPetter Reinholdtsen 							matchInstance++;
1794*c18ec02fSPetter Reinholdtsen 							hasChanged = TRUE;
1795*c18ec02fSPetter Reinholdtsen 						}
1796*c18ec02fSPetter Reinholdtsen 						else if(!strncmp((char *)argv[OEM_KONTRON_NAME_ARG_POS],
1797*c18ec02fSPetter Reinholdtsen 							(const char *)(fru_data+offset), nameLen)){
1798*c18ec02fSPetter Reinholdtsen 							printf ("Skipped : %s  [instance %d]\n",argv[OEM_KONTRON_NAME_ARG_POS],
1799*c18ec02fSPetter Reinholdtsen 									(unsigned int)matchInstance);
1800*c18ec02fSPetter Reinholdtsen 							matchInstance++;
1801*c18ec02fSPetter Reinholdtsen 							offset+=nameLen;
1802*c18ec02fSPetter Reinholdtsen 						}
1803*c18ec02fSPetter Reinholdtsen 						else {
1804*c18ec02fSPetter Reinholdtsen 							offset+=nameLen;
1805*c18ec02fSPetter Reinholdtsen 						}
1806*c18ec02fSPetter Reinholdtsen 
1807*c18ec02fSPetter Reinholdtsen 						if( version == 0 )
1808*c18ec02fSPetter Reinholdtsen 						{
1809*c18ec02fSPetter Reinholdtsen 							offset+= sizeof(tOemKontronInformationRecordV0);
1810*c18ec02fSPetter Reinholdtsen 						}
1811*c18ec02fSPetter Reinholdtsen 						else
1812*c18ec02fSPetter Reinholdtsen 						{
1813*c18ec02fSPetter Reinholdtsen 							offset+= sizeof(tOemKontronInformationRecordV1);
1814*c18ec02fSPetter Reinholdtsen 						}
1815*c18ec02fSPetter Reinholdtsen 						offset++;
1816*c18ec02fSPetter Reinholdtsen 					}
1817*c18ec02fSPetter Reinholdtsen 					else
1818*c18ec02fSPetter Reinholdtsen 					{
1819*c18ec02fSPetter Reinholdtsen 						printf ("  Unsupported version %d\n",version);
1820*c18ec02fSPetter Reinholdtsen 					}
1821*c18ec02fSPetter Reinholdtsen 				}
1822*c18ec02fSPetter Reinholdtsen 			}
1823*c18ec02fSPetter Reinholdtsen 			else{
1824*c18ec02fSPetter Reinholdtsen 				printf("   Version: %d\n",version);
1825*c18ec02fSPetter Reinholdtsen 			}
1826*c18ec02fSPetter Reinholdtsen 		}
1827*c18ec02fSPetter Reinholdtsen 		if( hasChanged ){
1828*c18ec02fSPetter Reinholdtsen 
1829*c18ec02fSPetter Reinholdtsen 			uint8_t record_checksum =0;
1830*c18ec02fSPetter Reinholdtsen 			uint8_t header_checksum =0;
1831*c18ec02fSPetter Reinholdtsen 			int index;
1832*c18ec02fSPetter Reinholdtsen 
1833*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG,"Initial record checksum : %x",h->record_checksum);
1834*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG,"Initial header checksum : %x",h->header_checksum);
1835*c18ec02fSPetter Reinholdtsen 			for(index=0;index<length;index++){
1836*c18ec02fSPetter Reinholdtsen 				record_checksum+=  fru_data[start+index];
1837*c18ec02fSPetter Reinholdtsen 			}
1838*c18ec02fSPetter Reinholdtsen 			/* Update Record checksum */
1839*c18ec02fSPetter Reinholdtsen 			h->record_checksum =  ~record_checksum + 1;
1840*c18ec02fSPetter Reinholdtsen 
1841*c18ec02fSPetter Reinholdtsen 
1842*c18ec02fSPetter Reinholdtsen 			for(index=0;index<(sizeof(struct fru_multirec_header) -1);index++){
1843*c18ec02fSPetter Reinholdtsen 				uint8_t data= *( (uint8_t *)h+ index);
1844*c18ec02fSPetter Reinholdtsen 				header_checksum+=data;
1845*c18ec02fSPetter Reinholdtsen 			}
1846*c18ec02fSPetter Reinholdtsen 			/* Update header checksum */
1847*c18ec02fSPetter Reinholdtsen 			h->header_checksum =  ~header_checksum + 1;
1848*c18ec02fSPetter Reinholdtsen 
1849*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG,"Final record checksum : %x",h->record_checksum);
1850*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG,"Final header checksum : %x",h->header_checksum);
1851*c18ec02fSPetter Reinholdtsen 
1852*c18ec02fSPetter Reinholdtsen 			/* write back data */
1853*c18ec02fSPetter Reinholdtsen 		}
1854*c18ec02fSPetter Reinholdtsen 	}
1855*c18ec02fSPetter Reinholdtsen 
1856*c18ec02fSPetter Reinholdtsen 	return hasChanged;
1857*c18ec02fSPetter Reinholdtsen }
1858*c18ec02fSPetter Reinholdtsen 
1859*c18ec02fSPetter Reinholdtsen /* ipmi_fru_picmg_ext_edit  -  Query new values to replace original FRU content
1860*c18ec02fSPetter Reinholdtsen *
1861*c18ec02fSPetter Reinholdtsen * @data:   FRU data
1862*c18ec02fSPetter Reinholdtsen * @offset: start of the current multi record (start of header)
1863*c18ec02fSPetter Reinholdtsen * @len:    len of the current record (excluding header)
1864*c18ec02fSPetter Reinholdtsen * @h:      pointer to record header
1865*c18ec02fSPetter Reinholdtsen * @oh:     pointer to OEM /PICMG header
1866*c18ec02fSPetter Reinholdtsen *
1867*c18ec02fSPetter Reinholdtsen * returns: TRUE if data changed
1868*c18ec02fSPetter Reinholdtsen * returns: FALSE if data not changed
1869*c18ec02fSPetter Reinholdtsen */
1870*c18ec02fSPetter Reinholdtsen static int ipmi_fru_picmg_ext_edit(uint8_t * fru_data,
1871*c18ec02fSPetter Reinholdtsen 												int off,int len,
1872*c18ec02fSPetter Reinholdtsen 												struct fru_multirec_header *h,
1873*c18ec02fSPetter Reinholdtsen 												struct fru_multirec_oem_header *oh)
1874*c18ec02fSPetter Reinholdtsen {
1875*c18ec02fSPetter Reinholdtsen 	int hasChanged = FALSE;
1876*c18ec02fSPetter Reinholdtsen 	int start = off;
1877*c18ec02fSPetter Reinholdtsen 	int offset = start;
1878*c18ec02fSPetter Reinholdtsen 	int length = len;
1879*c18ec02fSPetter Reinholdtsen 	offset += sizeof(struct fru_multirec_oem_header);
1880*c18ec02fSPetter Reinholdtsen 
1881*c18ec02fSPetter Reinholdtsen 	switch (oh->record_id)
1882*c18ec02fSPetter Reinholdtsen 	{
1883*c18ec02fSPetter Reinholdtsen 		case FRU_AMC_ACTIVATION:
1884*c18ec02fSPetter Reinholdtsen 			printf("    FRU_AMC_ACTIVATION\n");
1885*c18ec02fSPetter Reinholdtsen 			{
1886*c18ec02fSPetter Reinholdtsen 				int index=offset;
1887*c18ec02fSPetter Reinholdtsen 				uint16_t max_current;
1888*c18ec02fSPetter Reinholdtsen 
1889*c18ec02fSPetter Reinholdtsen 				max_current = fru_data[offset];
1890*c18ec02fSPetter Reinholdtsen 				max_current |= fru_data[++offset]<<8;
1891*c18ec02fSPetter Reinholdtsen 
1892*c18ec02fSPetter Reinholdtsen 				printf("      Maximum Internal Current(@12V): %.2f A (0x%02x)\n",
1893*c18ec02fSPetter Reinholdtsen 								(float)max_current / 10.0f, max_current);
1894*c18ec02fSPetter Reinholdtsen 
1895*c18ec02fSPetter Reinholdtsen 				if( ipmi_fru_query_new_value(fru_data,index,2) ){
1896*c18ec02fSPetter Reinholdtsen 					max_current = fru_data[index];
1897*c18ec02fSPetter Reinholdtsen 					max_current |= fru_data[++index]<<8;
1898*c18ec02fSPetter Reinholdtsen 					printf("      New Maximum Internal Current(@12V): %.2f A (0x%02x)\n",
1899*c18ec02fSPetter Reinholdtsen 								(float)max_current / 10.0f, max_current);
1900*c18ec02fSPetter Reinholdtsen 					hasChanged = TRUE;
1901*c18ec02fSPetter Reinholdtsen 
1902*c18ec02fSPetter Reinholdtsen 				}
1903*c18ec02fSPetter Reinholdtsen 
1904*c18ec02fSPetter Reinholdtsen 				printf("      Module Activation Readiness:       %i sec.\n", fru_data[++offset]);
1905*c18ec02fSPetter Reinholdtsen 				printf("      Descriptor Count: %i\n", fru_data[++offset]);
1906*c18ec02fSPetter Reinholdtsen 				printf("\n");
1907*c18ec02fSPetter Reinholdtsen 
1908*c18ec02fSPetter Reinholdtsen 				for (++offset;
1909*c18ec02fSPetter Reinholdtsen 					offset < (off + length);
1910*c18ec02fSPetter Reinholdtsen 					offset += sizeof(struct fru_picmgext_activation_record)) {
1911*c18ec02fSPetter Reinholdtsen 					struct fru_picmgext_activation_record * a =
1912*c18ec02fSPetter Reinholdtsen 						(struct fru_picmgext_activation_record *) &fru_data[offset];
1913*c18ec02fSPetter Reinholdtsen 
1914*c18ec02fSPetter Reinholdtsen 					printf("        IPMB-Address:         0x%x\n", a->ibmb_addr);
1915*c18ec02fSPetter Reinholdtsen 					printf("        Max. Module Current:  %.2f A\n", (float)a->max_module_curr / 10.0f);
1916*c18ec02fSPetter Reinholdtsen 
1917*c18ec02fSPetter Reinholdtsen 					printf("\n");
1918*c18ec02fSPetter Reinholdtsen 				}
1919*c18ec02fSPetter Reinholdtsen 			}
1920*c18ec02fSPetter Reinholdtsen 			break;
1921*c18ec02fSPetter Reinholdtsen 
1922*c18ec02fSPetter Reinholdtsen 		case FRU_AMC_CURRENT:
1923*c18ec02fSPetter Reinholdtsen 			printf("    FRU_AMC_CURRENT\n");
1924*c18ec02fSPetter Reinholdtsen 			{
1925*c18ec02fSPetter Reinholdtsen 				int index=offset;
1926*c18ec02fSPetter Reinholdtsen 				unsigned char current;
1927*c18ec02fSPetter Reinholdtsen 
1928*c18ec02fSPetter Reinholdtsen 				current = fru_data[index];
1929*c18ec02fSPetter Reinholdtsen 
1930*c18ec02fSPetter Reinholdtsen 				printf("      Current draw(@12V): %.2f A (0x%02x)\n",
1931*c18ec02fSPetter Reinholdtsen 								(float)current / 10.0f, current);
1932*c18ec02fSPetter Reinholdtsen 
1933*c18ec02fSPetter Reinholdtsen 				if( ipmi_fru_query_new_value(fru_data, index, 1) ){
1934*c18ec02fSPetter Reinholdtsen 					current = fru_data[index];
1935*c18ec02fSPetter Reinholdtsen 
1936*c18ec02fSPetter Reinholdtsen 					printf("      New Current draw(@12V): %.2f A (0x%02x)\n",
1937*c18ec02fSPetter Reinholdtsen 								(float)current / 10.0f, current);
1938*c18ec02fSPetter Reinholdtsen 					hasChanged = TRUE;
1939*c18ec02fSPetter Reinholdtsen 				}
1940*c18ec02fSPetter Reinholdtsen 			}
1941*c18ec02fSPetter Reinholdtsen 			break;
1942*c18ec02fSPetter Reinholdtsen 	}
1943*c18ec02fSPetter Reinholdtsen 
1944*c18ec02fSPetter Reinholdtsen 	if( hasChanged ){
1945*c18ec02fSPetter Reinholdtsen 
1946*c18ec02fSPetter Reinholdtsen 		uint8_t record_checksum =0;
1947*c18ec02fSPetter Reinholdtsen 		uint8_t header_checksum =0;
1948*c18ec02fSPetter Reinholdtsen 		int index;
1949*c18ec02fSPetter Reinholdtsen 
1950*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_DEBUG,"Initial record checksum : %x",h->record_checksum);
1951*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_DEBUG,"Initial header checksum : %x",h->header_checksum);
1952*c18ec02fSPetter Reinholdtsen 		for(index=0;index<length;index++){
1953*c18ec02fSPetter Reinholdtsen 			record_checksum+=  fru_data[start+index];
1954*c18ec02fSPetter Reinholdtsen 		}
1955*c18ec02fSPetter Reinholdtsen 		/* Update Record checksum */
1956*c18ec02fSPetter Reinholdtsen 		h->record_checksum =  ~record_checksum + 1;
1957*c18ec02fSPetter Reinholdtsen 
1958*c18ec02fSPetter Reinholdtsen 
1959*c18ec02fSPetter Reinholdtsen 		for(index=0;index<(sizeof(struct fru_multirec_header) -1);index++){
1960*c18ec02fSPetter Reinholdtsen 			uint8_t data= *( (uint8_t *)h+ index);
1961*c18ec02fSPetter Reinholdtsen 			header_checksum+=data;
1962*c18ec02fSPetter Reinholdtsen 		}
1963*c18ec02fSPetter Reinholdtsen 		/* Update header checksum */
1964*c18ec02fSPetter Reinholdtsen 		h->header_checksum =  ~header_checksum + 1;
1965*c18ec02fSPetter Reinholdtsen 
1966*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_DEBUG,"Final record checksum : %x",h->record_checksum);
1967*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_DEBUG,"Final header checksum : %x",h->header_checksum);
1968*c18ec02fSPetter Reinholdtsen 
1969*c18ec02fSPetter Reinholdtsen 		/* write back data */
1970*c18ec02fSPetter Reinholdtsen 	}
1971*c18ec02fSPetter Reinholdtsen 
1972*c18ec02fSPetter Reinholdtsen 	return hasChanged;
1973*c18ec02fSPetter Reinholdtsen }
1974*c18ec02fSPetter Reinholdtsen 
1975*c18ec02fSPetter Reinholdtsen /* ipmi_fru_picmg_ext_print  - prints OEM fru record (PICMG)
1976*c18ec02fSPetter Reinholdtsen *
1977*c18ec02fSPetter Reinholdtsen * @fru_data:  FRU data
1978*c18ec02fSPetter Reinholdtsen * @offset:    offset of the bytes to be modified in data
1979*c18ec02fSPetter Reinholdtsen * @length:    size of the record
1980*c18ec02fSPetter Reinholdtsen *
1981*c18ec02fSPetter Reinholdtsen * returns : n/a
1982*c18ec02fSPetter Reinholdtsen */
1983*c18ec02fSPetter Reinholdtsen static void ipmi_fru_picmg_ext_print(uint8_t * fru_data, int off, int length)
1984*c18ec02fSPetter Reinholdtsen {
1985*c18ec02fSPetter Reinholdtsen 	struct fru_multirec_oem_header *h;
1986*c18ec02fSPetter Reinholdtsen 	int guid_count;
1987*c18ec02fSPetter Reinholdtsen 	int offset = off;
1988*c18ec02fSPetter Reinholdtsen 	int start_offset = off;
1989*c18ec02fSPetter Reinholdtsen 	int i;
1990*c18ec02fSPetter Reinholdtsen 
1991*c18ec02fSPetter Reinholdtsen 	h = (struct fru_multirec_oem_header *) &fru_data[offset];
1992*c18ec02fSPetter Reinholdtsen 	offset += sizeof(struct fru_multirec_oem_header);
1993*c18ec02fSPetter Reinholdtsen 
1994*c18ec02fSPetter Reinholdtsen 	switch (h->record_id)
1995*c18ec02fSPetter Reinholdtsen 	{
1996*c18ec02fSPetter Reinholdtsen 		case FRU_PICMG_BACKPLANE_P2P:
1997*c18ec02fSPetter Reinholdtsen 		{
1998*c18ec02fSPetter Reinholdtsen 			uint8_t index;
1999*c18ec02fSPetter Reinholdtsen 			unsigned int data;
2000*c18ec02fSPetter Reinholdtsen 			struct fru_picmgext_slot_desc *slot_d;
2001*c18ec02fSPetter Reinholdtsen 
2002*c18ec02fSPetter Reinholdtsen 			slot_d =
2003*c18ec02fSPetter Reinholdtsen 				(struct fru_picmgext_slot_desc*)&fru_data[offset];
2004*c18ec02fSPetter Reinholdtsen 			offset += sizeof(struct fru_picmgext_slot_desc);
2005*c18ec02fSPetter Reinholdtsen 			printf("    FRU_PICMG_BACKPLANE_P2P\n");
2006*c18ec02fSPetter Reinholdtsen 
2007*c18ec02fSPetter Reinholdtsen 			while (offset <= (start_offset+length)) {
2008*c18ec02fSPetter Reinholdtsen 				printf("\n");
2009*c18ec02fSPetter Reinholdtsen 				printf("    Channel Type:  ");
2010*c18ec02fSPetter Reinholdtsen 				switch (slot_d->chan_type)
2011*c18ec02fSPetter Reinholdtsen 				{
2012*c18ec02fSPetter Reinholdtsen 					case 0x00:
2013*c18ec02fSPetter Reinholdtsen 					case 0x07:
2014*c18ec02fSPetter Reinholdtsen 						printf("PICMG 2.9\n");
2015*c18ec02fSPetter Reinholdtsen 						break;
2016*c18ec02fSPetter Reinholdtsen 					case 0x08:
2017*c18ec02fSPetter Reinholdtsen 						printf("Single Port Fabric IF\n");
2018*c18ec02fSPetter Reinholdtsen 						break;
2019*c18ec02fSPetter Reinholdtsen 					case 0x09:
2020*c18ec02fSPetter Reinholdtsen 						printf("Double Port Fabric IF\n");
2021*c18ec02fSPetter Reinholdtsen 						break;
2022*c18ec02fSPetter Reinholdtsen 					case 0x0a:
2023*c18ec02fSPetter Reinholdtsen 						printf("Full Channel Fabric IF\n");
2024*c18ec02fSPetter Reinholdtsen 						break;
2025*c18ec02fSPetter Reinholdtsen 					case 0x0b:
2026*c18ec02fSPetter Reinholdtsen 						printf("Base IF\n");
2027*c18ec02fSPetter Reinholdtsen 						break;
2028*c18ec02fSPetter Reinholdtsen 					case 0x0c:
2029*c18ec02fSPetter Reinholdtsen 						printf("Update Channel IF\n");
2030*c18ec02fSPetter Reinholdtsen 						break;
2031*c18ec02fSPetter Reinholdtsen 					case 0x0d:
2032*c18ec02fSPetter Reinholdtsen 						printf("ShMC Cross Connect\n");
2033*c18ec02fSPetter Reinholdtsen 						break;
2034*c18ec02fSPetter Reinholdtsen 					default:
2035*c18ec02fSPetter Reinholdtsen 						printf("Unknown IF (0x%x)\n",
2036*c18ec02fSPetter Reinholdtsen 								slot_d->chan_type);
2037*c18ec02fSPetter Reinholdtsen 						break;
2038*c18ec02fSPetter Reinholdtsen 				}
2039*c18ec02fSPetter Reinholdtsen 				printf("    Slot Addr.   : %02x\n",
2040*c18ec02fSPetter Reinholdtsen 						slot_d->slot_addr );
2041*c18ec02fSPetter Reinholdtsen 				printf("    Channel Count: %i\n",
2042*c18ec02fSPetter Reinholdtsen 						slot_d->chn_count);
2043*c18ec02fSPetter Reinholdtsen 
2044*c18ec02fSPetter Reinholdtsen 				for (index = 0;
2045*c18ec02fSPetter Reinholdtsen 						index < (slot_d->chn_count);
2046*c18ec02fSPetter Reinholdtsen 						index++) {
2047*c18ec02fSPetter Reinholdtsen 					struct fru_picmgext_chn_desc *d;
2048*c18ec02fSPetter Reinholdtsen 					data = (fru_data[offset+0]) |
2049*c18ec02fSPetter Reinholdtsen 						(fru_data[offset+1] << 8) |
2050*c18ec02fSPetter Reinholdtsen 						(fru_data[offset+2] << 16);
2051*c18ec02fSPetter Reinholdtsen 					d = (struct fru_picmgext_chn_desc *)&data;
2052*c18ec02fSPetter Reinholdtsen 					if (verbose) {
2053*c18ec02fSPetter Reinholdtsen 						printf( "       "
2054*c18ec02fSPetter Reinholdtsen 								"Chn: %02x  ->  "
2055*c18ec02fSPetter Reinholdtsen 								"Chn: %02x in "
2056*c18ec02fSPetter Reinholdtsen 								"Slot: %02x\n",
2057*c18ec02fSPetter Reinholdtsen 								d->local_chn,
2058*c18ec02fSPetter Reinholdtsen 								d->remote_chn,
2059*c18ec02fSPetter Reinholdtsen 								d->remote_slot);
2060*c18ec02fSPetter Reinholdtsen 					}
2061*c18ec02fSPetter Reinholdtsen 					offset += FRU_PICMGEXT_CHN_DESC_RECORD_SIZE;
2062*c18ec02fSPetter Reinholdtsen 				}
2063*c18ec02fSPetter Reinholdtsen 				slot_d = (struct fru_picmgext_slot_desc*)&fru_data[offset];
2064*c18ec02fSPetter Reinholdtsen 				offset += sizeof(struct fru_picmgext_slot_desc);
2065*c18ec02fSPetter Reinholdtsen 			}
2066*c18ec02fSPetter Reinholdtsen 		}
2067*c18ec02fSPetter Reinholdtsen 		break;
2068*c18ec02fSPetter Reinholdtsen 
2069*c18ec02fSPetter Reinholdtsen 		case FRU_PICMG_ADDRESS_TABLE:
2070*c18ec02fSPetter Reinholdtsen 		{
2071*c18ec02fSPetter Reinholdtsen 			unsigned int hwaddr;
2072*c18ec02fSPetter Reinholdtsen 			unsigned int sitetype;
2073*c18ec02fSPetter Reinholdtsen 			unsigned int sitenum;
2074*c18ec02fSPetter Reinholdtsen 			unsigned int entries;
2075*c18ec02fSPetter Reinholdtsen 			unsigned int i;
2076*c18ec02fSPetter Reinholdtsen 			char *picmg_site_type_strings[] = {
2077*c18ec02fSPetter Reinholdtsen 					"AdvancedTCA Board",
2078*c18ec02fSPetter Reinholdtsen 					"Power Entry",
2079*c18ec02fSPetter Reinholdtsen 					"Shelf FRU Information",
2080*c18ec02fSPetter Reinholdtsen 					"Dedicated ShMC",
2081*c18ec02fSPetter Reinholdtsen 					"Fan Tray",
2082*c18ec02fSPetter Reinholdtsen 					"Fan Filter Tray",
2083*c18ec02fSPetter Reinholdtsen 					"Alarm",
2084*c18ec02fSPetter Reinholdtsen 					"AdvancedMC Module",
2085*c18ec02fSPetter Reinholdtsen 					"PMC",
2086*c18ec02fSPetter Reinholdtsen 					"Rear Transition Module"};
2087*c18ec02fSPetter Reinholdtsen 
2088*c18ec02fSPetter Reinholdtsen 
2089*c18ec02fSPetter Reinholdtsen 			printf("    FRU_PICMG_ADDRESS_TABLE\n");
2090*c18ec02fSPetter Reinholdtsen 			printf("      Type/Len:  0x%02x\n", fru_data[offset++]);
2091*c18ec02fSPetter Reinholdtsen 			printf("      Shelf Addr: ");
2092*c18ec02fSPetter Reinholdtsen 			for (i=0;i<20;i++) {
2093*c18ec02fSPetter Reinholdtsen 				printf("0x%02x ", fru_data[offset++]);
2094*c18ec02fSPetter Reinholdtsen 			}
2095*c18ec02fSPetter Reinholdtsen 			printf("\n");
2096*c18ec02fSPetter Reinholdtsen 
2097*c18ec02fSPetter Reinholdtsen 			entries = fru_data[offset++];
2098*c18ec02fSPetter Reinholdtsen 			printf("      Addr Table Entries: 0x%02x\n", entries);
2099*c18ec02fSPetter Reinholdtsen 
2100*c18ec02fSPetter Reinholdtsen 			for (i=0; i<entries; i++) {
2101*c18ec02fSPetter Reinholdtsen 				hwaddr = fru_data[offset];
2102*c18ec02fSPetter Reinholdtsen 				sitenum = fru_data[offset + 1];
2103*c18ec02fSPetter Reinholdtsen 				sitetype = fru_data[offset + 2];
2104*c18ec02fSPetter Reinholdtsen 				printf(
2105*c18ec02fSPetter Reinholdtsen 						"        HWAddr: 0x%02x (0x%02x) SiteNum: %d SiteType: 0x%02x %s\n",
2106*c18ec02fSPetter Reinholdtsen 						hwaddr, hwaddr * 2,
2107*c18ec02fSPetter Reinholdtsen 						sitenum, sitetype,
2108*c18ec02fSPetter Reinholdtsen 						(sitetype < 0xa) ?
2109*c18ec02fSPetter Reinholdtsen 						picmg_site_type_strings[sitetype] :
2110*c18ec02fSPetter Reinholdtsen 						"Reserved");
2111*c18ec02fSPetter Reinholdtsen 				offset += 3;
2112*c18ec02fSPetter Reinholdtsen 			}
2113*c18ec02fSPetter Reinholdtsen 		}
2114*c18ec02fSPetter Reinholdtsen 		break;
2115*c18ec02fSPetter Reinholdtsen 
2116*c18ec02fSPetter Reinholdtsen 		case FRU_PICMG_SHELF_POWER_DIST:
2117*c18ec02fSPetter Reinholdtsen 		{
2118*c18ec02fSPetter Reinholdtsen 			unsigned int entries;
2119*c18ec02fSPetter Reinholdtsen 			unsigned int feeds;
2120*c18ec02fSPetter Reinholdtsen 			unsigned int feedcnt;
2121*c18ec02fSPetter Reinholdtsen 			unsigned int hwaddr;
2122*c18ec02fSPetter Reinholdtsen 			unsigned int i;
2123*c18ec02fSPetter Reinholdtsen 			unsigned int id;
2124*c18ec02fSPetter Reinholdtsen 			unsigned int j;
2125*c18ec02fSPetter Reinholdtsen 			unsigned int maxext;
2126*c18ec02fSPetter Reinholdtsen 			unsigned int maxint;
2127*c18ec02fSPetter Reinholdtsen 			unsigned int minexp;
2128*c18ec02fSPetter Reinholdtsen 
2129*c18ec02fSPetter Reinholdtsen 			printf("    FRU_PICMG_SHELF_POWER_DIST\n");
2130*c18ec02fSPetter Reinholdtsen 
2131*c18ec02fSPetter Reinholdtsen 			feeds = fru_data[offset++];
2132*c18ec02fSPetter Reinholdtsen 			printf("      Number of Power Feeds:   0x%02x\n",
2133*c18ec02fSPetter Reinholdtsen 					feeds);
2134*c18ec02fSPetter Reinholdtsen 
2135*c18ec02fSPetter Reinholdtsen 			for (i=0; i<feeds; i++) {
2136*c18ec02fSPetter Reinholdtsen 				printf("    Feed %d:\n", i);
2137*c18ec02fSPetter Reinholdtsen 				maxext = fru_data[offset] |
2138*c18ec02fSPetter Reinholdtsen 					(fru_data[offset+1] << 8);
2139*c18ec02fSPetter Reinholdtsen 				offset += 2;
2140*c18ec02fSPetter Reinholdtsen 				maxint = fru_data[offset] |
2141*c18ec02fSPetter Reinholdtsen 					(fru_data[offset+1] << 8);
2142*c18ec02fSPetter Reinholdtsen 				offset += 2;
2143*c18ec02fSPetter Reinholdtsen 				minexp = fru_data[offset];
2144*c18ec02fSPetter Reinholdtsen 				offset += 1;
2145*c18ec02fSPetter Reinholdtsen 				entries = fru_data[offset];
2146*c18ec02fSPetter Reinholdtsen 				offset += 1;
2147*c18ec02fSPetter Reinholdtsen 
2148*c18ec02fSPetter Reinholdtsen 				printf(
2149*c18ec02fSPetter Reinholdtsen 						"      Max External Current:   %d.%d Amps (0x%04x)\n",
2150*c18ec02fSPetter Reinholdtsen 						maxext / 10, maxext % 10, maxext);
2151*c18ec02fSPetter Reinholdtsen 				if (maxint < 0xffff) {
2152*c18ec02fSPetter Reinholdtsen 					printf(
2153*c18ec02fSPetter Reinholdtsen 							"      Max Internal Current:   %d.%d Amps (0x%04x)\n",
2154*c18ec02fSPetter Reinholdtsen 							maxint / 10, maxint % 10,
2155*c18ec02fSPetter Reinholdtsen 							maxint);
2156*c18ec02fSPetter Reinholdtsen 				} else {
2157*c18ec02fSPetter Reinholdtsen 					printf(
2158*c18ec02fSPetter Reinholdtsen 							"      Max Internal Current:   Not Specified\n");
2159*c18ec02fSPetter Reinholdtsen 				}
2160*c18ec02fSPetter Reinholdtsen 
2161*c18ec02fSPetter Reinholdtsen 				if (minexp >= 0x48 && minexp <= 0x90) {
2162*c18ec02fSPetter Reinholdtsen 					printf(
2163*c18ec02fSPetter Reinholdtsen 							"      Min Expected Voltage:   -%02d.%dV\n",
2164*c18ec02fSPetter Reinholdtsen 							minexp / 2, (minexp % 2) * 5);
2165*c18ec02fSPetter Reinholdtsen 				} else {
2166*c18ec02fSPetter Reinholdtsen 					printf(
2167*c18ec02fSPetter Reinholdtsen 							"      Min Expected Voltage:   -%dV (actual invalid value 0x%x)\n",
2168*c18ec02fSPetter Reinholdtsen 							36, minexp);
2169*c18ec02fSPetter Reinholdtsen 				}
2170*c18ec02fSPetter Reinholdtsen 				for (j=0; j < entries; j++) {
2171*c18ec02fSPetter Reinholdtsen 					hwaddr = fru_data[offset++];
2172*c18ec02fSPetter Reinholdtsen 					id = fru_data[offset++];
2173*c18ec02fSPetter Reinholdtsen 					printf(
2174*c18ec02fSPetter Reinholdtsen 							"        FRU HW Addr: 0x%02x (0x%02x)",
2175*c18ec02fSPetter Reinholdtsen 							hwaddr, hwaddr * 2);
2176*c18ec02fSPetter Reinholdtsen 					printf(
2177*c18ec02fSPetter Reinholdtsen 							"   FRU ID: 0x%02x\n",
2178*c18ec02fSPetter Reinholdtsen 							id);
2179*c18ec02fSPetter Reinholdtsen 				}
2180*c18ec02fSPetter Reinholdtsen 			}
2181*c18ec02fSPetter Reinholdtsen 		}
2182*c18ec02fSPetter Reinholdtsen 		break;
2183*c18ec02fSPetter Reinholdtsen 
2184*c18ec02fSPetter Reinholdtsen 		case FRU_PICMG_SHELF_ACTIVATION:
2185*c18ec02fSPetter Reinholdtsen 		{
2186*c18ec02fSPetter Reinholdtsen 			unsigned int i;
2187*c18ec02fSPetter Reinholdtsen 			unsigned int count = 0;
2188*c18ec02fSPetter Reinholdtsen 
2189*c18ec02fSPetter Reinholdtsen 			printf("    FRU_PICMG_SHELF_ACTIVATION\n");
2190*c18ec02fSPetter Reinholdtsen 			printf(
2191*c18ec02fSPetter Reinholdtsen 					"      Allowance for FRU Act Readiness:   0x%02x\n",
2192*c18ec02fSPetter Reinholdtsen 					fru_data[offset++]);
2193*c18ec02fSPetter Reinholdtsen 
2194*c18ec02fSPetter Reinholdtsen 			count = fru_data[offset++];
2195*c18ec02fSPetter Reinholdtsen 			printf(
2196*c18ec02fSPetter Reinholdtsen 					"      FRU activation and Power Desc Cnt: 0x%02x\n",
2197*c18ec02fSPetter Reinholdtsen 					count);
2198*c18ec02fSPetter Reinholdtsen 
2199*c18ec02fSPetter Reinholdtsen 			for (i=0; i<count; i++) {
2200*c18ec02fSPetter Reinholdtsen 				printf("         HW Addr: 0x%02x ",
2201*c18ec02fSPetter Reinholdtsen 						fru_data[offset++]);
2202*c18ec02fSPetter Reinholdtsen 				printf("         FRU ID: 0x%02x ",
2203*c18ec02fSPetter Reinholdtsen 						fru_data[offset++]);
2204*c18ec02fSPetter Reinholdtsen 				printf("         Max FRU Power: 0x%04x ",
2205*c18ec02fSPetter Reinholdtsen 						fru_data[offset+0] |
2206*c18ec02fSPetter Reinholdtsen 						(fru_data[offset+1]<<8));
2207*c18ec02fSPetter Reinholdtsen 				offset += 2;
2208*c18ec02fSPetter Reinholdtsen 				printf("         Config: 0x%02x \n",
2209*c18ec02fSPetter Reinholdtsen 						fru_data[offset++]);
2210*c18ec02fSPetter Reinholdtsen 			}
2211*c18ec02fSPetter Reinholdtsen 		}
2212*c18ec02fSPetter Reinholdtsen 		break;
2213*c18ec02fSPetter Reinholdtsen 
2214*c18ec02fSPetter Reinholdtsen 		case FRU_PICMG_SHMC_IP_CONN:
2215*c18ec02fSPetter Reinholdtsen 			printf("    FRU_PICMG_SHMC_IP_CONN\n");
2216*c18ec02fSPetter Reinholdtsen 			break;
2217*c18ec02fSPetter Reinholdtsen 
2218*c18ec02fSPetter Reinholdtsen 		case FRU_PICMG_BOARD_P2P:
2219*c18ec02fSPetter Reinholdtsen 			printf("    FRU_PICMG_BOARD_P2P\n");
2220*c18ec02fSPetter Reinholdtsen 
2221*c18ec02fSPetter Reinholdtsen 			guid_count = fru_data[offset++];
2222*c18ec02fSPetter Reinholdtsen 			printf("      GUID count: %2d\n", guid_count);
2223*c18ec02fSPetter Reinholdtsen 			for (i = 0 ; i < guid_count; i++ ) {
2224*c18ec02fSPetter Reinholdtsen 				int j;
2225*c18ec02fSPetter Reinholdtsen 				printf("        GUID [%2d]: 0x", i);
2226*c18ec02fSPetter Reinholdtsen 
2227*c18ec02fSPetter Reinholdtsen 				for (j=0; j < sizeof(struct fru_picmgext_guid);
2228*c18ec02fSPetter Reinholdtsen 						j++) {
2229*c18ec02fSPetter Reinholdtsen 					printf("%02x", fru_data[offset+j]);
2230*c18ec02fSPetter Reinholdtsen 				}
2231*c18ec02fSPetter Reinholdtsen 
2232*c18ec02fSPetter Reinholdtsen 				printf("\n");
2233*c18ec02fSPetter Reinholdtsen 				offset += sizeof(struct fru_picmgext_guid);
2234*c18ec02fSPetter Reinholdtsen 			}
2235*c18ec02fSPetter Reinholdtsen 			printf("\n");
2236*c18ec02fSPetter Reinholdtsen 
2237*c18ec02fSPetter Reinholdtsen 			for (; offset < off + length;
2238*c18ec02fSPetter Reinholdtsen 					offset += sizeof(struct fru_picmgext_link_desc)) {
2239*c18ec02fSPetter Reinholdtsen 
2240*c18ec02fSPetter Reinholdtsen 				/* to solve little endian /big endian problem */
2241*c18ec02fSPetter Reinholdtsen 				struct fru_picmgext_link_desc *d;
2242*c18ec02fSPetter Reinholdtsen 				unsigned int data = (fru_data[offset+0]) |
2243*c18ec02fSPetter Reinholdtsen 					(fru_data[offset+1] << 8) |
2244*c18ec02fSPetter Reinholdtsen 					(fru_data[offset+2] << 16) |
2245*c18ec02fSPetter Reinholdtsen 					(fru_data[offset+3] << 24);
2246*c18ec02fSPetter Reinholdtsen 				d = (struct fru_picmgext_link_desc *) &data;
2247*c18ec02fSPetter Reinholdtsen 
2248*c18ec02fSPetter Reinholdtsen 				printf("      Link Grouping ID:     0x%02x\n",
2249*c18ec02fSPetter Reinholdtsen 						d->grouping);
2250*c18ec02fSPetter Reinholdtsen 				printf("      Link Type Extension:  0x%02x - ",
2251*c18ec02fSPetter Reinholdtsen 						d->ext);
2252*c18ec02fSPetter Reinholdtsen 				if (d->type == FRU_PICMGEXT_LINK_TYPE_BASE) {
2253*c18ec02fSPetter Reinholdtsen 					switch (d->ext)
2254*c18ec02fSPetter Reinholdtsen 					{
2255*c18ec02fSPetter Reinholdtsen 						case 0:
2256*c18ec02fSPetter Reinholdtsen 							printf("10/100/1000BASE-T Link (four-pair)\n");
2257*c18ec02fSPetter Reinholdtsen 							break;
2258*c18ec02fSPetter Reinholdtsen 						case 1:
2259*c18ec02fSPetter Reinholdtsen 							printf("ShMC Cross-connect (two-pair)\n");
2260*c18ec02fSPetter Reinholdtsen 							break;
2261*c18ec02fSPetter Reinholdtsen 						default:
2262*c18ec02fSPetter Reinholdtsen 							printf("Unknwon\n");
2263*c18ec02fSPetter Reinholdtsen 							break;
2264*c18ec02fSPetter Reinholdtsen 					}
2265*c18ec02fSPetter Reinholdtsen 				} else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET) {
2266*c18ec02fSPetter Reinholdtsen 					switch (d->ext)
2267*c18ec02fSPetter Reinholdtsen 					{
2268*c18ec02fSPetter Reinholdtsen 						case 0:
2269*c18ec02fSPetter Reinholdtsen 							printf("Fixed 1000Base-BX\n");
2270*c18ec02fSPetter Reinholdtsen 							break;
2271*c18ec02fSPetter Reinholdtsen 						case 1:
2272*c18ec02fSPetter Reinholdtsen 							printf("Fixed 10GBASE-BX4 [XAUI]\n");
2273*c18ec02fSPetter Reinholdtsen 							break;
2274*c18ec02fSPetter Reinholdtsen 						case 2:
2275*c18ec02fSPetter Reinholdtsen 							printf("FC-PI\n");
2276*c18ec02fSPetter Reinholdtsen 							break;
2277*c18ec02fSPetter Reinholdtsen 						default:
2278*c18ec02fSPetter Reinholdtsen 							printf("Unknwon\n");
2279*c18ec02fSPetter Reinholdtsen 							break;
2280*c18ec02fSPetter Reinholdtsen 					}
2281*c18ec02fSPetter Reinholdtsen 				} else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND) {
2282*c18ec02fSPetter Reinholdtsen 					printf("Unknwon\n");
2283*c18ec02fSPetter Reinholdtsen 				} else if (d->type == FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR) {
2284*c18ec02fSPetter Reinholdtsen 					printf("Unknwon\n");
2285*c18ec02fSPetter Reinholdtsen 				} else if (d->type == FRU_PICMGEXT_LINK_TYPE_PCIE) {
2286*c18ec02fSPetter Reinholdtsen 					printf("Unknwon\n");
2287*c18ec02fSPetter Reinholdtsen 				} else {
2288*c18ec02fSPetter Reinholdtsen 					printf("Unknwon\n");
2289*c18ec02fSPetter Reinholdtsen 				}
2290*c18ec02fSPetter Reinholdtsen 
2291*c18ec02fSPetter Reinholdtsen 				printf("      Link Type:            0x%02x - ",
2292*c18ec02fSPetter Reinholdtsen 						d->type);
2293*c18ec02fSPetter Reinholdtsen 				if (d->type == 0 || d->type == 0xff) {
2294*c18ec02fSPetter Reinholdtsen 					printf("Reserved\n");
2295*c18ec02fSPetter Reinholdtsen 				}
2296*c18ec02fSPetter Reinholdtsen 				else if (d->type >= 0x06 && d->type <= 0xef) {
2297*c18ec02fSPetter Reinholdtsen 					printf("Reserved\n");
2298*c18ec02fSPetter Reinholdtsen 				}
2299*c18ec02fSPetter Reinholdtsen 				else if (d->type >= 0xf0 && d->type <= 0xfe) {
2300*c18ec02fSPetter Reinholdtsen 					printf("OEM GUID Definition\n");
2301*c18ec02fSPetter Reinholdtsen 				}
2302*c18ec02fSPetter Reinholdtsen 				else {
2303*c18ec02fSPetter Reinholdtsen 					switch (d->type)
2304*c18ec02fSPetter Reinholdtsen 					{
2305*c18ec02fSPetter Reinholdtsen 						case FRU_PICMGEXT_LINK_TYPE_BASE:
2306*c18ec02fSPetter Reinholdtsen 							printf("PICMG 3.0 Base Interface 10/100/1000\n");
2307*c18ec02fSPetter Reinholdtsen 							break;
2308*c18ec02fSPetter Reinholdtsen 						case FRU_PICMGEXT_LINK_TYPE_FABRIC_ETHERNET:
2309*c18ec02fSPetter Reinholdtsen 							printf("PICMG 3.1 Ethernet Fabric Interface\n");
2310*c18ec02fSPetter Reinholdtsen 							break;
2311*c18ec02fSPetter Reinholdtsen 						case FRU_PICMGEXT_LINK_TYPE_FABRIC_INFINIBAND:
2312*c18ec02fSPetter Reinholdtsen 							printf("PICMG 3.2 Infiniband Fabric Interface\n");
2313*c18ec02fSPetter Reinholdtsen 							break;
2314*c18ec02fSPetter Reinholdtsen 						case FRU_PICMGEXT_LINK_TYPE_FABRIC_STAR:
2315*c18ec02fSPetter Reinholdtsen 							printf("PICMG 3.3 Star Fabric Interface\n");
2316*c18ec02fSPetter Reinholdtsen 							break;
2317*c18ec02fSPetter Reinholdtsen 						case  FRU_PICMGEXT_LINK_TYPE_PCIE:
2318*c18ec02fSPetter Reinholdtsen 							printf("PICMG 3.4 PCI Express Fabric Interface\n");
2319*c18ec02fSPetter Reinholdtsen 							break;
2320*c18ec02fSPetter Reinholdtsen 						default:
2321*c18ec02fSPetter Reinholdtsen 							printf("Invalid\n");
2322*c18ec02fSPetter Reinholdtsen 							break;
2323*c18ec02fSPetter Reinholdtsen 					}
2324*c18ec02fSPetter Reinholdtsen 				}
2325*c18ec02fSPetter Reinholdtsen 				printf("      Link Designator: \n");
2326*c18ec02fSPetter Reinholdtsen 				printf("        Port Flag:            0x%02x\n",
2327*c18ec02fSPetter Reinholdtsen 						d->desig_port);
2328*c18ec02fSPetter Reinholdtsen 				printf("        Interface:            0x%02x - ",
2329*c18ec02fSPetter Reinholdtsen 						d->desig_if);
2330*c18ec02fSPetter Reinholdtsen 				switch (d->desig_if)
2331*c18ec02fSPetter Reinholdtsen 				{
2332*c18ec02fSPetter Reinholdtsen 					case FRU_PICMGEXT_DESIGN_IF_BASE:
2333*c18ec02fSPetter Reinholdtsen 						printf("Base Interface\n");
2334*c18ec02fSPetter Reinholdtsen 						break;
2335*c18ec02fSPetter Reinholdtsen 					case FRU_PICMGEXT_DESIGN_IF_FABRIC:
2336*c18ec02fSPetter Reinholdtsen 						printf("Fabric Interface\n");
2337*c18ec02fSPetter Reinholdtsen 						break;
2338*c18ec02fSPetter Reinholdtsen 					case FRU_PICMGEXT_DESIGN_IF_UPDATE_CHANNEL:
2339*c18ec02fSPetter Reinholdtsen 						printf("Update Channel\n");
2340*c18ec02fSPetter Reinholdtsen 						break;
2341*c18ec02fSPetter Reinholdtsen 					case FRU_PICMGEXT_DESIGN_IF_RESERVED:
2342*c18ec02fSPetter Reinholdtsen 						printf("Reserved\n");
2343*c18ec02fSPetter Reinholdtsen 						break;
2344*c18ec02fSPetter Reinholdtsen 					default:
2345*c18ec02fSPetter Reinholdtsen 						printf("Invalid");
2346*c18ec02fSPetter Reinholdtsen 						break;
2347*c18ec02fSPetter Reinholdtsen 				}
2348*c18ec02fSPetter Reinholdtsen 				printf("        Channel Number:       0x%02x\n",
2349*c18ec02fSPetter Reinholdtsen 						d->desig_channel);
2350*c18ec02fSPetter Reinholdtsen 				printf("\n");
2351*c18ec02fSPetter Reinholdtsen 			}
2352*c18ec02fSPetter Reinholdtsen 
2353*c18ec02fSPetter Reinholdtsen 			break;
2354*c18ec02fSPetter Reinholdtsen 
2355*c18ec02fSPetter Reinholdtsen 		case FRU_AMC_CURRENT:
2356*c18ec02fSPetter Reinholdtsen 		{
2357*c18ec02fSPetter Reinholdtsen 			unsigned char current;
2358*c18ec02fSPetter Reinholdtsen 			printf("    FRU_AMC_CURRENT\n");
2359*c18ec02fSPetter Reinholdtsen 
2360*c18ec02fSPetter Reinholdtsen 			current = fru_data[offset];
2361*c18ec02fSPetter Reinholdtsen 			printf("      Current draw(@12V): %.2f A [ %.2f Watt ]\n",
2362*c18ec02fSPetter Reinholdtsen 					(float)current / 10.0f,
2363*c18ec02fSPetter Reinholdtsen 					(float)current / 10.0f * 12.0f);
2364*c18ec02fSPetter Reinholdtsen 			printf("\n");
2365*c18ec02fSPetter Reinholdtsen 		}
2366*c18ec02fSPetter Reinholdtsen 		break;
2367*c18ec02fSPetter Reinholdtsen 
2368*c18ec02fSPetter Reinholdtsen 		case FRU_AMC_ACTIVATION:
2369*c18ec02fSPetter Reinholdtsen 			printf("    FRU_AMC_ACTIVATION\n");
2370*c18ec02fSPetter Reinholdtsen 			{
2371*c18ec02fSPetter Reinholdtsen 				uint16_t max_current;
2372*c18ec02fSPetter Reinholdtsen 
2373*c18ec02fSPetter Reinholdtsen 				max_current = fru_data[offset];
2374*c18ec02fSPetter Reinholdtsen 				max_current |= fru_data[++offset]<<8;
2375*c18ec02fSPetter Reinholdtsen 				printf("      Maximum Internal Current(@12V): %.2f A [ %.2f Watt ]\n",
2376*c18ec02fSPetter Reinholdtsen 						(float)max_current / 10.0f,
2377*c18ec02fSPetter Reinholdtsen 						(float)max_current / 10.0f * 12.0f);
2378*c18ec02fSPetter Reinholdtsen 
2379*c18ec02fSPetter Reinholdtsen 				printf("      Module Activation Readiness:    %i sec.\n", fru_data[++offset]);
2380*c18ec02fSPetter Reinholdtsen 				printf("      Descriptor Count: %i\n", fru_data[++offset]);
2381*c18ec02fSPetter Reinholdtsen 				printf("\n");
2382*c18ec02fSPetter Reinholdtsen 
2383*c18ec02fSPetter Reinholdtsen 				for(++offset; offset < off + length;
2384*c18ec02fSPetter Reinholdtsen 						offset += sizeof(struct fru_picmgext_activation_record))
2385*c18ec02fSPetter Reinholdtsen 				{
2386*c18ec02fSPetter Reinholdtsen 					struct fru_picmgext_activation_record *a;
2387*c18ec02fSPetter Reinholdtsen 					a = (struct fru_picmgext_activation_record *)&fru_data[offset];
2388*c18ec02fSPetter Reinholdtsen 					printf("        IPMB-Address:         0x%x\n",
2389*c18ec02fSPetter Reinholdtsen 							a->ibmb_addr);
2390*c18ec02fSPetter Reinholdtsen 					printf("        Max. Module Current:  %.2f A\n",
2391*c18ec02fSPetter Reinholdtsen 							(float)a->max_module_curr / 10.0f);
2392*c18ec02fSPetter Reinholdtsen 					printf("\n");
2393*c18ec02fSPetter Reinholdtsen 				}
2394*c18ec02fSPetter Reinholdtsen 			}
2395*c18ec02fSPetter Reinholdtsen 			break;
2396*c18ec02fSPetter Reinholdtsen 
2397*c18ec02fSPetter Reinholdtsen 		case FRU_AMC_CARRIER_P2P:
2398*c18ec02fSPetter Reinholdtsen 			{
2399*c18ec02fSPetter Reinholdtsen 				uint16_t index;
2400*c18ec02fSPetter Reinholdtsen 				printf("    FRU_CARRIER_P2P\n");
2401*c18ec02fSPetter Reinholdtsen 				for(; offset < off + length; ) {
2402*c18ec02fSPetter Reinholdtsen 					struct fru_picmgext_carrier_p2p_record * h =
2403*c18ec02fSPetter Reinholdtsen 						(struct fru_picmgext_carrier_p2p_record *)&fru_data[offset];
2404*c18ec02fSPetter Reinholdtsen 					printf("\n");
2405*c18ec02fSPetter Reinholdtsen 					printf("      Resource ID:      %i",
2406*c18ec02fSPetter Reinholdtsen 							(h->resource_id & 0x07));
2407*c18ec02fSPetter Reinholdtsen 						printf("  Type: ");
2408*c18ec02fSPetter Reinholdtsen 					if ((h->resource_id>>7) == 1) {
2409*c18ec02fSPetter Reinholdtsen 						printf("AMC\n");
2410*c18ec02fSPetter Reinholdtsen 					} else {
2411*c18ec02fSPetter Reinholdtsen 						printf("Local\n");
2412*c18ec02fSPetter Reinholdtsen 					}
2413*c18ec02fSPetter Reinholdtsen 					printf("      Descriptor Count: %i\n",
2414*c18ec02fSPetter Reinholdtsen 							h->p2p_count);
2415*c18ec02fSPetter Reinholdtsen 					offset += sizeof(struct fru_picmgext_carrier_p2p_record);
2416*c18ec02fSPetter Reinholdtsen 					for (index = 0; index < h->p2p_count; index++) {
2417*c18ec02fSPetter Reinholdtsen 						/* to solve little endian /big endian problem */
2418*c18ec02fSPetter Reinholdtsen 						unsigned char data[3];
2419*c18ec02fSPetter Reinholdtsen 						struct fru_picmgext_carrier_p2p_descriptor * desc;
2420*c18ec02fSPetter Reinholdtsen # ifndef WORDS_BIGENDIAN
2421*c18ec02fSPetter Reinholdtsen 						data[0] = fru_data[offset+0];
2422*c18ec02fSPetter Reinholdtsen 						data[1] = fru_data[offset+1];
2423*c18ec02fSPetter Reinholdtsen 						data[2] = fru_data[offset+2];
2424*c18ec02fSPetter Reinholdtsen # else
2425*c18ec02fSPetter Reinholdtsen 						data[0] = fru_data[offset+2];
2426*c18ec02fSPetter Reinholdtsen 						data[1] = fru_data[offset+1];
2427*c18ec02fSPetter Reinholdtsen 						data[2] = fru_data[offset+0];
2428*c18ec02fSPetter Reinholdtsen # endif
2429*c18ec02fSPetter Reinholdtsen 						desc = (struct fru_picmgext_carrier_p2p_descriptor*)&data;
2430*c18ec02fSPetter Reinholdtsen 						printf("        Port: %02d\t->  Remote Port: %02d\t",
2431*c18ec02fSPetter Reinholdtsen 								desc->local_port, desc->remote_port);
2432*c18ec02fSPetter Reinholdtsen 						if ((desc->remote_resource_id >> 7) == 1) {
2433*c18ec02fSPetter Reinholdtsen 							printf("[ AMC   ID: %02d ]\n",
2434*c18ec02fSPetter Reinholdtsen 									desc->remote_resource_id & 0x0F);
2435*c18ec02fSPetter Reinholdtsen 						} else {
2436*c18ec02fSPetter Reinholdtsen 							printf("[ local ID: %02d ]\n",
2437*c18ec02fSPetter Reinholdtsen 									desc->remote_resource_id & 0x0F);
2438*c18ec02fSPetter Reinholdtsen 						}
2439*c18ec02fSPetter Reinholdtsen 						offset += sizeof(struct fru_picmgext_carrier_p2p_descriptor);
2440*c18ec02fSPetter Reinholdtsen 					}
2441*c18ec02fSPetter Reinholdtsen 				}
2442*c18ec02fSPetter Reinholdtsen 			}
2443*c18ec02fSPetter Reinholdtsen 			break;
2444*c18ec02fSPetter Reinholdtsen 
2445*c18ec02fSPetter Reinholdtsen 		case FRU_AMC_P2P:
2446*c18ec02fSPetter Reinholdtsen 			{
2447*c18ec02fSPetter Reinholdtsen 				unsigned int index;
2448*c18ec02fSPetter Reinholdtsen 				unsigned char channel_count;
2449*c18ec02fSPetter Reinholdtsen 				struct fru_picmgext_amc_p2p_record * h;
2450*c18ec02fSPetter Reinholdtsen 				printf("    FRU_AMC_P2P\n");
2451*c18ec02fSPetter Reinholdtsen 				guid_count = fru_data[offset];
2452*c18ec02fSPetter Reinholdtsen 				printf("      GUID count: %2d\n", guid_count);
2453*c18ec02fSPetter Reinholdtsen 				for (i = 0 ; i < guid_count; i++) {
2454*c18ec02fSPetter Reinholdtsen 					int j;
2455*c18ec02fSPetter Reinholdtsen 					printf("        GUID %2d: ", i);
2456*c18ec02fSPetter Reinholdtsen 					for (j=0; j < sizeof(struct fru_picmgext_guid);
2457*c18ec02fSPetter Reinholdtsen 							j++) {
2458*c18ec02fSPetter Reinholdtsen 						printf("%02x", fru_data[offset+j]);
2459*c18ec02fSPetter Reinholdtsen 						offset += sizeof(struct fru_picmgext_guid);
2460*c18ec02fSPetter Reinholdtsen 						printf("\n");
2461*c18ec02fSPetter Reinholdtsen 					}
2462*c18ec02fSPetter Reinholdtsen 					h = (struct fru_picmgext_amc_p2p_record *)&fru_data[++offset];
2463*c18ec02fSPetter Reinholdtsen 					printf("      %s",
2464*c18ec02fSPetter Reinholdtsen 							(h->record_type ?
2465*c18ec02fSPetter Reinholdtsen 							 "AMC Module:" : "On-Carrier Device"));
2466*c18ec02fSPetter Reinholdtsen 					printf("   Resource ID: %i\n", h->resource_id);
2467*c18ec02fSPetter Reinholdtsen 					offset += sizeof(struct fru_picmgext_amc_p2p_record);
2468*c18ec02fSPetter Reinholdtsen 					channel_count = fru_data[offset++];
2469*c18ec02fSPetter Reinholdtsen 					printf("       Descriptor Count: %i\n",
2470*c18ec02fSPetter Reinholdtsen 							channel_count);
2471*c18ec02fSPetter Reinholdtsen 					for (index = 0; index < channel_count; index++) {
2472*c18ec02fSPetter Reinholdtsen 						unsigned int data;
2473*c18ec02fSPetter Reinholdtsen 						struct fru_picmgext_amc_channel_desc_record *d;
2474*c18ec02fSPetter Reinholdtsen 						/* pack the data in little endian format.
2475*c18ec02fSPetter Reinholdtsen 						 * Stupid intel...
2476*c18ec02fSPetter Reinholdtsen 						 */
2477*c18ec02fSPetter Reinholdtsen 						data = fru_data[offset] |
2478*c18ec02fSPetter Reinholdtsen 							(fru_data[offset + 1] << 8) |
2479*c18ec02fSPetter Reinholdtsen 							(fru_data[offset + 2] << 16);
2480*c18ec02fSPetter Reinholdtsen 						d = (struct fru_picmgext_amc_channel_desc_record *)&data;
2481*c18ec02fSPetter Reinholdtsen 						printf("        Lane 0 Port: %i\n",
2482*c18ec02fSPetter Reinholdtsen 								d->lane0port);
2483*c18ec02fSPetter Reinholdtsen 						printf("        Lane 1 Port: %i\n",
2484*c18ec02fSPetter Reinholdtsen 								d->lane1port);
2485*c18ec02fSPetter Reinholdtsen 						printf("        Lane 2 Port: %i\n",
2486*c18ec02fSPetter Reinholdtsen 								d->lane2port);
2487*c18ec02fSPetter Reinholdtsen 						printf("        Lane 3 Port: %i\n\n",
2488*c18ec02fSPetter Reinholdtsen 								d->lane3port);
2489*c18ec02fSPetter Reinholdtsen 						offset += FRU_PICMGEXT_AMC_CHANNEL_DESC_RECORD_SIZE;
2490*c18ec02fSPetter Reinholdtsen 					}
2491*c18ec02fSPetter Reinholdtsen 					for (; offset < off + length;) {
2492*c18ec02fSPetter Reinholdtsen 						unsigned int data[2];
2493*c18ec02fSPetter Reinholdtsen 						struct fru_picmgext_amc_link_desc_record *l;
2494*c18ec02fSPetter Reinholdtsen 						l = (struct fru_picmgext_amc_link_desc_record *)&data[0];
2495*c18ec02fSPetter Reinholdtsen 						data[0] = fru_data[offset] |
2496*c18ec02fSPetter Reinholdtsen 							(fru_data[offset + 1] << 8) |
2497*c18ec02fSPetter Reinholdtsen 							(fru_data[offset + 2] << 16) |
2498*c18ec02fSPetter Reinholdtsen 							(fru_data[offset + 3] << 24);
2499*c18ec02fSPetter Reinholdtsen 						data[1] = fru_data[offset + 4];
2500*c18ec02fSPetter Reinholdtsen 						printf( "      Link Designator:  Channel ID: %i\n"
2501*c18ec02fSPetter Reinholdtsen 								"            Port Flag 0: %s%s%s%s\n",
2502*c18ec02fSPetter Reinholdtsen 								l->channel_id,
2503*c18ec02fSPetter Reinholdtsen 								(l->port_flag_0)?"o":"-",
2504*c18ec02fSPetter Reinholdtsen 								(l->port_flag_1)?"o":"-",
2505*c18ec02fSPetter Reinholdtsen 								(l->port_flag_2)?"o":"-",
2506*c18ec02fSPetter Reinholdtsen 								(l->port_flag_3)?"o":"-"  );
2507*c18ec02fSPetter Reinholdtsen 						switch (l->type) {
2508*c18ec02fSPetter Reinholdtsen 							case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE:
2509*c18ec02fSPetter Reinholdtsen 								/* AMC.1 */
2510*c18ec02fSPetter Reinholdtsen 								printf( "        Link Type:       %02x - "
2511*c18ec02fSPetter Reinholdtsen 										"AMC.1 PCI Express\n", l->type);
2512*c18ec02fSPetter Reinholdtsen 								switch (l->type_ext) {
2513*c18ec02fSPetter Reinholdtsen 									case AMC_LINK_TYPE_EXT_PCIE_G1_NSSC:
2514*c18ec02fSPetter Reinholdtsen 										printf( "        Link Type Ext:   %i - "
2515*c18ec02fSPetter Reinholdtsen 												" Gen 1 capable - non SSC\n",
2516*c18ec02fSPetter Reinholdtsen 												l->type_ext);
2517*c18ec02fSPetter Reinholdtsen 									break;
2518*c18ec02fSPetter Reinholdtsen 									case AMC_LINK_TYPE_EXT_PCIE_G1_SSC:
2519*c18ec02fSPetter Reinholdtsen 										printf( "        Link Type Ext:   %i - "
2520*c18ec02fSPetter Reinholdtsen 												" Gen 1 capable - SSC\n",
2521*c18ec02fSPetter Reinholdtsen 												l->type_ext);
2522*c18ec02fSPetter Reinholdtsen 										break;
2523*c18ec02fSPetter Reinholdtsen 									case AMC_LINK_TYPE_EXT_PCIE_G2_NSSC:
2524*c18ec02fSPetter Reinholdtsen 										printf( "        Link Type Ext:   %i - "
2525*c18ec02fSPetter Reinholdtsen 												" Gen 2 capable - non SSC\n",
2526*c18ec02fSPetter Reinholdtsen 												l->type_ext);
2527*c18ec02fSPetter Reinholdtsen 										break;
2528*c18ec02fSPetter Reinholdtsen 									case AMC_LINK_TYPE_EXT_PCIE_G2_SSC:
2529*c18ec02fSPetter Reinholdtsen 										printf( "        Link Type Ext:   %i - "
2530*c18ec02fSPetter Reinholdtsen 												" Gen 2 capable - SSC\n",
2531*c18ec02fSPetter Reinholdtsen 												l->type_ext);
2532*c18ec02fSPetter Reinholdtsen 										break;
2533*c18ec02fSPetter Reinholdtsen 									default:
2534*c18ec02fSPetter Reinholdtsen 										printf( "        Link Type Ext:   %i - "
2535*c18ec02fSPetter Reinholdtsen 												" Invalid\n",
2536*c18ec02fSPetter Reinholdtsen 												l->type_ext);
2537*c18ec02fSPetter Reinholdtsen 										break;
2538*c18ec02fSPetter Reinholdtsen 								}
2539*c18ec02fSPetter Reinholdtsen 								break;
2540*c18ec02fSPetter Reinholdtsen 
2541*c18ec02fSPetter Reinholdtsen 							case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS1:
2542*c18ec02fSPetter Reinholdtsen 							case FRU_PICMGEXT_AMC_LINK_TYPE_PCIE_AS2:
2543*c18ec02fSPetter Reinholdtsen 								/* AMC.1 */
2544*c18ec02fSPetter Reinholdtsen 								printf( "        Link Type:       %02x - "
2545*c18ec02fSPetter Reinholdtsen 										"AMC.1 PCI Express Advanced Switching\n",
2546*c18ec02fSPetter Reinholdtsen 										l->type);
2547*c18ec02fSPetter Reinholdtsen 								printf("        Link Type Ext:   %i\n",
2548*c18ec02fSPetter Reinholdtsen 										l->type_ext);
2549*c18ec02fSPetter Reinholdtsen 								break;
2550*c18ec02fSPetter Reinholdtsen 
2551*c18ec02fSPetter Reinholdtsen 							case FRU_PICMGEXT_AMC_LINK_TYPE_ETHERNET:
2552*c18ec02fSPetter Reinholdtsen 								/* AMC.2 */
2553*c18ec02fSPetter Reinholdtsen 								printf( "        Link Type:       %02x - "
2554*c18ec02fSPetter Reinholdtsen 										"AMC.2 Ethernet\n",
2555*c18ec02fSPetter Reinholdtsen 										l->type);
2556*c18ec02fSPetter Reinholdtsen 								switch (l->type_ext) {
2557*c18ec02fSPetter Reinholdtsen 									case AMC_LINK_TYPE_EXT_ETH_1000_BX:
2558*c18ec02fSPetter Reinholdtsen 										printf( "        Link Type Ext:   %i - "
2559*c18ec02fSPetter Reinholdtsen 												" 1000Base-Bx (SerDES Gigabit) Ethernet Link\n",
2560*c18ec02fSPetter Reinholdtsen 												l->type_ext);
2561*c18ec02fSPetter Reinholdtsen 										break;
2562*c18ec02fSPetter Reinholdtsen 
2563*c18ec02fSPetter Reinholdtsen 									case AMC_LINK_TYPE_EXT_ETH_10G_XAUI:
2564*c18ec02fSPetter Reinholdtsen 										printf( "        Link Type Ext:   %i - "
2565*c18ec02fSPetter Reinholdtsen 												" 10Gbit XAUI Ethernet Link\n",
2566*c18ec02fSPetter Reinholdtsen 										l->type_ext);
2567*c18ec02fSPetter Reinholdtsen 										break;
2568*c18ec02fSPetter Reinholdtsen 
2569*c18ec02fSPetter Reinholdtsen 									default:
2570*c18ec02fSPetter Reinholdtsen 										printf( "        Link Type Ext:   %i - "
2571*c18ec02fSPetter Reinholdtsen 												" Invalid\n",
2572*c18ec02fSPetter Reinholdtsen 												l->type_ext);
2573*c18ec02fSPetter Reinholdtsen 										break;
2574*c18ec02fSPetter Reinholdtsen 								}
2575*c18ec02fSPetter Reinholdtsen 								break;
2576*c18ec02fSPetter Reinholdtsen 
2577*c18ec02fSPetter Reinholdtsen 							case FRU_PICMGEXT_AMC_LINK_TYPE_STORAGE:
2578*c18ec02fSPetter Reinholdtsen 								/* AMC.3 */
2579*c18ec02fSPetter Reinholdtsen 								printf( "        Link Type:       %02x - "
2580*c18ec02fSPetter Reinholdtsen 										"AMC.3 Storage\n",
2581*c18ec02fSPetter Reinholdtsen 										l->type);
2582*c18ec02fSPetter Reinholdtsen 								switch (l->type_ext) {
2583*c18ec02fSPetter Reinholdtsen 									case AMC_LINK_TYPE_EXT_STORAGE_FC:
2584*c18ec02fSPetter Reinholdtsen 										printf( "        Link Type Ext:   %i - "
2585*c18ec02fSPetter Reinholdtsen 												" Fibre Channel\n",
2586*c18ec02fSPetter Reinholdtsen 												l->type_ext);
2587*c18ec02fSPetter Reinholdtsen 										break;
2588*c18ec02fSPetter Reinholdtsen 
2589*c18ec02fSPetter Reinholdtsen 									case AMC_LINK_TYPE_EXT_STORAGE_SATA:
2590*c18ec02fSPetter Reinholdtsen 										printf( "        Link Type Ext:   %i - "
2591*c18ec02fSPetter Reinholdtsen 												" Serial ATA\n",
2592*c18ec02fSPetter Reinholdtsen 												l->type_ext);
2593*c18ec02fSPetter Reinholdtsen 										break;
2594*c18ec02fSPetter Reinholdtsen 
2595*c18ec02fSPetter Reinholdtsen 									case AMC_LINK_TYPE_EXT_STORAGE_SAS:
2596*c18ec02fSPetter Reinholdtsen 										printf( "        Link Type Ext:   %i - "
2597*c18ec02fSPetter Reinholdtsen 												" Serial Attached SCSI\n",
2598*c18ec02fSPetter Reinholdtsen 												l->type_ext);
2599*c18ec02fSPetter Reinholdtsen 										break;
2600*c18ec02fSPetter Reinholdtsen 
2601*c18ec02fSPetter Reinholdtsen 									default:
2602*c18ec02fSPetter Reinholdtsen 										printf( "        Link Type Ext:   %i - "
2603*c18ec02fSPetter Reinholdtsen 												" Invalid\n",
2604*c18ec02fSPetter Reinholdtsen 												l->type_ext);
2605*c18ec02fSPetter Reinholdtsen 										break;
2606*c18ec02fSPetter Reinholdtsen 								}
2607*c18ec02fSPetter Reinholdtsen 								break;
2608*c18ec02fSPetter Reinholdtsen 
2609*c18ec02fSPetter Reinholdtsen 							case FRU_PICMGEXT_AMC_LINK_TYPE_RAPIDIO:
2610*c18ec02fSPetter Reinholdtsen 								/* AMC.4 */
2611*c18ec02fSPetter Reinholdtsen 								printf( "        Link Type:       %02x - "
2612*c18ec02fSPetter Reinholdtsen 										"AMC.4 Serial Rapid IO\n",
2613*c18ec02fSPetter Reinholdtsen 										l->type);
2614*c18ec02fSPetter Reinholdtsen 								printf("        Link Type Ext:   %i\n",
2615*c18ec02fSPetter Reinholdtsen 										l->type_ext);
2616*c18ec02fSPetter Reinholdtsen 								break;
2617*c18ec02fSPetter Reinholdtsen 
2618*c18ec02fSPetter Reinholdtsen 							default:
2619*c18ec02fSPetter Reinholdtsen 								printf( "        Link Type:       %02x - "
2620*c18ec02fSPetter Reinholdtsen 										"reserved or OEM GUID",
2621*c18ec02fSPetter Reinholdtsen 										l->type);
2622*c18ec02fSPetter Reinholdtsen 								printf("        Link Type Ext:   %i\n",
2623*c18ec02fSPetter Reinholdtsen 										l->type_ext);
2624*c18ec02fSPetter Reinholdtsen 								break;
2625*c18ec02fSPetter Reinholdtsen 						}
2626*c18ec02fSPetter Reinholdtsen 
2627*c18ec02fSPetter Reinholdtsen 						printf("        Link group Id:   %i\n",
2628*c18ec02fSPetter Reinholdtsen 								l->group_id);
2629*c18ec02fSPetter Reinholdtsen 						printf("        Link Asym Match: %i\n\n",
2630*c18ec02fSPetter Reinholdtsen 								l->asym_match);
2631*c18ec02fSPetter Reinholdtsen 						offset += FRU_PICMGEXT_AMC_LINK_DESC_RECORD_SIZE;
2632*c18ec02fSPetter Reinholdtsen 					}
2633*c18ec02fSPetter Reinholdtsen 				}
2634*c18ec02fSPetter Reinholdtsen 			}
2635*c18ec02fSPetter Reinholdtsen 			break;
2636*c18ec02fSPetter Reinholdtsen 
2637*c18ec02fSPetter Reinholdtsen 		case FRU_AMC_CARRIER_INFO:
2638*c18ec02fSPetter Reinholdtsen 		{
2639*c18ec02fSPetter Reinholdtsen 			unsigned char extVersion;
2640*c18ec02fSPetter Reinholdtsen 			unsigned char siteCount;
2641*c18ec02fSPetter Reinholdtsen 
2642*c18ec02fSPetter Reinholdtsen 			printf("    FRU_CARRIER_INFO\n");
2643*c18ec02fSPetter Reinholdtsen 
2644*c18ec02fSPetter Reinholdtsen 			extVersion = fru_data[offset++];
2645*c18ec02fSPetter Reinholdtsen 			siteCount  = fru_data[offset++];
2646*c18ec02fSPetter Reinholdtsen 
2647*c18ec02fSPetter Reinholdtsen 			printf("      AMC.0 extension version: R%d.%d\n",
2648*c18ec02fSPetter Reinholdtsen 					(extVersion >> 0)& 0x0F,
2649*c18ec02fSPetter Reinholdtsen 					(extVersion >> 4)& 0x0F );
2650*c18ec02fSPetter Reinholdtsen 			printf("      Carrier Sie Number Cnt: %d\n", siteCount);
2651*c18ec02fSPetter Reinholdtsen 
2652*c18ec02fSPetter Reinholdtsen 			for (i = 0 ; i < siteCount; i++ ){
2653*c18ec02fSPetter Reinholdtsen 				printf("       Site ID: %i \n", fru_data[offset++]);
2654*c18ec02fSPetter Reinholdtsen 			}
2655*c18ec02fSPetter Reinholdtsen 			printf("\n");
2656*c18ec02fSPetter Reinholdtsen 		}
2657*c18ec02fSPetter Reinholdtsen 		break;
2658*c18ec02fSPetter Reinholdtsen 		case FRU_PICMG_CLK_CARRIER_P2P:
2659*c18ec02fSPetter Reinholdtsen 		{
2660*c18ec02fSPetter Reinholdtsen 			unsigned char desc_count;
2661*c18ec02fSPetter Reinholdtsen 			int i,j;
2662*c18ec02fSPetter Reinholdtsen 
2663*c18ec02fSPetter Reinholdtsen 			printf("    FRU_PICMG_CLK_CARRIER_P2P\n");
2664*c18ec02fSPetter Reinholdtsen 
2665*c18ec02fSPetter Reinholdtsen 			desc_count = fru_data[offset++];
2666*c18ec02fSPetter Reinholdtsen 
2667*c18ec02fSPetter Reinholdtsen 			for(i=0; i<desc_count; i++){
2668*c18ec02fSPetter Reinholdtsen 				unsigned char resource_id;
2669*c18ec02fSPetter Reinholdtsen 				unsigned char channel_count;
2670*c18ec02fSPetter Reinholdtsen 
2671*c18ec02fSPetter Reinholdtsen 				resource_id   = fru_data[offset++];
2672*c18ec02fSPetter Reinholdtsen 				channel_count = fru_data[offset++];
2673*c18ec02fSPetter Reinholdtsen 
2674*c18ec02fSPetter Reinholdtsen 				printf("\n");
2675*c18ec02fSPetter Reinholdtsen 				printf("      Clock Resource ID: 0x%02x  Type: ", resource_id);
2676*c18ec02fSPetter Reinholdtsen 				if((resource_id & 0xC0)>>6 == 0) {printf("On-Carrier-Device\n");}
2677*c18ec02fSPetter Reinholdtsen 				else if((resource_id & 0xC0)>>6 == 1) {printf("AMC slot\n");}
2678*c18ec02fSPetter Reinholdtsen 				else if((resource_id & 0xC0)>>6 == 2) {printf("Backplane\n");}
2679*c18ec02fSPetter Reinholdtsen 				else{ printf("reserved\n");}
2680*c18ec02fSPetter Reinholdtsen 				printf("      Channel Count: 0x%02x\n", channel_count);
2681*c18ec02fSPetter Reinholdtsen 
2682*c18ec02fSPetter Reinholdtsen 				for(j=0; j<channel_count; j++){
2683*c18ec02fSPetter Reinholdtsen 					unsigned char loc_channel, rem_channel, rem_resource;
2684*c18ec02fSPetter Reinholdtsen 
2685*c18ec02fSPetter Reinholdtsen 					loc_channel  = fru_data[offset++];
2686*c18ec02fSPetter Reinholdtsen 					rem_channel  = fru_data[offset++];
2687*c18ec02fSPetter Reinholdtsen 					rem_resource = fru_data[offset++];
2688*c18ec02fSPetter Reinholdtsen 
2689*c18ec02fSPetter Reinholdtsen 					printf("        CLK-ID: 0x%02x    ->", loc_channel);
2690*c18ec02fSPetter Reinholdtsen 					printf(" remote CLKID: 0x%02x   ", rem_channel);
2691*c18ec02fSPetter Reinholdtsen 					if((rem_resource & 0xC0)>>6 == 0) {printf("[ Carrier-Dev");}
2692*c18ec02fSPetter Reinholdtsen 					else if((rem_resource & 0xC0)>>6 == 1) {printf("[ AMC slot   ");}
2693*c18ec02fSPetter Reinholdtsen 					else if((rem_resource & 0xC0)>>6 == 2) {printf("[ Backplane  ");}
2694*c18ec02fSPetter Reinholdtsen 					else{ printf("reserved         ");}
2695*c18ec02fSPetter Reinholdtsen 					printf(" 0x%02x ]\n", rem_resource&0xF);
2696*c18ec02fSPetter Reinholdtsen 				}
2697*c18ec02fSPetter Reinholdtsen 			}
2698*c18ec02fSPetter Reinholdtsen 			printf("\n");
2699*c18ec02fSPetter Reinholdtsen 		}
2700*c18ec02fSPetter Reinholdtsen 		break;
2701*c18ec02fSPetter Reinholdtsen 		case FRU_PICMG_CLK_CONFIG:
2702*c18ec02fSPetter Reinholdtsen 		{
2703*c18ec02fSPetter Reinholdtsen 			unsigned char resource_id, descr_count;
2704*c18ec02fSPetter Reinholdtsen 			int i,j;
2705*c18ec02fSPetter Reinholdtsen 
2706*c18ec02fSPetter Reinholdtsen 			printf("    FRU_PICMG_CLK_CONFIG\n");
2707*c18ec02fSPetter Reinholdtsen 
2708*c18ec02fSPetter Reinholdtsen 			resource_id = fru_data[offset++];
2709*c18ec02fSPetter Reinholdtsen 			descr_count = fru_data[offset++];
2710*c18ec02fSPetter Reinholdtsen 
2711*c18ec02fSPetter Reinholdtsen 			printf("\n");
2712*c18ec02fSPetter Reinholdtsen 			printf("      Clock Resource ID: 0x%02x\n", resource_id);
2713*c18ec02fSPetter Reinholdtsen 			printf("      Descr. Count:      0x%02x\n", descr_count);
2714*c18ec02fSPetter Reinholdtsen 
2715*c18ec02fSPetter Reinholdtsen 			for(i=0; i<descr_count; i++){
2716*c18ec02fSPetter Reinholdtsen 				unsigned char channel_id, control;
2717*c18ec02fSPetter Reinholdtsen 				unsigned char indirect_cnt, direct_cnt;
2718*c18ec02fSPetter Reinholdtsen 
2719*c18ec02fSPetter Reinholdtsen 				channel_id = fru_data[offset++];
2720*c18ec02fSPetter Reinholdtsen 				control    = fru_data[offset++];
2721*c18ec02fSPetter Reinholdtsen 				printf("        CLK-ID: 0x%02x  -  ", channel_id);
2722*c18ec02fSPetter Reinholdtsen 				printf("CTRL 0x%02x [ %12s ]\n",
2723*c18ec02fSPetter Reinholdtsen 									control,
2724*c18ec02fSPetter Reinholdtsen 									((control&0x1)==0)?"Carrier IPMC":"Application");
2725*c18ec02fSPetter Reinholdtsen 
2726*c18ec02fSPetter Reinholdtsen 				indirect_cnt = fru_data[offset++];
2727*c18ec02fSPetter Reinholdtsen 				direct_cnt   = fru_data[offset++];
2728*c18ec02fSPetter Reinholdtsen 				printf("         Cnt: Indirect 0x%02x  /  Direct 0x%02x\n",
2729*c18ec02fSPetter Reinholdtsen 						indirect_cnt,
2730*c18ec02fSPetter Reinholdtsen 						direct_cnt);
2731*c18ec02fSPetter Reinholdtsen 
2732*c18ec02fSPetter Reinholdtsen 				/* indirect desc */
2733*c18ec02fSPetter Reinholdtsen 				for(j=0; j<indirect_cnt; j++){
2734*c18ec02fSPetter Reinholdtsen 					unsigned char feature;
2735*c18ec02fSPetter Reinholdtsen 					unsigned char dep_chn_id;
2736*c18ec02fSPetter Reinholdtsen 
2737*c18ec02fSPetter Reinholdtsen 					feature    = fru_data[offset++];
2738*c18ec02fSPetter Reinholdtsen 					dep_chn_id = fru_data[offset++];
2739*c18ec02fSPetter Reinholdtsen 
2740*c18ec02fSPetter Reinholdtsen 					printf("          Feature: 0x%02x [%8s] - ", feature, (feature&0x1)==1?"Source":"Receiver");
2741*c18ec02fSPetter Reinholdtsen 					printf("          Dep. CLK-ID: 0x%02x\n", dep_chn_id);
2742*c18ec02fSPetter Reinholdtsen 				}
2743*c18ec02fSPetter Reinholdtsen 
2744*c18ec02fSPetter Reinholdtsen 				/* direct desc */
2745*c18ec02fSPetter Reinholdtsen 				for(j=0; j<direct_cnt; j++){
2746*c18ec02fSPetter Reinholdtsen 					unsigned char feature, family, accuracy;
2747*c18ec02fSPetter Reinholdtsen 					unsigned int freq, min_freq, max_freq;
2748*c18ec02fSPetter Reinholdtsen 
2749*c18ec02fSPetter Reinholdtsen 					feature  = fru_data[offset++];
2750*c18ec02fSPetter Reinholdtsen 					family   = fru_data[offset++];
2751*c18ec02fSPetter Reinholdtsen 					accuracy = fru_data[offset++];
2752*c18ec02fSPetter Reinholdtsen 					freq     = (fru_data[offset+0] << 0 ) | (fru_data[offset+1] << 8 )
2753*c18ec02fSPetter Reinholdtsen 								| (fru_data[offset+2] << 16) | (fru_data[offset+3] << 24);
2754*c18ec02fSPetter Reinholdtsen 					offset += 4;
2755*c18ec02fSPetter Reinholdtsen 					min_freq = (fru_data[offset+0] << 0 ) | (fru_data[offset+1] << 8 )
2756*c18ec02fSPetter Reinholdtsen 								| (fru_data[offset+2] << 16) | (fru_data[offset+3] << 24);
2757*c18ec02fSPetter Reinholdtsen 					offset += 4;
2758*c18ec02fSPetter Reinholdtsen 					max_freq = (fru_data[offset+0] << 0 ) | (fru_data[offset+1] << 8 )
2759*c18ec02fSPetter Reinholdtsen 								| (fru_data[offset+2] << 16) | (fru_data[offset+3] << 24);
2760*c18ec02fSPetter Reinholdtsen 					offset += 4;
2761*c18ec02fSPetter Reinholdtsen 
2762*c18ec02fSPetter Reinholdtsen 					printf("          - Feature: 0x%02x  - PLL: %x / Asym: %s\n",
2763*c18ec02fSPetter Reinholdtsen 							feature,
2764*c18ec02fSPetter Reinholdtsen 							(feature > 1) & 1,
2765*c18ec02fSPetter Reinholdtsen 							(feature&1)?"Source":"Receiver");
2766*c18ec02fSPetter Reinholdtsen 					printf("            Family:  0x%02x  - AccLVL: 0x%02x\n", family, accuracy);
2767*c18ec02fSPetter Reinholdtsen 					printf("            FRQ: %-9ld - min: %-9ld - max: %-9ld\n",
2768*c18ec02fSPetter Reinholdtsen 							freq, min_freq, max_freq);
2769*c18ec02fSPetter Reinholdtsen 				}
2770*c18ec02fSPetter Reinholdtsen 				printf("\n");
2771*c18ec02fSPetter Reinholdtsen 			}
2772*c18ec02fSPetter Reinholdtsen 			printf("\n");
2773*c18ec02fSPetter Reinholdtsen 		}
2774*c18ec02fSPetter Reinholdtsen 		break;
2775*c18ec02fSPetter Reinholdtsen 
2776*c18ec02fSPetter Reinholdtsen 		case FRU_UTCA_FRU_INFO_TABLE:
2777*c18ec02fSPetter Reinholdtsen 		case FRU_UTCA_CARRIER_MNG_IP:
2778*c18ec02fSPetter Reinholdtsen 		case FRU_UTCA_CARRIER_INFO:
2779*c18ec02fSPetter Reinholdtsen 		case FRU_UTCA_CARRIER_LOCATION:
2780*c18ec02fSPetter Reinholdtsen 		case FRU_UTCA_SHMC_IP_LINK:
2781*c18ec02fSPetter Reinholdtsen 		case FRU_UTCA_POWER_POLICY:
2782*c18ec02fSPetter Reinholdtsen 		case FRU_UTCA_ACTIVATION:
2783*c18ec02fSPetter Reinholdtsen 		case FRU_UTCA_PM_CAPABILTY:
2784*c18ec02fSPetter Reinholdtsen 		case FRU_UTCA_FAN_GEOGRAPHY:
2785*c18ec02fSPetter Reinholdtsen 		case FRU_UTCA_CLOCK_MAPPING:
2786*c18ec02fSPetter Reinholdtsen 		case FRU_UTCA_MSG_BRIDGE_POLICY:
2787*c18ec02fSPetter Reinholdtsen 		case FRU_UTCA_OEM_MODULE_DESC:
2788*c18ec02fSPetter Reinholdtsen 			printf("    Not implemented yet. uTCA specific record found!!\n");
2789*c18ec02fSPetter Reinholdtsen 			printf("     - Record ID: 0x%02x\n", h->record_id);
2790*c18ec02fSPetter Reinholdtsen 		break;
2791*c18ec02fSPetter Reinholdtsen 
2792*c18ec02fSPetter Reinholdtsen 		default:
2793*c18ec02fSPetter Reinholdtsen 			printf("    Unknown OEM Extension Record ID: %x\n", h->record_id);
2794*c18ec02fSPetter Reinholdtsen 		break;
2795*c18ec02fSPetter Reinholdtsen 
2796*c18ec02fSPetter Reinholdtsen 	}
2797*c18ec02fSPetter Reinholdtsen }
2798*c18ec02fSPetter Reinholdtsen 
2799*c18ec02fSPetter Reinholdtsen 
2800*c18ec02fSPetter Reinholdtsen /* __ipmi_fru_print  -  Do actual work to print a FRU by its ID
2801*c18ec02fSPetter Reinholdtsen *
2802*c18ec02fSPetter Reinholdtsen * @intf:   ipmi interface
2803*c18ec02fSPetter Reinholdtsen * @id:     fru id
2804*c18ec02fSPetter Reinholdtsen *
2805*c18ec02fSPetter Reinholdtsen * returns -1 on error
2806*c18ec02fSPetter Reinholdtsen * returns 0 if successful
2807*c18ec02fSPetter Reinholdtsen * returns 1 if device not present
2808*c18ec02fSPetter Reinholdtsen */
2809*c18ec02fSPetter Reinholdtsen static int
2810*c18ec02fSPetter Reinholdtsen __ipmi_fru_print(struct ipmi_intf * intf, uint8_t id)
2811*c18ec02fSPetter Reinholdtsen {
2812*c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
2813*c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
2814*c18ec02fSPetter Reinholdtsen 	struct fru_info fru;
2815*c18ec02fSPetter Reinholdtsen 	struct fru_header header;
2816*c18ec02fSPetter Reinholdtsen 	uint8_t msg_data[4];
2817*c18ec02fSPetter Reinholdtsen 
2818*c18ec02fSPetter Reinholdtsen 	memset(&fru, 0, sizeof(struct fru_info));
2819*c18ec02fSPetter Reinholdtsen 	memset(&header, 0, sizeof(struct fru_header));
2820*c18ec02fSPetter Reinholdtsen 
2821*c18ec02fSPetter Reinholdtsen 	/*
2822*c18ec02fSPetter Reinholdtsen 	* get info about this FRU
2823*c18ec02fSPetter Reinholdtsen 	*/
2824*c18ec02fSPetter Reinholdtsen 	memset(msg_data, 0, 4);
2825*c18ec02fSPetter Reinholdtsen 	msg_data[0] = id;
2826*c18ec02fSPetter Reinholdtsen 
2827*c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
2828*c18ec02fSPetter Reinholdtsen 	req.msg.netfn = IPMI_NETFN_STORAGE;
2829*c18ec02fSPetter Reinholdtsen 	req.msg.cmd = GET_FRU_INFO;
2830*c18ec02fSPetter Reinholdtsen 	req.msg.data = msg_data;
2831*c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 1;
2832*c18ec02fSPetter Reinholdtsen 
2833*c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
2834*c18ec02fSPetter Reinholdtsen 	if (rsp == NULL) {
2835*c18ec02fSPetter Reinholdtsen 		printf(" Device not present (No Response)\n");
2836*c18ec02fSPetter Reinholdtsen 		return -1;
2837*c18ec02fSPetter Reinholdtsen 	}
2838*c18ec02fSPetter Reinholdtsen 	if (rsp->ccode > 0) {
2839*c18ec02fSPetter Reinholdtsen 		printf(" Device not present (%s)\n",
2840*c18ec02fSPetter Reinholdtsen 			val2str(rsp->ccode, completion_code_vals));
2841*c18ec02fSPetter Reinholdtsen 		return -1;
2842*c18ec02fSPetter Reinholdtsen 	}
2843*c18ec02fSPetter Reinholdtsen 
2844*c18ec02fSPetter Reinholdtsen 	memset(&fru, 0, sizeof(fru));
2845*c18ec02fSPetter Reinholdtsen 	fru.size = (rsp->data[1] << 8) | rsp->data[0];
2846*c18ec02fSPetter Reinholdtsen 	fru.access = rsp->data[2] & 0x1;
2847*c18ec02fSPetter Reinholdtsen 
2848*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "fru.size = %d bytes (accessed by %s)",
2849*c18ec02fSPetter Reinholdtsen 		fru.size, fru.access ? "words" : "bytes");
2850*c18ec02fSPetter Reinholdtsen 
2851*c18ec02fSPetter Reinholdtsen 	if (fru.size < 1) {
2852*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, " Invalid FRU size %d", fru.size);
2853*c18ec02fSPetter Reinholdtsen 		return -1;
2854*c18ec02fSPetter Reinholdtsen 	}
2855*c18ec02fSPetter Reinholdtsen 
2856*c18ec02fSPetter Reinholdtsen 	/*
2857*c18ec02fSPetter Reinholdtsen 	* retrieve the FRU header
2858*c18ec02fSPetter Reinholdtsen 	*/
2859*c18ec02fSPetter Reinholdtsen 	msg_data[0] = id;
2860*c18ec02fSPetter Reinholdtsen 	msg_data[1] = 0;
2861*c18ec02fSPetter Reinholdtsen 	msg_data[2] = 0;
2862*c18ec02fSPetter Reinholdtsen 	msg_data[3] = 8;
2863*c18ec02fSPetter Reinholdtsen 
2864*c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
2865*c18ec02fSPetter Reinholdtsen 	req.msg.netfn = IPMI_NETFN_STORAGE;
2866*c18ec02fSPetter Reinholdtsen 	req.msg.cmd = GET_FRU_DATA;
2867*c18ec02fSPetter Reinholdtsen 	req.msg.data = msg_data;
2868*c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 4;
2869*c18ec02fSPetter Reinholdtsen 
2870*c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
2871*c18ec02fSPetter Reinholdtsen 	if (rsp == NULL) {
2872*c18ec02fSPetter Reinholdtsen 		printf(" Device not present (No Response)\n");
2873*c18ec02fSPetter Reinholdtsen 		return 1;
2874*c18ec02fSPetter Reinholdtsen 	}
2875*c18ec02fSPetter Reinholdtsen 	if (rsp->ccode > 0) {
2876*c18ec02fSPetter Reinholdtsen 		printf(" Device not present (%s)\n",
2877*c18ec02fSPetter Reinholdtsen 				val2str(rsp->ccode, completion_code_vals));
2878*c18ec02fSPetter Reinholdtsen 		return 1;
2879*c18ec02fSPetter Reinholdtsen 	}
2880*c18ec02fSPetter Reinholdtsen 
2881*c18ec02fSPetter Reinholdtsen 	if (verbose > 1)
2882*c18ec02fSPetter Reinholdtsen 		printbuf(rsp->data, rsp->data_len, "FRU DATA");
2883*c18ec02fSPetter Reinholdtsen 
2884*c18ec02fSPetter Reinholdtsen 	memcpy(&header, rsp->data + 1, 8);
2885*c18ec02fSPetter Reinholdtsen 
2886*c18ec02fSPetter Reinholdtsen 	if (header.version != 1) {
2887*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, " Unknown FRU header version 0x%02x",
2888*c18ec02fSPetter Reinholdtsen 			header.version);
2889*c18ec02fSPetter Reinholdtsen 		return -1;
2890*c18ec02fSPetter Reinholdtsen 	}
2891*c18ec02fSPetter Reinholdtsen 
2892*c18ec02fSPetter Reinholdtsen 	/* offsets need converted to bytes
2893*c18ec02fSPetter Reinholdtsen 	* but that conversion is not done to the structure
2894*c18ec02fSPetter Reinholdtsen 	* because we may end up with offset > 255
2895*c18ec02fSPetter Reinholdtsen 	* which would overflow our 1-byte offset field */
2896*c18ec02fSPetter Reinholdtsen 
2897*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "fru.header.version:         0x%x",
2898*c18ec02fSPetter Reinholdtsen 		header.version);
2899*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "fru.header.offset.internal: 0x%x",
2900*c18ec02fSPetter Reinholdtsen 		header.offset.internal * 8);
2901*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "fru.header.offset.chassis:  0x%x",
2902*c18ec02fSPetter Reinholdtsen 		header.offset.chassis * 8);
2903*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "fru.header.offset.board:    0x%x",
2904*c18ec02fSPetter Reinholdtsen 		header.offset.board * 8);
2905*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "fru.header.offset.product:  0x%x",
2906*c18ec02fSPetter Reinholdtsen 		header.offset.product * 8);
2907*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "fru.header.offset.multi:    0x%x",
2908*c18ec02fSPetter Reinholdtsen 		header.offset.multi * 8);
2909*c18ec02fSPetter Reinholdtsen 
2910*c18ec02fSPetter Reinholdtsen 	/*
2911*c18ec02fSPetter Reinholdtsen 	* rather than reading the entire part
2912*c18ec02fSPetter Reinholdtsen 	* only read the areas we'll format
2913*c18ec02fSPetter Reinholdtsen 	*/
2914*c18ec02fSPetter Reinholdtsen 	/* chassis area */
2915*c18ec02fSPetter Reinholdtsen 	if ((header.offset.chassis*8) >= sizeof(struct fru_header))
2916*c18ec02fSPetter Reinholdtsen 		fru_area_print_chassis(intf, &fru, id, header.offset.chassis*8);
2917*c18ec02fSPetter Reinholdtsen 
2918*c18ec02fSPetter Reinholdtsen 	/* board area */
2919*c18ec02fSPetter Reinholdtsen 	if ((header.offset.board*8) >= sizeof(struct fru_header))
2920*c18ec02fSPetter Reinholdtsen 		fru_area_print_board(intf, &fru, id, header.offset.board*8);
2921*c18ec02fSPetter Reinholdtsen 
2922*c18ec02fSPetter Reinholdtsen 	/* product area */
2923*c18ec02fSPetter Reinholdtsen 	if ((header.offset.product*8) >= sizeof(struct fru_header))
2924*c18ec02fSPetter Reinholdtsen 		fru_area_print_product(intf, &fru, id, header.offset.product*8);
2925*c18ec02fSPetter Reinholdtsen 
2926*c18ec02fSPetter Reinholdtsen 	/* multirecord area */
2927*c18ec02fSPetter Reinholdtsen 	if( verbose==0 ) /* scipp parsing multirecord */
2928*c18ec02fSPetter Reinholdtsen 		return 0;
2929*c18ec02fSPetter Reinholdtsen 
2930*c18ec02fSPetter Reinholdtsen 	if ((header.offset.multi*8) >= sizeof(struct fru_header))
2931*c18ec02fSPetter Reinholdtsen 		fru_area_print_multirec(intf, &fru, id, header.offset.multi*8);
2932*c18ec02fSPetter Reinholdtsen 
2933*c18ec02fSPetter Reinholdtsen 	return 0;
2934*c18ec02fSPetter Reinholdtsen }
2935*c18ec02fSPetter Reinholdtsen 
2936*c18ec02fSPetter Reinholdtsen /* ipmi_fru_print  -  Print a FRU from its SDR locator record
2937*c18ec02fSPetter Reinholdtsen *
2938*c18ec02fSPetter Reinholdtsen * @intf:   ipmi interface
2939*c18ec02fSPetter Reinholdtsen * @fru: SDR FRU Locator Record
2940*c18ec02fSPetter Reinholdtsen *
2941*c18ec02fSPetter Reinholdtsen * returns -1 on error
2942*c18ec02fSPetter Reinholdtsen */
2943*c18ec02fSPetter Reinholdtsen int
2944*c18ec02fSPetter Reinholdtsen ipmi_fru_print(struct ipmi_intf * intf, struct sdr_record_fru_locator * fru)
2945*c18ec02fSPetter Reinholdtsen {
2946*c18ec02fSPetter Reinholdtsen 	char desc[17];
2947*c18ec02fSPetter Reinholdtsen 	uint8_t  bridged_request = 0;
2948*c18ec02fSPetter Reinholdtsen 	uint32_t save_addr;
2949*c18ec02fSPetter Reinholdtsen 	uint32_t save_channel;
2950*c18ec02fSPetter Reinholdtsen 	int rc = 0;
2951*c18ec02fSPetter Reinholdtsen 
2952*c18ec02fSPetter Reinholdtsen 	if (fru == NULL)
2953*c18ec02fSPetter Reinholdtsen 		return __ipmi_fru_print(intf, 0);
2954*c18ec02fSPetter Reinholdtsen 
2955*c18ec02fSPetter Reinholdtsen 	/* Logical FRU Device
2956*c18ec02fSPetter Reinholdtsen 	*  dev_type == 0x10
2957*c18ec02fSPetter Reinholdtsen 	*  modifier
2958*c18ec02fSPetter Reinholdtsen 	*   0x00 = IPMI FRU Inventory
2959*c18ec02fSPetter Reinholdtsen 	*   0x01 = DIMM Memory ID
2960*c18ec02fSPetter Reinholdtsen 	*   0x02 = IPMI FRU Inventory
2961*c18ec02fSPetter Reinholdtsen 	*   0x03 = System Processor FRU
2962*c18ec02fSPetter Reinholdtsen 	*   0xff = unspecified
2963*c18ec02fSPetter Reinholdtsen 	*
2964*c18ec02fSPetter Reinholdtsen 	* EEPROM 24C01 or equivalent
2965*c18ec02fSPetter Reinholdtsen 	*  dev_type >= 0x08 && dev_type <= 0x0f
2966*c18ec02fSPetter Reinholdtsen 	*  modifier
2967*c18ec02fSPetter Reinholdtsen 	*   0x00 = unspecified
2968*c18ec02fSPetter Reinholdtsen 	*   0x01 = DIMM Memory ID
2969*c18ec02fSPetter Reinholdtsen 	*   0x02 = IPMI FRU Inventory
2970*c18ec02fSPetter Reinholdtsen 	*   0x03 = System Processor Cartridge
2971*c18ec02fSPetter Reinholdtsen 	*/
2972*c18ec02fSPetter Reinholdtsen 	if (fru->dev_type != 0x10 &&
2973*c18ec02fSPetter Reinholdtsen 		(fru->dev_type_modifier != 0x02 ||
2974*c18ec02fSPetter Reinholdtsen 		fru->dev_type < 0x08 || fru->dev_type > 0x0f))
2975*c18ec02fSPetter Reinholdtsen 		return -1;
2976*c18ec02fSPetter Reinholdtsen 
2977*c18ec02fSPetter Reinholdtsen 	if (fru->dev_slave_addr == IPMI_BMC_SLAVE_ADDR &&
2978*c18ec02fSPetter Reinholdtsen 		fru->device_id == 0)
2979*c18ec02fSPetter Reinholdtsen 		return 0;
2980*c18ec02fSPetter Reinholdtsen 
2981*c18ec02fSPetter Reinholdtsen 	memset(desc, 0, sizeof(desc));
2982*c18ec02fSPetter Reinholdtsen 	memcpy(desc, fru->id_string, fru->id_code & 0x01f);
2983*c18ec02fSPetter Reinholdtsen 	desc[fru->id_code & 0x01f] = 0;
2984*c18ec02fSPetter Reinholdtsen 	printf("FRU Device Description : %s (ID %d)\n", desc, fru->device_id);
2985*c18ec02fSPetter Reinholdtsen 
2986*c18ec02fSPetter Reinholdtsen 	switch (fru->dev_type_modifier) {
2987*c18ec02fSPetter Reinholdtsen 	case 0x00:
2988*c18ec02fSPetter Reinholdtsen 	case 0x02:
2989*c18ec02fSPetter Reinholdtsen 		if (BRIDGE_TO_SENSOR(intf, fru->dev_slave_addr,
2990*c18ec02fSPetter Reinholdtsen 					   fru->channel_num)) {
2991*c18ec02fSPetter Reinholdtsen 			bridged_request = 1;
2992*c18ec02fSPetter Reinholdtsen 			save_addr = intf->target_addr;
2993*c18ec02fSPetter Reinholdtsen 			intf->target_addr = fru->dev_slave_addr;
2994*c18ec02fSPetter Reinholdtsen 			save_channel = intf->target_channel;
2995*c18ec02fSPetter Reinholdtsen 			intf->target_channel = fru->channel_num;
2996*c18ec02fSPetter Reinholdtsen 		}
2997*c18ec02fSPetter Reinholdtsen 		/* print FRU */
2998*c18ec02fSPetter Reinholdtsen 		rc = __ipmi_fru_print(intf, fru->device_id);
2999*c18ec02fSPetter Reinholdtsen 		if (bridged_request) {
3000*c18ec02fSPetter Reinholdtsen 			intf->target_addr = save_addr;
3001*c18ec02fSPetter Reinholdtsen 			intf->target_channel = save_channel;
3002*c18ec02fSPetter Reinholdtsen 		}
3003*c18ec02fSPetter Reinholdtsen 		break;
3004*c18ec02fSPetter Reinholdtsen 	case 0x01:
3005*c18ec02fSPetter Reinholdtsen 		rc = ipmi_spd_print_fru(intf, fru->device_id);
3006*c18ec02fSPetter Reinholdtsen 		break;
3007*c18ec02fSPetter Reinholdtsen 	default:
3008*c18ec02fSPetter Reinholdtsen 		if (verbose)
3009*c18ec02fSPetter Reinholdtsen 			printf(" Unsupported device 0x%02x "
3010*c18ec02fSPetter Reinholdtsen 					"type 0x%02x with modifier 0x%02x\n",
3011*c18ec02fSPetter Reinholdtsen 					fru->device_id, fru->dev_type,
3012*c18ec02fSPetter Reinholdtsen 					fru->dev_type_modifier);
3013*c18ec02fSPetter Reinholdtsen 		else
3014*c18ec02fSPetter Reinholdtsen 			printf(" Unsupported device\n");
3015*c18ec02fSPetter Reinholdtsen 	}
3016*c18ec02fSPetter Reinholdtsen 	printf("\n");
3017*c18ec02fSPetter Reinholdtsen 
3018*c18ec02fSPetter Reinholdtsen 	return rc;
3019*c18ec02fSPetter Reinholdtsen }
3020*c18ec02fSPetter Reinholdtsen 
3021*c18ec02fSPetter Reinholdtsen /* ipmi_fru_print_all  -  Print builtin FRU + SDR FRU Locator records
3022*c18ec02fSPetter Reinholdtsen *
3023*c18ec02fSPetter Reinholdtsen * @intf:   ipmi interface
3024*c18ec02fSPetter Reinholdtsen *
3025*c18ec02fSPetter Reinholdtsen * returns -1 on error
3026*c18ec02fSPetter Reinholdtsen */
3027*c18ec02fSPetter Reinholdtsen static int
3028*c18ec02fSPetter Reinholdtsen ipmi_fru_print_all(struct ipmi_intf * intf)
3029*c18ec02fSPetter Reinholdtsen {
3030*c18ec02fSPetter Reinholdtsen 	struct ipmi_sdr_iterator * itr;
3031*c18ec02fSPetter Reinholdtsen 	struct sdr_get_rs * header;
3032*c18ec02fSPetter Reinholdtsen 	struct sdr_record_fru_locator * fru;
3033*c18ec02fSPetter Reinholdtsen 	int rc;
3034*c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
3035*c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
3036*c18ec02fSPetter Reinholdtsen 	struct ipm_devid_rsp *devid;
3037*c18ec02fSPetter Reinholdtsen 	struct sdr_record_mc_locator * mc;
3038*c18ec02fSPetter Reinholdtsen 	uint32_t save_addr;
3039*c18ec02fSPetter Reinholdtsen 
3040*c18ec02fSPetter Reinholdtsen 	printf("FRU Device Description : Builtin FRU Device (ID 0)\n");
3041*c18ec02fSPetter Reinholdtsen 	/* TODO: Figure out if FRU device 0 may show up in SDR records. */
3042*c18ec02fSPetter Reinholdtsen 
3043*c18ec02fSPetter Reinholdtsen 	/* Do a Get Device ID command to determine device support */
3044*c18ec02fSPetter Reinholdtsen 	memset (&req, 0, sizeof(req));
3045*c18ec02fSPetter Reinholdtsen 	req.msg.netfn = IPMI_NETFN_APP;
3046*c18ec02fSPetter Reinholdtsen 	req.msg.cmd = BMC_GET_DEVICE_ID;
3047*c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 0;
3048*c18ec02fSPetter Reinholdtsen 
3049*c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
3050*c18ec02fSPetter Reinholdtsen 	if (rsp == NULL) {
3051*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Get Device ID command failed");
3052*c18ec02fSPetter Reinholdtsen 		return -1;
3053*c18ec02fSPetter Reinholdtsen 	}
3054*c18ec02fSPetter Reinholdtsen 	if (rsp->ccode > 0) {
3055*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Get Device ID command failed: %s",
3056*c18ec02fSPetter Reinholdtsen 			val2str(rsp->ccode, completion_code_vals));
3057*c18ec02fSPetter Reinholdtsen 		return -1;
3058*c18ec02fSPetter Reinholdtsen 	}
3059*c18ec02fSPetter Reinholdtsen 
3060*c18ec02fSPetter Reinholdtsen 	devid = (struct ipm_devid_rsp *) rsp->data;
3061*c18ec02fSPetter Reinholdtsen 
3062*c18ec02fSPetter Reinholdtsen 	/* Check the FRU inventory device bit to decide whether various */
3063*c18ec02fSPetter Reinholdtsen 	/* FRU commands can be issued to FRU device #0 LUN 0		*/
3064*c18ec02fSPetter Reinholdtsen 
3065*c18ec02fSPetter Reinholdtsen 	if (devid->adtl_device_support & 0x08) {	/* FRU Inventory Device bit? */
3066*c18ec02fSPetter Reinholdtsen 		rc = ipmi_fru_print(intf, NULL);
3067*c18ec02fSPetter Reinholdtsen 		printf("\n");
3068*c18ec02fSPetter Reinholdtsen 	}
3069*c18ec02fSPetter Reinholdtsen 
3070*c18ec02fSPetter Reinholdtsen 	if ((itr = ipmi_sdr_start(intf, 0)) == NULL)
3071*c18ec02fSPetter Reinholdtsen 		return -1;
3072*c18ec02fSPetter Reinholdtsen 
3073*c18ec02fSPetter Reinholdtsen 	/* Walk the SDRs looking for FRU Devices and Management Controller Devices. */
3074*c18ec02fSPetter Reinholdtsen 	/* For FRU devices, print the FRU from the SDR locator record.		    */
3075*c18ec02fSPetter Reinholdtsen 	/* For MC devices, issue FRU commands to the satellite controller to print  */
3076*c18ec02fSPetter Reinholdtsen 	/* FRU data.								    */
3077*c18ec02fSPetter Reinholdtsen 	while ((header = ipmi_sdr_get_next_header(intf, itr)) != NULL)
3078*c18ec02fSPetter Reinholdtsen 	{
3079*c18ec02fSPetter Reinholdtsen 		if (header->type == SDR_RECORD_TYPE_MC_DEVICE_LOCATOR ) {
3080*c18ec02fSPetter Reinholdtsen 			/* Check the capabilities of the Management Controller Device */
3081*c18ec02fSPetter Reinholdtsen 			mc = (struct sdr_record_mc_locator *)
3082*c18ec02fSPetter Reinholdtsen 				ipmi_sdr_get_record(intf, header, itr);
3083*c18ec02fSPetter Reinholdtsen 			/* Does this MC device support FRU inventory device? */
3084*c18ec02fSPetter Reinholdtsen 			if (mc && (mc->dev_support & 0x08)) {	 /* FRU inventory device? */
3085*c18ec02fSPetter Reinholdtsen 				/* Yes. Prepare to issue FRU commands to FRU device #0 LUN 0  */
3086*c18ec02fSPetter Reinholdtsen 				/* using the slave address specified in the MC record.	      */
3087*c18ec02fSPetter Reinholdtsen 
3088*c18ec02fSPetter Reinholdtsen 				/* save current target address */
3089*c18ec02fSPetter Reinholdtsen 				save_addr = intf->target_addr;
3090*c18ec02fSPetter Reinholdtsen 
3091*c18ec02fSPetter Reinholdtsen 				/* set new target address to satellite controller */
3092*c18ec02fSPetter Reinholdtsen 				intf->target_addr = mc->dev_slave_addr;
3093*c18ec02fSPetter Reinholdtsen 
3094*c18ec02fSPetter Reinholdtsen 				printf("FRU Device Description : %-16s\n", mc->id_string);
3095*c18ec02fSPetter Reinholdtsen 
3096*c18ec02fSPetter Reinholdtsen 				/* print the FRU by issuing FRU commands to the satellite     */
3097*c18ec02fSPetter Reinholdtsen 				/* controller.						      */
3098*c18ec02fSPetter Reinholdtsen 				rc = __ipmi_fru_print(intf, 0);
3099*c18ec02fSPetter Reinholdtsen 
3100*c18ec02fSPetter Reinholdtsen 				printf("\n");
3101*c18ec02fSPetter Reinholdtsen 
3102*c18ec02fSPetter Reinholdtsen 				/* restore previous target */
3103*c18ec02fSPetter Reinholdtsen 				intf->target_addr = save_addr;
3104*c18ec02fSPetter Reinholdtsen 			}
3105*c18ec02fSPetter Reinholdtsen 
3106*c18ec02fSPetter Reinholdtsen 			if (mc) {
3107*c18ec02fSPetter Reinholdtsen 				free(mc);
3108*c18ec02fSPetter Reinholdtsen 				mc = NULL;
3109*c18ec02fSPetter Reinholdtsen 			}
3110*c18ec02fSPetter Reinholdtsen 
3111*c18ec02fSPetter Reinholdtsen 			continue;
3112*c18ec02fSPetter Reinholdtsen 		}
3113*c18ec02fSPetter Reinholdtsen 
3114*c18ec02fSPetter Reinholdtsen 		if (header->type != SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR)
3115*c18ec02fSPetter Reinholdtsen 			continue;
3116*c18ec02fSPetter Reinholdtsen 
3117*c18ec02fSPetter Reinholdtsen 		/* Print the FRU from the SDR locator record. */
3118*c18ec02fSPetter Reinholdtsen 		fru = (struct sdr_record_fru_locator *)
3119*c18ec02fSPetter Reinholdtsen 			ipmi_sdr_get_record(intf, header, itr);
3120*c18ec02fSPetter Reinholdtsen 		if (fru == NULL || !fru->logical) {
3121*c18ec02fSPetter Reinholdtsen 			if (fru) {
3122*c18ec02fSPetter Reinholdtsen 				free(fru);
3123*c18ec02fSPetter Reinholdtsen 				fru = NULL;
3124*c18ec02fSPetter Reinholdtsen 			}
3125*c18ec02fSPetter Reinholdtsen 			continue;
3126*c18ec02fSPetter Reinholdtsen 		}
3127*c18ec02fSPetter Reinholdtsen 		rc = ipmi_fru_print(intf, fru);
3128*c18ec02fSPetter Reinholdtsen 		free(fru);
3129*c18ec02fSPetter Reinholdtsen 		fru = NULL;
3130*c18ec02fSPetter Reinholdtsen 	}
3131*c18ec02fSPetter Reinholdtsen 
3132*c18ec02fSPetter Reinholdtsen 	ipmi_sdr_end(intf, itr);
3133*c18ec02fSPetter Reinholdtsen 
3134*c18ec02fSPetter Reinholdtsen 	return rc;
3135*c18ec02fSPetter Reinholdtsen }
3136*c18ec02fSPetter Reinholdtsen 
3137*c18ec02fSPetter Reinholdtsen /* ipmi_fru_read_help() - print help text for 'read'
3138*c18ec02fSPetter Reinholdtsen  *
3139*c18ec02fSPetter Reinholdtsen  * returns void
3140*c18ec02fSPetter Reinholdtsen  */
3141*c18ec02fSPetter Reinholdtsen void
3142*c18ec02fSPetter Reinholdtsen ipmi_fru_read_help()
3143*c18ec02fSPetter Reinholdtsen {
3144*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_NOTICE, "fru read <fru id> <fru file>");
3145*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_NOTICE, "Note: FRU ID and file(incl. full path) must be specified.");
3146*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_NOTICE, "Example: ipmitool fru read 0 /root/fru.bin");
3147*c18ec02fSPetter Reinholdtsen } /* ipmi_fru_read_help() */
3148*c18ec02fSPetter Reinholdtsen 
3149*c18ec02fSPetter Reinholdtsen static void
3150*c18ec02fSPetter Reinholdtsen ipmi_fru_read_to_bin(struct ipmi_intf * intf,
3151*c18ec02fSPetter Reinholdtsen 			char * pFileName,
3152*c18ec02fSPetter Reinholdtsen 			uint8_t fruId)
3153*c18ec02fSPetter Reinholdtsen {
3154*c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
3155*c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
3156*c18ec02fSPetter Reinholdtsen 	struct fru_info fru;
3157*c18ec02fSPetter Reinholdtsen 	uint8_t msg_data[4];
3158*c18ec02fSPetter Reinholdtsen 	uint8_t * pFruBuf;
3159*c18ec02fSPetter Reinholdtsen 
3160*c18ec02fSPetter Reinholdtsen 	msg_data[0] = fruId;
3161*c18ec02fSPetter Reinholdtsen 
3162*c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
3163*c18ec02fSPetter Reinholdtsen 	req.msg.netfn = IPMI_NETFN_STORAGE;
3164*c18ec02fSPetter Reinholdtsen 	req.msg.cmd = GET_FRU_INFO;
3165*c18ec02fSPetter Reinholdtsen 	req.msg.data = msg_data;
3166*c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 1;
3167*c18ec02fSPetter Reinholdtsen 
3168*c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
3169*c18ec02fSPetter Reinholdtsen 	if (!rsp)
3170*c18ec02fSPetter Reinholdtsen 		return;
3171*c18ec02fSPetter Reinholdtsen 
3172*c18ec02fSPetter Reinholdtsen 	if (rsp->ccode > 0) {
3173*c18ec02fSPetter Reinholdtsen 		if (rsp->ccode == 0xc3)
3174*c18ec02fSPetter Reinholdtsen 			printf ("  Timeout accessing FRU info. (Device not present?)\n");
3175*c18ec02fSPetter Reinholdtsen 		return;
3176*c18ec02fSPetter Reinholdtsen 	}
3177*c18ec02fSPetter Reinholdtsen 
3178*c18ec02fSPetter Reinholdtsen 	memset(&fru, 0, sizeof(fru));
3179*c18ec02fSPetter Reinholdtsen 	fru.size = (rsp->data[1] << 8) | rsp->data[0];
3180*c18ec02fSPetter Reinholdtsen 	fru.access = rsp->data[2] & 0x1;
3181*c18ec02fSPetter Reinholdtsen 
3182*c18ec02fSPetter Reinholdtsen 	if (verbose) {
3183*c18ec02fSPetter Reinholdtsen 		printf("Fru Size   = %d bytes\n",fru.size);
3184*c18ec02fSPetter Reinholdtsen 		printf("Fru Access = %xh\n", fru.access);
3185*c18ec02fSPetter Reinholdtsen 	}
3186*c18ec02fSPetter Reinholdtsen 
3187*c18ec02fSPetter Reinholdtsen 	pFruBuf = malloc(fru.size);
3188*c18ec02fSPetter Reinholdtsen 	if (pFruBuf != NULL) {
3189*c18ec02fSPetter Reinholdtsen 		printf("Fru Size         : %d bytes\n",fru.size);
3190*c18ec02fSPetter Reinholdtsen 		read_fru_area(intf, &fru, fruId, 0, fru.size, pFruBuf);
3191*c18ec02fSPetter Reinholdtsen 	} else {
3192*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Cannot allocate %d bytes\n", fru.size);
3193*c18ec02fSPetter Reinholdtsen 		return;
3194*c18ec02fSPetter Reinholdtsen 	}
3195*c18ec02fSPetter Reinholdtsen 
3196*c18ec02fSPetter Reinholdtsen 	if(pFruBuf != NULL)
3197*c18ec02fSPetter Reinholdtsen 	{
3198*c18ec02fSPetter Reinholdtsen 		FILE * pFile;
3199*c18ec02fSPetter Reinholdtsen 		pFile = fopen(pFileName,"wb");
3200*c18ec02fSPetter Reinholdtsen 		if (pFile) {
3201*c18ec02fSPetter Reinholdtsen 			fwrite(pFruBuf, fru.size, 1, pFile);
3202*c18ec02fSPetter Reinholdtsen 			printf("Done\n");
3203*c18ec02fSPetter Reinholdtsen 		} else {
3204*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "Error opening file %s\n", pFileName);
3205*c18ec02fSPetter Reinholdtsen 			free(pFruBuf);
3206*c18ec02fSPetter Reinholdtsen 			pFruBuf = NULL;
3207*c18ec02fSPetter Reinholdtsen 			return;
3208*c18ec02fSPetter Reinholdtsen 		}
3209*c18ec02fSPetter Reinholdtsen 		fclose(pFile);
3210*c18ec02fSPetter Reinholdtsen 	}
3211*c18ec02fSPetter Reinholdtsen 	free(pFruBuf);
3212*c18ec02fSPetter Reinholdtsen 	pFruBuf = NULL;
3213*c18ec02fSPetter Reinholdtsen }
3214*c18ec02fSPetter Reinholdtsen 
3215*c18ec02fSPetter Reinholdtsen static void
3216*c18ec02fSPetter Reinholdtsen ipmi_fru_write_from_bin(struct ipmi_intf * intf,
3217*c18ec02fSPetter Reinholdtsen 			char * pFileName,
3218*c18ec02fSPetter Reinholdtsen 			uint8_t fruId)
3219*c18ec02fSPetter Reinholdtsen {
3220*c18ec02fSPetter Reinholdtsen 	struct ipmi_rs *rsp;
3221*c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
3222*c18ec02fSPetter Reinholdtsen 	struct fru_info fru;
3223*c18ec02fSPetter Reinholdtsen 	uint8_t msg_data[4];
3224*c18ec02fSPetter Reinholdtsen 	uint8_t *pFruBuf;
3225*c18ec02fSPetter Reinholdtsen 	uint16_t len = 0;
3226*c18ec02fSPetter Reinholdtsen 	FILE *pFile;
3227*c18ec02fSPetter Reinholdtsen 
3228*c18ec02fSPetter Reinholdtsen 	msg_data[0] = fruId;
3229*c18ec02fSPetter Reinholdtsen 
3230*c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof (req));
3231*c18ec02fSPetter Reinholdtsen 	req.msg.netfn = IPMI_NETFN_STORAGE;
3232*c18ec02fSPetter Reinholdtsen 	req.msg.cmd = GET_FRU_INFO;
3233*c18ec02fSPetter Reinholdtsen 	req.msg.data = msg_data;
3234*c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 1;
3235*c18ec02fSPetter Reinholdtsen 
3236*c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
3237*c18ec02fSPetter Reinholdtsen 	if (!rsp)
3238*c18ec02fSPetter Reinholdtsen 		return;
3239*c18ec02fSPetter Reinholdtsen 
3240*c18ec02fSPetter Reinholdtsen 	if (rsp->ccode) {
3241*c18ec02fSPetter Reinholdtsen 		if (rsp->ccode == 0xc3)
3242*c18ec02fSPetter Reinholdtsen 			printf("  Timeout accessing FRU info. (Device not present?)\n");
3243*c18ec02fSPetter Reinholdtsen 		return;
3244*c18ec02fSPetter Reinholdtsen 	}
3245*c18ec02fSPetter Reinholdtsen 
3246*c18ec02fSPetter Reinholdtsen 	memset(&fru, 0, sizeof(fru));
3247*c18ec02fSPetter Reinholdtsen 	fru.size = (rsp->data[1] << 8) | rsp->data[0];
3248*c18ec02fSPetter Reinholdtsen 	fru.access = rsp->data[2] & 0x1;
3249*c18ec02fSPetter Reinholdtsen 
3250*c18ec02fSPetter Reinholdtsen 	if (verbose) {
3251*c18ec02fSPetter Reinholdtsen 		printf("Fru Size   = %d bytes\n", fru.size);
3252*c18ec02fSPetter Reinholdtsen 		printf("Fru Access = %xh\n", fru.access);
3253*c18ec02fSPetter Reinholdtsen 	}
3254*c18ec02fSPetter Reinholdtsen 
3255*c18ec02fSPetter Reinholdtsen 	pFruBuf = malloc(fru.size);
3256*c18ec02fSPetter Reinholdtsen 	if (pFruBuf == NULL) {
3257*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Cannot allocate %d bytes\n", fru.size);
3258*c18ec02fSPetter Reinholdtsen 		return;
3259*c18ec02fSPetter Reinholdtsen 	}
3260*c18ec02fSPetter Reinholdtsen 
3261*c18ec02fSPetter Reinholdtsen 		pFile = fopen(pFileName, "rb");
3262*c18ec02fSPetter Reinholdtsen 		if (pFile != NULL) {
3263*c18ec02fSPetter Reinholdtsen 			len = fread(pFruBuf, 1, fru.size, pFile);
3264*c18ec02fSPetter Reinholdtsen 			printf("Fru Size         : %d bytes\n", fru.size);
3265*c18ec02fSPetter Reinholdtsen 			printf("Size to Write    : %d bytes\n", len);
3266*c18ec02fSPetter Reinholdtsen 			fclose(pFile);
3267*c18ec02fSPetter Reinholdtsen 		} else {
3268*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Error opening file %s\n", pFileName);
3269*c18ec02fSPetter Reinholdtsen 		}
3270*c18ec02fSPetter Reinholdtsen 
3271*c18ec02fSPetter Reinholdtsen 		if (len != 0) {
3272*c18ec02fSPetter Reinholdtsen 			write_fru_area(intf, &fru, fruId,0, 0, len, pFruBuf);
3273*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_INFO,"Done");
3274*c18ec02fSPetter Reinholdtsen 		}
3275*c18ec02fSPetter Reinholdtsen 
3276*c18ec02fSPetter Reinholdtsen 	free(pFruBuf);
3277*c18ec02fSPetter Reinholdtsen 	pFruBuf = NULL;
3278*c18ec02fSPetter Reinholdtsen }
3279*c18ec02fSPetter Reinholdtsen 
3280*c18ec02fSPetter Reinholdtsen /* ipmi_fru_write_help() - print help text for 'write'
3281*c18ec02fSPetter Reinholdtsen  *
3282*c18ec02fSPetter Reinholdtsen  * retruns void
3283*c18ec02fSPetter Reinholdtsen  */
3284*c18ec02fSPetter Reinholdtsen void
3285*c18ec02fSPetter Reinholdtsen ipmi_fru_write_help()
3286*c18ec02fSPetter Reinholdtsen {
3287*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_NOTICE, "fru write <fru id> <fru file>");
3288*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_NOTICE, "Note: FRU ID and file(incl. full path) must be specified.");
3289*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_NOTICE, "Example: ipmitool fru write 0 /root/fru.bin");
3290*c18ec02fSPetter Reinholdtsen } /* ipmi_fru_write_help() */
3291*c18ec02fSPetter Reinholdtsen 
3292*c18ec02fSPetter Reinholdtsen /* ipmi_fru_edit_help - print help text for 'fru edit' command
3293*c18ec02fSPetter Reinholdtsen  *
3294*c18ec02fSPetter Reinholdtsen  * returns void
3295*c18ec02fSPetter Reinholdtsen  */
3296*c18ec02fSPetter Reinholdtsen void
3297*c18ec02fSPetter Reinholdtsen ipmi_fru_edit_help()
3298*c18ec02fSPetter Reinholdtsen {
3299*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_NOTICE,
3300*c18ec02fSPetter Reinholdtsen 			"fru edit <fruid> field <section> <index> <string> - edit FRU string");
3301*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_NOTICE,
3302*c18ec02fSPetter Reinholdtsen 			"fru edit <fruid> oem iana <record> <format> <args> - limited OEM support");
3303*c18ec02fSPetter Reinholdtsen } /* ipmi_fru_edit_help() */
3304*c18ec02fSPetter Reinholdtsen 
3305*c18ec02fSPetter Reinholdtsen /* ipmi_fru_edit_multirec  -  Query new values to replace original FRU content
3306*c18ec02fSPetter Reinholdtsen *
3307*c18ec02fSPetter Reinholdtsen * @intf:   interface to use
3308*c18ec02fSPetter Reinholdtsen * @id:  FRU id to work on
3309*c18ec02fSPetter Reinholdtsen *
3310*c18ec02fSPetter Reinholdtsen * returns: nothing
3311*c18ec02fSPetter Reinholdtsen */
3312*c18ec02fSPetter Reinholdtsen /* Work in progress, copy paste most of the stuff for other functions in this
3313*c18ec02fSPetter Reinholdtsen 	file ... not elegant yet */
3314*c18ec02fSPetter Reinholdtsen static int
3315*c18ec02fSPetter Reinholdtsen ipmi_fru_edit_multirec(struct ipmi_intf * intf, uint8_t id ,
3316*c18ec02fSPetter Reinholdtsen 												int argc, char ** argv)
3317*c18ec02fSPetter Reinholdtsen {
3318*c18ec02fSPetter Reinholdtsen 
3319*c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
3320*c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
3321*c18ec02fSPetter Reinholdtsen 	struct fru_info fru;
3322*c18ec02fSPetter Reinholdtsen 	struct fru_header header;
3323*c18ec02fSPetter Reinholdtsen 	uint8_t msg_data[4];
3324*c18ec02fSPetter Reinholdtsen 
3325*c18ec02fSPetter Reinholdtsen 	uint16_t retStatus = 0;
3326*c18ec02fSPetter Reinholdtsen 	uint32_t offFruMultiRec;
3327*c18ec02fSPetter Reinholdtsen 	uint32_t fruMultiRecSize = 0;
3328*c18ec02fSPetter Reinholdtsen 	struct fru_info fruInfo;
3329*c18ec02fSPetter Reinholdtsen 	retStatus = ipmi_fru_get_multirec_location_from_fru(intf, id, &fruInfo,
3330*c18ec02fSPetter Reinholdtsen 								&offFruMultiRec,
3331*c18ec02fSPetter Reinholdtsen 								&fruMultiRecSize);
3332*c18ec02fSPetter Reinholdtsen 
3333*c18ec02fSPetter Reinholdtsen 
3334*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "FRU Size        : %lu\n", fruMultiRecSize);
3335*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "Multi Rec offset: %lu\n", offFruMultiRec);
3336*c18ec02fSPetter Reinholdtsen 
3337*c18ec02fSPetter Reinholdtsen 	{
3338*c18ec02fSPetter Reinholdtsen 
3339*c18ec02fSPetter Reinholdtsen 
3340*c18ec02fSPetter Reinholdtsen 	memset(&fru, 0, sizeof(struct fru_info));
3341*c18ec02fSPetter Reinholdtsen 	memset(&header, 0, sizeof(struct fru_header));
3342*c18ec02fSPetter Reinholdtsen 
3343*c18ec02fSPetter Reinholdtsen 	/*
3344*c18ec02fSPetter Reinholdtsen 	* get info about this FRU
3345*c18ec02fSPetter Reinholdtsen 	*/
3346*c18ec02fSPetter Reinholdtsen 	memset(msg_data, 0, 4);
3347*c18ec02fSPetter Reinholdtsen 	msg_data[0] = id;
3348*c18ec02fSPetter Reinholdtsen 
3349*c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
3350*c18ec02fSPetter Reinholdtsen 	req.msg.netfn = IPMI_NETFN_STORAGE;
3351*c18ec02fSPetter Reinholdtsen 	req.msg.cmd = GET_FRU_INFO;
3352*c18ec02fSPetter Reinholdtsen 	req.msg.data = msg_data;
3353*c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 1;
3354*c18ec02fSPetter Reinholdtsen 
3355*c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
3356*c18ec02fSPetter Reinholdtsen 	if (rsp == NULL) {
3357*c18ec02fSPetter Reinholdtsen 		printf(" Device not present (No Response)\n");
3358*c18ec02fSPetter Reinholdtsen 		return -1;
3359*c18ec02fSPetter Reinholdtsen 	}
3360*c18ec02fSPetter Reinholdtsen 	if (rsp->ccode > 0) {
3361*c18ec02fSPetter Reinholdtsen 		printf(" Device not present (%s)\n",
3362*c18ec02fSPetter Reinholdtsen 			val2str(rsp->ccode, completion_code_vals));
3363*c18ec02fSPetter Reinholdtsen 		return -1;
3364*c18ec02fSPetter Reinholdtsen 	}
3365*c18ec02fSPetter Reinholdtsen 
3366*c18ec02fSPetter Reinholdtsen 	memset(&fru, 0, sizeof(fru));
3367*c18ec02fSPetter Reinholdtsen 	fru.size = (rsp->data[1] << 8) | rsp->data[0];
3368*c18ec02fSPetter Reinholdtsen 	fru.access = rsp->data[2] & 0x1;
3369*c18ec02fSPetter Reinholdtsen 
3370*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "fru.size = %d bytes (accessed by %s)",
3371*c18ec02fSPetter Reinholdtsen 		fru.size, fru.access ? "words" : "bytes");
3372*c18ec02fSPetter Reinholdtsen 
3373*c18ec02fSPetter Reinholdtsen 	if (fru.size < 1) {
3374*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, " Invalid FRU size %d", fru.size);
3375*c18ec02fSPetter Reinholdtsen 		return -1;
3376*c18ec02fSPetter Reinholdtsen 	}
3377*c18ec02fSPetter Reinholdtsen 	}
3378*c18ec02fSPetter Reinholdtsen 
3379*c18ec02fSPetter Reinholdtsen 	{
3380*c18ec02fSPetter Reinholdtsen 		uint8_t * fru_data;
3381*c18ec02fSPetter Reinholdtsen 		uint32_t fru_len, i;
3382*c18ec02fSPetter Reinholdtsen 		uint32_t offset= offFruMultiRec;
3383*c18ec02fSPetter Reinholdtsen 		struct fru_multirec_header * h;
3384*c18ec02fSPetter Reinholdtsen 		uint32_t last_off, len;
3385*c18ec02fSPetter Reinholdtsen 		uint8_t error=0;
3386*c18ec02fSPetter Reinholdtsen 
3387*c18ec02fSPetter Reinholdtsen 		i = last_off = offset;
3388*c18ec02fSPetter Reinholdtsen 		fru_len = 0;
3389*c18ec02fSPetter Reinholdtsen 
3390*c18ec02fSPetter Reinholdtsen 		memset(&fru, 0, sizeof(fru));
3391*c18ec02fSPetter Reinholdtsen 		fru_data = malloc(fru.size + 1);
3392*c18ec02fSPetter Reinholdtsen 		if (fru_data == NULL) {
3393*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, " Out of memory!");
3394*c18ec02fSPetter Reinholdtsen 			return -1;
3395*c18ec02fSPetter Reinholdtsen 		}
3396*c18ec02fSPetter Reinholdtsen 		memset(fru_data, 0, fru.size + 1);
3397*c18ec02fSPetter Reinholdtsen 
3398*c18ec02fSPetter Reinholdtsen 		do {
3399*c18ec02fSPetter Reinholdtsen 			h = (struct fru_multirec_header *) (fru_data + i);
3400*c18ec02fSPetter Reinholdtsen 
3401*c18ec02fSPetter Reinholdtsen 			/* read area in (at most) FRU_MULTIREC_CHUNK_SIZE bytes at a time */
3402*c18ec02fSPetter Reinholdtsen 			if ((last_off < (i + sizeof(*h))) || (last_off < (i + h->len)))
3403*c18ec02fSPetter Reinholdtsen 			{
3404*c18ec02fSPetter Reinholdtsen 				len = fru.size - last_off;
3405*c18ec02fSPetter Reinholdtsen 				if (len > FRU_MULTIREC_CHUNK_SIZE)
3406*c18ec02fSPetter Reinholdtsen 					len = FRU_MULTIREC_CHUNK_SIZE;
3407*c18ec02fSPetter Reinholdtsen 
3408*c18ec02fSPetter Reinholdtsen 				if (read_fru_area(intf, &fru, id, last_off, len, fru_data) < 0)
3409*c18ec02fSPetter Reinholdtsen 					break;
3410*c18ec02fSPetter Reinholdtsen 
3411*c18ec02fSPetter Reinholdtsen 				last_off += len;
3412*c18ec02fSPetter Reinholdtsen 			}
3413*c18ec02fSPetter Reinholdtsen 			if( h->type ==  FRU_RECORD_TYPE_OEM_EXTENSION ){
3414*c18ec02fSPetter Reinholdtsen 
3415*c18ec02fSPetter Reinholdtsen 				struct fru_multirec_oem_header *oh=(struct fru_multirec_oem_header *)
3416*c18ec02fSPetter Reinholdtsen 										&fru_data[i + sizeof(struct fru_multirec_header)];
3417*c18ec02fSPetter Reinholdtsen 				uint32_t iana = oh->mfg_id[0] | oh->mfg_id[1]<<8 | oh->mfg_id[2]<<16;
3418*c18ec02fSPetter Reinholdtsen 
3419*c18ec02fSPetter Reinholdtsen 				uint32_t suppliedIana = 0 ;
3420*c18ec02fSPetter Reinholdtsen 				/* Now makes sure this is really PICMG record */
3421*c18ec02fSPetter Reinholdtsen 
3422*c18ec02fSPetter Reinholdtsen 				/* Default to PICMG for backward compatibility */
3423*c18ec02fSPetter Reinholdtsen 				if( argc <=2 ) {
3424*c18ec02fSPetter Reinholdtsen 					suppliedIana =  IPMI_OEM_PICMG;
3425*c18ec02fSPetter Reinholdtsen 				}  else {
3426*c18ec02fSPetter Reinholdtsen 					if( !strncmp( argv[2] , "oem" , 3 )) {
3427*c18ec02fSPetter Reinholdtsen 						/* Expect IANA number next */
3428*c18ec02fSPetter Reinholdtsen 						if( argc <= 3 ) {
3429*c18ec02fSPetter Reinholdtsen 							lprintf(LOG_ERR, "oem iana <record> <format> [<args>]");
3430*c18ec02fSPetter Reinholdtsen 							error = 1;
3431*c18ec02fSPetter Reinholdtsen 						} else {
3432*c18ec02fSPetter Reinholdtsen 							if (str2uint(argv[3], &suppliedIana) == 0) {
3433*c18ec02fSPetter Reinholdtsen 								lprintf(LOG_DEBUG,
3434*c18ec02fSPetter Reinholdtsen 										"using iana: %d",
3435*c18ec02fSPetter Reinholdtsen 										suppliedIana);
3436*c18ec02fSPetter Reinholdtsen 							} else {
3437*c18ec02fSPetter Reinholdtsen 								lprintf(LOG_ERR,
3438*c18ec02fSPetter Reinholdtsen 										"Given IANA '%s' is invalid.",
3439*c18ec02fSPetter Reinholdtsen 										argv[3]);
3440*c18ec02fSPetter Reinholdtsen 								error = 1;
3441*c18ec02fSPetter Reinholdtsen 							}
3442*c18ec02fSPetter Reinholdtsen 						}
3443*c18ec02fSPetter Reinholdtsen 					}
3444*c18ec02fSPetter Reinholdtsen 				}
3445*c18ec02fSPetter Reinholdtsen 
3446*c18ec02fSPetter Reinholdtsen 				if( suppliedIana == iana ) {
3447*c18ec02fSPetter Reinholdtsen 					lprintf(LOG_DEBUG, "Matching record found" );
3448*c18ec02fSPetter Reinholdtsen 
3449*c18ec02fSPetter Reinholdtsen 					if( iana == IPMI_OEM_PICMG ){
3450*c18ec02fSPetter Reinholdtsen 						if( ipmi_fru_picmg_ext_edit(fru_data,
3451*c18ec02fSPetter Reinholdtsen 						i + sizeof(struct fru_multirec_header),
3452*c18ec02fSPetter Reinholdtsen 						h->len, h, oh )){
3453*c18ec02fSPetter Reinholdtsen 							/* The fru changed */
3454*c18ec02fSPetter Reinholdtsen 							write_fru_area(intf,&fru,id, i,i,
3455*c18ec02fSPetter Reinholdtsen 						h->len+ sizeof(struct fru_multirec_header), fru_data);
3456*c18ec02fSPetter Reinholdtsen 						}
3457*c18ec02fSPetter Reinholdtsen 					}
3458*c18ec02fSPetter Reinholdtsen 					else if( iana == IPMI_OEM_KONTRON ) {
3459*c18ec02fSPetter Reinholdtsen 						if( ipmi_fru_oemkontron_edit( argc,argv,fru_data,
3460*c18ec02fSPetter Reinholdtsen 						i + sizeof(struct fru_multirec_header),
3461*c18ec02fSPetter Reinholdtsen 						h->len, h, oh )){
3462*c18ec02fSPetter Reinholdtsen 							/* The fru changed */
3463*c18ec02fSPetter Reinholdtsen 							write_fru_area(intf,&fru,id, i,i,
3464*c18ec02fSPetter Reinholdtsen 						h->len+ sizeof(struct fru_multirec_header), fru_data);
3465*c18ec02fSPetter Reinholdtsen 						}
3466*c18ec02fSPetter Reinholdtsen 					}
3467*c18ec02fSPetter Reinholdtsen 					/* FIXME: Add OEM record support here */
3468*c18ec02fSPetter Reinholdtsen 					else{
3469*c18ec02fSPetter Reinholdtsen 						printf("  OEM IANA (%s) Record not support in this mode\n",
3470*c18ec02fSPetter Reinholdtsen 															val2str( iana,  ipmi_oem_info));
3471*c18ec02fSPetter Reinholdtsen 						error = 1;
3472*c18ec02fSPetter Reinholdtsen 					}
3473*c18ec02fSPetter Reinholdtsen 				}
3474*c18ec02fSPetter Reinholdtsen 			}
3475*c18ec02fSPetter Reinholdtsen 			i += h->len + sizeof (struct fru_multirec_header);
3476*c18ec02fSPetter Reinholdtsen 		} while (!(h->format & 0x80) && (error != 1));
3477*c18ec02fSPetter Reinholdtsen 
3478*c18ec02fSPetter Reinholdtsen 		free(fru_data);
3479*c18ec02fSPetter Reinholdtsen 		fru_data = NULL;
3480*c18ec02fSPetter Reinholdtsen 	}
3481*c18ec02fSPetter Reinholdtsen 	return 0;
3482*c18ec02fSPetter Reinholdtsen }
3483*c18ec02fSPetter Reinholdtsen 
3484*c18ec02fSPetter Reinholdtsen /* ipmi_fru_get_help - print help text for 'fru get'
3485*c18ec02fSPetter Reinholdtsen  *
3486*c18ec02fSPetter Reinholdtsen  * returns void
3487*c18ec02fSPetter Reinholdtsen  */
3488*c18ec02fSPetter Reinholdtsen void
3489*c18ec02fSPetter Reinholdtsen ipmi_fru_get_help()
3490*c18ec02fSPetter Reinholdtsen {
3491*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_NOTICE,
3492*c18ec02fSPetter Reinholdtsen 			"fru get <fruid> oem iana <record> <format> <args> - limited OEM support");
3493*c18ec02fSPetter Reinholdtsen } /* ipmi_fru_get_help() */
3494*c18ec02fSPetter Reinholdtsen 
3495*c18ec02fSPetter Reinholdtsen void
3496*c18ec02fSPetter Reinholdtsen ipmi_fru_internaluse_help()
3497*c18ec02fSPetter Reinholdtsen {
3498*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_NOTICE,
3499*c18ec02fSPetter Reinholdtsen 			"fru internaluse <fru id> info             - get internal use area size");
3500*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_NOTICE,
3501*c18ec02fSPetter Reinholdtsen 			"fru internaluse <fru id> print            - print internal use area in hex");
3502*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_NOTICE,
3503*c18ec02fSPetter Reinholdtsen 			"fru internaluse <fru id> read  <fru file> - read internal use area to file");
3504*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_NOTICE,
3505*c18ec02fSPetter Reinholdtsen 			"fru internaluse <fru id> write <fru file> - write internal use area from file");
3506*c18ec02fSPetter Reinholdtsen } /* void ipmi_fru_internaluse_help() */
3507*c18ec02fSPetter Reinholdtsen 
3508*c18ec02fSPetter Reinholdtsen /* ipmi_fru_get_multirec   -  Query new values to replace original FRU content
3509*c18ec02fSPetter Reinholdtsen *
3510*c18ec02fSPetter Reinholdtsen * @intf:   interface to use
3511*c18ec02fSPetter Reinholdtsen * @id:  FRU id to work on
3512*c18ec02fSPetter Reinholdtsen *
3513*c18ec02fSPetter Reinholdtsen * returns: nothing
3514*c18ec02fSPetter Reinholdtsen */
3515*c18ec02fSPetter Reinholdtsen /* Work in progress, copy paste most of the stuff for other functions in this
3516*c18ec02fSPetter Reinholdtsen 	file ... not elegant yet */
3517*c18ec02fSPetter Reinholdtsen static int
3518*c18ec02fSPetter Reinholdtsen ipmi_fru_get_multirec(struct ipmi_intf * intf, uint8_t id ,
3519*c18ec02fSPetter Reinholdtsen 												int argc, char ** argv)
3520*c18ec02fSPetter Reinholdtsen {
3521*c18ec02fSPetter Reinholdtsen 
3522*c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
3523*c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
3524*c18ec02fSPetter Reinholdtsen 	struct fru_info fru;
3525*c18ec02fSPetter Reinholdtsen 	struct fru_header header;
3526*c18ec02fSPetter Reinholdtsen 	uint8_t msg_data[4];
3527*c18ec02fSPetter Reinholdtsen 
3528*c18ec02fSPetter Reinholdtsen 	uint16_t retStatus = 0;
3529*c18ec02fSPetter Reinholdtsen 	uint32_t offFruMultiRec;
3530*c18ec02fSPetter Reinholdtsen 	uint32_t fruMultiRecSize = 0;
3531*c18ec02fSPetter Reinholdtsen 	struct fru_info fruInfo;
3532*c18ec02fSPetter Reinholdtsen 	retStatus = ipmi_fru_get_multirec_location_from_fru(intf, id, &fruInfo,
3533*c18ec02fSPetter Reinholdtsen 								&offFruMultiRec,
3534*c18ec02fSPetter Reinholdtsen 								&fruMultiRecSize);
3535*c18ec02fSPetter Reinholdtsen 
3536*c18ec02fSPetter Reinholdtsen 
3537*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "FRU Size        : %lu\n", fruMultiRecSize);
3538*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "Multi Rec offset: %lu\n", offFruMultiRec);
3539*c18ec02fSPetter Reinholdtsen 
3540*c18ec02fSPetter Reinholdtsen 	{
3541*c18ec02fSPetter Reinholdtsen 
3542*c18ec02fSPetter Reinholdtsen 
3543*c18ec02fSPetter Reinholdtsen 	memset(&fru, 0, sizeof(struct fru_info));
3544*c18ec02fSPetter Reinholdtsen 	memset(&header, 0, sizeof(struct fru_header));
3545*c18ec02fSPetter Reinholdtsen 
3546*c18ec02fSPetter Reinholdtsen 	/*
3547*c18ec02fSPetter Reinholdtsen 	* get info about this FRU
3548*c18ec02fSPetter Reinholdtsen 	*/
3549*c18ec02fSPetter Reinholdtsen 	memset(msg_data, 0, 4);
3550*c18ec02fSPetter Reinholdtsen 	msg_data[0] = id;
3551*c18ec02fSPetter Reinholdtsen 
3552*c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
3553*c18ec02fSPetter Reinholdtsen 	req.msg.netfn = IPMI_NETFN_STORAGE;
3554*c18ec02fSPetter Reinholdtsen 	req.msg.cmd = GET_FRU_INFO;
3555*c18ec02fSPetter Reinholdtsen 	req.msg.data = msg_data;
3556*c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 1;
3557*c18ec02fSPetter Reinholdtsen 
3558*c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
3559*c18ec02fSPetter Reinholdtsen 	if (rsp == NULL) {
3560*c18ec02fSPetter Reinholdtsen 		printf(" Device not present (No Response)\n");
3561*c18ec02fSPetter Reinholdtsen 		return -1;
3562*c18ec02fSPetter Reinholdtsen 	}
3563*c18ec02fSPetter Reinholdtsen 	if (rsp->ccode > 0) {
3564*c18ec02fSPetter Reinholdtsen 		printf(" Device not present (%s)\n",
3565*c18ec02fSPetter Reinholdtsen 			val2str(rsp->ccode, completion_code_vals));
3566*c18ec02fSPetter Reinholdtsen 		return -1;
3567*c18ec02fSPetter Reinholdtsen 	}
3568*c18ec02fSPetter Reinholdtsen 
3569*c18ec02fSPetter Reinholdtsen 	memset(&fru, 0, sizeof(fru));
3570*c18ec02fSPetter Reinholdtsen 	fru.size = (rsp->data[1] << 8) | rsp->data[0];
3571*c18ec02fSPetter Reinholdtsen 	fru.access = rsp->data[2] & 0x1;
3572*c18ec02fSPetter Reinholdtsen 
3573*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "fru.size = %d bytes (accessed by %s)",
3574*c18ec02fSPetter Reinholdtsen 		fru.size, fru.access ? "words" : "bytes");
3575*c18ec02fSPetter Reinholdtsen 
3576*c18ec02fSPetter Reinholdtsen 	if (fru.size < 1) {
3577*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, " Invalid FRU size %d", fru.size);
3578*c18ec02fSPetter Reinholdtsen 		return -1;
3579*c18ec02fSPetter Reinholdtsen 	}
3580*c18ec02fSPetter Reinholdtsen 	}
3581*c18ec02fSPetter Reinholdtsen 
3582*c18ec02fSPetter Reinholdtsen 	{
3583*c18ec02fSPetter Reinholdtsen 		uint8_t * fru_data;
3584*c18ec02fSPetter Reinholdtsen 		uint32_t fru_len, i;
3585*c18ec02fSPetter Reinholdtsen 		uint32_t offset= offFruMultiRec;
3586*c18ec02fSPetter Reinholdtsen 		struct fru_multirec_header * h;
3587*c18ec02fSPetter Reinholdtsen 		uint32_t last_off, len;
3588*c18ec02fSPetter Reinholdtsen 		uint8_t error=0;
3589*c18ec02fSPetter Reinholdtsen 
3590*c18ec02fSPetter Reinholdtsen 		i = last_off = offset;
3591*c18ec02fSPetter Reinholdtsen 		fru_len = 0;
3592*c18ec02fSPetter Reinholdtsen 
3593*c18ec02fSPetter Reinholdtsen 		fru_data = malloc(fru.size + 1);
3594*c18ec02fSPetter Reinholdtsen 		if (fru_data == NULL) {
3595*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, " Out of memory!");
3596*c18ec02fSPetter Reinholdtsen 			return -1;
3597*c18ec02fSPetter Reinholdtsen 		}
3598*c18ec02fSPetter Reinholdtsen 		memset(fru_data, 0, fru.size + 1);
3599*c18ec02fSPetter Reinholdtsen 
3600*c18ec02fSPetter Reinholdtsen 		do {
3601*c18ec02fSPetter Reinholdtsen 			h = (struct fru_multirec_header *) (fru_data + i);
3602*c18ec02fSPetter Reinholdtsen 
3603*c18ec02fSPetter Reinholdtsen 			/* read area in (at most) FRU_MULTIREC_CHUNK_SIZE bytes at a time */
3604*c18ec02fSPetter Reinholdtsen 			if ((last_off < (i + sizeof(*h))) || (last_off < (i + h->len)))
3605*c18ec02fSPetter Reinholdtsen 			{
3606*c18ec02fSPetter Reinholdtsen 				len = fru.size - last_off;
3607*c18ec02fSPetter Reinholdtsen 				if (len > FRU_MULTIREC_CHUNK_SIZE)
3608*c18ec02fSPetter Reinholdtsen 					len = FRU_MULTIREC_CHUNK_SIZE;
3609*c18ec02fSPetter Reinholdtsen 
3610*c18ec02fSPetter Reinholdtsen 				if (read_fru_area(intf, &fru, id, last_off, len, fru_data) < 0)
3611*c18ec02fSPetter Reinholdtsen 					break;
3612*c18ec02fSPetter Reinholdtsen 
3613*c18ec02fSPetter Reinholdtsen 				last_off += len;
3614*c18ec02fSPetter Reinholdtsen 			}
3615*c18ec02fSPetter Reinholdtsen 			if( h->type ==  FRU_RECORD_TYPE_OEM_EXTENSION ){
3616*c18ec02fSPetter Reinholdtsen 
3617*c18ec02fSPetter Reinholdtsen 				struct fru_multirec_oem_header *oh=(struct fru_multirec_oem_header *)
3618*c18ec02fSPetter Reinholdtsen 										&fru_data[i + sizeof(struct fru_multirec_header)];
3619*c18ec02fSPetter Reinholdtsen 				uint32_t iana = oh->mfg_id[0] | oh->mfg_id[1]<<8 | oh->mfg_id[2]<<16;
3620*c18ec02fSPetter Reinholdtsen 
3621*c18ec02fSPetter Reinholdtsen 				uint32_t suppliedIana = 0 ;
3622*c18ec02fSPetter Reinholdtsen 				/* Now makes sure this is really PICMG record */
3623*c18ec02fSPetter Reinholdtsen 				if( !strncmp( argv[2] , "oem" , 3 )) {
3624*c18ec02fSPetter Reinholdtsen 					/* Expect IANA number next */
3625*c18ec02fSPetter Reinholdtsen 					if( argc <= 3 ) {
3626*c18ec02fSPetter Reinholdtsen 						lprintf(LOG_ERR, "oem iana <record> <format>");
3627*c18ec02fSPetter Reinholdtsen 						error = 1;
3628*c18ec02fSPetter Reinholdtsen 					} else {
3629*c18ec02fSPetter Reinholdtsen 						if (str2uint(argv[3], &suppliedIana) == 0) {
3630*c18ec02fSPetter Reinholdtsen 							lprintf(LOG_DEBUG,
3631*c18ec02fSPetter Reinholdtsen 									"using iana: %d",
3632*c18ec02fSPetter Reinholdtsen 									suppliedIana);
3633*c18ec02fSPetter Reinholdtsen 						} else {
3634*c18ec02fSPetter Reinholdtsen 							lprintf(LOG_ERR,
3635*c18ec02fSPetter Reinholdtsen 									"Given IANA '%s' is invalid.",
3636*c18ec02fSPetter Reinholdtsen 									argv[3]);
3637*c18ec02fSPetter Reinholdtsen 							error = 1;
3638*c18ec02fSPetter Reinholdtsen 						}
3639*c18ec02fSPetter Reinholdtsen 					}
3640*c18ec02fSPetter Reinholdtsen 				}
3641*c18ec02fSPetter Reinholdtsen 
3642*c18ec02fSPetter Reinholdtsen 				if( suppliedIana == iana ) {
3643*c18ec02fSPetter Reinholdtsen 					lprintf(LOG_DEBUG, "Matching record found" );
3644*c18ec02fSPetter Reinholdtsen 
3645*c18ec02fSPetter Reinholdtsen 				if( iana == IPMI_OEM_KONTRON ) {
3646*c18ec02fSPetter Reinholdtsen 						ipmi_fru_oemkontron_get( argc,argv,fru_data,
3647*c18ec02fSPetter Reinholdtsen 						i + sizeof(struct fru_multirec_header),
3648*c18ec02fSPetter Reinholdtsen 						h->len, h, oh );
3649*c18ec02fSPetter Reinholdtsen 					}
3650*c18ec02fSPetter Reinholdtsen 					/* FIXME: Add OEM record support here */
3651*c18ec02fSPetter Reinholdtsen 					else{
3652*c18ec02fSPetter Reinholdtsen 						printf("  OEM IANA (%s) Record not supported in this mode\n",
3653*c18ec02fSPetter Reinholdtsen 															val2str( iana,  ipmi_oem_info));
3654*c18ec02fSPetter Reinholdtsen 						error = 1;
3655*c18ec02fSPetter Reinholdtsen 					}
3656*c18ec02fSPetter Reinholdtsen 				}
3657*c18ec02fSPetter Reinholdtsen 			}
3658*c18ec02fSPetter Reinholdtsen 			i += h->len + sizeof (struct fru_multirec_header);
3659*c18ec02fSPetter Reinholdtsen 		} while (!(h->format & 0x80) && (error != 1));
3660*c18ec02fSPetter Reinholdtsen 
3661*c18ec02fSPetter Reinholdtsen 		free(fru_data);
3662*c18ec02fSPetter Reinholdtsen 		fru_data = NULL;
3663*c18ec02fSPetter Reinholdtsen 	}
3664*c18ec02fSPetter Reinholdtsen 	return 0;
3665*c18ec02fSPetter Reinholdtsen }
3666*c18ec02fSPetter Reinholdtsen 
3667*c18ec02fSPetter Reinholdtsen static int
3668*c18ec02fSPetter Reinholdtsen ipmi_fru_upg_ekeying(struct ipmi_intf * intf,
3669*c18ec02fSPetter Reinholdtsen 			char * pFileName,
3670*c18ec02fSPetter Reinholdtsen 			uint8_t fruId)
3671*c18ec02fSPetter Reinholdtsen {
3672*c18ec02fSPetter Reinholdtsen 	struct fru_info fruInfo;
3673*c18ec02fSPetter Reinholdtsen 	uint8_t *buf = NULL;
3674*c18ec02fSPetter Reinholdtsen 	uint32_t offFruMultiRec = 0;
3675*c18ec02fSPetter Reinholdtsen 	uint32_t fruMultiRecSize = 0;
3676*c18ec02fSPetter Reinholdtsen 	uint32_t offFileMultiRec = 0;
3677*c18ec02fSPetter Reinholdtsen 	uint32_t fileMultiRecSize = 0;
3678*c18ec02fSPetter Reinholdtsen 	if (pFileName == NULL) {
3679*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "File expected, but none given.");
3680*c18ec02fSPetter Reinholdtsen 		return (-1);
3681*c18ec02fSPetter Reinholdtsen 	}
3682*c18ec02fSPetter Reinholdtsen 	if (ipmi_fru_get_multirec_location_from_fru(intf, fruId, &fruInfo,
3683*c18ec02fSPetter Reinholdtsen 							&offFruMultiRec, &fruMultiRecSize) != 0) {
3684*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Failed to get multirec location from FRU.");
3685*c18ec02fSPetter Reinholdtsen 		return (-1);
3686*c18ec02fSPetter Reinholdtsen 	}
3687*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "FRU Size        : %lu\n", fruMultiRecSize);
3688*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "Multi Rec offset: %lu\n", offFruMultiRec);
3689*c18ec02fSPetter Reinholdtsen 	if (ipmi_fru_get_multirec_size_from_file(pFileName, &fileMultiRecSize,
3690*c18ec02fSPetter Reinholdtsen 				&offFileMultiRec) != 0) {
3691*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Failed to get multirec size from file '%s'.", pFileName);
3692*c18ec02fSPetter Reinholdtsen 		return (-1);
3693*c18ec02fSPetter Reinholdtsen 	}
3694*c18ec02fSPetter Reinholdtsen 	buf = malloc(fileMultiRecSize);
3695*c18ec02fSPetter Reinholdtsen 	if (buf == NULL) {
3696*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "ipmitool: malloc failure");
3697*c18ec02fSPetter Reinholdtsen 		return (-1);
3698*c18ec02fSPetter Reinholdtsen 	}
3699*c18ec02fSPetter Reinholdtsen 	if (ipmi_fru_get_multirec_from_file(pFileName, buf, fileMultiRecSize,
3700*c18ec02fSPetter Reinholdtsen 				offFileMultiRec) != 0) {
3701*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Failed to get multirec from file '%s'.", pFileName);
3702*c18ec02fSPetter Reinholdtsen 		if (buf != NULL) {
3703*c18ec02fSPetter Reinholdtsen 			free(buf);
3704*c18ec02fSPetter Reinholdtsen 			buf = NULL;
3705*c18ec02fSPetter Reinholdtsen 		}
3706*c18ec02fSPetter Reinholdtsen 		return (-1);
3707*c18ec02fSPetter Reinholdtsen 	}
3708*c18ec02fSPetter Reinholdtsen 	if (ipmi_fru_get_adjust_size_from_buffer(buf, &fileMultiRecSize) != 0) {
3709*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Failed to adjust size from buffer.");
3710*c18ec02fSPetter Reinholdtsen 		if (buf != NULL) {
3711*c18ec02fSPetter Reinholdtsen 			free(buf);
3712*c18ec02fSPetter Reinholdtsen 			buf = NULL;
3713*c18ec02fSPetter Reinholdtsen 		}
3714*c18ec02fSPetter Reinholdtsen 		return (-1);
3715*c18ec02fSPetter Reinholdtsen 	}
3716*c18ec02fSPetter Reinholdtsen 	if (write_fru_area(intf, &fruInfo, fruId, 0, offFruMultiRec,
3717*c18ec02fSPetter Reinholdtsen 				fileMultiRecSize, buf) != 0) {
3718*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Failed to write FRU area.");
3719*c18ec02fSPetter Reinholdtsen 		if (buf != NULL) {
3720*c18ec02fSPetter Reinholdtsen 			free(buf);
3721*c18ec02fSPetter Reinholdtsen 			buf = NULL;
3722*c18ec02fSPetter Reinholdtsen 		}
3723*c18ec02fSPetter Reinholdtsen 		return (-1);
3724*c18ec02fSPetter Reinholdtsen 	}
3725*c18ec02fSPetter Reinholdtsen 	if (buf != NULL) {
3726*c18ec02fSPetter Reinholdtsen 		free(buf);
3727*c18ec02fSPetter Reinholdtsen 		buf = NULL;
3728*c18ec02fSPetter Reinholdtsen 	}
3729*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_INFO, "Done upgrading Ekey.");
3730*c18ec02fSPetter Reinholdtsen 	return 0;
3731*c18ec02fSPetter Reinholdtsen }
3732*c18ec02fSPetter Reinholdtsen 
3733*c18ec02fSPetter Reinholdtsen /* ipmi_fru_upgekey_help - print help text for 'upgEkey'
3734*c18ec02fSPetter Reinholdtsen  *
3735*c18ec02fSPetter Reinholdtsen  * returns void
3736*c18ec02fSPetter Reinholdtsen  */
3737*c18ec02fSPetter Reinholdtsen void
3738*c18ec02fSPetter Reinholdtsen ipmi_fru_upgekey_help()
3739*c18ec02fSPetter Reinholdtsen {
3740*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_NOTICE, "fru upgEkey <fru id> <fru file>");
3741*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_NOTICE, "Note: FRU ID and file(incl. full path) must be specified.");
3742*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_NOTICE, "Example: ipmitool fru upgEkey 0 /root/fru.bin");
3743*c18ec02fSPetter Reinholdtsen } /* ipmi_fru_upgekey_help() */
3744*c18ec02fSPetter Reinholdtsen 
3745*c18ec02fSPetter Reinholdtsen static int
3746*c18ec02fSPetter Reinholdtsen ipmi_fru_get_multirec_size_from_file(char * pFileName,
3747*c18ec02fSPetter Reinholdtsen 					uint32_t * pSize,
3748*c18ec02fSPetter Reinholdtsen 					uint32_t * pOffset)
3749*c18ec02fSPetter Reinholdtsen {
3750*c18ec02fSPetter Reinholdtsen 	struct fru_header header;
3751*c18ec02fSPetter Reinholdtsen 	FILE * pFile;
3752*c18ec02fSPetter Reinholdtsen 	uint8_t len = 0;
3753*c18ec02fSPetter Reinholdtsen 	uint32_t end = 0;
3754*c18ec02fSPetter Reinholdtsen 	*pSize = 0;
3755*c18ec02fSPetter Reinholdtsen 
3756*c18ec02fSPetter Reinholdtsen 	pFile = fopen(pFileName,"rb");
3757*c18ec02fSPetter Reinholdtsen 	if (pFile) {
3758*c18ec02fSPetter Reinholdtsen 		rewind(pFile);
3759*c18ec02fSPetter Reinholdtsen 		len = fread(&header, 1, 8, pFile);
3760*c18ec02fSPetter Reinholdtsen 		fseek(pFile, 0, SEEK_END);
3761*c18ec02fSPetter Reinholdtsen 		end = ftell(pFile);
3762*c18ec02fSPetter Reinholdtsen 		fclose(pFile);
3763*c18ec02fSPetter Reinholdtsen 	}
3764*c18ec02fSPetter Reinholdtsen 
3765*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "File Size = %lu\n", end);
3766*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "Len = %u\n", len);
3767*c18ec02fSPetter Reinholdtsen 
3768*c18ec02fSPetter Reinholdtsen 	if (len != 8) {
3769*c18ec02fSPetter Reinholdtsen 		printf("Error with file %s in getting size\n", pFileName);
3770*c18ec02fSPetter Reinholdtsen 		return -1;
3771*c18ec02fSPetter Reinholdtsen 	}
3772*c18ec02fSPetter Reinholdtsen 
3773*c18ec02fSPetter Reinholdtsen 	if (header.version != 0x01) {
3774*c18ec02fSPetter Reinholdtsen 		printf ("Unknown FRU header version %02x.\n", header.version);
3775*c18ec02fSPetter Reinholdtsen 		return -1;
3776*c18ec02fSPetter Reinholdtsen 	}
3777*c18ec02fSPetter Reinholdtsen 
3778*c18ec02fSPetter Reinholdtsen 	/* Retreive length */
3779*c18ec02fSPetter Reinholdtsen 	if (((header.offset.internal * 8) > (header.offset.internal * 8)) &&
3780*c18ec02fSPetter Reinholdtsen 		((header.offset.internal * 8) < end))
3781*c18ec02fSPetter Reinholdtsen 		end = (header.offset.internal * 8);
3782*c18ec02fSPetter Reinholdtsen 
3783*c18ec02fSPetter Reinholdtsen 	if (((header.offset.chassis * 8) > (header.offset.chassis * 8)) &&
3784*c18ec02fSPetter Reinholdtsen 		((header.offset.chassis * 8) < end))
3785*c18ec02fSPetter Reinholdtsen 		end = (header.offset.chassis * 8);
3786*c18ec02fSPetter Reinholdtsen 
3787*c18ec02fSPetter Reinholdtsen 	if (((header.offset.board * 8) > (header.offset.board * 8)) &&
3788*c18ec02fSPetter Reinholdtsen 		((header.offset.board * 8) < end))
3789*c18ec02fSPetter Reinholdtsen 		end = (header.offset.board * 8);
3790*c18ec02fSPetter Reinholdtsen 
3791*c18ec02fSPetter Reinholdtsen 	if (((header.offset.product * 8) > (header.offset.product * 8)) &&
3792*c18ec02fSPetter Reinholdtsen 		((header.offset.product * 8) < end))
3793*c18ec02fSPetter Reinholdtsen 		end = (header.offset.product * 8);
3794*c18ec02fSPetter Reinholdtsen 
3795*c18ec02fSPetter Reinholdtsen 	*pSize = end - (header.offset.multi * 8);
3796*c18ec02fSPetter Reinholdtsen 	*pOffset = (header.offset.multi * 8);
3797*c18ec02fSPetter Reinholdtsen 
3798*c18ec02fSPetter Reinholdtsen 	return 0;
3799*c18ec02fSPetter Reinholdtsen }
3800*c18ec02fSPetter Reinholdtsen 
3801*c18ec02fSPetter Reinholdtsen int
3802*c18ec02fSPetter Reinholdtsen ipmi_fru_get_adjust_size_from_buffer(uint8_t * fru_data, uint32_t *pSize)
3803*c18ec02fSPetter Reinholdtsen {
3804*c18ec02fSPetter Reinholdtsen 	struct fru_multirec_header * head;
3805*c18ec02fSPetter Reinholdtsen 	int status = 0;
3806*c18ec02fSPetter Reinholdtsen 	uint8_t checksum = 0;
3807*c18ec02fSPetter Reinholdtsen 	uint8_t counter = 0;
3808*c18ec02fSPetter Reinholdtsen 	uint16_t count = 0;
3809*c18ec02fSPetter Reinholdtsen 	do {
3810*c18ec02fSPetter Reinholdtsen 		checksum = 0;
3811*c18ec02fSPetter Reinholdtsen 		head = (struct fru_multirec_header *) (fru_data + count);
3812*c18ec02fSPetter Reinholdtsen 		if (verbose) {
3813*c18ec02fSPetter Reinholdtsen 			printf("Adding (");
3814*c18ec02fSPetter Reinholdtsen 		}
3815*c18ec02fSPetter Reinholdtsen 		for (counter = 0; counter < sizeof(struct fru_multirec_header); counter++) {
3816*c18ec02fSPetter Reinholdtsen 			if (verbose) {
3817*c18ec02fSPetter Reinholdtsen 				printf(" %02X", *(fru_data + count + counter));
3818*c18ec02fSPetter Reinholdtsen 			}
3819*c18ec02fSPetter Reinholdtsen 			checksum += *(fru_data + count + counter);
3820*c18ec02fSPetter Reinholdtsen 		}
3821*c18ec02fSPetter Reinholdtsen 		if (verbose) {
3822*c18ec02fSPetter Reinholdtsen 			printf(")");
3823*c18ec02fSPetter Reinholdtsen 		}
3824*c18ec02fSPetter Reinholdtsen 		if (checksum != 0) {
3825*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "Bad checksum in Multi Records");
3826*c18ec02fSPetter Reinholdtsen 			status = (-1);
3827*c18ec02fSPetter Reinholdtsen 			if (verbose) {
3828*c18ec02fSPetter Reinholdtsen 				printf("--> FAIL");
3829*c18ec02fSPetter Reinholdtsen 			}
3830*c18ec02fSPetter Reinholdtsen 		} else if (verbose) {
3831*c18ec02fSPetter Reinholdtsen 			printf("--> OK");
3832*c18ec02fSPetter Reinholdtsen 		}
3833*c18ec02fSPetter Reinholdtsen 		if (verbose > 1 && checksum == 0) {
3834*c18ec02fSPetter Reinholdtsen 			for (counter = 0; counter < head->len; counter++) {
3835*c18ec02fSPetter Reinholdtsen 				printf(" %02X", *(fru_data + count + counter
3836*c18ec02fSPetter Reinholdtsen 							+ sizeof(struct fru_multirec_header)));
3837*c18ec02fSPetter Reinholdtsen 			}
3838*c18ec02fSPetter Reinholdtsen 		}
3839*c18ec02fSPetter Reinholdtsen 		if (verbose) {
3840*c18ec02fSPetter Reinholdtsen 			printf("\n");
3841*c18ec02fSPetter Reinholdtsen 		}
3842*c18ec02fSPetter Reinholdtsen 		count += head->len + sizeof (struct fru_multirec_header);
3843*c18ec02fSPetter Reinholdtsen 	} while ((!(head->format & 0x80)) && (status == 0));
3844*c18ec02fSPetter Reinholdtsen 
3845*c18ec02fSPetter Reinholdtsen 	*pSize = count;
3846*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "Size of multirec: %lu\n", *pSize);
3847*c18ec02fSPetter Reinholdtsen 	return status;
3848*c18ec02fSPetter Reinholdtsen }
3849*c18ec02fSPetter Reinholdtsen 
3850*c18ec02fSPetter Reinholdtsen static int
3851*c18ec02fSPetter Reinholdtsen ipmi_fru_get_multirec_from_file(char * pFileName, uint8_t * pBufArea,
3852*c18ec02fSPetter Reinholdtsen 		uint32_t size, uint32_t offset)
3853*c18ec02fSPetter Reinholdtsen {
3854*c18ec02fSPetter Reinholdtsen 	FILE * pFile;
3855*c18ec02fSPetter Reinholdtsen 	uint32_t len = 0;
3856*c18ec02fSPetter Reinholdtsen 	if (pFileName == NULL) {
3857*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Invalid file name given.");
3858*c18ec02fSPetter Reinholdtsen 		return (-1);
3859*c18ec02fSPetter Reinholdtsen 	}
3860*c18ec02fSPetter Reinholdtsen 
3861*c18ec02fSPetter Reinholdtsen 	errno = 0;
3862*c18ec02fSPetter Reinholdtsen 	pFile = fopen(pFileName, "rb");
3863*c18ec02fSPetter Reinholdtsen 	if (!pFile) {
3864*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Error opening file '%s': %i -> %s.", pFileName, errno,
3865*c18ec02fSPetter Reinholdtsen 				strerror(errno));
3866*c18ec02fSPetter Reinholdtsen 		return (-1);
3867*c18ec02fSPetter Reinholdtsen 	}
3868*c18ec02fSPetter Reinholdtsen 	errno = 0;
3869*c18ec02fSPetter Reinholdtsen 	if (fseek(pFile, offset, SEEK_SET) != 0) {
3870*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Failed to seek in file '%s': %i -> %s.", pFileName, errno,
3871*c18ec02fSPetter Reinholdtsen 				strerror(errno));
3872*c18ec02fSPetter Reinholdtsen 		fclose(pFile);
3873*c18ec02fSPetter Reinholdtsen 		return (-1);
3874*c18ec02fSPetter Reinholdtsen 	}
3875*c18ec02fSPetter Reinholdtsen 	len = fread(pBufArea, size, 1, pFile);
3876*c18ec02fSPetter Reinholdtsen 	fclose(pFile);
3877*c18ec02fSPetter Reinholdtsen 
3878*c18ec02fSPetter Reinholdtsen 	if (len != 1) {
3879*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Error in file '%s'.", pFileName);
3880*c18ec02fSPetter Reinholdtsen 		return (-1);
3881*c18ec02fSPetter Reinholdtsen 	}
3882*c18ec02fSPetter Reinholdtsen 	return 0;
3883*c18ec02fSPetter Reinholdtsen }
3884*c18ec02fSPetter Reinholdtsen 
3885*c18ec02fSPetter Reinholdtsen static int
3886*c18ec02fSPetter Reinholdtsen ipmi_fru_get_multirec_location_from_fru(struct ipmi_intf * intf,
3887*c18ec02fSPetter Reinholdtsen 					uint8_t fruId,
3888*c18ec02fSPetter Reinholdtsen 												struct fru_info *pFruInfo,
3889*c18ec02fSPetter Reinholdtsen 					uint32_t * pRetLocation,
3890*c18ec02fSPetter Reinholdtsen 					uint32_t * pRetSize)
3891*c18ec02fSPetter Reinholdtsen {
3892*c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
3893*c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
3894*c18ec02fSPetter Reinholdtsen 	uint8_t msg_data[4];
3895*c18ec02fSPetter Reinholdtsen 	uint32_t end;
3896*c18ec02fSPetter Reinholdtsen 	struct fru_header header;
3897*c18ec02fSPetter Reinholdtsen 
3898*c18ec02fSPetter Reinholdtsen 	*pRetLocation = 0;
3899*c18ec02fSPetter Reinholdtsen 
3900*c18ec02fSPetter Reinholdtsen 	msg_data[0] = fruId;
3901*c18ec02fSPetter Reinholdtsen 
3902*c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
3903*c18ec02fSPetter Reinholdtsen 	req.msg.netfn = IPMI_NETFN_STORAGE;
3904*c18ec02fSPetter Reinholdtsen 	req.msg.cmd = GET_FRU_INFO;
3905*c18ec02fSPetter Reinholdtsen 	req.msg.data = msg_data;
3906*c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 1;
3907*c18ec02fSPetter Reinholdtsen 
3908*c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
3909*c18ec02fSPetter Reinholdtsen 	if (!rsp) {
3910*c18ec02fSPetter Reinholdtsen 		if (verbose > 1)
3911*c18ec02fSPetter Reinholdtsen 			printf("no response\n");
3912*c18ec02fSPetter Reinholdtsen 		return -1;
3913*c18ec02fSPetter Reinholdtsen 	}
3914*c18ec02fSPetter Reinholdtsen 
3915*c18ec02fSPetter Reinholdtsen 	if (rsp->ccode > 0) {
3916*c18ec02fSPetter Reinholdtsen 		if (rsp->ccode == 0xc3)
3917*c18ec02fSPetter Reinholdtsen 			printf ("  Timeout accessing FRU info. (Device not present?)\n");
3918*c18ec02fSPetter Reinholdtsen 		else
3919*c18ec02fSPetter Reinholdtsen 			printf ("   CCODE = 0x%02x\n", rsp->ccode);
3920*c18ec02fSPetter Reinholdtsen 		return -1;
3921*c18ec02fSPetter Reinholdtsen 	}
3922*c18ec02fSPetter Reinholdtsen 	pFruInfo->size = (rsp->data[1] << 8) | rsp->data[0];
3923*c18ec02fSPetter Reinholdtsen 	pFruInfo->access = rsp->data[2] & 0x1;
3924*c18ec02fSPetter Reinholdtsen 
3925*c18ec02fSPetter Reinholdtsen 	if (verbose > 1)
3926*c18ec02fSPetter Reinholdtsen 		printf("pFruInfo->size = %d bytes (accessed by %s)\n",
3927*c18ec02fSPetter Reinholdtsen 				pFruInfo->size, pFruInfo->access ? "words" : "bytes");
3928*c18ec02fSPetter Reinholdtsen 
3929*c18ec02fSPetter Reinholdtsen 	if (!pFruInfo->size)
3930*c18ec02fSPetter Reinholdtsen 		return -1;
3931*c18ec02fSPetter Reinholdtsen 
3932*c18ec02fSPetter Reinholdtsen 	msg_data[0] = fruId;
3933*c18ec02fSPetter Reinholdtsen 	msg_data[1] = 0;
3934*c18ec02fSPetter Reinholdtsen 	msg_data[2] = 0;
3935*c18ec02fSPetter Reinholdtsen 	msg_data[3] = 8;
3936*c18ec02fSPetter Reinholdtsen 
3937*c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
3938*c18ec02fSPetter Reinholdtsen 	req.msg.netfn = IPMI_NETFN_STORAGE;
3939*c18ec02fSPetter Reinholdtsen 	req.msg.cmd = GET_FRU_DATA;
3940*c18ec02fSPetter Reinholdtsen 	req.msg.data = msg_data;
3941*c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 4;
3942*c18ec02fSPetter Reinholdtsen 
3943*c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
3944*c18ec02fSPetter Reinholdtsen 
3945*c18ec02fSPetter Reinholdtsen 	if (!rsp)
3946*c18ec02fSPetter Reinholdtsen 		return -1;
3947*c18ec02fSPetter Reinholdtsen 	if (rsp->ccode > 0) {
3948*c18ec02fSPetter Reinholdtsen 		if (rsp->ccode == 0xc3)
3949*c18ec02fSPetter Reinholdtsen 			printf ("  Timeout while reading FRU data. (Device not present?)\n");
3950*c18ec02fSPetter Reinholdtsen 		return -1;
3951*c18ec02fSPetter Reinholdtsen 	}
3952*c18ec02fSPetter Reinholdtsen 
3953*c18ec02fSPetter Reinholdtsen 	if (verbose > 1)
3954*c18ec02fSPetter Reinholdtsen 		printbuf(rsp->data, rsp->data_len, "FRU DATA");
3955*c18ec02fSPetter Reinholdtsen 
3956*c18ec02fSPetter Reinholdtsen 	memcpy(&header, rsp->data + 1, 8);
3957*c18ec02fSPetter Reinholdtsen 
3958*c18ec02fSPetter Reinholdtsen 	if (header.version != 0x01) {
3959*c18ec02fSPetter Reinholdtsen 		printf ("  Unknown FRU header version %02x.\n", header.version);
3960*c18ec02fSPetter Reinholdtsen 		return -1;
3961*c18ec02fSPetter Reinholdtsen 	}
3962*c18ec02fSPetter Reinholdtsen 
3963*c18ec02fSPetter Reinholdtsen 	end = pFruInfo->size;
3964*c18ec02fSPetter Reinholdtsen 
3965*c18ec02fSPetter Reinholdtsen 	/* Retreive length */
3966*c18ec02fSPetter Reinholdtsen 	if (((header.offset.internal * 8) > (header.offset.internal * 8)) &&
3967*c18ec02fSPetter Reinholdtsen 		((header.offset.internal * 8) < end))
3968*c18ec02fSPetter Reinholdtsen 		end = (header.offset.internal * 8);
3969*c18ec02fSPetter Reinholdtsen 
3970*c18ec02fSPetter Reinholdtsen 	if (((header.offset.chassis * 8) > (header.offset.chassis * 8)) &&
3971*c18ec02fSPetter Reinholdtsen 		((header.offset.chassis * 8) < end))
3972*c18ec02fSPetter Reinholdtsen 		end = (header.offset.chassis * 8);
3973*c18ec02fSPetter Reinholdtsen 
3974*c18ec02fSPetter Reinholdtsen 	if (((header.offset.board * 8) > (header.offset.board * 8)) &&
3975*c18ec02fSPetter Reinholdtsen 		((header.offset.board * 8) < end))
3976*c18ec02fSPetter Reinholdtsen 		end = (header.offset.board * 8);
3977*c18ec02fSPetter Reinholdtsen 
3978*c18ec02fSPetter Reinholdtsen 	if (((header.offset.product * 8) > (header.offset.product * 8)) &&
3979*c18ec02fSPetter Reinholdtsen 		((header.offset.product * 8) < end))
3980*c18ec02fSPetter Reinholdtsen 		end = (header.offset.product * 8);
3981*c18ec02fSPetter Reinholdtsen 
3982*c18ec02fSPetter Reinholdtsen 	*pRetSize = end;
3983*c18ec02fSPetter Reinholdtsen 	*pRetLocation = 8 * header.offset.multi;
3984*c18ec02fSPetter Reinholdtsen 
3985*c18ec02fSPetter Reinholdtsen 	return 0;
3986*c18ec02fSPetter Reinholdtsen }
3987*c18ec02fSPetter Reinholdtsen 
3988*c18ec02fSPetter Reinholdtsen /* ipmi_fru_get_internal_use_offset -  Retreive internal use offset
3989*c18ec02fSPetter Reinholdtsen *
3990*c18ec02fSPetter Reinholdtsen * @intf:   ipmi interface
3991*c18ec02fSPetter Reinholdtsen * @id:     fru id
3992*c18ec02fSPetter Reinholdtsen *
3993*c18ec02fSPetter Reinholdtsen * returns -1 on error
3994*c18ec02fSPetter Reinholdtsen * returns 0 if successful
3995*c18ec02fSPetter Reinholdtsen * returns 1 if device not present
3996*c18ec02fSPetter Reinholdtsen */
3997*c18ec02fSPetter Reinholdtsen static int
3998*c18ec02fSPetter Reinholdtsen ipmi_fru_get_internal_use_info(  struct ipmi_intf * intf,
3999*c18ec02fSPetter Reinholdtsen 											uint8_t id,
4000*c18ec02fSPetter Reinholdtsen 											struct fru_info * fru,
4001*c18ec02fSPetter Reinholdtsen 											uint16_t * size,
4002*c18ec02fSPetter Reinholdtsen 											uint16_t * offset)
4003*c18ec02fSPetter Reinholdtsen {
4004*c18ec02fSPetter Reinholdtsen 	struct ipmi_rs * rsp;
4005*c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
4006*c18ec02fSPetter Reinholdtsen 	struct fru_header header;
4007*c18ec02fSPetter Reinholdtsen 	uint8_t msg_data[4];
4008*c18ec02fSPetter Reinholdtsen 
4009*c18ec02fSPetter Reinholdtsen 	// Init output value
4010*c18ec02fSPetter Reinholdtsen 	* offset = 0;
4011*c18ec02fSPetter Reinholdtsen 	* size = 0;
4012*c18ec02fSPetter Reinholdtsen 
4013*c18ec02fSPetter Reinholdtsen 	memset(fru, 0, sizeof(struct fru_info));
4014*c18ec02fSPetter Reinholdtsen 	memset(&header, 0, sizeof(struct fru_header));
4015*c18ec02fSPetter Reinholdtsen 
4016*c18ec02fSPetter Reinholdtsen 	/*
4017*c18ec02fSPetter Reinholdtsen 	* get info about this FRU
4018*c18ec02fSPetter Reinholdtsen 	*/
4019*c18ec02fSPetter Reinholdtsen 	memset(msg_data, 0, 4);
4020*c18ec02fSPetter Reinholdtsen 	msg_data[0] = id;
4021*c18ec02fSPetter Reinholdtsen 
4022*c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
4023*c18ec02fSPetter Reinholdtsen 	req.msg.netfn = IPMI_NETFN_STORAGE;
4024*c18ec02fSPetter Reinholdtsen 	req.msg.cmd = GET_FRU_INFO;
4025*c18ec02fSPetter Reinholdtsen 	req.msg.data = msg_data;
4026*c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 1;
4027*c18ec02fSPetter Reinholdtsen 
4028*c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
4029*c18ec02fSPetter Reinholdtsen 	if (rsp == NULL) {
4030*c18ec02fSPetter Reinholdtsen 		printf(" Device not present (No Response)\n");
4031*c18ec02fSPetter Reinholdtsen 		return -1;
4032*c18ec02fSPetter Reinholdtsen 	}
4033*c18ec02fSPetter Reinholdtsen 	if (rsp->ccode > 0) {
4034*c18ec02fSPetter Reinholdtsen 		printf(" Device not present (%s)\n",
4035*c18ec02fSPetter Reinholdtsen 			val2str(rsp->ccode, completion_code_vals));
4036*c18ec02fSPetter Reinholdtsen 		return -1;
4037*c18ec02fSPetter Reinholdtsen 	}
4038*c18ec02fSPetter Reinholdtsen 
4039*c18ec02fSPetter Reinholdtsen 	memset(&fru, 0, sizeof(fru));
4040*c18ec02fSPetter Reinholdtsen 	fru->size = (rsp->data[1] << 8) | rsp->data[0];
4041*c18ec02fSPetter Reinholdtsen 	fru->access = rsp->data[2] & 0x1;
4042*c18ec02fSPetter Reinholdtsen 
4043*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "fru.size = %d bytes (accessed by %s)",
4044*c18ec02fSPetter Reinholdtsen 		fru->size, fru->access ? "words" : "bytes");
4045*c18ec02fSPetter Reinholdtsen 
4046*c18ec02fSPetter Reinholdtsen 	if (fru->size < 1) {
4047*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, " Invalid FRU size %d", fru->size);
4048*c18ec02fSPetter Reinholdtsen 		return -1;
4049*c18ec02fSPetter Reinholdtsen 	}
4050*c18ec02fSPetter Reinholdtsen 
4051*c18ec02fSPetter Reinholdtsen 	/*
4052*c18ec02fSPetter Reinholdtsen 	* retrieve the FRU header
4053*c18ec02fSPetter Reinholdtsen 	*/
4054*c18ec02fSPetter Reinholdtsen 	msg_data[0] = id;
4055*c18ec02fSPetter Reinholdtsen 	msg_data[1] = 0;
4056*c18ec02fSPetter Reinholdtsen 	msg_data[2] = 0;
4057*c18ec02fSPetter Reinholdtsen 	msg_data[3] = 8;
4058*c18ec02fSPetter Reinholdtsen 
4059*c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
4060*c18ec02fSPetter Reinholdtsen 	req.msg.netfn = IPMI_NETFN_STORAGE;
4061*c18ec02fSPetter Reinholdtsen 	req.msg.cmd = GET_FRU_DATA;
4062*c18ec02fSPetter Reinholdtsen 	req.msg.data = msg_data;
4063*c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 4;
4064*c18ec02fSPetter Reinholdtsen 
4065*c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
4066*c18ec02fSPetter Reinholdtsen 	if (rsp == NULL) {
4067*c18ec02fSPetter Reinholdtsen 		printf(" Device not present (No Response)\n");
4068*c18ec02fSPetter Reinholdtsen 		return 1;
4069*c18ec02fSPetter Reinholdtsen 	}
4070*c18ec02fSPetter Reinholdtsen 	if (rsp->ccode > 0) {
4071*c18ec02fSPetter Reinholdtsen 		printf(" Device not present (%s)\n",
4072*c18ec02fSPetter Reinholdtsen 				val2str(rsp->ccode, completion_code_vals));
4073*c18ec02fSPetter Reinholdtsen 		return 1;
4074*c18ec02fSPetter Reinholdtsen 	}
4075*c18ec02fSPetter Reinholdtsen 
4076*c18ec02fSPetter Reinholdtsen 	if (verbose > 1)
4077*c18ec02fSPetter Reinholdtsen 		printbuf(rsp->data, rsp->data_len, "FRU DATA");
4078*c18ec02fSPetter Reinholdtsen 
4079*c18ec02fSPetter Reinholdtsen 	memcpy(&header, rsp->data + 1, 8);
4080*c18ec02fSPetter Reinholdtsen 
4081*c18ec02fSPetter Reinholdtsen 	if (header.version != 1) {
4082*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, " Unknown FRU header version 0x%02x",
4083*c18ec02fSPetter Reinholdtsen 			header.version);
4084*c18ec02fSPetter Reinholdtsen 		return -1;
4085*c18ec02fSPetter Reinholdtsen 	}
4086*c18ec02fSPetter Reinholdtsen 
4087*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "fru.header.version:         0x%x",
4088*c18ec02fSPetter Reinholdtsen 		header.version);
4089*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "fru.header.offset.internal: 0x%x",
4090*c18ec02fSPetter Reinholdtsen 		header.offset.internal * 8);
4091*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "fru.header.offset.chassis:  0x%x",
4092*c18ec02fSPetter Reinholdtsen 		header.offset.chassis * 8);
4093*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "fru.header.offset.board:    0x%x",
4094*c18ec02fSPetter Reinholdtsen 		header.offset.board * 8);
4095*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "fru.header.offset.product:  0x%x",
4096*c18ec02fSPetter Reinholdtsen 		header.offset.product * 8);
4097*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_DEBUG, "fru.header.offset.multi:    0x%x",
4098*c18ec02fSPetter Reinholdtsen 		header.offset.multi * 8);
4099*c18ec02fSPetter Reinholdtsen 
4100*c18ec02fSPetter Reinholdtsen 	if((header.offset.internal*8) == 0)
4101*c18ec02fSPetter Reinholdtsen 	{
4102*c18ec02fSPetter Reinholdtsen 		* size = 0;
4103*c18ec02fSPetter Reinholdtsen 		* offset = 0;
4104*c18ec02fSPetter Reinholdtsen 	}
4105*c18ec02fSPetter Reinholdtsen 	else
4106*c18ec02fSPetter Reinholdtsen 	{
4107*c18ec02fSPetter Reinholdtsen 		(* offset) = (header.offset.internal*8);
4108*c18ec02fSPetter Reinholdtsen 
4109*c18ec02fSPetter Reinholdtsen 		if(header.offset.chassis != 0)
4110*c18ec02fSPetter Reinholdtsen 		{
4111*c18ec02fSPetter Reinholdtsen 			(* size) = ((header.offset.chassis*8)-(* offset));
4112*c18ec02fSPetter Reinholdtsen 		}
4113*c18ec02fSPetter Reinholdtsen 		else if(header.offset.board != 0)
4114*c18ec02fSPetter Reinholdtsen 		{
4115*c18ec02fSPetter Reinholdtsen 			(* size) = ((header.offset.board*8)-(* offset));
4116*c18ec02fSPetter Reinholdtsen 		}
4117*c18ec02fSPetter Reinholdtsen 		else if(header.offset.product != 0)
4118*c18ec02fSPetter Reinholdtsen 		{
4119*c18ec02fSPetter Reinholdtsen 			(* size) = ((header.offset.product*8)-(* offset));
4120*c18ec02fSPetter Reinholdtsen 		}
4121*c18ec02fSPetter Reinholdtsen 		else if(header.offset.multi != 0)
4122*c18ec02fSPetter Reinholdtsen 		{
4123*c18ec02fSPetter Reinholdtsen 			(* size) = ((header.offset.multi*8)-(* offset));
4124*c18ec02fSPetter Reinholdtsen 		}
4125*c18ec02fSPetter Reinholdtsen 		else
4126*c18ec02fSPetter Reinholdtsen 		{
4127*c18ec02fSPetter Reinholdtsen 			(* size) = (fru->size - (* offset));
4128*c18ec02fSPetter Reinholdtsen 		}
4129*c18ec02fSPetter Reinholdtsen 	}
4130*c18ec02fSPetter Reinholdtsen 	return 0;
4131*c18ec02fSPetter Reinholdtsen }
4132*c18ec02fSPetter Reinholdtsen 
4133*c18ec02fSPetter Reinholdtsen /* ipmi_fru_info_internal_use -  print internal use info
4134*c18ec02fSPetter Reinholdtsen *
4135*c18ec02fSPetter Reinholdtsen * @intf:   ipmi interface
4136*c18ec02fSPetter Reinholdtsen * @id:     fru id
4137*c18ec02fSPetter Reinholdtsen *
4138*c18ec02fSPetter Reinholdtsen * returns -1 on error
4139*c18ec02fSPetter Reinholdtsen * returns 0 if successful
4140*c18ec02fSPetter Reinholdtsen * returns 1 if device not present
4141*c18ec02fSPetter Reinholdtsen */
4142*c18ec02fSPetter Reinholdtsen static int
4143*c18ec02fSPetter Reinholdtsen ipmi_fru_info_internal_use(struct ipmi_intf * intf, uint8_t id)
4144*c18ec02fSPetter Reinholdtsen {
4145*c18ec02fSPetter Reinholdtsen 	struct fru_info fru;
4146*c18ec02fSPetter Reinholdtsen 	uint16_t size;
4147*c18ec02fSPetter Reinholdtsen 	uint16_t offset;
4148*c18ec02fSPetter Reinholdtsen 	int rc = 0;
4149*c18ec02fSPetter Reinholdtsen 
4150*c18ec02fSPetter Reinholdtsen 	rc = ipmi_fru_get_internal_use_info(intf, id, &fru, &size, &offset);
4151*c18ec02fSPetter Reinholdtsen 
4152*c18ec02fSPetter Reinholdtsen 	if(rc == 0)
4153*c18ec02fSPetter Reinholdtsen 	{
4154*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_DEBUG, "Internal Use Area Offset: %i", offset);
4155*c18ec02fSPetter Reinholdtsen 		printf(          "Internal Use Area Size  : %i\n", size);
4156*c18ec02fSPetter Reinholdtsen 	}
4157*c18ec02fSPetter Reinholdtsen 	else
4158*c18ec02fSPetter Reinholdtsen 	{
4159*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Cannot access internal use area");
4160*c18ec02fSPetter Reinholdtsen 		return -1;
4161*c18ec02fSPetter Reinholdtsen 	}
4162*c18ec02fSPetter Reinholdtsen 	return 0;
4163*c18ec02fSPetter Reinholdtsen }
4164*c18ec02fSPetter Reinholdtsen 
4165*c18ec02fSPetter Reinholdtsen /* ipmi_fru_help - print help text for FRU subcommand
4166*c18ec02fSPetter Reinholdtsen  *
4167*c18ec02fSPetter Reinholdtsen  * returns void
4168*c18ec02fSPetter Reinholdtsen  */
4169*c18ec02fSPetter Reinholdtsen void
4170*c18ec02fSPetter Reinholdtsen ipmi_fru_help()
4171*c18ec02fSPetter Reinholdtsen {
4172*c18ec02fSPetter Reinholdtsen 	lprintf(LOG_NOTICE,
4173*c18ec02fSPetter Reinholdtsen 			"FRU Commands:  print read write upgEkey edit internaluse get");
4174*c18ec02fSPetter Reinholdtsen } /* ipmi_fru_help() */
4175*c18ec02fSPetter Reinholdtsen 
4176*c18ec02fSPetter Reinholdtsen /* ipmi_fru_read_internal_use -  print internal use are in hex or file
4177*c18ec02fSPetter Reinholdtsen *
4178*c18ec02fSPetter Reinholdtsen * @intf:   ipmi interface
4179*c18ec02fSPetter Reinholdtsen * @id:     fru id
4180*c18ec02fSPetter Reinholdtsen *
4181*c18ec02fSPetter Reinholdtsen * returns -1 on error
4182*c18ec02fSPetter Reinholdtsen * returns 0 if successful
4183*c18ec02fSPetter Reinholdtsen * returns 1 if device not present
4184*c18ec02fSPetter Reinholdtsen */
4185*c18ec02fSPetter Reinholdtsen static int
4186*c18ec02fSPetter Reinholdtsen ipmi_fru_read_internal_use(struct ipmi_intf * intf, uint8_t id, char * pFileName)
4187*c18ec02fSPetter Reinholdtsen {
4188*c18ec02fSPetter Reinholdtsen 	struct fru_info fru;
4189*c18ec02fSPetter Reinholdtsen 	uint16_t size;
4190*c18ec02fSPetter Reinholdtsen 	uint16_t offset;
4191*c18ec02fSPetter Reinholdtsen 	int rc = 0;
4192*c18ec02fSPetter Reinholdtsen 
4193*c18ec02fSPetter Reinholdtsen 	rc = ipmi_fru_get_internal_use_info(intf, id, &fru, &size, &offset);
4194*c18ec02fSPetter Reinholdtsen 
4195*c18ec02fSPetter Reinholdtsen 	if(rc == 0)
4196*c18ec02fSPetter Reinholdtsen 	{
4197*c18ec02fSPetter Reinholdtsen 		uint8_t * frubuf;
4198*c18ec02fSPetter Reinholdtsen 
4199*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_DEBUG, "Internal Use Area Offset: %i", offset);
4200*c18ec02fSPetter Reinholdtsen 		printf(          "Internal Use Area Size  : %i\n", size);
4201*c18ec02fSPetter Reinholdtsen 
4202*c18ec02fSPetter Reinholdtsen 		frubuf = malloc( size );
4203*c18ec02fSPetter Reinholdtsen 		if(frubuf)
4204*c18ec02fSPetter Reinholdtsen 		{
4205*c18ec02fSPetter Reinholdtsen 			rc = read_fru_area_section(intf, &fru, id, offset, size, frubuf);
4206*c18ec02fSPetter Reinholdtsen 
4207*c18ec02fSPetter Reinholdtsen 			if(rc == 0)
4208*c18ec02fSPetter Reinholdtsen 			{
4209*c18ec02fSPetter Reinholdtsen 				if(pFileName == NULL)
4210*c18ec02fSPetter Reinholdtsen 				{
4211*c18ec02fSPetter Reinholdtsen 					uint16_t counter;
4212*c18ec02fSPetter Reinholdtsen 					for(counter = 0; counter < size; counter ++)
4213*c18ec02fSPetter Reinholdtsen 					{
4214*c18ec02fSPetter Reinholdtsen 						if((counter % 16) == 0)
4215*c18ec02fSPetter Reinholdtsen 							printf("\n%02i- ", (counter / 16));
4216*c18ec02fSPetter Reinholdtsen 						printf("%02X ", frubuf[counter]);
4217*c18ec02fSPetter Reinholdtsen 					}
4218*c18ec02fSPetter Reinholdtsen 				}
4219*c18ec02fSPetter Reinholdtsen 				else
4220*c18ec02fSPetter Reinholdtsen 				{
4221*c18ec02fSPetter Reinholdtsen 					FILE * pFile;
4222*c18ec02fSPetter Reinholdtsen 					pFile = fopen(pFileName,"wb");
4223*c18ec02fSPetter Reinholdtsen 					if (pFile)
4224*c18ec02fSPetter Reinholdtsen 					{
4225*c18ec02fSPetter Reinholdtsen 						fwrite(frubuf, size, 1, pFile);
4226*c18ec02fSPetter Reinholdtsen 						printf("Done\n");
4227*c18ec02fSPetter Reinholdtsen 					}
4228*c18ec02fSPetter Reinholdtsen 					else
4229*c18ec02fSPetter Reinholdtsen 					{
4230*c18ec02fSPetter Reinholdtsen 						lprintf(LOG_ERR, "Error opening file %s\n", pFileName);
4231*c18ec02fSPetter Reinholdtsen 						free(frubuf);
4232*c18ec02fSPetter Reinholdtsen 						frubuf = NULL;
4233*c18ec02fSPetter Reinholdtsen 						return -1;
4234*c18ec02fSPetter Reinholdtsen 					}
4235*c18ec02fSPetter Reinholdtsen 					fclose(pFile);
4236*c18ec02fSPetter Reinholdtsen 				}
4237*c18ec02fSPetter Reinholdtsen 			}
4238*c18ec02fSPetter Reinholdtsen 			printf("\n");
4239*c18ec02fSPetter Reinholdtsen 
4240*c18ec02fSPetter Reinholdtsen 			free(frubuf);
4241*c18ec02fSPetter Reinholdtsen 			frubuf = NULL;
4242*c18ec02fSPetter Reinholdtsen 		}
4243*c18ec02fSPetter Reinholdtsen 
4244*c18ec02fSPetter Reinholdtsen 	}
4245*c18ec02fSPetter Reinholdtsen 	else
4246*c18ec02fSPetter Reinholdtsen 	{
4247*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Cannot access internal use area");
4248*c18ec02fSPetter Reinholdtsen 	}
4249*c18ec02fSPetter Reinholdtsen 	return 0;
4250*c18ec02fSPetter Reinholdtsen }
4251*c18ec02fSPetter Reinholdtsen 
4252*c18ec02fSPetter Reinholdtsen /* ipmi_fru_write_internal_use   -  print internal use are in hex or file
4253*c18ec02fSPetter Reinholdtsen *
4254*c18ec02fSPetter Reinholdtsen * @intf:   ipmi interface
4255*c18ec02fSPetter Reinholdtsen * @id:     fru id
4256*c18ec02fSPetter Reinholdtsen *
4257*c18ec02fSPetter Reinholdtsen * returns -1 on error
4258*c18ec02fSPetter Reinholdtsen * returns 0 if successful
4259*c18ec02fSPetter Reinholdtsen * returns 1 if device not present
4260*c18ec02fSPetter Reinholdtsen */
4261*c18ec02fSPetter Reinholdtsen static int
4262*c18ec02fSPetter Reinholdtsen ipmi_fru_write_internal_use(struct ipmi_intf * intf, uint8_t id, char * pFileName)
4263*c18ec02fSPetter Reinholdtsen {
4264*c18ec02fSPetter Reinholdtsen 	struct fru_info fru;
4265*c18ec02fSPetter Reinholdtsen 	uint16_t size;
4266*c18ec02fSPetter Reinholdtsen 	uint16_t offset;
4267*c18ec02fSPetter Reinholdtsen 	int rc = 0;
4268*c18ec02fSPetter Reinholdtsen 
4269*c18ec02fSPetter Reinholdtsen 	rc = ipmi_fru_get_internal_use_info(intf, id, &fru, &size, &offset);
4270*c18ec02fSPetter Reinholdtsen 
4271*c18ec02fSPetter Reinholdtsen 	if(rc == 0)
4272*c18ec02fSPetter Reinholdtsen 	{
4273*c18ec02fSPetter Reinholdtsen 		uint8_t * frubuf;
4274*c18ec02fSPetter Reinholdtsen 		FILE * fp;
4275*c18ec02fSPetter Reinholdtsen 		uint32_t fileLength = 0;
4276*c18ec02fSPetter Reinholdtsen 
4277*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_DEBUG, "Internal Use Area Offset: %i", offset);
4278*c18ec02fSPetter Reinholdtsen 		printf(            "Internal Use Area Size  : %i\n", size);
4279*c18ec02fSPetter Reinholdtsen 
4280*c18ec02fSPetter Reinholdtsen 		fp = fopen(pFileName, "r");
4281*c18ec02fSPetter Reinholdtsen 
4282*c18ec02fSPetter Reinholdtsen 		if(fp)
4283*c18ec02fSPetter Reinholdtsen 		{
4284*c18ec02fSPetter Reinholdtsen 			/* Retreive file length, check if it's fits the Eeprom Size */
4285*c18ec02fSPetter Reinholdtsen 			fseek(fp, 0 ,SEEK_END);
4286*c18ec02fSPetter Reinholdtsen 			fileLength = ftell(fp);
4287*c18ec02fSPetter Reinholdtsen 
4288*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "File Size: %i", fileLength);
4289*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "Area Size: %i", size);
4290*c18ec02fSPetter Reinholdtsen 			if(fileLength != size)
4291*c18ec02fSPetter Reinholdtsen 			{
4292*c18ec02fSPetter Reinholdtsen 				lprintf(LOG_ERR, "File size does not fit Eeprom Size");
4293*c18ec02fSPetter Reinholdtsen 				fclose(fp);
4294*c18ec02fSPetter Reinholdtsen 				fp = NULL;
4295*c18ec02fSPetter Reinholdtsen 			}
4296*c18ec02fSPetter Reinholdtsen 			else
4297*c18ec02fSPetter Reinholdtsen 			{
4298*c18ec02fSPetter Reinholdtsen 				fseek(fp, 0 ,SEEK_SET);
4299*c18ec02fSPetter Reinholdtsen 			}
4300*c18ec02fSPetter Reinholdtsen 		}
4301*c18ec02fSPetter Reinholdtsen 
4302*c18ec02fSPetter Reinholdtsen 		if(fp)
4303*c18ec02fSPetter Reinholdtsen 		{
4304*c18ec02fSPetter Reinholdtsen 			frubuf = malloc( size );
4305*c18ec02fSPetter Reinholdtsen 			if(frubuf)
4306*c18ec02fSPetter Reinholdtsen 			{
4307*c18ec02fSPetter Reinholdtsen 				uint16_t fru_read_size;
4308*c18ec02fSPetter Reinholdtsen 				fru_read_size = fread(frubuf, 1, size, fp);
4309*c18ec02fSPetter Reinholdtsen 
4310*c18ec02fSPetter Reinholdtsen 				if(fru_read_size == size)
4311*c18ec02fSPetter Reinholdtsen 				{
4312*c18ec02fSPetter Reinholdtsen 					rc = write_fru_area(intf, &fru, id, 0, offset, size, frubuf);
4313*c18ec02fSPetter Reinholdtsen 
4314*c18ec02fSPetter Reinholdtsen 					if(rc == 0)
4315*c18ec02fSPetter Reinholdtsen 					{
4316*c18ec02fSPetter Reinholdtsen 						lprintf(LOG_INFO, "Done\n");
4317*c18ec02fSPetter Reinholdtsen 					}
4318*c18ec02fSPetter Reinholdtsen 				}
4319*c18ec02fSPetter Reinholdtsen 				else
4320*c18ec02fSPetter Reinholdtsen 				{
4321*c18ec02fSPetter Reinholdtsen 					lprintf(LOG_ERR, "Unable to read file: %i\n", fru_read_size);
4322*c18ec02fSPetter Reinholdtsen 				}
4323*c18ec02fSPetter Reinholdtsen 
4324*c18ec02fSPetter Reinholdtsen 				free(frubuf);
4325*c18ec02fSPetter Reinholdtsen 				frubuf = NULL;
4326*c18ec02fSPetter Reinholdtsen 			}
4327*c18ec02fSPetter Reinholdtsen 			fclose(fp);
4328*c18ec02fSPetter Reinholdtsen 			fp = NULL;
4329*c18ec02fSPetter Reinholdtsen 		}
4330*c18ec02fSPetter Reinholdtsen 	}
4331*c18ec02fSPetter Reinholdtsen 	else
4332*c18ec02fSPetter Reinholdtsen 	{
4333*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Cannot access internal use area");
4334*c18ec02fSPetter Reinholdtsen 	}
4335*c18ec02fSPetter Reinholdtsen 	return 0;
4336*c18ec02fSPetter Reinholdtsen }
4337*c18ec02fSPetter Reinholdtsen 
4338*c18ec02fSPetter Reinholdtsen int
4339*c18ec02fSPetter Reinholdtsen ipmi_fru_main(struct ipmi_intf * intf, int argc, char ** argv)
4340*c18ec02fSPetter Reinholdtsen {
4341*c18ec02fSPetter Reinholdtsen 	int rc = 0;
4342*c18ec02fSPetter Reinholdtsen 	uint8_t fru_id = 0;
4343*c18ec02fSPetter Reinholdtsen 
4344*c18ec02fSPetter Reinholdtsen 	if (argc < 1) {
4345*c18ec02fSPetter Reinholdtsen 		rc = ipmi_fru_print_all(intf);
4346*c18ec02fSPetter Reinholdtsen 	}
4347*c18ec02fSPetter Reinholdtsen 	else if (strncmp(argv[0], "help", 4) == 0) {
4348*c18ec02fSPetter Reinholdtsen 		ipmi_fru_help();
4349*c18ec02fSPetter Reinholdtsen 		return 0;
4350*c18ec02fSPetter Reinholdtsen 	}
4351*c18ec02fSPetter Reinholdtsen 	else if (strncmp(argv[0], "print", 5) == 0 ||
4352*c18ec02fSPetter Reinholdtsen 		strncmp(argv[0], "list", 4) == 0) {
4353*c18ec02fSPetter Reinholdtsen 		if (argc > 1) {
4354*c18ec02fSPetter Reinholdtsen 			if (strcmp(argv[1], "help") == 0) {
4355*c18ec02fSPetter Reinholdtsen 				lprintf(LOG_NOTICE, "fru print [fru id] - print information about FRU(s)");
4356*c18ec02fSPetter Reinholdtsen 				return 0;
4357*c18ec02fSPetter Reinholdtsen 			}
4358*c18ec02fSPetter Reinholdtsen 
4359*c18ec02fSPetter Reinholdtsen 			if (is_fru_id(argv[1], &fru_id) != 0)
4360*c18ec02fSPetter Reinholdtsen 				return (-1);
4361*c18ec02fSPetter Reinholdtsen 
4362*c18ec02fSPetter Reinholdtsen 			rc = __ipmi_fru_print(intf, fru_id);
4363*c18ec02fSPetter Reinholdtsen 		} else {
4364*c18ec02fSPetter Reinholdtsen 			rc = ipmi_fru_print_all(intf);
4365*c18ec02fSPetter Reinholdtsen 		}
4366*c18ec02fSPetter Reinholdtsen 	}
4367*c18ec02fSPetter Reinholdtsen 	else if (!strncmp(argv[0], "read", 5)) {
4368*c18ec02fSPetter Reinholdtsen 		if (argc > 1 && strcmp(argv[1], "help") == 0) {
4369*c18ec02fSPetter Reinholdtsen 			ipmi_fru_read_help();
4370*c18ec02fSPetter Reinholdtsen 			return 0;
4371*c18ec02fSPetter Reinholdtsen 		} else if (argc < 3) {
4372*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "Not enough parameters given.");
4373*c18ec02fSPetter Reinholdtsen 			ipmi_fru_read_help();
4374*c18ec02fSPetter Reinholdtsen 			return (-1);
4375*c18ec02fSPetter Reinholdtsen 		}
4376*c18ec02fSPetter Reinholdtsen 
4377*c18ec02fSPetter Reinholdtsen 		if (is_fru_id(argv[1], &fru_id) != 0)
4378*c18ec02fSPetter Reinholdtsen 			return (-1);
4379*c18ec02fSPetter Reinholdtsen 
4380*c18ec02fSPetter Reinholdtsen 		/* There is a file name in the parameters */
4381*c18ec02fSPetter Reinholdtsen 		if (is_valid_filename(argv[2]) != 0)
4382*c18ec02fSPetter Reinholdtsen 				return (-1);
4383*c18ec02fSPetter Reinholdtsen 
4384*c18ec02fSPetter Reinholdtsen 		if (verbose) {
4385*c18ec02fSPetter Reinholdtsen 			printf("FRU ID           : %d\n", fru_id);
4386*c18ec02fSPetter Reinholdtsen 			printf("FRU File         : %s\n", argv[2]);
4387*c18ec02fSPetter Reinholdtsen 		}
4388*c18ec02fSPetter Reinholdtsen 		/* TODO - rc is missing */
4389*c18ec02fSPetter Reinholdtsen 		ipmi_fru_read_to_bin(intf, argv[2], fru_id);
4390*c18ec02fSPetter Reinholdtsen 	}
4391*c18ec02fSPetter Reinholdtsen 	else if (!strncmp(argv[0], "write", 5)) {
4392*c18ec02fSPetter Reinholdtsen 		if (argc > 1 && strcmp(argv[1], "help") == 0) {
4393*c18ec02fSPetter Reinholdtsen 			ipmi_fru_write_help();
4394*c18ec02fSPetter Reinholdtsen 			return 0;
4395*c18ec02fSPetter Reinholdtsen 		} else if (argc < 3) {
4396*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "Not enough parameters given.");
4397*c18ec02fSPetter Reinholdtsen 			ipmi_fru_write_help();
4398*c18ec02fSPetter Reinholdtsen 			return (-1);
4399*c18ec02fSPetter Reinholdtsen 		}
4400*c18ec02fSPetter Reinholdtsen 
4401*c18ec02fSPetter Reinholdtsen 		if (is_fru_id(argv[1], &fru_id) != 0)
4402*c18ec02fSPetter Reinholdtsen 			return (-1);
4403*c18ec02fSPetter Reinholdtsen 
4404*c18ec02fSPetter Reinholdtsen 		/* There is a file name in the parameters */
4405*c18ec02fSPetter Reinholdtsen 		if (is_valid_filename(argv[2]) != 0)
4406*c18ec02fSPetter Reinholdtsen 				return (-1);
4407*c18ec02fSPetter Reinholdtsen 
4408*c18ec02fSPetter Reinholdtsen 		if (verbose) {
4409*c18ec02fSPetter Reinholdtsen 			printf("FRU ID           : %d\n", fru_id);
4410*c18ec02fSPetter Reinholdtsen 			printf("FRU File         : %s\n", argv[2]);
4411*c18ec02fSPetter Reinholdtsen 		}
4412*c18ec02fSPetter Reinholdtsen 		/* TODO - rc is missing */
4413*c18ec02fSPetter Reinholdtsen 		ipmi_fru_write_from_bin(intf, argv[2], fru_id);
4414*c18ec02fSPetter Reinholdtsen 	}
4415*c18ec02fSPetter Reinholdtsen 	else if (!strncmp(argv[0], "upgEkey", 7)) {
4416*c18ec02fSPetter Reinholdtsen 		if (argc > 1 && strcmp(argv[1], "help") == 0) {
4417*c18ec02fSPetter Reinholdtsen 			ipmi_fru_upgekey_help();
4418*c18ec02fSPetter Reinholdtsen 			return 0;
4419*c18ec02fSPetter Reinholdtsen 		} else if (argc < 3) {
4420*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "Not enough parameters given.");
4421*c18ec02fSPetter Reinholdtsen 			ipmi_fru_upgekey_help();
4422*c18ec02fSPetter Reinholdtsen 			return (-1);
4423*c18ec02fSPetter Reinholdtsen 		}
4424*c18ec02fSPetter Reinholdtsen 
4425*c18ec02fSPetter Reinholdtsen 		if (is_fru_id(argv[1], &fru_id) != 0)
4426*c18ec02fSPetter Reinholdtsen 			return (-1);
4427*c18ec02fSPetter Reinholdtsen 
4428*c18ec02fSPetter Reinholdtsen 		/* There is a file name in the parameters */
4429*c18ec02fSPetter Reinholdtsen 		if (is_valid_filename(argv[2]) != 0)
4430*c18ec02fSPetter Reinholdtsen 				return (-1);
4431*c18ec02fSPetter Reinholdtsen 
4432*c18ec02fSPetter Reinholdtsen 		rc = ipmi_fru_upg_ekeying(intf, argv[2], fru_id);
4433*c18ec02fSPetter Reinholdtsen 	}
4434*c18ec02fSPetter Reinholdtsen 	else if (!strncmp(argv[0], "internaluse", 11)) {
4435*c18ec02fSPetter Reinholdtsen 		if (argc > 1 && strcmp(argv[1], "help") == 0) {
4436*c18ec02fSPetter Reinholdtsen 			ipmi_fru_internaluse_help();
4437*c18ec02fSPetter Reinholdtsen 			return 0;
4438*c18ec02fSPetter Reinholdtsen 		}
4439*c18ec02fSPetter Reinholdtsen 
4440*c18ec02fSPetter Reinholdtsen 		if ( (argc >= 3) && (!strncmp(argv[2], "info", 4)) ) {
4441*c18ec02fSPetter Reinholdtsen 
4442*c18ec02fSPetter Reinholdtsen 			if (is_fru_id(argv[1], &fru_id) != 0)
4443*c18ec02fSPetter Reinholdtsen 				return (-1);
4444*c18ec02fSPetter Reinholdtsen 
4445*c18ec02fSPetter Reinholdtsen 			rc = ipmi_fru_info_internal_use(intf, fru_id);
4446*c18ec02fSPetter Reinholdtsen 		}
4447*c18ec02fSPetter Reinholdtsen 		else if ( (argc >= 3) && (!strncmp(argv[2], "print", 5)) ) {
4448*c18ec02fSPetter Reinholdtsen 
4449*c18ec02fSPetter Reinholdtsen 			if (is_fru_id(argv[1], &fru_id) != 0)
4450*c18ec02fSPetter Reinholdtsen 				return (-1);
4451*c18ec02fSPetter Reinholdtsen 
4452*c18ec02fSPetter Reinholdtsen 			rc = ipmi_fru_read_internal_use(intf, fru_id, NULL);
4453*c18ec02fSPetter Reinholdtsen 		}
4454*c18ec02fSPetter Reinholdtsen 		else if ( (argc >= 4) && (!strncmp(argv[2], "read", 4)) ) {
4455*c18ec02fSPetter Reinholdtsen 
4456*c18ec02fSPetter Reinholdtsen 			if (is_fru_id(argv[1], &fru_id) != 0)
4457*c18ec02fSPetter Reinholdtsen 				return (-1);
4458*c18ec02fSPetter Reinholdtsen 
4459*c18ec02fSPetter Reinholdtsen 			/* There is a file name in the parameters */
4460*c18ec02fSPetter Reinholdtsen 			if (is_valid_filename(argv[3]) != 0)
4461*c18ec02fSPetter Reinholdtsen 					return (-1);
4462*c18ec02fSPetter Reinholdtsen 
4463*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG, "FRU ID           : %d", fru_id);
4464*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG, "FRU File         : %s", argv[3]);
4465*c18ec02fSPetter Reinholdtsen 
4466*c18ec02fSPetter Reinholdtsen 			rc = ipmi_fru_read_internal_use(intf, fru_id, argv[3]);
4467*c18ec02fSPetter Reinholdtsen 		}
4468*c18ec02fSPetter Reinholdtsen 		else if ( (argc >= 4) && (!strncmp(argv[2], "write", 5)) ) {
4469*c18ec02fSPetter Reinholdtsen 
4470*c18ec02fSPetter Reinholdtsen 			if (is_fru_id(argv[1], &fru_id) != 0)
4471*c18ec02fSPetter Reinholdtsen 				return (-1);
4472*c18ec02fSPetter Reinholdtsen 
4473*c18ec02fSPetter Reinholdtsen 			/* There is a file name in the parameters */
4474*c18ec02fSPetter Reinholdtsen 			if (is_valid_filename(argv[3]) != 0)
4475*c18ec02fSPetter Reinholdtsen 					return (-1);
4476*c18ec02fSPetter Reinholdtsen 
4477*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG, "FRU ID           : %d", fru_id);
4478*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_DEBUG, "FRU File         : %s", argv[3]);
4479*c18ec02fSPetter Reinholdtsen 
4480*c18ec02fSPetter Reinholdtsen 			rc = ipmi_fru_write_internal_use(intf, fru_id, argv[3]);
4481*c18ec02fSPetter Reinholdtsen 		} else {
4482*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR,
4483*c18ec02fSPetter Reinholdtsen 					"Either unknown command or not enough parameters given.");
4484*c18ec02fSPetter Reinholdtsen 			ipmi_fru_internaluse_help();
4485*c18ec02fSPetter Reinholdtsen 			return (-1);
4486*c18ec02fSPetter Reinholdtsen 		}
4487*c18ec02fSPetter Reinholdtsen 	}
4488*c18ec02fSPetter Reinholdtsen 	else if (!strncmp(argv[0], "edit", 4)) {
4489*c18ec02fSPetter Reinholdtsen 		if (argc > 1 && strcmp(argv[1], "help") == 0) {
4490*c18ec02fSPetter Reinholdtsen 			ipmi_fru_edit_help();
4491*c18ec02fSPetter Reinholdtsen 			return 0;
4492*c18ec02fSPetter Reinholdtsen 		} else if (argc < 2) {
4493*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "Not enough parameters given.");
4494*c18ec02fSPetter Reinholdtsen 			ipmi_fru_edit_help();
4495*c18ec02fSPetter Reinholdtsen 			return (-1);
4496*c18ec02fSPetter Reinholdtsen 		}
4497*c18ec02fSPetter Reinholdtsen 
4498*c18ec02fSPetter Reinholdtsen 		if (argc >= 2) {
4499*c18ec02fSPetter Reinholdtsen 			if (is_fru_id(argv[1], &fru_id) != 0)
4500*c18ec02fSPetter Reinholdtsen 				return (-1);
4501*c18ec02fSPetter Reinholdtsen 
4502*c18ec02fSPetter Reinholdtsen 			if (verbose) {
4503*c18ec02fSPetter Reinholdtsen 				printf("FRU ID           : %d\n", fru_id);
4504*c18ec02fSPetter Reinholdtsen 			}
4505*c18ec02fSPetter Reinholdtsen 		} else {
4506*c18ec02fSPetter Reinholdtsen 			printf("Using default FRU ID: %d\n", fru_id);
4507*c18ec02fSPetter Reinholdtsen 		}
4508*c18ec02fSPetter Reinholdtsen 
4509*c18ec02fSPetter Reinholdtsen 		if (argc >= 3) {
4510*c18ec02fSPetter Reinholdtsen 			if (!strncmp(argv[2], "field", 5)) {
4511*c18ec02fSPetter Reinholdtsen 				if (argc != 6) {
4512*c18ec02fSPetter Reinholdtsen 					lprintf(LOG_ERR, "Not enough parameters given.");
4513*c18ec02fSPetter Reinholdtsen 					ipmi_fru_edit_help();
4514*c18ec02fSPetter Reinholdtsen 					return (-1);
4515*c18ec02fSPetter Reinholdtsen 				}
4516*c18ec02fSPetter Reinholdtsen 				rc = ipmi_fru_set_field_string(intf, fru_id, *argv[3], *argv[4],
4517*c18ec02fSPetter Reinholdtsen 						(char *) argv[5]);
4518*c18ec02fSPetter Reinholdtsen 			} else if (!strncmp(argv[2], "oem", 3)) {
4519*c18ec02fSPetter Reinholdtsen 				rc = ipmi_fru_edit_multirec(intf, fru_id, argc, argv);
4520*c18ec02fSPetter Reinholdtsen 			} else {
4521*c18ec02fSPetter Reinholdtsen 				lprintf(LOG_ERR, "Invalid command: %s", argv[2]);
4522*c18ec02fSPetter Reinholdtsen 				ipmi_fru_edit_help();
4523*c18ec02fSPetter Reinholdtsen 				return (-1);
4524*c18ec02fSPetter Reinholdtsen 			}
4525*c18ec02fSPetter Reinholdtsen 		} else {
4526*c18ec02fSPetter Reinholdtsen 			rc = ipmi_fru_edit_multirec(intf, fru_id, argc, argv);
4527*c18ec02fSPetter Reinholdtsen 		}
4528*c18ec02fSPetter Reinholdtsen 	}
4529*c18ec02fSPetter Reinholdtsen 	else if (!strncmp(argv[0], "get", 4)) {
4530*c18ec02fSPetter Reinholdtsen 		if (argc > 1 && (strncmp(argv[1], "help", 4) == 0)) {
4531*c18ec02fSPetter Reinholdtsen 			ipmi_fru_get_help();
4532*c18ec02fSPetter Reinholdtsen 			return 0;
4533*c18ec02fSPetter Reinholdtsen 		} else if (argc < 2) {
4534*c18ec02fSPetter Reinholdtsen 			lprintf(LOG_ERR, "Not enough parameters given.");
4535*c18ec02fSPetter Reinholdtsen 			ipmi_fru_get_help();
4536*c18ec02fSPetter Reinholdtsen 			return (-1);
4537*c18ec02fSPetter Reinholdtsen 		}
4538*c18ec02fSPetter Reinholdtsen 
4539*c18ec02fSPetter Reinholdtsen 		if (argc >= 2) {
4540*c18ec02fSPetter Reinholdtsen 			if (is_fru_id(argv[1], &fru_id) != 0)
4541*c18ec02fSPetter Reinholdtsen 				return (-1);
4542*c18ec02fSPetter Reinholdtsen 
4543*c18ec02fSPetter Reinholdtsen 			if (verbose) {
4544*c18ec02fSPetter Reinholdtsen 				printf("FRU ID           : %d\n", fru_id);
4545*c18ec02fSPetter Reinholdtsen 			}
4546*c18ec02fSPetter Reinholdtsen 		} else {
4547*c18ec02fSPetter Reinholdtsen 			printf("Using default FRU ID: %d\n", fru_id);
4548*c18ec02fSPetter Reinholdtsen 		}
4549*c18ec02fSPetter Reinholdtsen 
4550*c18ec02fSPetter Reinholdtsen 		if (argc >= 3) {
4551*c18ec02fSPetter Reinholdtsen 			if (!strncmp(argv[2], "oem", 3)) {
4552*c18ec02fSPetter Reinholdtsen 				rc = ipmi_fru_get_multirec(intf, fru_id, argc, argv);
4553*c18ec02fSPetter Reinholdtsen 			} else {
4554*c18ec02fSPetter Reinholdtsen 				lprintf(LOG_ERR, "Invalid command: %s", argv[2]);
4555*c18ec02fSPetter Reinholdtsen 				ipmi_fru_get_help();
4556*c18ec02fSPetter Reinholdtsen 				return (-1);
4557*c18ec02fSPetter Reinholdtsen 			}
4558*c18ec02fSPetter Reinholdtsen 		} else {
4559*c18ec02fSPetter Reinholdtsen 			rc = ipmi_fru_get_multirec(intf, fru_id, argc, argv);
4560*c18ec02fSPetter Reinholdtsen 		}
4561*c18ec02fSPetter Reinholdtsen 	}
4562*c18ec02fSPetter Reinholdtsen 	else {
4563*c18ec02fSPetter Reinholdtsen 		lprintf(LOG_ERR, "Invalid FRU command: %s", argv[0]);
4564*c18ec02fSPetter Reinholdtsen 		ipmi_fru_help();
4565*c18ec02fSPetter Reinholdtsen 		return (-1);
4566*c18ec02fSPetter Reinholdtsen 	}
4567*c18ec02fSPetter Reinholdtsen 
4568*c18ec02fSPetter Reinholdtsen 	return rc;
4569*c18ec02fSPetter Reinholdtsen }
4570*c18ec02fSPetter Reinholdtsen 
4571*c18ec02fSPetter Reinholdtsen /* ipmi_fru_set_field_string -  Set a field string to a new value, Need to be the same size.  If
4572*c18ec02fSPetter Reinholdtsen *                              size if not equal, the function ipmi_fru_set_field_string_rebuild
4573*c18ec02fSPetter Reinholdtsen *                              will be called.
4574*c18ec02fSPetter Reinholdtsen *
4575*c18ec02fSPetter Reinholdtsen * @intf:       ipmi interface
4576*c18ec02fSPetter Reinholdtsen * @id:         fru id
4577*c18ec02fSPetter Reinholdtsen * @f_type:    Type of the Field : c=Chassis b=Board p=Product
4578*c18ec02fSPetter Reinholdtsen * @f_index:   findex of the field, zero indexed.
4579*c18ec02fSPetter Reinholdtsen * @f_string:  NULL terminated string
4580*c18ec02fSPetter Reinholdtsen *
4581*c18ec02fSPetter Reinholdtsen * returns -1 on error
4582*c18ec02fSPetter Reinholdtsen * returns 1 if successful
4583*c18ec02fSPetter Reinholdtsen */
4584*c18ec02fSPetter Reinholdtsen static int
4585*c18ec02fSPetter Reinholdtsen ipmi_fru_set_field_string(struct ipmi_intf * intf, uint8_t fruId, uint8_t
4586*c18ec02fSPetter Reinholdtsen f_type, uint8_t f_index, char *f_string)
4587*c18ec02fSPetter Reinholdtsen {
4588*c18ec02fSPetter Reinholdtsen 	struct ipmi_rs *rsp;
4589*c18ec02fSPetter Reinholdtsen 	struct ipmi_rq req;
4590*c18ec02fSPetter Reinholdtsen 
4591*c18ec02fSPetter Reinholdtsen 	struct fru_info fru;
4592*c18ec02fSPetter Reinholdtsen 	struct fru_header header;
4593*c18ec02fSPetter Reinholdtsen 	uint8_t msg_data[4];
4594*c18ec02fSPetter Reinholdtsen 	uint8_t checksum;
4595*c18ec02fSPetter Reinholdtsen 	int i = 0;
4596*c18ec02fSPetter Reinholdtsen 	int rc = 1;
4597*c18ec02fSPetter Reinholdtsen 	uint8_t *fru_data = NULL;
4598*c18ec02fSPetter Reinholdtsen 	uint8_t *fru_area = NULL;
4599*c18ec02fSPetter Reinholdtsen 	uint32_t fru_field_offset, fru_field_offset_tmp;
4600*c18ec02fSPetter Reinholdtsen 	uint32_t fru_section_len, header_offset;
4601*c18ec02fSPetter Reinholdtsen 
4602*c18ec02fSPetter Reinholdtsen 	memset(msg_data, 0, 4);
4603*c18ec02fSPetter Reinholdtsen 	msg_data[0] = fruId;
4604*c18ec02fSPetter Reinholdtsen 
4605*c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
4606*c18ec02fSPetter Reinholdtsen 	req.msg.netfn = IPMI_NETFN_STORAGE;
4607*c18ec02fSPetter Reinholdtsen 	req.msg.cmd = GET_FRU_INFO;
4608*c18ec02fSPetter Reinholdtsen 	req.msg.data = msg_data;
4609*c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 1;
4610*c18ec02fSPetter Reinholdtsen 
4611*c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
4612*c18ec02fSPetter Reinholdtsen 	if (rsp == NULL) {
4613*c18ec02fSPetter Reinholdtsen 		printf(" Device not present (No Response)\n");
4614*c18ec02fSPetter Reinholdtsen 		rc = (-1);
4615*c18ec02fSPetter Reinholdtsen 		goto ipmi_fru_set_field_string_out;
4616*c18ec02fSPetter Reinholdtsen 	}
4617*c18ec02fSPetter Reinholdtsen 	if (rsp->ccode > 0) {
4618*c18ec02fSPetter Reinholdtsen 		printf(" Device not present (%s)\n",
4619*c18ec02fSPetter Reinholdtsen 			val2str(rsp->ccode, completion_code_vals));
4620*c18ec02fSPetter Reinholdtsen 		rc = (-1);
4621*c18ec02fSPetter Reinholdtsen 		goto ipmi_fru_set_field_string_out;
4622*c18ec02fSPetter Reinholdtsen 	}
4623*c18ec02fSPetter Reinholdtsen 
4624*c18ec02fSPetter Reinholdtsen 	memset(&fru, 0, sizeof(fru));
4625*c18ec02fSPetter Reinholdtsen 	fru.size = (rsp->data[1] << 8) | rsp->data[0];
4626*c18ec02fSPetter Reinholdtsen 	fru.access = rsp->data[2] & 0x1;
4627*c18ec02fSPetter Reinholdtsen 
4628*c18ec02fSPetter Reinholdtsen 	if (fru.size < 1) {
4629*c18ec02fSPetter Reinholdtsen 		printf(" Invalid FRU size %d", fru.size);
4630*c18ec02fSPetter Reinholdtsen 		rc = (-1);
4631*c18ec02fSPetter Reinholdtsen 		goto ipmi_fru_set_field_string_out;
4632*c18ec02fSPetter Reinholdtsen 	}
4633*c18ec02fSPetter Reinholdtsen 	/*
4634*c18ec02fSPetter Reinholdtsen 	* retrieve the FRU header
4635*c18ec02fSPetter Reinholdtsen 	*/
4636*c18ec02fSPetter Reinholdtsen 	msg_data[0] = fruId;
4637*c18ec02fSPetter Reinholdtsen 	msg_data[1] = 0;
4638*c18ec02fSPetter Reinholdtsen 	msg_data[2] = 0;
4639*c18ec02fSPetter Reinholdtsen 	msg_data[3] = 8;
4640*c18ec02fSPetter Reinholdtsen 
4641*c18ec02fSPetter Reinholdtsen 	memset(&req, 0, sizeof(req));
4642*c18ec02fSPetter Reinholdtsen 	req.msg.netfn = IPMI_NETFN_STORAGE;
4643*c18ec02fSPetter Reinholdtsen 	req.msg.cmd = GET_FRU_DATA;
4644*c18ec02fSPetter Reinholdtsen 	req.msg.data = msg_data;
4645*c18ec02fSPetter Reinholdtsen 	req.msg.data_len = 4;
4646*c18ec02fSPetter Reinholdtsen 
4647*c18ec02fSPetter Reinholdtsen 	rsp = intf->sendrecv(intf, &req);
4648*c18ec02fSPetter Reinholdtsen 	if (rsp == NULL)
4649*c18ec02fSPetter Reinholdtsen 	{
4650*c18ec02fSPetter Reinholdtsen 		printf(" Device not present (No Response)\n");
4651*c18ec02fSPetter Reinholdtsen 		rc = (-1);
4652*c18ec02fSPetter Reinholdtsen 		goto ipmi_fru_set_field_string_out;
4653*c18ec02fSPetter Reinholdtsen 	}
4654*c18ec02fSPetter Reinholdtsen 	if (rsp->ccode > 0)
4655*c18ec02fSPetter Reinholdtsen 	{
4656*c18ec02fSPetter Reinholdtsen 		printf(" Device not present (%s)\n",
4657*c18ec02fSPetter Reinholdtsen 				val2str(rsp->ccode, completion_code_vals));
4658*c18ec02fSPetter Reinholdtsen 		rc = (-1);
4659*c18ec02fSPetter Reinholdtsen 		goto ipmi_fru_set_field_string_out;
4660*c18ec02fSPetter Reinholdtsen 	}
4661*c18ec02fSPetter Reinholdtsen 
4662*c18ec02fSPetter Reinholdtsen 	if (verbose > 1)
4663*c18ec02fSPetter Reinholdtsen 		printbuf(rsp->data, rsp->data_len, "FRU DATA");
4664*c18ec02fSPetter Reinholdtsen 
4665*c18ec02fSPetter Reinholdtsen 	memcpy(&header, rsp->data + 1, 8);
4666*c18ec02fSPetter Reinholdtsen 
4667*c18ec02fSPetter Reinholdtsen 	if (header.version != 1)
4668*c18ec02fSPetter Reinholdtsen 	{
4669*c18ec02fSPetter Reinholdtsen 		printf(" Unknown FRU header version 0x%02x",
4670*c18ec02fSPetter Reinholdtsen 			header.version);
4671*c18ec02fSPetter Reinholdtsen 		rc = (-1);
4672*c18ec02fSPetter Reinholdtsen 		goto ipmi_fru_set_field_string_out;
4673*c18ec02fSPetter Reinholdtsen 	}
4674*c18ec02fSPetter Reinholdtsen 
4675*c18ec02fSPetter Reinholdtsen 	fru_data = malloc( fru.size );
4676*c18ec02fSPetter Reinholdtsen 
4677*c18ec02fSPetter Reinholdtsen 	if( fru_data == NULL )
4678*c18ec02fSPetter Reinholdtsen 	{
4679*c18ec02fSPetter Reinholdtsen 		printf("Out of memory!\n");
4680*c18ec02fSPetter Reinholdtsen 		rc = (-1);
4681*c18ec02fSPetter Reinholdtsen 		goto ipmi_fru_set_field_string_out;
4682*c18ec02fSPetter Reinholdtsen 	}
4683*c18ec02fSPetter Reinholdtsen 
4684*c18ec02fSPetter Reinholdtsen 	/* Setup offset from the field type */
4685*c18ec02fSPetter Reinholdtsen 
4686*c18ec02fSPetter Reinholdtsen 	/* Chassis type field */
4687*c18ec02fSPetter Reinholdtsen 	if (f_type == 'c' ) {
4688*c18ec02fSPetter Reinholdtsen 		header_offset = (header.offset.chassis * 8);
4689*c18ec02fSPetter Reinholdtsen 		read_fru_area(intf ,&fru, fruId, header_offset , 3 , fru_data);
4690*c18ec02fSPetter Reinholdtsen 		fru_field_offset = (header.offset.chassis * 8) + 3;
4691*c18ec02fSPetter Reinholdtsen 		fru_section_len = *(fru_data + header_offset + 1) * 8;
4692*c18ec02fSPetter Reinholdtsen 	}
4693*c18ec02fSPetter Reinholdtsen 	/* Board type field */
4694*c18ec02fSPetter Reinholdtsen 	else if (f_type == 'b' ) {
4695*c18ec02fSPetter Reinholdtsen 		header_offset = (header.offset.board * 8);
4696*c18ec02fSPetter Reinholdtsen 		read_fru_area(intf ,&fru, fruId, header_offset , 3 , fru_data);
4697*c18ec02fSPetter Reinholdtsen 		fru_field_offset = (header.offset.board * 8) + 6;
4698*c18ec02fSPetter Reinholdtsen 		fru_section_len = *(fru_data + header_offset + 1) * 8;
4699*c18ec02fSPetter Reinholdtsen 	}
4700*c18ec02fSPetter Reinholdtsen 	/* Product type field */
4701*c18ec02fSPetter Reinholdtsen 	else if (f_type == 'p' ) {
4702*c18ec02fSPetter Reinholdtsen 		header_offset = (header.offset.product * 8);
4703*c18ec02fSPetter Reinholdtsen 		read_fru_area(intf ,&fru, fruId, header_offset , 3 , fru_data);
4704*c18ec02fSPetter Reinholdtsen 		fru_field_offset = (header.offset.product * 8) + 3;
4705*c18ec02fSPetter Reinholdtsen 		fru_section_len = *(fru_data + header_offset + 1) * 8;
4706*c18ec02fSPetter Reinholdtsen 	}
4707*c18ec02fSPetter Reinholdtsen 	else
4708*c18ec02fSPetter Reinholdtsen 	{
4709*c18ec02fSPetter Reinholdtsen 		printf("Wrong field type.");
4710*c18ec02fSPetter Reinholdtsen 		rc = (-1);
4711*c18ec02fSPetter Reinholdtsen 		goto ipmi_fru_set_field_string_out;
4712*c18ec02fSPetter Reinholdtsen 	}
4713*c18ec02fSPetter Reinholdtsen 	memset(fru_data, 0, fru.size);
4714*c18ec02fSPetter Reinholdtsen 	if( read_fru_area(intf ,&fru, fruId, header_offset ,
4715*c18ec02fSPetter Reinholdtsen 					fru_section_len , fru_data) < 0 )
4716*c18ec02fSPetter Reinholdtsen 	{
4717*c18ec02fSPetter Reinholdtsen 		rc = (-1);
4718*c18ec02fSPetter Reinholdtsen 		goto ipmi_fru_set_field_string_out;
4719*c18ec02fSPetter Reinholdtsen 	}
4720*c18ec02fSPetter Reinholdtsen 	/* Convert index from character to decimal */
4721*c18ec02fSPetter Reinholdtsen 	f_index= f_index - 0x30;
4722*c18ec02fSPetter Reinholdtsen 
4723*c18ec02fSPetter Reinholdtsen 	/*Seek to field index */
4724*c18ec02fSPetter Reinholdtsen 	for (i=0; i <= f_index; i++) {
4725*c18ec02fSPetter Reinholdtsen 		fru_field_offset_tmp = fru_field_offset;
4726*c18ec02fSPetter Reinholdtsen 		if (fru_area != NULL) {
4727*c18ec02fSPetter Reinholdtsen 			free(fru_area);
4728*c18ec02fSPetter Reinholdtsen 			fru_area = NULL;
4729*c18ec02fSPetter Reinholdtsen 		}
4730*c18ec02fSPetter Reinholdtsen 		fru_area = (uint8_t *) get_fru_area_str(fru_data, &fru_field_offset);
4731*c18ec02fSPetter Reinholdtsen 	}
4732*c18ec02fSPetter Reinholdtsen 
4733*c18ec02fSPetter Reinholdtsen 	if( (fru_area == NULL )  || strlen((const char *)fru_area) == 0 ) {
4734*c18ec02fSPetter Reinholdtsen 		printf("Field not found !\n");
4735*c18ec02fSPetter Reinholdtsen 		rc = (-1);
4736*c18ec02fSPetter Reinholdtsen 		goto ipmi_fru_set_field_string_out;
4737*c18ec02fSPetter Reinholdtsen 	}
4738*c18ec02fSPetter Reinholdtsen 
4739*c18ec02fSPetter Reinholdtsen 	if ( strlen((const char *)fru_area) == strlen((const char *)f_string) )
4740*c18ec02fSPetter Reinholdtsen 	{
4741*c18ec02fSPetter Reinholdtsen 		printf("Updating Field '%s' with '%s' ...\n", fru_area, f_string );
4742*c18ec02fSPetter Reinholdtsen 		memcpy(fru_data + fru_field_offset_tmp + 1,
4743*c18ec02fSPetter Reinholdtsen 								f_string, strlen(f_string));
4744*c18ec02fSPetter Reinholdtsen 
4745*c18ec02fSPetter Reinholdtsen 		checksum = 0;
4746*c18ec02fSPetter Reinholdtsen 		/* Calculate Header Checksum */
4747*c18ec02fSPetter Reinholdtsen 		for( i = header_offset; i < header_offset
4748*c18ec02fSPetter Reinholdtsen 						+ fru_section_len - 1; i ++ )
4749*c18ec02fSPetter Reinholdtsen 		{
4750*c18ec02fSPetter Reinholdtsen 			checksum += fru_data[i];
4751*c18ec02fSPetter Reinholdtsen 		}
4752*c18ec02fSPetter Reinholdtsen 		checksum = (~checksum) + 1;
4753*c18ec02fSPetter Reinholdtsen 		fru_data[header_offset + fru_section_len - 1] = checksum;
4754*c18ec02fSPetter Reinholdtsen 
4755*c18ec02fSPetter Reinholdtsen 		/* Write the updated section to the FRU data */
4756*c18ec02fSPetter Reinholdtsen 		if( write_fru_area(intf, &fru, fruId, header_offset,
4757*c18ec02fSPetter Reinholdtsen 				header_offset, fru_section_len, fru_data) < 0 )
4758*c18ec02fSPetter Reinholdtsen 		{
4759*c18ec02fSPetter Reinholdtsen 			printf("Write to FRU data failed.\n");
4760*c18ec02fSPetter Reinholdtsen 			rc = (-1);
4761*c18ec02fSPetter Reinholdtsen 			goto ipmi_fru_set_field_string_out;
4762*c18ec02fSPetter Reinholdtsen 		}
4763*c18ec02fSPetter Reinholdtsen 	}
4764*c18ec02fSPetter Reinholdtsen 	else {
4765*c18ec02fSPetter Reinholdtsen 		printf("String size are not equal, resizing fru to fit new string\n");
4766*c18ec02fSPetter Reinholdtsen 		if(
4767*c18ec02fSPetter Reinholdtsen 				ipmi_fru_set_field_string_rebuild(intf,fruId,fru,header,f_type,f_index,f_string)
4768*c18ec02fSPetter Reinholdtsen 		)
4769*c18ec02fSPetter Reinholdtsen 		{
4770*c18ec02fSPetter Reinholdtsen 			rc = (-1);
4771*c18ec02fSPetter Reinholdtsen 			goto ipmi_fru_set_field_string_out;
4772*c18ec02fSPetter Reinholdtsen 		}
4773*c18ec02fSPetter Reinholdtsen 	}
4774*c18ec02fSPetter Reinholdtsen 
4775*c18ec02fSPetter Reinholdtsen 	ipmi_fru_set_field_string_out:
4776*c18ec02fSPetter Reinholdtsen 	if (fru_data != NULL) {
4777*c18ec02fSPetter Reinholdtsen 		free(fru_data);
4778*c18ec02fSPetter Reinholdtsen 		fru_data = NULL;
4779*c18ec02fSPetter Reinholdtsen 	}
4780*c18ec02fSPetter Reinholdtsen 	if (fru_area != NULL) {
4781*c18ec02fSPetter Reinholdtsen 		free(fru_area);
4782*c18ec02fSPetter Reinholdtsen 		fru_area = NULL;
4783*c18ec02fSPetter Reinholdtsen 	}
4784*c18ec02fSPetter Reinholdtsen 
4785*c18ec02fSPetter Reinholdtsen 	return rc;
4786*c18ec02fSPetter Reinholdtsen }
4787*c18ec02fSPetter Reinholdtsen 
4788*c18ec02fSPetter Reinholdtsen /*
4789*c18ec02fSPetter Reinholdtsen 	This function can update a string within of the following section when the size is not equal:
4790*c18ec02fSPetter Reinholdtsen 
4791*c18ec02fSPetter Reinholdtsen 	Chassis
4792*c18ec02fSPetter Reinholdtsen 	Product
4793*c18ec02fSPetter Reinholdtsen 	Board
4794*c18ec02fSPetter Reinholdtsen */
4795*c18ec02fSPetter Reinholdtsen /* ipmi_fru_set_field_string_rebuild -  Set a field string to a new value, When size are not
4796*c18ec02fSPetter Reinholdtsen *                                      the same size.
4797*c18ec02fSPetter Reinholdtsen *
4798*c18ec02fSPetter Reinholdtsen *  This function can update a string within of the following section when the size is not equal:
4799*c18ec02fSPetter Reinholdtsen *
4800*c18ec02fSPetter Reinholdtsen *      - Chassis
4801*c18ec02fSPetter Reinholdtsen *      - Product
4802*c18ec02fSPetter Reinholdtsen *      - Board
4803*c18ec02fSPetter Reinholdtsen *
4804*c18ec02fSPetter Reinholdtsen * @intf:     ipmi interface
4805*c18ec02fSPetter Reinholdtsen * @fruId:    fru id
4806*c18ec02fSPetter Reinholdtsen * @fru:      info about fru
4807*c18ec02fSPetter Reinholdtsen * @header:   contain the header of the FRU
4808*c18ec02fSPetter Reinholdtsen * @f_type:   Type of the Field : c=Chassis b=Board p=Product
4809*c18ec02fSPetter Reinholdtsen * @f_index:  findex of the field, zero indexed.
4810*c18ec02fSPetter Reinholdtsen * @f_string: NULL terminated string
4811*c18ec02fSPetter Reinholdtsen *
4812*c18ec02fSPetter Reinholdtsen * returns -1 on error
4813*c18ec02fSPetter Reinholdtsen * returns 1 if successful
4814*c18ec02fSPetter Reinholdtsen */
4815*c18ec02fSPetter Reinholdtsen 
4816*c18ec02fSPetter Reinholdtsen #define DBG_RESIZE_FRU
4817*c18ec02fSPetter Reinholdtsen static int
4818*c18ec02fSPetter Reinholdtsen ipmi_fru_set_field_string_rebuild(struct ipmi_intf * intf, uint8_t fruId,
4819*c18ec02fSPetter Reinholdtsen 											struct fru_info fru, struct fru_header header,
4820*c18ec02fSPetter Reinholdtsen 											uint8_t f_type, uint8_t f_index, char *f_string)
4821*c18ec02fSPetter Reinholdtsen {
4822*c18ec02fSPetter Reinholdtsen 	uint8_t msg_data[4];
4823*c18ec02fSPetter Reinholdtsen 	uint8_t checksum;
4824*c18ec02fSPetter Reinholdtsen 	int i = 0;
4825*c18ec02fSPetter Reinholdtsen 	uint8_t *fru_data_old = NULL;
4826*c18ec02fSPetter Reinholdtsen 	uint8_t *fru_data_new = NULL;
4827*c18ec02fSPetter Reinholdtsen 	uint8_t *fru_area = NULL;
4828*c18ec02fSPetter Reinholdtsen 	uint32_t fru_field_offset, fru_field_offset_tmp;
4829*c18ec02fSPetter Reinholdtsen 	uint32_t fru_section_len, old_section_len, header_offset;
4830*c18ec02fSPetter Reinholdtsen 	uint32_t chassis_offset, board_offset, product_offset;
4831*c18ec02fSPetter Reinholdtsen 	uint32_t chassis_len, board_len, product_len, product_len_new;
4832*c18ec02fSPetter Reinholdtsen 	int      num_byte_change = 0, padding_len = 0;
4833*c18ec02fSPetter Reinholdtsen 	uint32_t counter;
4834*c18ec02fSPetter Reinholdtsen 	unsigned char cksum;
4835*c18ec02fSPetter Reinholdtsen 	int rc = 1;
4836*c18ec02fSPetter Reinholdtsen 
4837*c18ec02fSPetter Reinholdtsen 	fru_data_old = calloc( fru.size, sizeof(uint8_t) );
4838*c18ec02fSPetter Reinholdtsen 
4839*c18ec02fSPetter Reinholdtsen 	fru_data_new = malloc( fru.size );
4840*c18ec02fSPetter Reinholdtsen 
4841*c18ec02fSPetter Reinholdtsen 	if( fru_data_old == NULL || fru_data_new == NULL )
4842*c18ec02fSPetter Reinholdtsen 	{
4843*c18ec02fSPetter Reinholdtsen 		printf("Out of memory!\n");
4844*c18ec02fSPetter Reinholdtsen 		rc = (-1);
4845*c18ec02fSPetter Reinholdtsen 		goto ipmi_fru_set_field_string_rebuild_out;
4846*c18ec02fSPetter Reinholdtsen 	}
4847*c18ec02fSPetter Reinholdtsen 
4848*c18ec02fSPetter Reinholdtsen 	/*************************
4849*c18ec02fSPetter Reinholdtsen 	1) Read ALL FRU */
4850*c18ec02fSPetter Reinholdtsen 	printf("Read All FRU area\n");
4851*c18ec02fSPetter Reinholdtsen 	printf("Fru Size       : %u bytes\n", fru.size);
4852*c18ec02fSPetter Reinholdtsen 
4853*c18ec02fSPetter Reinholdtsen 	/* Read current fru data */
4854*c18ec02fSPetter Reinholdtsen 	read_fru_area(intf ,&fru, fruId, 0, fru.size , fru_data_old);
4855*c18ec02fSPetter Reinholdtsen 
4856*c18ec02fSPetter Reinholdtsen 	#ifdef DBG_RESIZE_FRU
4857*c18ec02fSPetter Reinholdtsen 	printf("Copy to new FRU\n");
4858*c18ec02fSPetter Reinholdtsen 	#endif
4859*c18ec02fSPetter Reinholdtsen 
4860*c18ec02fSPetter Reinholdtsen 	/*************************
4861*c18ec02fSPetter Reinholdtsen 	2) Copy all FRU to new FRU */
4862*c18ec02fSPetter Reinholdtsen 	memcpy(fru_data_new, fru_data_old, fru.size);
4863*c18ec02fSPetter Reinholdtsen 
4864*c18ec02fSPetter Reinholdtsen 	/* Build location of all modifiable components */
4865*c18ec02fSPetter Reinholdtsen 	chassis_offset = (header.offset.chassis * 8);
4866*c18ec02fSPetter Reinholdtsen 	board_offset   = (header.offset.board   * 8);
4867*c18ec02fSPetter Reinholdtsen 	product_offset = (header.offset.product * 8);
4868*c18ec02fSPetter Reinholdtsen 
4869*c18ec02fSPetter Reinholdtsen 	/* Retrieve length of all modifiable components */
4870*c18ec02fSPetter Reinholdtsen 	chassis_len    =  *(fru_data_old + chassis_offset + 1) * 8;
4871*c18ec02fSPetter Reinholdtsen 	board_len      =  *(fru_data_old + board_offset   + 1) * 8;
4872*c18ec02fSPetter Reinholdtsen 	product_len    =  *(fru_data_old + product_offset + 1) * 8;
4873*c18ec02fSPetter Reinholdtsen 	product_len_new = product_len;
4874*c18ec02fSPetter Reinholdtsen 
4875*c18ec02fSPetter Reinholdtsen 	/* Chassis type field */
4876*c18ec02fSPetter Reinholdtsen 	if (f_type == 'c' )
4877*c18ec02fSPetter Reinholdtsen 	{
4878*c18ec02fSPetter Reinholdtsen 		header_offset    = chassis_offset;
4879*c18ec02fSPetter Reinholdtsen 		fru_field_offset = chassis_offset + 3;
4880*c18ec02fSPetter Reinholdtsen 		fru_section_len  = chassis_len;
4881*c18ec02fSPetter Reinholdtsen 	}
4882*c18ec02fSPetter Reinholdtsen 	/* Board type field */
4883*c18ec02fSPetter Reinholdtsen 	else if (f_type == 'b' )
4884*c18ec02fSPetter Reinholdtsen 	{
4885*c18ec02fSPetter Reinholdtsen 		header_offset    = board_offset;
4886*c18ec02fSPetter Reinholdtsen 		fru_field_offset = board_offset + 6;
4887*c18ec02fSPetter Reinholdtsen 		fru_section_len  = board_len;
4888*c18ec02fSPetter Reinholdtsen 	}
4889*c18ec02fSPetter Reinholdtsen 	/* Product type field */
4890*c18ec02fSPetter Reinholdtsen 	else if (f_type == 'p' )
4891*c18ec02fSPetter Reinholdtsen 	{
4892*c18ec02fSPetter Reinholdtsen 		header_offset    = product_offset;
4893*c18ec02fSPetter Reinholdtsen 		fru_field_offset = product_offset + 3;
4894*c18ec02fSPetter Reinholdtsen 		fru_section_len  = product_len;
4895*c18ec02fSPetter Reinholdtsen 	}
4896*c18ec02fSPetter Reinholdtsen 	else
4897*c18ec02fSPetter Reinholdtsen 	{
4898*c18ec02fSPetter Reinholdtsen 		printf("Wrong field type.");
4899*c18ec02fSPetter Reinholdtsen 		rc = (-1);
4900*c18ec02fSPetter Reinholdtsen 		goto ipmi_fru_set_field_string_rebuild_out;
4901*c18ec02fSPetter Reinholdtsen 	}
4902*c18ec02fSPetter Reinholdtsen 
4903*c18ec02fSPetter Reinholdtsen 	/* Keep length for future old section display */
4904*c18ec02fSPetter Reinholdtsen 	old_section_len = fru_section_len;
4905*c18ec02fSPetter Reinholdtsen 
4906*c18ec02fSPetter Reinholdtsen 	/*************************
4907*c18ec02fSPetter Reinholdtsen 	3) Seek to field index */
4908*c18ec02fSPetter Reinholdtsen 	for (i = 0;i <= f_index; i++) {
4909*c18ec02fSPetter Reinholdtsen 		fru_field_offset_tmp = fru_field_offset;
4910*c18ec02fSPetter Reinholdtsen 		if (fru_area != NULL) {
4911*c18ec02fSPetter Reinholdtsen 			free(fru_area);
4912*c18ec02fSPetter Reinholdtsen 			fru_area = NULL;
4913*c18ec02fSPetter Reinholdtsen 		}
4914*c18ec02fSPetter Reinholdtsen 		fru_area = (uint8_t *) get_fru_area_str(fru_data_old, &fru_field_offset);
4915*c18ec02fSPetter Reinholdtsen 	}
4916*c18ec02fSPetter Reinholdtsen 
4917*c18ec02fSPetter Reinholdtsen 	if( (fru_area == NULL )  || strlen((const char *)fru_area) == 0 ) {
4918*c18ec02fSPetter Reinholdtsen 		printf("Field not found (1)!\n");
4919*c18ec02fSPetter Reinholdtsen 		rc = (-1);
4920*c18ec02fSPetter Reinholdtsen 		goto ipmi_fru_set_field_string_rebuild_out;
4921*c18ec02fSPetter Reinholdtsen 	}
4922*c18ec02fSPetter Reinholdtsen 
4923*c18ec02fSPetter Reinholdtsen 	#ifdef DBG_RESIZE_FRU
4924*c18ec02fSPetter Reinholdtsen 	printf("Section Length: %u\n", fru_section_len);
4925*c18ec02fSPetter Reinholdtsen 	#endif
4926*c18ec02fSPetter Reinholdtsen 
4927*c18ec02fSPetter Reinholdtsen 	/*************************
4928*c18ec02fSPetter Reinholdtsen 	4) Check number of padding bytes and bytes changed */
4929*c18ec02fSPetter Reinholdtsen 	for(counter = 2; counter < fru_section_len; counter ++)
4930*c18ec02fSPetter Reinholdtsen 	{
4931*c18ec02fSPetter Reinholdtsen 		if(*(fru_data_old + (header_offset + fru_section_len - counter)) == 0)
4932*c18ec02fSPetter Reinholdtsen 			padding_len ++;
4933*c18ec02fSPetter Reinholdtsen 		else
4934*c18ec02fSPetter Reinholdtsen 			break;
4935*c18ec02fSPetter Reinholdtsen 	}
4936*c18ec02fSPetter Reinholdtsen 	num_byte_change = strlen(f_string) - strlen(fru_area);
4937*c18ec02fSPetter Reinholdtsen 
4938*c18ec02fSPetter Reinholdtsen 	#ifdef DBG_RESIZE_FRU
4939*c18ec02fSPetter Reinholdtsen 	printf("Padding Length: %u\n", padding_len);
4940*c18ec02fSPetter Reinholdtsen 	printf("NumByte Change: %i\n", num_byte_change);
4941*c18ec02fSPetter Reinholdtsen 	printf("Start SecChnge: %x\n", *(fru_data_old + fru_field_offset_tmp));
4942*c18ec02fSPetter Reinholdtsen 	printf("End SecChnge  : %x\n", *(fru_data_old + fru_field_offset_tmp + strlen(f_string) + 1));
4943*c18ec02fSPetter Reinholdtsen 
4944*c18ec02fSPetter Reinholdtsen 	printf("Start Section : %x\n", *(fru_data_old + header_offset));
4945*c18ec02fSPetter Reinholdtsen 	printf("End Sec wo Pad: %x\n", *(fru_data_old + header_offset + fru_section_len - 2 - padding_len));
4946*c18ec02fSPetter Reinholdtsen 	printf("End Section   : %x\n", *(fru_data_old + header_offset + fru_section_len - 1));
4947*c18ec02fSPetter Reinholdtsen 	#endif
4948*c18ec02fSPetter Reinholdtsen 
4949*c18ec02fSPetter Reinholdtsen 	/* Calculate New Padding Length */
4950*c18ec02fSPetter Reinholdtsen 	padding_len -= num_byte_change;
4951*c18ec02fSPetter Reinholdtsen 
4952*c18ec02fSPetter Reinholdtsen 	#ifdef DBG_RESIZE_FRU
4953*c18ec02fSPetter Reinholdtsen 	printf("New Padding Length: %i\n", padding_len);
4954*c18ec02fSPetter Reinholdtsen 	#endif
4955*c18ec02fSPetter Reinholdtsen 
4956*c18ec02fSPetter Reinholdtsen 	/*************************
4957*c18ec02fSPetter Reinholdtsen 	5) Check if section must be resize.  This occur when padding length is not between 0 and 7 */
4958*c18ec02fSPetter Reinholdtsen 	if( (padding_len < 0) || (padding_len >= 8))
4959*c18ec02fSPetter Reinholdtsen 	{
4960*c18ec02fSPetter Reinholdtsen 		uint32_t remaining_offset = ((header.offset.product * 8) + product_len);
4961*c18ec02fSPetter Reinholdtsen 		int change_size_by_8;
4962*c18ec02fSPetter Reinholdtsen 
4963*c18ec02fSPetter Reinholdtsen 		if(padding_len >= 8)
4964*c18ec02fSPetter Reinholdtsen 		{
4965*c18ec02fSPetter Reinholdtsen 			/* Section must be set smaller */
4966*c18ec02fSPetter Reinholdtsen 			change_size_by_8 = ((padding_len) / 8) * (-1);
4967*c18ec02fSPetter Reinholdtsen 		}
4968*c18ec02fSPetter Reinholdtsen 		else
4969*c18ec02fSPetter Reinholdtsen 		{
4970*c18ec02fSPetter Reinholdtsen 			/* Section must be set bigger */
4971*c18ec02fSPetter Reinholdtsen 			change_size_by_8 = 1 + (((padding_len+1) / 8) * (-1));
4972*c18ec02fSPetter Reinholdtsen 		}
4973*c18ec02fSPetter Reinholdtsen 
4974*c18ec02fSPetter Reinholdtsen 		/* Recalculate padding and section length base on the section changes */
4975*c18ec02fSPetter Reinholdtsen 		fru_section_len += (change_size_by_8 * 8);
4976*c18ec02fSPetter Reinholdtsen 		padding_len     += (change_size_by_8 * 8);
4977*c18ec02fSPetter Reinholdtsen 
4978*c18ec02fSPetter Reinholdtsen 		#ifdef DBG_RESIZE_FRU
4979*c18ec02fSPetter Reinholdtsen 		printf("change_size_by_8: %i\n", change_size_by_8);
4980*c18ec02fSPetter Reinholdtsen 		printf("New Padding Length: %i\n", padding_len);
4981*c18ec02fSPetter Reinholdtsen 		printf("change_size_by_8: %i\n", change_size_by_8);
4982*c18ec02fSPetter Reinholdtsen 		printf("header.offset.board: %i\n", header.offset.board);
4983*c18ec02fSPetter Reinholdtsen 		#endif
4984*c18ec02fSPetter Reinholdtsen 
4985*c18ec02fSPetter Reinholdtsen 		/* Must move sections */
4986*c18ec02fSPetter Reinholdtsen 		/* Section that can be modified are as follow
4987*c18ec02fSPetter Reinholdtsen 			Chassis
4988*c18ec02fSPetter Reinholdtsen 			Board
4989*c18ec02fSPetter Reinholdtsen 			product */
4990*c18ec02fSPetter Reinholdtsen 
4991*c18ec02fSPetter Reinholdtsen 		/* Chassis type field */
4992*c18ec02fSPetter Reinholdtsen 		if (f_type == 'c' )
4993*c18ec02fSPetter Reinholdtsen 		{
4994*c18ec02fSPetter Reinholdtsen 			printf("Moving Section Chassis, from %i to %i\n",
4995*c18ec02fSPetter Reinholdtsen 						((header.offset.board) * 8),
4996*c18ec02fSPetter Reinholdtsen 						((header.offset.board + change_size_by_8) * 8)
4997*c18ec02fSPetter Reinholdtsen 					);
4998*c18ec02fSPetter Reinholdtsen 			memcpy(
4999*c18ec02fSPetter Reinholdtsen 						(fru_data_new + ((header.offset.board + change_size_by_8) * 8)),
5000*c18ec02fSPetter Reinholdtsen 						(fru_data_old + (header.offset.board) * 8),
5001*c18ec02fSPetter Reinholdtsen 						board_len
5002*c18ec02fSPetter Reinholdtsen 					);
5003*c18ec02fSPetter Reinholdtsen 			header.offset.board   += change_size_by_8;
5004*c18ec02fSPetter Reinholdtsen 		}
5005*c18ec02fSPetter Reinholdtsen 		/* Board type field */
5006*c18ec02fSPetter Reinholdtsen 		if ((f_type == 'c' ) || (f_type == 'b' ))
5007*c18ec02fSPetter Reinholdtsen 		{
5008*c18ec02fSPetter Reinholdtsen 			printf("Moving Section Product, from %i to %i\n",
5009*c18ec02fSPetter Reinholdtsen 						((header.offset.product) * 8),
5010*c18ec02fSPetter Reinholdtsen 						((header.offset.product + change_size_by_8) * 8)
5011*c18ec02fSPetter Reinholdtsen 					);
5012*c18ec02fSPetter Reinholdtsen 			memcpy(
5013*c18ec02fSPetter Reinholdtsen 						(fru_data_new + ((header.offset.product + change_size_by_8) * 8)),
5014*c18ec02fSPetter Reinholdtsen 						(fru_data_old + (header.offset.product) * 8),
5015*c18ec02fSPetter Reinholdtsen 						product_len
5016*c18ec02fSPetter Reinholdtsen 					);
5017*c18ec02fSPetter Reinholdtsen 			header.offset.product += change_size_by_8;
5018*c18ec02fSPetter Reinholdtsen 		}
5019*c18ec02fSPetter Reinholdtsen 
5020*c18ec02fSPetter Reinholdtsen 		/* Adjust length of the section */
5021*c18ec02fSPetter Reinholdtsen 		if (f_type == 'c')
5022*c18ec02fSPetter Reinholdtsen 		{
5023*c18ec02fSPetter Reinholdtsen 			*(fru_data_new + chassis_offset + 1) += change_size_by_8;
5024*c18ec02fSPetter Reinholdtsen 		}
5025*c18ec02fSPetter Reinholdtsen 		else if( f_type == 'b')
5026*c18ec02fSPetter Reinholdtsen 		{
5027*c18ec02fSPetter Reinholdtsen 			*(fru_data_new + board_offset + 1)   += change_size_by_8;
5028*c18ec02fSPetter Reinholdtsen 		}
5029*c18ec02fSPetter Reinholdtsen 		else if( f_type == 'p')
5030*c18ec02fSPetter Reinholdtsen 		{
5031*c18ec02fSPetter Reinholdtsen 			*(fru_data_new + product_offset + 1) += change_size_by_8;
5032*c18ec02fSPetter Reinholdtsen 			product_len_new = *(fru_data_new + product_offset + 1) * 8;
5033*c18ec02fSPetter Reinholdtsen 		}
5034*c18ec02fSPetter Reinholdtsen 
5035*c18ec02fSPetter Reinholdtsen 		/* Rebuild Header checksum */
5036*c18ec02fSPetter Reinholdtsen 		{
5037*c18ec02fSPetter Reinholdtsen 			unsigned char * pfru_header = (unsigned char *) &header;
5038*c18ec02fSPetter Reinholdtsen 			header.checksum = 0;
5039*c18ec02fSPetter Reinholdtsen 			for(counter = 0; counter < (sizeof(struct fru_header) -1); counter ++)
5040*c18ec02fSPetter Reinholdtsen 			{
5041*c18ec02fSPetter Reinholdtsen 				header.checksum += pfru_header[counter];
5042*c18ec02fSPetter Reinholdtsen 			}
5043*c18ec02fSPetter Reinholdtsen 			header.checksum = (0 - header.checksum);
5044*c18ec02fSPetter Reinholdtsen 			memcpy(fru_data_new, pfru_header, sizeof(struct fru_header));
5045*c18ec02fSPetter Reinholdtsen 		}
5046*c18ec02fSPetter Reinholdtsen 
5047*c18ec02fSPetter Reinholdtsen 		/* Move remaining sections in 1 copy */
5048*c18ec02fSPetter Reinholdtsen 		printf("Moving Remaining Bytes (Multi-Rec , etc..), from %i to %i\n",
5049*c18ec02fSPetter Reinholdtsen 					remaining_offset,
5050*c18ec02fSPetter Reinholdtsen 					((header.offset.product) * 8) + product_len_new
5051*c18ec02fSPetter Reinholdtsen 				);
5052*c18ec02fSPetter Reinholdtsen 		if(((header.offset.product * 8) + product_len_new - remaining_offset) < 0)
5053*c18ec02fSPetter Reinholdtsen 		{
5054*c18ec02fSPetter Reinholdtsen 			memcpy(
5055*c18ec02fSPetter Reinholdtsen 						fru_data_new + (header.offset.product * 8) + product_len_new,
5056*c18ec02fSPetter Reinholdtsen 						fru_data_old + remaining_offset,
5057*c18ec02fSPetter Reinholdtsen 						fru.size - remaining_offset
5058*c18ec02fSPetter Reinholdtsen 					);
5059*c18ec02fSPetter Reinholdtsen 		}
5060*c18ec02fSPetter Reinholdtsen 		else
5061*c18ec02fSPetter Reinholdtsen 		{
5062*c18ec02fSPetter Reinholdtsen 			memcpy(
5063*c18ec02fSPetter Reinholdtsen 						fru_data_new + (header.offset.product * 8) + product_len_new,
5064*c18ec02fSPetter Reinholdtsen 						fru_data_old + remaining_offset,
5065*c18ec02fSPetter Reinholdtsen 						fru.size - ((header.offset.product * 8) + product_len_new)
5066*c18ec02fSPetter Reinholdtsen 					);
5067*c18ec02fSPetter Reinholdtsen 		}
5068*c18ec02fSPetter Reinholdtsen 	}
5069*c18ec02fSPetter Reinholdtsen 
5070*c18ec02fSPetter Reinholdtsen 	/* Update only if it's fits padding length as defined in the spec, otherwise, it's an internal
5071*c18ec02fSPetter Reinholdtsen 	error */
5072*c18ec02fSPetter Reinholdtsen 	/*************************
5073*c18ec02fSPetter Reinholdtsen 	6) Update Field and sections */
5074*c18ec02fSPetter Reinholdtsen 	if( (padding_len >=0) && (padding_len < 8))
5075*c18ec02fSPetter Reinholdtsen 	{
5076*c18ec02fSPetter Reinholdtsen 		/* Do not requires any change in other section */
5077*c18ec02fSPetter Reinholdtsen 
5078*c18ec02fSPetter Reinholdtsen 		/* Change field length */
5079*c18ec02fSPetter Reinholdtsen 		printf(
5080*c18ec02fSPetter Reinholdtsen 			"Updating Field : '%s' with '%s' ... (Length from '%d' to '%d')\n",
5081*c18ec02fSPetter Reinholdtsen 			fru_area, f_string,
5082*c18ec02fSPetter Reinholdtsen 			(int)*(fru_data_old + fru_field_offset_tmp),
5083*c18ec02fSPetter Reinholdtsen 			(int)(0xc0 + strlen(f_string)));
5084*c18ec02fSPetter Reinholdtsen 		*(fru_data_new + fru_field_offset_tmp) = (0xc0 + strlen(f_string));
5085*c18ec02fSPetter Reinholdtsen 		memcpy(fru_data_new + fru_field_offset_tmp + 1, f_string, strlen(f_string));
5086*c18ec02fSPetter Reinholdtsen 
5087*c18ec02fSPetter Reinholdtsen 		/* Copy remaing bytes in section */
5088*c18ec02fSPetter Reinholdtsen #ifdef DBG_RESIZE_FRU
5089*c18ec02fSPetter Reinholdtsen 		printf("Copying remaining of sections: %d \n",
5090*c18ec02fSPetter Reinholdtsen 		 (int)((fru_data_old + header_offset + fru_section_len - 1) -
5091*c18ec02fSPetter Reinholdtsen 		 (fru_data_old + fru_field_offset_tmp + strlen(f_string) + 1)));
5092*c18ec02fSPetter Reinholdtsen #endif
5093*c18ec02fSPetter Reinholdtsen 
5094*c18ec02fSPetter Reinholdtsen 		memcpy((fru_data_new + fru_field_offset_tmp + 1 +
5095*c18ec02fSPetter Reinholdtsen 			strlen(f_string)),
5096*c18ec02fSPetter Reinholdtsen 			(fru_data_old + fru_field_offset_tmp + 1 +
5097*c18ec02fSPetter Reinholdtsen 			strlen(fru_area)),
5098*c18ec02fSPetter Reinholdtsen 		((fru_data_old + header_offset + fru_section_len - 1) -
5099*c18ec02fSPetter Reinholdtsen 		(fru_data_old + fru_field_offset_tmp + strlen(f_string) + 1)));
5100*c18ec02fSPetter Reinholdtsen 
5101*c18ec02fSPetter Reinholdtsen 		/* Add Padding if required */
5102*c18ec02fSPetter Reinholdtsen 		for(counter = 0; counter < padding_len; counter ++)
5103*c18ec02fSPetter Reinholdtsen 		{
5104*c18ec02fSPetter Reinholdtsen 			*(fru_data_new + header_offset + fru_section_len - 1 -
5105*c18ec02fSPetter Reinholdtsen 			  padding_len + counter) = 0;
5106*c18ec02fSPetter Reinholdtsen 		}
5107*c18ec02fSPetter Reinholdtsen 
5108*c18ec02fSPetter Reinholdtsen 		/* Calculate New Checksum */
5109*c18ec02fSPetter Reinholdtsen 		cksum = 0;
5110*c18ec02fSPetter Reinholdtsen 		for( counter = 0; counter <fru_section_len-1; counter ++ )
5111*c18ec02fSPetter Reinholdtsen 		{
5112*c18ec02fSPetter Reinholdtsen 			cksum += *(fru_data_new + header_offset + counter);
5113*c18ec02fSPetter Reinholdtsen 		}
5114*c18ec02fSPetter Reinholdtsen 		*(fru_data_new + header_offset + fru_section_len - 1) = (0 - cksum);
5115*c18ec02fSPetter Reinholdtsen 
5116*c18ec02fSPetter Reinholdtsen 		#ifdef DBG_RESIZE_FRU
5117*c18ec02fSPetter Reinholdtsen 		printf("Calculate New Checksum: %x\n", (0 - cksum));
5118*c18ec02fSPetter Reinholdtsen 		#endif
5119*c18ec02fSPetter Reinholdtsen 
5120*c18ec02fSPetter Reinholdtsen 		/****** ENABLE to show section modified before and after ********/
5121*c18ec02fSPetter Reinholdtsen 		#if 0
5122*c18ec02fSPetter Reinholdtsen 		printf("Section: ");
5123*c18ec02fSPetter Reinholdtsen 		for( counter = 0; counter <old_section_len; counter ++ )
5124*c18ec02fSPetter Reinholdtsen 		{
5125*c18ec02fSPetter Reinholdtsen 			if((counter %16) == 0)
5126*c18ec02fSPetter Reinholdtsen 			{
5127*c18ec02fSPetter Reinholdtsen 				printf("\n");
5128*c18ec02fSPetter Reinholdtsen 			}
5129*c18ec02fSPetter Reinholdtsen 			printf( "%02X ", *(fru_data_old + header_offset + counter) );
5130*c18ec02fSPetter Reinholdtsen 		}
5131*c18ec02fSPetter Reinholdtsen 		printf("\n");
5132*c18ec02fSPetter Reinholdtsen 
5133*c18ec02fSPetter Reinholdtsen 		printf("Section: ");
5134*c18ec02fSPetter Reinholdtsen 		for( counter = 0; counter <fru_section_len; counter ++ )
5135*c18ec02fSPetter Reinholdtsen 		{
5136*c18ec02fSPetter Reinholdtsen 			if((counter %16) == 0)
5137*c18ec02fSPetter Reinholdtsen 			{
5138*c18ec02fSPetter Reinholdtsen 				printf("\n");
5139*c18ec02fSPetter Reinholdtsen 			}
5140*c18ec02fSPetter Reinholdtsen 			printf( "%02X ", *(fru_data_new + header_offset + counter) );
5141*c18ec02fSPetter Reinholdtsen 		}
5142*c18ec02fSPetter Reinholdtsen 		printf("\n");
5143*c18ec02fSPetter Reinholdtsen 		#endif
5144*c18ec02fSPetter Reinholdtsen 	}
5145*c18ec02fSPetter Reinholdtsen 	else
5146*c18ec02fSPetter Reinholdtsen 	{
5147*c18ec02fSPetter Reinholdtsen 		printf( "Internal error, padding length %i (must be from 0 to 7) ", padding_len );
5148*c18ec02fSPetter Reinholdtsen 		rc = (-1);
5149*c18ec02fSPetter Reinholdtsen 		goto ipmi_fru_set_field_string_rebuild_out;
5150*c18ec02fSPetter Reinholdtsen 	}
5151*c18ec02fSPetter Reinholdtsen 
5152*c18ec02fSPetter Reinholdtsen 	/*************************
5153*c18ec02fSPetter Reinholdtsen 	7) Finally, write new FRU */
5154*c18ec02fSPetter Reinholdtsen 	printf("Writing new FRU.\n");
5155*c18ec02fSPetter Reinholdtsen 	if( write_fru_area( intf, &fru, fruId, 0, 0, fru.size, fru_data_new ) < 0 )
5156*c18ec02fSPetter Reinholdtsen 	{
5157*c18ec02fSPetter Reinholdtsen 		printf("Write to FRU data failed.\n");
5158*c18ec02fSPetter Reinholdtsen 		rc = (-1);
5159*c18ec02fSPetter Reinholdtsen 		goto ipmi_fru_set_field_string_rebuild_out;
5160*c18ec02fSPetter Reinholdtsen 	}
5161*c18ec02fSPetter Reinholdtsen 
5162*c18ec02fSPetter Reinholdtsen 	printf("Done.\n");
5163*c18ec02fSPetter Reinholdtsen 
5164*c18ec02fSPetter Reinholdtsen 	ipmi_fru_set_field_string_rebuild_out:
5165*c18ec02fSPetter Reinholdtsen 	if (fru_area != NULL) {
5166*c18ec02fSPetter Reinholdtsen 		free(fru_area);
5167*c18ec02fSPetter Reinholdtsen 		fru_area = NULL;
5168*c18ec02fSPetter Reinholdtsen 	}
5169*c18ec02fSPetter Reinholdtsen 	if (fru_data_new != NULL) {
5170*c18ec02fSPetter Reinholdtsen 		free(fru_data_new);
5171*c18ec02fSPetter Reinholdtsen 		fru_data_new = NULL;
5172*c18ec02fSPetter Reinholdtsen 	}
5173*c18ec02fSPetter Reinholdtsen 	if (fru_data_old != NULL) {
5174*c18ec02fSPetter Reinholdtsen 		free(fru_data_old);
5175*c18ec02fSPetter Reinholdtsen 		fru_data_old = NULL;
5176*c18ec02fSPetter Reinholdtsen 	}
5177*c18ec02fSPetter Reinholdtsen 
5178*c18ec02fSPetter Reinholdtsen 	return rc;
5179*c18ec02fSPetter Reinholdtsen }
5180