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