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