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