blob: 7979f7015a3c35c66e58b848559cadf1add18e16 [file] [log] [blame]
Hariharasubramanian R44473092015-10-15 08:25:28 -05001/*
2 * Copyright (C) 2003-2014 FreeIPMI Core Team
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18/*****************************************************************************\
19 * Copyright (C) 2007-2014 Lawrence Livermore National Security, LLC.
20 * Copyright (C) 2007 The Regents of the University of California.
21 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
22 * Written by Albert Chu <chu11@llnl.gov>
23 * UCRL-CODE-232183
24 *
25 * This file is part of Ipmi-fru, a tool used for retrieving
26 * motherboard field replaceable unit (FRU) information. For details,
27 * see http://www.llnl.gov/linux/.
28 *
29 * Ipmi-fru is free software; you can redistribute it and/or modify
30 * it under the terms of the GNU General Public License as published by the
31 * Free Software Foundation; either version 3 of the License, or (at your
32 * option) any later version.
33 *
34 * Ipmi-fru is distributed in the hope that it will be useful, but
35 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
36 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
37 * for more details.
38 *
39 * You should have received a copy of the GNU General Public License along
40 * with Ipmi-fru. If not, see <http://www.gnu.org/licenses/>.
41\*****************************************************************************/
42#include <stdio.h>
43#include <unistd.h>
44#include <string.h>
45#include <time.h>
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -050046#include <systemd/sd-bus.h>
Hariharasubramanian R44473092015-10-15 08:25:28 -050047
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -050048#define IPMI_FRU_PARSER_DEBUG 1
Hariharasubramanian R44473092015-10-15 08:25:28 -050049#define uint8_t unsigned char
50#define uint32_t unsigned int
51
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -050052#define TEXTSTR(a) #a
53# define ASSERT(x) \
54do { \
55if (0 == (x)) { \
56fprintf(stderr, \
57"Assertion failed: %s, " \
58"%d at \'%s\'\n", \
59__FILE__, \
60__LINE__, \
61TEXTSTR(a)); \
62return -1; \
63} \
64} while (0)
Hariharasubramanian R44473092015-10-15 08:25:28 -050065
66#define IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX 512
67#define IPMI_FRU_SENTINEL_VALUE 0xC1
68#define IPMI_FRU_TYPE_LENGTH_TYPE_CODE_MASK 0xC0
69#define IPMI_FRU_TYPE_LENGTH_TYPE_CODE_SHIFT 0x06
70#define IPMI_FRU_TYPE_LENGTH_NUMBER_OF_DATA_BYTES_MASK 0x3F
71#define IPMI_FRU_TYPE_LENGTH_TYPE_CODE_LANGUAGE_CODE 0x03
72
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -050073/* OpenBMC defines for Parser */
74#define IPMI_FRU_AREA_INTERNAL_USE 0x00
75#define IPMI_FRU_AREA_CHASSIS_INFO 0x01
76#define IPMI_FRU_AREA_BOARD_INFO 0x02
77#define IPMI_FRU_AREA_PRODUCT_INFO 0x03
78#define IPMI_FRU_AREA_MULTI_RECORD 0x04
79#define IPMI_FRU_AREA_TYPE_MAX 0x05
80
81#define OPENBMC_VPD_KEY_LEN 64
82#define OPENBMC_VPD_VAL_LEN 512
Hariharasubramanian R44473092015-10-15 08:25:28 -050083
84struct ipmi_fru_field
85{
86 uint8_t type_length_field[IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX];
87 /* store length of data stored in buffer */
88 unsigned int type_length_field_length;
89};
90
91typedef struct ipmi_fru_field ipmi_fru_field_t;
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -050092/*
93 * FRU Parser
94 */
Hariharasubramanian R44473092015-10-15 08:25:28 -050095
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -050096typedef struct ipmi_fru_area_info
97{
98 uint8_t off;
99 uint8_t len;
100} ipmi_fru_area_info_t;
101
102typedef struct ipmi_fru_common_hdr
103{
104 uint8_t fmtver;
105 uint8_t internal;
106 uint8_t chassis;
107 uint8_t board;
108 uint8_t product;
109 uint8_t multirec;
110} __attribute__((packed)) ipmi_fru_common_hdr_t;
111
112enum openbmc_vpd_key_id
113{
114 OPENBMC_VPD_KEY_CHASSIS_TYPE = 1, /* not a type/len */
115 OPENBMC_VPD_KEY_CHASSIS_PART_NUM,
116 OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM,
117 OPENBMC_VPD_KEY_CHASSIS_MAX = OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM,
118 /* TODO: chassis_custom_fields */
119
120 OPENBMC_VPD_KEY_BOARD_MFG_DATE, /* not a type/len */
121 OPENBMC_VPD_KEY_BOARD_MFR,
122 OPENBMC_VPD_KEY_BOARD_NAME,
123 OPENBMC_VPD_KEY_BOARD_SERIAL_NUM,
124 OPENBMC_VPD_KEY_BOARD_PART_NUM,
125 OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID,
126 OPENBMC_VPD_KEY_BOARD_MAX = OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID,
127 /* TODO: board_custom_fields */
128
129 OPENBMC_VPD_KEY_PRODUCT_MFR,
130 OPENBMC_VPD_KEY_PRODUCT_NAME,
131 OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM,
132 OPENBMC_VPD_KEY_PRODUCT_VER,
133 OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM,
134 OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG,
135 OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID,
136 OPENBMC_VPD_KEY_PRODUCT_MAX = OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID,
137 /* TODO: product_custom_fields */
138
139 OPENBMC_VPD_KEY_MAX,
140
141};
142
143const char* vpd_key_names [] =
144{
145 "Key Names Table Start",
146 "Chassis Type", /*OPENBMC_VPD_KEY_CHASSIS_TYPE*/
147 "Chassis Part Number", /*OPENBMC_VPD_KEY_CHASSIS_PART_NUM,*/
148 "Chassis Serial Number", /*OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM,*/
149
150 /* TODO: chassis_custom_fields */
151
152 "Board Mfg Date", /* OPENBMC_VPD_KEY_BOARD_MFG_DATE, */ /* not a type/len */
153 "Board Manufacturer", /* OPENBMC_VPD_KEY_BOARD_MFR, */
154 "Board Name", /* OPENBMC_VPD_KEY_BOARD_NAME, */
155 "Board Serial Number", /* OPENBMC_VPD_KEY_BOARD_SERIAL_NUM, */
156 "Board Part Number", /* OPENBMC_VPD_KEY_BOARD_PART_NUM, */
157 "Board FRU File ID", /* OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID, */
158 /* TODO: board_custom_fields */
159
160 "Product Manufacturer", /* OPENBMC_VPD_KEY_PRODUCT_MFR, */
161 "Product Name", /* OPENBMC_VPD_KEY_PRODUCT_NAME, */
162 "Product Model Number", /* OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM, */
163 "Product Version", /* OPENBMC_VPD_KEY_PRODUCT_VER, */
164 "Product Serial Number", /* OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM, */
165 "Product Asset Tag", /* OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG, */
166 "Product FRU File ID", /* OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID, */
167 /* TODO: product_custom_fields */
168
169 "Key Names Table End" /*OPENBMC_VPD_KEY_MAX,*/
170};
171
172
173/*
174 * --------------------------------------------------------------------
175 *
176 * --------------------------------------------------------------------
177 */
Hariharasubramanian R4a0b6fb2015-10-31 22:45:48 -0500178
179static size_t _to_time_str (uint32_t mfg_date_time, char* timestr, uint32_t len)
180{
181 struct tm tm;
182 time_t t;
183 size_t s;
184
185 ASSERT (timestr);
186 ASSERT (len);
187
188 memset (&tm, '\0', sizeof (struct tm));
189
190 t = mfg_date_time;
191 gmtime_r (&t, &tm);
192 s = strftime (timestr, len, "%F - %H:%M:%S", &tm);
193
194 return s;
195}
196
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500197/* private method to parse type/length */
Hariharasubramanian R44473092015-10-15 08:25:28 -0500198static int
199_parse_type_length (const void *areabuf,
200 unsigned int areabuflen,
201 unsigned int current_area_offset,
202 uint8_t *number_of_data_bytes,
203 ipmi_fru_field_t *field)
204{
205 const uint8_t *areabufptr = (const uint8_t*) areabuf;
206 uint8_t type_length;
207 uint8_t type_code;
208
209 ASSERT (areabuf);
210 ASSERT (areabuflen);
211 ASSERT (number_of_data_bytes);
212
213 type_length = areabufptr[current_area_offset];
214
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500215 /* ipmi workaround
Hariharasubramanian R44473092015-10-15 08:25:28 -0500216 *
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500217 * dell p weredge r610
Hariharasubramanian R44473092015-10-15 08:25:28 -0500218 *
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500219 * my reading of the fru spec is that all non-custom fields are
220 * required to be listed by the vendor. however, on this
Hariharasubramanian R44473092015-10-15 08:25:28 -0500221 * motherboard, some areas list this, indicating that there is
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500222 * no more data to be parsed. so now, for "required" fields, i
Hariharasubramanian R44473092015-10-15 08:25:28 -0500223 * check to see if the type-length field is a sentinel before
224 * calling this function.
225 */
226
227 ASSERT (type_length != IPMI_FRU_SENTINEL_VALUE);
228
229 type_code = (type_length & IPMI_FRU_TYPE_LENGTH_TYPE_CODE_MASK) >> IPMI_FRU_TYPE_LENGTH_TYPE_CODE_SHIFT;
230 (*number_of_data_bytes) = type_length & IPMI_FRU_TYPE_LENGTH_NUMBER_OF_DATA_BYTES_MASK;
231
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500232 /* special case: this shouldn't be a length of 0x01 (see type/length
233 * byte format in fru information storage definition).
Hariharasubramanian R44473092015-10-15 08:25:28 -0500234 */
235 if (type_code == IPMI_FRU_TYPE_LENGTH_TYPE_CODE_LANGUAGE_CODE
236 && (*number_of_data_bytes) == 0x01)
237 {
238 return (-1);
239 }
240
241 if ((current_area_offset + 1 + (*number_of_data_bytes)) > areabuflen)
242 {
243 return (-1);
244 }
245
246 if (field)
247 {
248 memset (field->type_length_field,
249 '\0',
250 IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX);
251 memcpy (field->type_length_field,
252 &areabufptr[current_area_offset],
253 1 + (*number_of_data_bytes));
254 field->type_length_field_length = 1 + (*number_of_data_bytes);
255 }
256
257 return (0);
258}
259
260int
261ipmi_fru_chassis_info_area (const void *areabuf,
262 unsigned int areabuflen,
263 uint8_t *chassis_type,
264 ipmi_fru_field_t *chassis_part_number,
265 ipmi_fru_field_t *chassis_serial_number,
266 ipmi_fru_field_t *chassis_custom_fields,
267 unsigned int chassis_custom_fields_len)
268{
269 const uint8_t *areabufptr = (const uint8_t*) areabuf;
270 unsigned int area_offset = 0;
271 unsigned int custom_fields_index = 0;
272 uint8_t number_of_data_bytes;
273 int rv = -1;
274
275 if (!areabuf || !areabuflen)
276 {
277 return (-1);
278 }
279
280 if (chassis_part_number)
281 memset (chassis_part_number,
282 '\0',
283 sizeof (ipmi_fru_field_t));
284 if (chassis_serial_number)
285 memset (chassis_serial_number,
286 '\0',
287 sizeof (ipmi_fru_field_t));
288 if (chassis_custom_fields && chassis_custom_fields_len)
289 memset (chassis_custom_fields,
290 '\0',
291 sizeof (ipmi_fru_field_t) * chassis_custom_fields_len);
292
293 if (chassis_type)
294 (*chassis_type) = areabufptr[area_offset];
295 area_offset++;
296
297 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
298 goto out;
299
300 if (_parse_type_length (areabufptr,
301 areabuflen,
302 area_offset,
303 &number_of_data_bytes,
304 chassis_part_number) < 0)
305 goto cleanup;
306 area_offset += 1; /* type/length byte */
307 area_offset += number_of_data_bytes;
308
309 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
310 goto out;
311
312 if (_parse_type_length (areabufptr,
313 areabuflen,
314 area_offset,
315 &number_of_data_bytes,
316 chassis_serial_number) < 0)
317 goto cleanup;
318 area_offset += 1; /* type/length byte */
319 area_offset += number_of_data_bytes;
320
321 while (area_offset < areabuflen
322 && areabufptr[area_offset] != IPMI_FRU_SENTINEL_VALUE)
323 {
324 ipmi_fru_field_t *field_ptr = NULL;
325
326 if (chassis_custom_fields && chassis_custom_fields_len)
327 {
328 if (custom_fields_index < chassis_custom_fields_len)
329 field_ptr = &chassis_custom_fields[custom_fields_index];
330 else
331 {
332 goto cleanup;
333 }
334 }
335
336 if (_parse_type_length (areabufptr,
337 areabuflen,
338 area_offset,
339 &number_of_data_bytes,
340 field_ptr) < 0)
341 goto cleanup;
342
343 area_offset += 1; /* type/length byte */
344 area_offset += number_of_data_bytes;
345 custom_fields_index++;
346 }
347
348
349 out:
350 rv = 0;
351 cleanup:
352 return (rv);
353}
354
355int
356ipmi_fru_board_info_area (const void *areabuf,
357 unsigned int areabuflen,
358 uint8_t *language_code,
359 uint32_t *mfg_date_time,
360 ipmi_fru_field_t *board_manufacturer,
361 ipmi_fru_field_t *board_product_name,
362 ipmi_fru_field_t *board_serial_number,
363 ipmi_fru_field_t *board_part_number,
364 ipmi_fru_field_t *board_fru_file_id,
365 ipmi_fru_field_t *board_custom_fields,
366 unsigned int board_custom_fields_len)
367{
368 const uint8_t *areabufptr = (const uint8_t*) areabuf;
369 uint32_t mfg_date_time_tmp = 0;
370 unsigned int area_offset = 0;
371 unsigned int custom_fields_index = 0;
372 uint8_t number_of_data_bytes;
373 int rv = -1;
374
375 if (!areabuf || !areabuflen)
376 {
377 return (-1);
378 }
379
380 if (board_manufacturer)
381 memset (board_manufacturer,
382 '\0',
383 sizeof (ipmi_fru_field_t));
384 if (board_product_name)
385 memset (board_product_name,
386 '\0',
387 sizeof (ipmi_fru_field_t));
388 if (board_serial_number)
389 memset (board_serial_number,
390 '\0',
391 sizeof (ipmi_fru_field_t));
392 if (board_part_number)
393 memset (board_part_number,
394 '\0',
395 sizeof (ipmi_fru_field_t));
396 if (board_fru_file_id)
397 memset (board_fru_file_id,
398 '\0',
399 sizeof (ipmi_fru_field_t));
400 if (board_custom_fields && board_custom_fields_len)
401 memset (board_custom_fields,
402 '\0',
403 sizeof (ipmi_fru_field_t) * board_custom_fields_len);
404
405 if (language_code)
406 (*language_code) = areabufptr[area_offset];
407 area_offset++;
408
409 if (mfg_date_time)
410 {
411 struct tm tm;
412 time_t t;
413
414 /* mfg_date_time is little endian - see spec */
415 mfg_date_time_tmp |= areabufptr[area_offset];
416 area_offset++;
417 mfg_date_time_tmp |= (areabufptr[area_offset] << 8);
418 area_offset++;
419 mfg_date_time_tmp |= (areabufptr[area_offset] << 16);
420 area_offset++;
421
422 /* mfg_date_time is in minutes, so multiple by 60 to get seconds */
423 mfg_date_time_tmp *= 60;
424
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500425 /* posix says individual calls need not clear/set all portions of
Hariharasubramanian R44473092015-10-15 08:25:28 -0500426 * 'struct tm', thus passing 'struct tm' between functions could
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500427 * have issues. so we need to memset.
Hariharasubramanian R44473092015-10-15 08:25:28 -0500428 */
429 memset (&tm, '\0', sizeof(struct tm));
430
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500431 /* in fru, epoch is 0:00 hrs 1/1/96
Hariharasubramanian R44473092015-10-15 08:25:28 -0500432 *
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500433 * so convert into ansi epoch
Hariharasubramanian R44473092015-10-15 08:25:28 -0500434 */
435
436 tm.tm_year = 96; /* years since 1900 */
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500437 tm.tm_mon = 0; /* months since january */
Hariharasubramanian R44473092015-10-15 08:25:28 -0500438 tm.tm_mday = 1; /* 1-31 */
439 tm.tm_hour = 0;
440 tm.tm_min = 0;
441 tm.tm_sec = 0;
442 tm.tm_isdst = -1;
443
444 if ((t = mktime (&tm)) == (time_t)-1)
445 {
446 goto cleanup;
447 }
448
449 mfg_date_time_tmp += (uint32_t)t;
450 (*mfg_date_time) = mfg_date_time_tmp;
451 }
452 else
453 area_offset += 3;
454
455 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
456 goto out;
457
458 if (_parse_type_length (areabufptr,
459 areabuflen,
460 area_offset,
461 &number_of_data_bytes,
462 board_manufacturer) < 0)
463 goto cleanup;
464 area_offset += 1; /* type/length byte */
465 area_offset += number_of_data_bytes;
466
467 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
468 goto out;
469
470 if (_parse_type_length (areabufptr,
471 areabuflen,
472 area_offset,
473 &number_of_data_bytes,
474 board_product_name) < 0)
475 goto cleanup;
476 area_offset += 1; /* type/length byte */
477 area_offset += number_of_data_bytes;
478
479 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
480 goto out;
481
482 if (_parse_type_length (areabufptr,
483 areabuflen,
484 area_offset,
485 &number_of_data_bytes,
486 board_serial_number) < 0)
487 goto cleanup;
488 area_offset += 1; /* type/length byte */
489 area_offset += number_of_data_bytes;
490
491 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
492 goto out;
493
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500494 if (_parse_type_length (areabufptr,
Hariharasubramanian R44473092015-10-15 08:25:28 -0500495 areabuflen,
496 area_offset,
497 &number_of_data_bytes,
498 board_part_number) < 0)
499 goto cleanup;
500 area_offset += 1; /* type/length byte */
501 area_offset += number_of_data_bytes;
502
503 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
504 goto out;
505
506 if (_parse_type_length (areabufptr,
507 areabuflen,
508 area_offset,
509 &number_of_data_bytes,
510 board_fru_file_id) < 0)
511 goto cleanup;
512 area_offset += 1; /* type/length byte */
513 area_offset += number_of_data_bytes;
514
515 while (area_offset < areabuflen
516 && areabufptr[area_offset] != IPMI_FRU_SENTINEL_VALUE)
517 {
518 ipmi_fru_field_t *field_ptr = NULL;
519
520 if (board_custom_fields && board_custom_fields_len)
521 {
522 if (custom_fields_index < board_custom_fields_len)
523 field_ptr = &board_custom_fields[custom_fields_index];
524 else
525 {
526 goto cleanup;
527 }
528 }
529
530 if (_parse_type_length (areabufptr,
531 areabuflen,
532 area_offset,
533 &number_of_data_bytes,
534 field_ptr) < 0)
535 goto cleanup;
536
537 area_offset += 1; /* type/length byte */
538 area_offset += number_of_data_bytes;
539 custom_fields_index++;
540 }
541
542 out:
543 rv = 0;
544 cleanup:
545 return (rv);
546}
547
548int
549ipmi_fru_product_info_area (const void *areabuf,
550 unsigned int areabuflen,
551 uint8_t *language_code,
552 ipmi_fru_field_t *product_manufacturer_name,
553 ipmi_fru_field_t *product_name,
554 ipmi_fru_field_t *product_part_model_number,
555 ipmi_fru_field_t *product_version,
556 ipmi_fru_field_t *product_serial_number,
557 ipmi_fru_field_t *product_asset_tag,
558 ipmi_fru_field_t *product_fru_file_id,
559 ipmi_fru_field_t *product_custom_fields,
560 unsigned int product_custom_fields_len)
561{
562 const uint8_t *areabufptr = (const uint8_t*) areabuf;
563 unsigned int area_offset = 0;
564 unsigned int custom_fields_index = 0;
565 uint8_t number_of_data_bytes;
566 int rv = -1;
567
568 if (!areabuf || !areabuflen)
569 {
570 return (-1);
571 }
572
573 if (product_manufacturer_name)
574 memset (product_manufacturer_name,
575 '\0',
576 sizeof (ipmi_fru_field_t));
577 if (product_name)
578 memset (product_name,
579 '\0',
580 sizeof (ipmi_fru_field_t));
581 if (product_part_model_number)
582 memset (product_part_model_number,
583 '\0',
584 sizeof (ipmi_fru_field_t));
585 if (product_version)
586 memset (product_version,
587 '\0',
588 sizeof (ipmi_fru_field_t));
589 if (product_serial_number)
590 memset (product_serial_number,
591 '\0',
592 sizeof (ipmi_fru_field_t));
593 if (product_asset_tag)
594 memset (product_asset_tag,
595 '\0',
596 sizeof (ipmi_fru_field_t));
597 if (product_fru_file_id)
598 memset (product_fru_file_id,
599 '\0',
600 sizeof (ipmi_fru_field_t));
601 if (product_custom_fields && product_custom_fields_len)
602 memset (product_custom_fields,
603 '\0',
604 sizeof (ipmi_fru_field_t) * product_custom_fields_len);
605
606 if (language_code)
607 (*language_code) = areabufptr[area_offset];
608 area_offset++;
609
610 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
611 goto out;
612
613 if (_parse_type_length (areabufptr,
614 areabuflen,
615 area_offset,
616 &number_of_data_bytes,
617 product_manufacturer_name) < 0)
618 goto cleanup;
619 area_offset += 1; /* type/length byte */
620 area_offset += number_of_data_bytes;
621
622 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
623 goto out;
624
625 if (_parse_type_length (areabufptr,
626 areabuflen,
627 area_offset,
628 &number_of_data_bytes,
629 product_name) < 0)
630 goto cleanup;
631 area_offset += 1; /* type/length byte */
632 area_offset += number_of_data_bytes;
633
634 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
635 goto out;
636
637 if (_parse_type_length (areabufptr,
638 areabuflen,
639 area_offset,
640 &number_of_data_bytes,
641 product_part_model_number) < 0)
642 goto cleanup;
643 area_offset += 1; /* type/length byte */
644 area_offset += number_of_data_bytes;
645
646 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
647 goto out;
648
649 if (_parse_type_length (areabufptr,
650 areabuflen,
651 area_offset,
652 &number_of_data_bytes,
653 product_version) < 0)
654 goto cleanup;
655 area_offset += 1; /* type/length byte */
656 area_offset += number_of_data_bytes;
657
658 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
659 goto out;
660
661 if (_parse_type_length (areabufptr,
662 areabuflen,
663 area_offset,
664 &number_of_data_bytes,
665 product_serial_number) < 0)
666 goto cleanup;
667 area_offset += 1; /* type/length byte */
668 area_offset += number_of_data_bytes;
669
670 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
671 goto out;
672
673 if (_parse_type_length (areabufptr,
674 areabuflen,
675 area_offset,
676 &number_of_data_bytes,
677 product_asset_tag) < 0)
678 goto cleanup;
679 area_offset += 1; /* type/length byte */
680 area_offset += number_of_data_bytes;
681
682 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
683 goto out;
684
685 if (_parse_type_length (areabufptr,
686 areabuflen,
687 area_offset,
688 &number_of_data_bytes,
689 product_fru_file_id) < 0)
690 goto cleanup;
691 area_offset += 1; /* type/length byte */
692 area_offset += number_of_data_bytes;
693
694 while (area_offset < areabuflen
695 && areabufptr[area_offset] != IPMI_FRU_SENTINEL_VALUE)
696 {
697 ipmi_fru_field_t *field_ptr = NULL;
698
699 if (product_custom_fields && product_custom_fields_len)
700 {
701 if (custom_fields_index < product_custom_fields_len)
702 field_ptr = &product_custom_fields[custom_fields_index];
703 else
704 {
705 goto cleanup;
706 }
707 }
708
709 if (_parse_type_length (areabufptr,
710 areabuflen,
711 area_offset,
712 &number_of_data_bytes,
713 field_ptr) < 0)
714 goto cleanup;
715
716 area_offset += 1; /* type/length byte */
717 area_offset += number_of_data_bytes;
718 custom_fields_index++;
719 }
720
721
722 out:
723 rv = 0;
724 cleanup:
725 return (rv);
726}
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500727
728
729int
730parse_fru (const void* msgbuf, sd_bus_message* vpdtbl)
731{
732 int ret = 0;
733 int rv = -1;
734 int i = 0;
735 ipmi_fru_area_info_t fru_area_info [ IPMI_FRU_AREA_TYPE_MAX ];
736 ipmi_fru_common_hdr_t* chdr = NULL;
737 uint8_t* hdr = NULL;
Hariharasubramanian R4a0b6fb2015-10-31 22:45:48 -0500738 char timestr [ OPENBMC_VPD_VAL_LEN ];
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500739
740
741 ipmi_fru_field_t vpd_info [ OPENBMC_VPD_KEY_MAX ];
742 /*char ipmi_fru_field_str [ IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX ];
743 uint32_t len=0;*/
744 const uint8_t* ipmi_fru_field_str;
745
746 /* Chassis */
747 uint8_t chassis_type;
748
749 /* Board */
750 uint32_t mfg_date_time;
751
752 /* Product */
753 unsigned int product_custom_fields_len;
754
755 ASSERT (msgbuf);
756 ASSERT (vpdtbl);
757
758 for (i=0; i<OPENBMC_VPD_KEY_MAX; i++)
759 {
760 memset (vpd_info[i].type_length_field, '\0', IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX);
761 vpd_info[i].type_length_field_length = 0;
762 }
763
764 for (i=0; i<IPMI_FRU_AREA_TYPE_MAX; i++)
765 {
766 fru_area_info [ i ].off = 0;
767 fru_area_info [ i ].len = 0;
768 }
769
770 chdr = (ipmi_fru_common_hdr_t*) msgbuf;
771 hdr = (uint8_t*) msgbuf;
772
773 fru_area_info [ IPMI_FRU_AREA_INTERNAL_USE ].off = chdr->internal;
774 fru_area_info [ IPMI_FRU_AREA_CHASSIS_INFO ].off = chdr->chassis;
775 fru_area_info [ IPMI_FRU_AREA_BOARD_INFO ].off = chdr->board;
776 fru_area_info [ IPMI_FRU_AREA_PRODUCT_INFO ].off = chdr->product;
777 fru_area_info [ IPMI_FRU_AREA_MULTI_RECORD ].off = chdr->multirec;
778
779 if (chdr->internal)
780 {
781 fru_area_info [ IPMI_FRU_AREA_INTERNAL_USE ].len = 8*(*(hdr+8*chdr->internal+1));
782
783 /* TODO: Parse internal use area */
784 }
785
786 if (chdr->chassis)
787 {
788 fru_area_info [ IPMI_FRU_AREA_CHASSIS_INFO ].len = 8*(*(hdr+8*chdr->chassis+1));
789 ipmi_fru_chassis_info_area (hdr+8*chdr->chassis+2,
790 fru_area_info [ IPMI_FRU_AREA_CHASSIS_INFO ].len,
791 &chassis_type,
792 &vpd_info [OPENBMC_VPD_KEY_CHASSIS_PART_NUM],
793 &vpd_info [OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM],
794 NULL, 0);
795 }
796
797 if (chdr->board)
798 {
799 fru_area_info [ IPMI_FRU_AREA_BOARD_INFO ].len = 8*(*(hdr+8*chdr->board+1));
800 ipmi_fru_board_info_area (hdr+8*chdr->board+2,
801 fru_area_info [ IPMI_FRU_AREA_BOARD_INFO ].len,
802 NULL,
803 &mfg_date_time,
804 &vpd_info [OPENBMC_VPD_KEY_BOARD_MFR],
805 &vpd_info [OPENBMC_VPD_KEY_BOARD_NAME],
806 &vpd_info [OPENBMC_VPD_KEY_BOARD_SERIAL_NUM],
807 &vpd_info [OPENBMC_VPD_KEY_BOARD_PART_NUM],
808 &vpd_info [OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID],
809 NULL, 0);
810 }
811
812 if (chdr->product)
813 {
814 fru_area_info [ IPMI_FRU_AREA_PRODUCT_INFO ].len = 8*(*(hdr+8*chdr->product+1));
815 ipmi_fru_product_info_area (hdr+8*chdr->product+2,
816 fru_area_info [ IPMI_FRU_AREA_PRODUCT_INFO ].len,
817 NULL,
818 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_MFR],
819 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_NAME],
820 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM],
821 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_VER],
822 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM],
823 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG],
824 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID],
825 NULL, 0);
826 }
827
828 if (chdr->multirec)
829 {
830 fru_area_info [ IPMI_FRU_AREA_MULTI_RECORD ].len = 8*(*(hdr+8*chdr->multirec+1));
831 /* TODO: Parse multi record area */
832 }
833
834 for (i=0; i<IPMI_FRU_AREA_TYPE_MAX; i++)
835 {
836#if IPMI_FRU_PARSER_DEBUG
837 printf ("IPMI_FRU_AREA_TYPE=[%d] : Offset=[%d] : Len=[%d]\n", i, fru_area_info [i].off, fru_area_info[i].len);
838#else
839;
840#endif
841 }
842
843 /* Populate VPD Table */
844 for (i=1; i<OPENBMC_VPD_KEY_MAX; i++)
845 {
846 if (i==OPENBMC_VPD_KEY_CHASSIS_TYPE)
847 {
848 sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "y", chassis_type);
849#if IPMI_FRU_PARSER_DEBUG
850 printf ("[%s] = [%d]\n", vpd_key_names[i], chassis_type);
851#else
852;
853#endif
854 continue;
855 }
856
857 if (i==OPENBMC_VPD_KEY_BOARD_MFG_DATE)
858 {
Hariharasubramanian R4a0b6fb2015-10-31 22:45:48 -0500859 _to_time_str (mfg_date_time, timestr, OPENBMC_VPD_VAL_LEN);
860 sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", timestr);
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500861#if IPMI_FRU_PARSER_DEBUG
862 printf ("[%s] = [%d]\n", vpd_key_names[i], mfg_date_time);
863#else
864;
865#endif
866 continue;
867 }
868
869 /* FIXME: Field type encoding *ASSUMED* to be *BINARY* */
870 ipmi_fru_field_str = (unsigned char*) &(vpd_info[i].type_length_field) + 1;
871 sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", ipmi_fru_field_str);
872 if (vpd_info[i].type_length_field_length)
873 {
874#if IPMI_FRU_PARSER_DEBUG
875 printf ("[%s] = [%s]\n", vpd_key_names[i], ipmi_fru_field_str);
876#else
877;
878#endif
879 }
880 }
881
882 out:
883 rv = 0;
884 cleanup:
885 return (rv);
886}
887
888int parse_fru_area (const uint8_t area, const void* msgbuf, const uint8_t len, sd_bus_message* vpdtbl)
889{
890 int ret = 0;
891 int rv = -1;
892 int i = 0;
893 ipmi_fru_area_info_t fru_area_info [ IPMI_FRU_AREA_TYPE_MAX ];
894 ipmi_fru_common_hdr_t* chdr = NULL;
895 uint8_t* hdr = NULL;
896 const uint8_t* ipmi_fru_field_str=NULL;
Hariharasubramanian R4a0b6fb2015-10-31 22:45:48 -0500897 char timestr [ OPENBMC_VPD_VAL_LEN ];
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500898
899
900 ipmi_fru_field_t vpd_info [ OPENBMC_VPD_KEY_MAX ];
901 for (i=0; i<OPENBMC_VPD_KEY_MAX; i++)
902 {
903 memset (vpd_info[i].type_length_field, '\0', IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX);
904 vpd_info[i].type_length_field_length = 0;
905 }
906
907 /* Chassis */
908 uint8_t chassis_type;
909
910 /* Board */
911 uint32_t mfg_date_time;
912
913 /* Product */
914 unsigned int product_custom_fields_len;
915
916 ASSERT (msgbuf);
917 ASSERT (vpdtbl);
918
919 switch (area)
920 {
921 case IPMI_FRU_AREA_CHASSIS_INFO:
922 ipmi_fru_chassis_info_area (msgbuf,
923 len,
924 &chassis_type,
925 &vpd_info [OPENBMC_VPD_KEY_CHASSIS_PART_NUM],
926 &vpd_info [OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM],
927 NULL, 0);
928
929 /* Populate VPD Table */
930 for (i=1; i<=OPENBMC_VPD_KEY_CHASSIS_MAX; i++)
931 {
932 if (i==OPENBMC_VPD_KEY_CHASSIS_TYPE)
933 {
934 sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "y", chassis_type);
935#if IPMI_FRU_PARSER_DEBUG
936 printf ("Chassis : [%s] = [%d]\n", vpd_key_names[i], chassis_type);
937#else
938;
939#endif
940 continue;
941 }
942 ipmi_fru_field_str = (unsigned char*) &(vpd_info[i].type_length_field) + 1;
943 sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", ipmi_fru_field_str);
944#if IPMI_FRU_PARSER_DEBUG
945 printf ("Chassis : [%s] = [%s]\n", vpd_key_names[i], ipmi_fru_field_str);
946#else
947;
948#endif
949 }
950 break;
951 case IPMI_FRU_AREA_BOARD_INFO:
952 ipmi_fru_board_info_area (msgbuf,
953 len,
954 NULL,
955 &mfg_date_time,
956 &vpd_info [OPENBMC_VPD_KEY_BOARD_MFR],
957 &vpd_info [OPENBMC_VPD_KEY_BOARD_NAME],
958 &vpd_info [OPENBMC_VPD_KEY_BOARD_SERIAL_NUM],
959 &vpd_info [OPENBMC_VPD_KEY_BOARD_PART_NUM],
960 &vpd_info [OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID],
961 NULL, 0);
962
963 /* Populate VPD Table */
964 for (i=OPENBMC_VPD_KEY_BOARD_MFR; i<=OPENBMC_VPD_KEY_BOARD_MAX; i++)
965 {
966 if (i==OPENBMC_VPD_KEY_BOARD_MFG_DATE)
967 {
Hariharasubramanian R4a0b6fb2015-10-31 22:45:48 -0500968 _to_time_str (mfg_date_time, timestr, OPENBMC_VPD_VAL_LEN);
969 sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", timestr);
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500970#if IPMI_FRU_PARSER_DEBUG
971 printf ("Board : [%s] = [%d]\n", vpd_key_names[i], mfg_date_time);
972#else
973;
974#endif
975 continue;
976 }
977 ipmi_fru_field_str = (unsigned char*) &(vpd_info[i].type_length_field) + 1;
978 sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", ipmi_fru_field_str);
979#if IPMI_FRU_PARSER_DEBUG
980 printf ("Board : [%s] = [%s]\n", vpd_key_names[i], ipmi_fru_field_str);
981#else
982;
983#endif
984 }
985 break;
986 case IPMI_FRU_AREA_PRODUCT_INFO:
987 ipmi_fru_product_info_area (msgbuf,
988 len,
989 NULL,
990 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_MFR],
991 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_NAME],
992 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM],
993 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_VER],
994 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM],
995 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG],
996 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID],
997 NULL, 0);
998 for (i=OPENBMC_VPD_KEY_PRODUCT_MFR; i<=OPENBMC_VPD_KEY_PRODUCT_MAX; i++)
999 {
1000 ipmi_fru_field_str = (unsigned char*) &(vpd_info[i].type_length_field) + 1;
1001 sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", ipmi_fru_field_str);
1002#if IPMI_FRU_PARSER_DEBUG
1003 printf ("Product : [%s] = [%s]\n", vpd_key_names[i], ipmi_fru_field_str);
1004#else
1005;
1006#endif
1007 }
1008 break;
1009 defualt:
1010 /* TODO: Parse Multi Rec / Internal use area */
1011 break;
1012 }
1013
1014 out:
1015 rv = 0;
1016 cleanup:
1017 return (rv);
1018}