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