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