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