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