blob: 4d3758a3e2036508c89674d732cabf8b8cf8e44c [file] [log] [blame]
Hariharasubramanian R44473092015-10-15 08:25:28 -05001/*
2 * Copyright (C) 2003-2014 FreeIPMI Core Team
Hariharasubramanian Ra032c772015-10-20 07:28:19 -05003 *
Hariharasubramanian R44473092015-10-15 08:25:28 -05004 * 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/>.
Hariharasubramanian Ra032c772015-10-20 07:28:19 -050016 *
Hariharasubramanian R44473092015-10-15 08:25:28 -050017 */
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 Ra032c772015-10-20 07:28:19 -050047#include <ctype.h>
Hariharasubramanian R44473092015-10-15 08:25:28 -050048
49#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 Ra032c772015-10-20 07:28:19 -050092/*
93 * FRU Parser
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -050094 */
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,
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500117 OPENBMC_VPD_KEY_CHASSIS_CUSTOM1,
118 OPENBMC_VPD_KEY_CHASSIS_CUSTOM2,
119 OPENBMC_VPD_KEY_CHASSIS_CUSTOM3,
120 OPENBMC_VPD_KEY_CHASSIS_CUSTOM4,
121 OPENBMC_VPD_KEY_CHASSIS_CUSTOM5,
122 OPENBMC_VPD_KEY_CHASSIS_CUSTOM6,
123 OPENBMC_VPD_KEY_CHASSIS_CUSTOM7,
124 OPENBMC_VPD_KEY_CHASSIS_CUSTOM8,
125 OPENBMC_VPD_KEY_CHASSIS_MAX = OPENBMC_VPD_KEY_CHASSIS_CUSTOM8,
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500126 /* TODO: chassis_custom_fields */
127
128 OPENBMC_VPD_KEY_BOARD_MFG_DATE, /* not a type/len */
129 OPENBMC_VPD_KEY_BOARD_MFR,
130 OPENBMC_VPD_KEY_BOARD_NAME,
131 OPENBMC_VPD_KEY_BOARD_SERIAL_NUM,
132 OPENBMC_VPD_KEY_BOARD_PART_NUM,
133 OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID,
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500134 OPENBMC_VPD_KEY_BOARD_CUSTOM1,
135 OPENBMC_VPD_KEY_BOARD_CUSTOM2,
136 OPENBMC_VPD_KEY_BOARD_CUSTOM3,
137 OPENBMC_VPD_KEY_BOARD_CUSTOM4,
138 OPENBMC_VPD_KEY_BOARD_CUSTOM5,
139 OPENBMC_VPD_KEY_BOARD_CUSTOM6,
140 OPENBMC_VPD_KEY_BOARD_CUSTOM7,
141 OPENBMC_VPD_KEY_BOARD_CUSTOM8,
142 OPENBMC_VPD_KEY_BOARD_MAX = OPENBMC_VPD_KEY_BOARD_CUSTOM8,
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500143 /* TODO: board_custom_fields */
144
145 OPENBMC_VPD_KEY_PRODUCT_MFR,
146 OPENBMC_VPD_KEY_PRODUCT_NAME,
147 OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM,
148 OPENBMC_VPD_KEY_PRODUCT_VER,
149 OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM,
150 OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG,
151 OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID,
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500152 OPENBMC_VPD_KEY_PRODUCT_CUSTOM1,
153 OPENBMC_VPD_KEY_PRODUCT_CUSTOM2,
154 OPENBMC_VPD_KEY_PRODUCT_CUSTOM3,
155 OPENBMC_VPD_KEY_PRODUCT_CUSTOM4,
156 OPENBMC_VPD_KEY_PRODUCT_CUSTOM5,
157 OPENBMC_VPD_KEY_PRODUCT_CUSTOM6,
158 OPENBMC_VPD_KEY_PRODUCT_CUSTOM7,
159 OPENBMC_VPD_KEY_PRODUCT_CUSTOM8,
160 OPENBMC_VPD_KEY_PRODUCT_MAX = OPENBMC_VPD_KEY_PRODUCT_CUSTOM8,
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500161
162 OPENBMC_VPD_KEY_MAX,
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500163 OPENBMC_VPD_KEY_CUSTOM_FIELDS_MAX=8,
164
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500165};
166
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500167const char* vpd_key_names [] =
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500168{
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500169 "Key Names Table Start",
170 "Type", /*OPENBMC_VPD_KEY_CHASSIS_TYPE*/
171 "Part Number", /*OPENBMC_VPD_KEY_CHASSIS_PART_NUM,*/
172 "Serial Number", /*OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM,*/
173 "Custom Field 1", /*OPENBMC_VPD_KEY_CHASSIS_CUSTOM1,*/
174 "Custom Field 2", /*OPENBMC_VPD_KEY_CHASSIS_CUSTOM2,*/
175 "Custom Field 3", /*OPENBMC_VPD_KEY_CHASSIS_CUSTOM3,*/
176 "Custom Field 4", /*OPENBMC_VPD_KEY_CHASSIS_CUSTOM4,*/
177 "Custom Field 5", /*OPENBMC_VPD_KEY_CHASSIS_CUSTOM5,*/
178 "Custom Field 6", /*OPENBMC_VPD_KEY_CHASSIS_CUSTOM6,*/
179 "Custom Field 7", /*OPENBMC_VPD_KEY_CHASSIS_CUSTOM7,*/
180 "Custom Field 8", /*OPENBMC_VPD_KEY_CHASSIS_CUSTOM8,*/
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500181
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500182 "Mfg Date", /* OPENBMC_VPD_KEY_BOARD_MFG_DATE, */ /* not a type/len */
183 "Manufacturer", /* OPENBMC_VPD_KEY_BOARD_MFR, */
184 "Name", /* OPENBMC_VPD_KEY_BOARD_NAME, */
185 "Serial Number", /* OPENBMC_VPD_KEY_BOARD_SERIAL_NUM, */
186 "Part Number", /* OPENBMC_VPD_KEY_BOARD_PART_NUM, */
187 "FRU File ID", /* OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID, */
188 "Custom Field 1", /*OPENBMC_VPD_KEY_BOARD_CUSTOM1,*/
189 "Custom Field 2", /*OPENBMC_VPD_KEY_BOARD_CUSTOM2,*/
190 "Custom Field 3", /*OPENBMC_VPD_KEY_BOARD_CUSTOM3,*/
191 "Custom Field 4", /*OPENBMC_VPD_KEY_BOARD_CUSTOM4,*/
192 "Custom Field 5", /*OPENBMC_VPD_KEY_BOARD_CUSTOM5,*/
193 "Custom Field 6", /*OPENBMC_VPD_KEY_BOARD_CUSTOM6,*/
194 "Custom Field 7", /*OPENBMC_VPD_KEY_BOARD_CUSTOM7,*/
195 "Custom Field 8", /*OPENBMC_VPD_KEY_BOARD_CUSTOM8,*/
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500196
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500197 "Manufacturer", /* OPENBMC_VPD_KEY_PRODUCT_MFR, */
198 "Name", /* OPENBMC_VPD_KEY_PRODUCT_NAME, */
199 "Model Number", /* OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM, */
200 "Version", /* OPENBMC_VPD_KEY_PRODUCT_VER, */
201 "Serial Number", /* OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM, */
202 "Asset Tag", /* OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG, */
203 "FRU File ID", /* OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID, */
204 "Custom Field 1", /*OPENBMC_VPD_KEY_PRODUCT_CUSTOM1,*/
205 "Custom Field 2", /*OPENBMC_VPD_KEY_PRODUCT_CUSTOM2,*/
206 "Custom Field 3", /*OPENBMC_VPD_KEY_PRODUCT_CUSTOM3,*/
207 "Custom Field 4", /*OPENBMC_VPD_KEY_PRODUCT_CUSTOM4,*/
208 "Custom Field 5", /*OPENBMC_VPD_KEY_PRODUCT_CUSTOM5,*/
209 "Custom Field 6", /*OPENBMC_VPD_KEY_PRODUCT_CUSTOM6,*/
210 "Custom Field 7", /*OPENBMC_VPD_KEY_PRODUCT_CUSTOM7,*/
211 "Custom Field 8", /*OPENBMC_VPD_KEY_PRODUCT_CUSTOM8,*/
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500212
213 "Key Names Table End" /*OPENBMC_VPD_KEY_MAX,*/
214};
215
216
217/*
218 * --------------------------------------------------------------------
219 *
220 * --------------------------------------------------------------------
221 */
Hariharasubramanian R4a0b6fb2015-10-31 22:45:48 -0500222
223static size_t _to_time_str (uint32_t mfg_date_time, char* timestr, uint32_t len)
224{
225 struct tm tm;
226 time_t t;
227 size_t s;
228
229 ASSERT (timestr);
230 ASSERT (len);
231
232 memset (&tm, '\0', sizeof (struct tm));
233
234 t = mfg_date_time;
235 gmtime_r (&t, &tm);
236 s = strftime (timestr, len, "%F - %H:%M:%S", &tm);
237
238 return s;
239}
240
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500241/* private method to parse type/length */
Hariharasubramanian R44473092015-10-15 08:25:28 -0500242static int
243_parse_type_length (const void *areabuf,
244 unsigned int areabuflen,
245 unsigned int current_area_offset,
246 uint8_t *number_of_data_bytes,
247 ipmi_fru_field_t *field)
248{
249 const uint8_t *areabufptr = (const uint8_t*) areabuf;
250 uint8_t type_length;
251 uint8_t type_code;
252
253 ASSERT (areabuf);
254 ASSERT (areabuflen);
255 ASSERT (number_of_data_bytes);
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500256
Hariharasubramanian R44473092015-10-15 08:25:28 -0500257 type_length = areabufptr[current_area_offset];
258
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500259 /* ipmi workaround
Hariharasubramanian R44473092015-10-15 08:25:28 -0500260 *
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500261 * dell p weredge r610
Hariharasubramanian R44473092015-10-15 08:25:28 -0500262 *
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500263 * my reading of the fru spec is that all non-custom fields are
264 * required to be listed by the vendor. however, on this
Hariharasubramanian R44473092015-10-15 08:25:28 -0500265 * motherboard, some areas list this, indicating that there is
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500266 * no more data to be parsed. so now, for "required" fields, i
Hariharasubramanian R44473092015-10-15 08:25:28 -0500267 * check to see if the type-length field is a sentinel before
268 * calling this function.
269 */
270
271 ASSERT (type_length != IPMI_FRU_SENTINEL_VALUE);
272
273 type_code = (type_length & IPMI_FRU_TYPE_LENGTH_TYPE_CODE_MASK) >> IPMI_FRU_TYPE_LENGTH_TYPE_CODE_SHIFT;
274 (*number_of_data_bytes) = type_length & IPMI_FRU_TYPE_LENGTH_NUMBER_OF_DATA_BYTES_MASK;
275
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500276 /* special case: this shouldn't be a length of 0x01 (see type/length
277 * byte format in fru information storage definition).
Hariharasubramanian R44473092015-10-15 08:25:28 -0500278 */
279 if (type_code == IPMI_FRU_TYPE_LENGTH_TYPE_CODE_LANGUAGE_CODE
280 && (*number_of_data_bytes) == 0x01)
281 {
282 return (-1);
283 }
284
285 if ((current_area_offset + 1 + (*number_of_data_bytes)) > areabuflen)
286 {
287 return (-1);
288 }
289
290 if (field)
291 {
292 memset (field->type_length_field,
293 '\0',
294 IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX);
295 memcpy (field->type_length_field,
296 &areabufptr[current_area_offset],
297 1 + (*number_of_data_bytes));
298 field->type_length_field_length = 1 + (*number_of_data_bytes);
299 }
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500300
Hariharasubramanian R44473092015-10-15 08:25:28 -0500301 return (0);
302}
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500303
Hariharasubramanian R44473092015-10-15 08:25:28 -0500304int
305ipmi_fru_chassis_info_area (const void *areabuf,
306 unsigned int areabuflen,
307 uint8_t *chassis_type,
308 ipmi_fru_field_t *chassis_part_number,
309 ipmi_fru_field_t *chassis_serial_number,
310 ipmi_fru_field_t *chassis_custom_fields,
311 unsigned int chassis_custom_fields_len)
312{
313 const uint8_t *areabufptr = (const uint8_t*) areabuf;
314 unsigned int area_offset = 0;
315 unsigned int custom_fields_index = 0;
316 uint8_t number_of_data_bytes;
317 int rv = -1;
318
319 if (!areabuf || !areabuflen)
320 {
321 return (-1);
322 }
323
324 if (chassis_part_number)
325 memset (chassis_part_number,
326 '\0',
327 sizeof (ipmi_fru_field_t));
328 if (chassis_serial_number)
329 memset (chassis_serial_number,
330 '\0',
331 sizeof (ipmi_fru_field_t));
332 if (chassis_custom_fields && chassis_custom_fields_len)
333 memset (chassis_custom_fields,
334 '\0',
335 sizeof (ipmi_fru_field_t) * chassis_custom_fields_len);
336
337 if (chassis_type)
338 (*chassis_type) = areabufptr[area_offset];
339 area_offset++;
340
341 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
342 goto out;
343
344 if (_parse_type_length (areabufptr,
345 areabuflen,
346 area_offset,
347 &number_of_data_bytes,
348 chassis_part_number) < 0)
349 goto cleanup;
350 area_offset += 1; /* type/length byte */
351 area_offset += number_of_data_bytes;
352
353 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
354 goto out;
355
356 if (_parse_type_length (areabufptr,
357 areabuflen,
358 area_offset,
359 &number_of_data_bytes,
360 chassis_serial_number) < 0)
361 goto cleanup;
362 area_offset += 1; /* type/length byte */
363 area_offset += number_of_data_bytes;
364
365 while (area_offset < areabuflen
366 && areabufptr[area_offset] != IPMI_FRU_SENTINEL_VALUE)
367 {
368 ipmi_fru_field_t *field_ptr = NULL;
369
370 if (chassis_custom_fields && chassis_custom_fields_len)
371 {
372 if (custom_fields_index < chassis_custom_fields_len)
373 field_ptr = &chassis_custom_fields[custom_fields_index];
374 else
375 {
376 goto cleanup;
377 }
378 }
379
380 if (_parse_type_length (areabufptr,
381 areabuflen,
382 area_offset,
383 &number_of_data_bytes,
384 field_ptr) < 0)
385 goto cleanup;
386
387 area_offset += 1; /* type/length byte */
388 area_offset += number_of_data_bytes;
389 custom_fields_index++;
390 }
391
392
393 out:
394 rv = 0;
395 cleanup:
396 return (rv);
397}
398
399int
400ipmi_fru_board_info_area (const void *areabuf,
401 unsigned int areabuflen,
402 uint8_t *language_code,
403 uint32_t *mfg_date_time,
404 ipmi_fru_field_t *board_manufacturer,
405 ipmi_fru_field_t *board_product_name,
406 ipmi_fru_field_t *board_serial_number,
407 ipmi_fru_field_t *board_part_number,
408 ipmi_fru_field_t *board_fru_file_id,
409 ipmi_fru_field_t *board_custom_fields,
410 unsigned int board_custom_fields_len)
411{
412 const uint8_t *areabufptr = (const uint8_t*) areabuf;
413 uint32_t mfg_date_time_tmp = 0;
414 unsigned int area_offset = 0;
415 unsigned int custom_fields_index = 0;
416 uint8_t number_of_data_bytes;
417 int rv = -1;
418
419 if (!areabuf || !areabuflen)
420 {
421 return (-1);
422 }
423
424 if (board_manufacturer)
425 memset (board_manufacturer,
426 '\0',
427 sizeof (ipmi_fru_field_t));
428 if (board_product_name)
429 memset (board_product_name,
430 '\0',
431 sizeof (ipmi_fru_field_t));
432 if (board_serial_number)
433 memset (board_serial_number,
434 '\0',
435 sizeof (ipmi_fru_field_t));
436 if (board_part_number)
437 memset (board_part_number,
438 '\0',
439 sizeof (ipmi_fru_field_t));
440 if (board_fru_file_id)
441 memset (board_fru_file_id,
442 '\0',
443 sizeof (ipmi_fru_field_t));
444 if (board_custom_fields && board_custom_fields_len)
445 memset (board_custom_fields,
446 '\0',
447 sizeof (ipmi_fru_field_t) * board_custom_fields_len);
448
449 if (language_code)
450 (*language_code) = areabufptr[area_offset];
451 area_offset++;
452
453 if (mfg_date_time)
454 {
455 struct tm tm;
456 time_t t;
457
458 /* mfg_date_time is little endian - see spec */
459 mfg_date_time_tmp |= areabufptr[area_offset];
460 area_offset++;
461 mfg_date_time_tmp |= (areabufptr[area_offset] << 8);
462 area_offset++;
463 mfg_date_time_tmp |= (areabufptr[area_offset] << 16);
464 area_offset++;
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500465
Hariharasubramanian R44473092015-10-15 08:25:28 -0500466 /* mfg_date_time is in minutes, so multiple by 60 to get seconds */
467 mfg_date_time_tmp *= 60;
468
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500469 /* posix says individual calls need not clear/set all portions of
Hariharasubramanian R44473092015-10-15 08:25:28 -0500470 * 'struct tm', thus passing 'struct tm' between functions could
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500471 * have issues. so we need to memset.
Hariharasubramanian R44473092015-10-15 08:25:28 -0500472 */
473 memset (&tm, '\0', sizeof(struct tm));
474
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500475 /* in fru, epoch is 0:00 hrs 1/1/96
Hariharasubramanian R44473092015-10-15 08:25:28 -0500476 *
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500477 * so convert into ansi epoch
Hariharasubramanian R44473092015-10-15 08:25:28 -0500478 */
479
480 tm.tm_year = 96; /* years since 1900 */
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500481 tm.tm_mon = 0; /* months since january */
Hariharasubramanian R44473092015-10-15 08:25:28 -0500482 tm.tm_mday = 1; /* 1-31 */
483 tm.tm_hour = 0;
484 tm.tm_min = 0;
485 tm.tm_sec = 0;
486 tm.tm_isdst = -1;
487
488 if ((t = mktime (&tm)) == (time_t)-1)
489 {
490 goto cleanup;
491 }
492
493 mfg_date_time_tmp += (uint32_t)t;
494 (*mfg_date_time) = mfg_date_time_tmp;
495 }
496 else
497 area_offset += 3;
498
499 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
500 goto out;
501
502 if (_parse_type_length (areabufptr,
503 areabuflen,
504 area_offset,
505 &number_of_data_bytes,
506 board_manufacturer) < 0)
507 goto cleanup;
508 area_offset += 1; /* type/length byte */
509 area_offset += number_of_data_bytes;
510
511 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
512 goto out;
513
514 if (_parse_type_length (areabufptr,
515 areabuflen,
516 area_offset,
517 &number_of_data_bytes,
518 board_product_name) < 0)
519 goto cleanup;
520 area_offset += 1; /* type/length byte */
521 area_offset += number_of_data_bytes;
522
523 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
524 goto out;
525
526 if (_parse_type_length (areabufptr,
527 areabuflen,
528 area_offset,
529 &number_of_data_bytes,
530 board_serial_number) < 0)
531 goto cleanup;
532 area_offset += 1; /* type/length byte */
533 area_offset += number_of_data_bytes;
534
535 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
536 goto out;
537
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500538 if (_parse_type_length (areabufptr,
Hariharasubramanian R44473092015-10-15 08:25:28 -0500539 areabuflen,
540 area_offset,
541 &number_of_data_bytes,
542 board_part_number) < 0)
543 goto cleanup;
544 area_offset += 1; /* type/length byte */
545 area_offset += number_of_data_bytes;
546
547 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
548 goto out;
549
550 if (_parse_type_length (areabufptr,
551 areabuflen,
552 area_offset,
553 &number_of_data_bytes,
554 board_fru_file_id) < 0)
555 goto cleanup;
556 area_offset += 1; /* type/length byte */
557 area_offset += number_of_data_bytes;
558
559 while (area_offset < areabuflen
560 && areabufptr[area_offset] != IPMI_FRU_SENTINEL_VALUE)
561 {
562 ipmi_fru_field_t *field_ptr = NULL;
563
564 if (board_custom_fields && board_custom_fields_len)
565 {
566 if (custom_fields_index < board_custom_fields_len)
567 field_ptr = &board_custom_fields[custom_fields_index];
568 else
569 {
570 goto cleanup;
571 }
572 }
573
574 if (_parse_type_length (areabufptr,
575 areabuflen,
576 area_offset,
577 &number_of_data_bytes,
578 field_ptr) < 0)
579 goto cleanup;
580
581 area_offset += 1; /* type/length byte */
582 area_offset += number_of_data_bytes;
583 custom_fields_index++;
584 }
585
586 out:
587 rv = 0;
588 cleanup:
589 return (rv);
590}
591
592int
593ipmi_fru_product_info_area (const void *areabuf,
594 unsigned int areabuflen,
595 uint8_t *language_code,
596 ipmi_fru_field_t *product_manufacturer_name,
597 ipmi_fru_field_t *product_name,
598 ipmi_fru_field_t *product_part_model_number,
599 ipmi_fru_field_t *product_version,
600 ipmi_fru_field_t *product_serial_number,
601 ipmi_fru_field_t *product_asset_tag,
602 ipmi_fru_field_t *product_fru_file_id,
603 ipmi_fru_field_t *product_custom_fields,
604 unsigned int product_custom_fields_len)
605{
606 const uint8_t *areabufptr = (const uint8_t*) areabuf;
607 unsigned int area_offset = 0;
608 unsigned int custom_fields_index = 0;
609 uint8_t number_of_data_bytes;
610 int rv = -1;
611
612 if (!areabuf || !areabuflen)
613 {
614 return (-1);
615 }
616
617 if (product_manufacturer_name)
618 memset (product_manufacturer_name,
619 '\0',
620 sizeof (ipmi_fru_field_t));
621 if (product_name)
622 memset (product_name,
623 '\0',
624 sizeof (ipmi_fru_field_t));
625 if (product_part_model_number)
626 memset (product_part_model_number,
627 '\0',
628 sizeof (ipmi_fru_field_t));
629 if (product_version)
630 memset (product_version,
631 '\0',
632 sizeof (ipmi_fru_field_t));
633 if (product_serial_number)
634 memset (product_serial_number,
635 '\0',
636 sizeof (ipmi_fru_field_t));
637 if (product_asset_tag)
638 memset (product_asset_tag,
639 '\0',
640 sizeof (ipmi_fru_field_t));
641 if (product_fru_file_id)
642 memset (product_fru_file_id,
643 '\0',
644 sizeof (ipmi_fru_field_t));
645 if (product_custom_fields && product_custom_fields_len)
646 memset (product_custom_fields,
647 '\0',
648 sizeof (ipmi_fru_field_t) * product_custom_fields_len);
649
650 if (language_code)
651 (*language_code) = areabufptr[area_offset];
652 area_offset++;
653
654 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
655 goto out;
656
657 if (_parse_type_length (areabufptr,
658 areabuflen,
659 area_offset,
660 &number_of_data_bytes,
661 product_manufacturer_name) < 0)
662 goto cleanup;
663 area_offset += 1; /* type/length byte */
664 area_offset += number_of_data_bytes;
665
666 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
667 goto out;
668
669 if (_parse_type_length (areabufptr,
670 areabuflen,
671 area_offset,
672 &number_of_data_bytes,
673 product_name) < 0)
674 goto cleanup;
675 area_offset += 1; /* type/length byte */
676 area_offset += number_of_data_bytes;
677
678 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
679 goto out;
680
681 if (_parse_type_length (areabufptr,
682 areabuflen,
683 area_offset,
684 &number_of_data_bytes,
685 product_part_model_number) < 0)
686 goto cleanup;
687 area_offset += 1; /* type/length byte */
688 area_offset += number_of_data_bytes;
689
690 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
691 goto out;
692
693 if (_parse_type_length (areabufptr,
694 areabuflen,
695 area_offset,
696 &number_of_data_bytes,
697 product_version) < 0)
698 goto cleanup;
699 area_offset += 1; /* type/length byte */
700 area_offset += number_of_data_bytes;
701
702 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
703 goto out;
704
705 if (_parse_type_length (areabufptr,
706 areabuflen,
707 area_offset,
708 &number_of_data_bytes,
709 product_serial_number) < 0)
710 goto cleanup;
711 area_offset += 1; /* type/length byte */
712 area_offset += number_of_data_bytes;
713
714 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
715 goto out;
716
717 if (_parse_type_length (areabufptr,
718 areabuflen,
719 area_offset,
720 &number_of_data_bytes,
721 product_asset_tag) < 0)
722 goto cleanup;
723 area_offset += 1; /* type/length byte */
724 area_offset += number_of_data_bytes;
725
726 if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
727 goto out;
728
729 if (_parse_type_length (areabufptr,
730 areabuflen,
731 area_offset,
732 &number_of_data_bytes,
733 product_fru_file_id) < 0)
734 goto cleanup;
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500735
Hariharasubramanian R44473092015-10-15 08:25:28 -0500736 area_offset += 1; /* type/length byte */
737 area_offset += number_of_data_bytes;
738
739 while (area_offset < areabuflen
740 && areabufptr[area_offset] != IPMI_FRU_SENTINEL_VALUE)
741 {
742 ipmi_fru_field_t *field_ptr = NULL;
743
744 if (product_custom_fields && product_custom_fields_len)
745 {
746 if (custom_fields_index < product_custom_fields_len)
747 field_ptr = &product_custom_fields[custom_fields_index];
748 else
749 {
750 goto cleanup;
751 }
752 }
753
754 if (_parse_type_length (areabufptr,
755 areabuflen,
756 area_offset,
757 &number_of_data_bytes,
758 field_ptr) < 0)
759 goto cleanup;
760
761 area_offset += 1; /* type/length byte */
762 area_offset += number_of_data_bytes;
763 custom_fields_index++;
764 }
765
766
767 out:
768 rv = 0;
769 cleanup:
770 return (rv);
771}
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500772
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500773int _append_to_dict (uint8_t vpd_key_id, uint8_t* vpd_key_val, sd_bus_message* vpdtbl)
774{
775 int type_length = vpd_key_val[0];
776 int type_code = (type_length & IPMI_FRU_TYPE_LENGTH_TYPE_CODE_MASK) >> IPMI_FRU_TYPE_LENGTH_TYPE_CODE_SHIFT;
777 int vpd_val_len = type_length & IPMI_FRU_TYPE_LENGTH_NUMBER_OF_DATA_BYTES_MASK;
778 int sdr=0;
779
vishwa24afbb92016-06-10 06:08:56 -0500780 /* Needed to convert each uint8_t byte to a ascii */
781 char bin_byte[3] = {0};
782
783 /*
784 * Max number of characters needed to represent 1 unsigned byte in string
785 * is number of bytes multipled by 2. Extra 3 for 0x and a ending '\0';
786 */
787 char bin_in_ascii_len = vpd_val_len * 2 + 3;
788
789 /* Binary converted to ascii in array */
790 char *bin_in_ascii = (char *)malloc(bin_in_ascii_len);
791
792 /* For reading byte from the area */
793 size_t val = 0;
794
795 char *bin_copy = &((char *)bin_in_ascii)[2];
796
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500797 switch (type_code)
798 {
799 case 0:
vishwa24afbb92016-06-10 06:08:56 -0500800 memset(bin_in_ascii, 0x0, bin_in_ascii_len);
801
802 /* Offset 1 is where actual data starts */
803 for(val = 1; val <= vpd_val_len ; val++)
804 {
805 /* 2 bytes for data and 1 for terminating '\0' */
806 snprintf(bin_byte, 3, "%02x", vpd_key_val[val]);
807
808 /* Its a running string so strip off the '\0' */
809 strncat(bin_copy, bin_byte, 2);
810 }
811
812 /* We need the data represented as 0x...... */
813 if(vpd_val_len > 0)
814 {
815 strncpy(bin_in_ascii, "0x", 2);
816 }
817
818 printf ("_append_to_dict: VPD Key = [%s] : Type Code = [BINARY] : Len = [%d] : Val = [%s]\n",
819 vpd_key_names [vpd_key_id], vpd_val_len, bin_in_ascii);
820 sdr = sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[vpd_key_id], "s", bin_in_ascii);
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500821 break;
vishwa24afbb92016-06-10 06:08:56 -0500822
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500823 case 3:
824 printf ("_append_to_dict: VPD Key = [%s] : Type Code = [ASCII+Latin] : Len = [%d] : Val = [%s]\n", vpd_key_names [vpd_key_id], vpd_val_len, &vpd_key_val[1]);
825 sdr = sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[vpd_key_id], "s", &vpd_key_val[1]);
826 break;
827 }
828
vishwa24afbb92016-06-10 06:08:56 -0500829 if(bin_in_ascii)
830 {
831 free(bin_in_ascii);
832 bin_in_ascii = NULL;
833 }
834
835
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500836 if (sdr < 0)
837 {
838#if IPMI_FRU_PARSER_DEBUG
839 printf ("_append_to_dict : sd_bus_message_append Failed [ %d ] for [%s]\n", sdr, vpd_key_names[vpd_key_id]);
840#endif
841 }
842}
843
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500844int
845parse_fru (const void* msgbuf, sd_bus_message* vpdtbl)
846{
847 int ret = 0;
848 int rv = -1;
849 int i = 0;
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500850 int j = 0;
851 int isprintable = 0;
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500852 ipmi_fru_area_info_t fru_area_info [ IPMI_FRU_AREA_TYPE_MAX ];
853 ipmi_fru_common_hdr_t* chdr = NULL;
854 uint8_t* hdr = NULL;
Hariharasubramanian R4a0b6fb2015-10-31 22:45:48 -0500855 char timestr [ OPENBMC_VPD_VAL_LEN ];
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500856
857
858 ipmi_fru_field_t vpd_info [ OPENBMC_VPD_KEY_MAX ];
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500859 uint8_t* ipmi_fru_field_str;
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500860
861 /* Chassis */
862 uint8_t chassis_type;
863
864 /* Board */
865 uint32_t mfg_date_time;
866
867 /* Product */
868 unsigned int product_custom_fields_len;
869
870 ASSERT (msgbuf);
871 ASSERT (vpdtbl);
872
873 for (i=0; i<OPENBMC_VPD_KEY_MAX; i++)
874 {
875 memset (vpd_info[i].type_length_field, '\0', IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX);
876 vpd_info[i].type_length_field_length = 0;
877 }
878
879 for (i=0; i<IPMI_FRU_AREA_TYPE_MAX; i++)
880 {
881 fru_area_info [ i ].off = 0;
882 fru_area_info [ i ].len = 0;
883 }
884
885 chdr = (ipmi_fru_common_hdr_t*) msgbuf;
886 hdr = (uint8_t*) msgbuf;
887
888 fru_area_info [ IPMI_FRU_AREA_INTERNAL_USE ].off = chdr->internal;
889 fru_area_info [ IPMI_FRU_AREA_CHASSIS_INFO ].off = chdr->chassis;
890 fru_area_info [ IPMI_FRU_AREA_BOARD_INFO ].off = chdr->board;
891 fru_area_info [ IPMI_FRU_AREA_PRODUCT_INFO ].off = chdr->product;
892 fru_area_info [ IPMI_FRU_AREA_MULTI_RECORD ].off = chdr->multirec;
893
894 if (chdr->internal)
895 {
896 fru_area_info [ IPMI_FRU_AREA_INTERNAL_USE ].len = 8*(*(hdr+8*chdr->internal+1));
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500897
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500898 /* TODO: Parse internal use area */
899 }
900
901 if (chdr->chassis)
902 {
903 fru_area_info [ IPMI_FRU_AREA_CHASSIS_INFO ].len = 8*(*(hdr+8*chdr->chassis+1));
904 ipmi_fru_chassis_info_area (hdr+8*chdr->chassis+2,
905 fru_area_info [ IPMI_FRU_AREA_CHASSIS_INFO ].len,
906 &chassis_type,
907 &vpd_info [OPENBMC_VPD_KEY_CHASSIS_PART_NUM],
908 &vpd_info [OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM],
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500909 &vpd_info [OPENBMC_VPD_KEY_CHASSIS_CUSTOM1],
910 OPENBMC_VPD_KEY_CUSTOM_FIELDS_MAX);
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500911 }
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500912
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500913 if (chdr->board)
914 {
915 fru_area_info [ IPMI_FRU_AREA_BOARD_INFO ].len = 8*(*(hdr+8*chdr->board+1));
916 ipmi_fru_board_info_area (hdr+8*chdr->board+2,
917 fru_area_info [ IPMI_FRU_AREA_BOARD_INFO ].len,
918 NULL,
919 &mfg_date_time,
920 &vpd_info [OPENBMC_VPD_KEY_BOARD_MFR],
921 &vpd_info [OPENBMC_VPD_KEY_BOARD_NAME],
922 &vpd_info [OPENBMC_VPD_KEY_BOARD_SERIAL_NUM],
923 &vpd_info [OPENBMC_VPD_KEY_BOARD_PART_NUM],
924 &vpd_info [OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID],
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500925 &vpd_info [OPENBMC_VPD_KEY_BOARD_CUSTOM1],
926 OPENBMC_VPD_KEY_CUSTOM_FIELDS_MAX);
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500927 }
928
929 if (chdr->product)
930 {
931 fru_area_info [ IPMI_FRU_AREA_PRODUCT_INFO ].len = 8*(*(hdr+8*chdr->product+1));
932 ipmi_fru_product_info_area (hdr+8*chdr->product+2,
933 fru_area_info [ IPMI_FRU_AREA_PRODUCT_INFO ].len,
934 NULL,
935 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_MFR],
936 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_NAME],
937 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM],
938 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_VER],
939 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM],
940 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG],
941 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID],
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500942 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_CUSTOM1],
943 OPENBMC_VPD_KEY_CUSTOM_FIELDS_MAX);
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500944 }
945
946 if (chdr->multirec)
947 {
948 fru_area_info [ IPMI_FRU_AREA_MULTI_RECORD ].len = 8*(*(hdr+8*chdr->multirec+1));
949 /* TODO: Parse multi record area */
950 }
951
952 for (i=0; i<IPMI_FRU_AREA_TYPE_MAX; i++)
953 {
954#if IPMI_FRU_PARSER_DEBUG
955 printf ("IPMI_FRU_AREA_TYPE=[%d] : Offset=[%d] : Len=[%d]\n", i, fru_area_info [i].off, fru_area_info[i].len);
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500956#endif
957 }
958
959 /* Populate VPD Table */
960 for (i=1; i<OPENBMC_VPD_KEY_MAX; i++)
961 {
962 if (i==OPENBMC_VPD_KEY_CHASSIS_TYPE)
963 {
964 sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "y", chassis_type);
965#if IPMI_FRU_PARSER_DEBUG
966 printf ("[%s] = [%d]\n", vpd_key_names[i], chassis_type);
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500967#endif
968 continue;
969 }
970
971 if (i==OPENBMC_VPD_KEY_BOARD_MFG_DATE)
972 {
Hariharasubramanian R4a0b6fb2015-10-31 22:45:48 -0500973 _to_time_str (mfg_date_time, timestr, OPENBMC_VPD_VAL_LEN);
974 sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", timestr);
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500975#if IPMI_FRU_PARSER_DEBUG
976 printf ("[%s] = [%d]\n", vpd_key_names[i], mfg_date_time);
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500977#endif
978 continue;
979 }
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500980
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500981 /* Append TypeLen Field to Dictionary */
982 _append_to_dict (i, vpd_info[i].type_length_field, vpdtbl);
983
984 /*ipmi_fru_field_str = (unsigned char*) &(vpd_info[i].type_length_field) + 1;*/
985 /*sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", ipmi_fru_field_str); */
986 }
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500987 out:
988 rv = 0;
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500989 return (rv);
990}
991
Adriana Kobylak81aecc62016-05-12 13:52:47 -0500992int parse_fru_area (const uint8_t area, const void* msgbuf, const size_t len, sd_bus_message* vpdtbl)
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -0500993{
994 int ret = 0;
995 int rv = -1;
996 int i = 0;
Hariharasubramanian Ra032c772015-10-20 07:28:19 -0500997 int j = 0;
998 int sdr = 0;
999 int isprintable = 0;
1000
1001 /* Chassis */
1002 uint8_t chassis_type;
1003 /* Board */
1004 uint32_t mfg_date_time;
1005 /* Product */
1006 unsigned int product_custom_fields_len;
1007
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -05001008 ipmi_fru_area_info_t fru_area_info [ IPMI_FRU_AREA_TYPE_MAX ];
Hariharasubramanian Ra032c772015-10-20 07:28:19 -05001009 ipmi_fru_field_t vpd_info [ OPENBMC_VPD_KEY_MAX ];
Hariharasubramanian R4a0b6fb2015-10-31 22:45:48 -05001010 char timestr [ OPENBMC_VPD_VAL_LEN ];
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -05001011
Hariharasubramanian Ra032c772015-10-20 07:28:19 -05001012 uint8_t* ipmi_fru_field_str=NULL;
1013 ipmi_fru_common_hdr_t* chdr = NULL;
1014 uint8_t* hdr = NULL;
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -05001015
Hariharasubramanian Ra032c772015-10-20 07:28:19 -05001016 ASSERT (msgbuf);
1017 ASSERT (vpdtbl);
1018
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -05001019 for (i=0; i<OPENBMC_VPD_KEY_MAX; i++)
1020 {
1021 memset (vpd_info[i].type_length_field, '\0', IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX);
1022 vpd_info[i].type_length_field_length = 0;
1023 }
1024
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -05001025 switch (area)
1026 {
1027 case IPMI_FRU_AREA_CHASSIS_INFO:
Hariharasubramanian Ra032c772015-10-20 07:28:19 -05001028#if IPMI_FRU_PARSER_DEBUG
1029 printf ("Chassis : Buf len = [%d]\n", len);
1030#endif
1031 ipmi_fru_chassis_info_area ((uint8_t*)msgbuf+2,
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -05001032 len,
1033 &chassis_type,
1034 &vpd_info [OPENBMC_VPD_KEY_CHASSIS_PART_NUM],
1035 &vpd_info [OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM],
Hariharasubramanian Ra032c772015-10-20 07:28:19 -05001036 &vpd_info [OPENBMC_VPD_KEY_CHASSIS_CUSTOM1],
1037 OPENBMC_VPD_KEY_CUSTOM_FIELDS_MAX);
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -05001038
1039 /* Populate VPD Table */
1040 for (i=1; i<=OPENBMC_VPD_KEY_CHASSIS_MAX; i++)
1041 {
1042 if (i==OPENBMC_VPD_KEY_CHASSIS_TYPE)
1043 {
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -05001044#if IPMI_FRU_PARSER_DEBUG
Hariharasubramanian Ra032c772015-10-20 07:28:19 -05001045 printf ("Chassis : Appending [%s] = [%d]\n", vpd_key_names[i], chassis_type);
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -05001046#endif
Hariharasubramanian Ra032c772015-10-20 07:28:19 -05001047 sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "y", chassis_type);
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -05001048 continue;
1049 }
Hariharasubramanian Ra032c772015-10-20 07:28:19 -05001050
1051 _append_to_dict (i, vpd_info[i].type_length_field, vpdtbl);
1052/*
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -05001053 ipmi_fru_field_str = (unsigned char*) &(vpd_info[i].type_length_field) + 1;
Hariharasubramanian Ra032c772015-10-20 07:28:19 -05001054 sdr = sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", ipmi_fru_field_str);
1055*/
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -05001056 }
1057 break;
1058 case IPMI_FRU_AREA_BOARD_INFO:
Hariharasubramanian Ra032c772015-10-20 07:28:19 -05001059#if IPMI_FRU_PARSER_DEBUG
1060 printf ("Board : Buf len = [%d]\n", len);
1061#endif
1062 ipmi_fru_board_info_area ((uint8_t*)msgbuf+2,
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -05001063 len,
1064 NULL,
1065 &mfg_date_time,
1066 &vpd_info [OPENBMC_VPD_KEY_BOARD_MFR],
1067 &vpd_info [OPENBMC_VPD_KEY_BOARD_NAME],
1068 &vpd_info [OPENBMC_VPD_KEY_BOARD_SERIAL_NUM],
1069 &vpd_info [OPENBMC_VPD_KEY_BOARD_PART_NUM],
1070 &vpd_info [OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID],
Hariharasubramanian Ra032c772015-10-20 07:28:19 -05001071 &vpd_info [OPENBMC_VPD_KEY_BOARD_CUSTOM1],
1072 OPENBMC_VPD_KEY_CUSTOM_FIELDS_MAX);
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -05001073
1074 /* Populate VPD Table */
1075 for (i=OPENBMC_VPD_KEY_BOARD_MFR; i<=OPENBMC_VPD_KEY_BOARD_MAX; i++)
1076 {
1077 if (i==OPENBMC_VPD_KEY_BOARD_MFG_DATE)
1078 {
Hariharasubramanian R4a0b6fb2015-10-31 22:45:48 -05001079 _to_time_str (mfg_date_time, timestr, OPENBMC_VPD_VAL_LEN);
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -05001080#if IPMI_FRU_PARSER_DEBUG
Hariharasubramanian Ra032c772015-10-20 07:28:19 -05001081 printf ("Board : Appending [%s] = [%d]\n", vpd_key_names[i], timestr);
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -05001082#endif
Hariharasubramanian Ra032c772015-10-20 07:28:19 -05001083 sdr = sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", timestr);
1084 if (sdr < 0)
1085 {
1086#if IPMI_FRU_PARSER_DEBUG
1087 printf ("ipmi_fru_board_info_area : sd_bus_message_append Failed [ %d ] for [%s]\n", sdr, vpd_key_names[i]);
1088#endif
1089 }
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -05001090 continue;
1091 }
Hariharasubramanian Ra032c772015-10-20 07:28:19 -05001092
1093 _append_to_dict (i, vpd_info[i].type_length_field, vpdtbl);
1094/*
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -05001095 ipmi_fru_field_str = (unsigned char*) &(vpd_info[i].type_length_field) + 1;
Hariharasubramanian Ra032c772015-10-20 07:28:19 -05001096 sdr = sd_bus_message_append (vpdtbl, "{sv}", vpd_key_names[i], "s", ipmi_fru_field_str);
1097*/
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -05001098 }
1099 break;
1100 case IPMI_FRU_AREA_PRODUCT_INFO:
Hariharasubramanian Ra032c772015-10-20 07:28:19 -05001101#if IPMI_FRU_PARSER_DEBUG
1102 printf ("Product : Buf len = [%d]\n", len);
1103#endif
1104 ipmi_fru_product_info_area ((uint8_t*)msgbuf+2,
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -05001105 len,
1106 NULL,
1107 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_MFR],
1108 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_NAME],
1109 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM],
1110 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_VER],
1111 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM],
1112 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG],
1113 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID],
Hariharasubramanian Ra032c772015-10-20 07:28:19 -05001114 &vpd_info [OPENBMC_VPD_KEY_PRODUCT_CUSTOM1],
1115 OPENBMC_VPD_KEY_CUSTOM_FIELDS_MAX);
1116
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -05001117 for (i=OPENBMC_VPD_KEY_PRODUCT_MFR; i<=OPENBMC_VPD_KEY_PRODUCT_MAX; i++)
1118 {
Hariharasubramanian Ra032c772015-10-20 07:28:19 -05001119 _append_to_dict (i, vpd_info[i].type_length_field, vpdtbl);
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -05001120 }
1121 break;
1122 defualt:
1123 /* TODO: Parse Multi Rec / Internal use area */
1124 break;
1125 }
1126
Hariharasubramanian Ra032c772015-10-20 07:28:19 -05001127#if IPMI_FRU_PARSER_DEBUG
1128 printf ("parse_fru_area : Dictionary Packing Complete\n");
1129#endif
Hariharasubramanian Rc2d79462015-10-16 06:47:56 -05001130 out:
1131 rv = 0;
1132 cleanup:
1133 return (rv);
1134}