1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <console/console.h>
11 #define MAX_FRU_BUSY_RETRY 5
12 #define READ_FRU_DATA_RETRY_INTERVAL_MS 30 /* From IPMI spec v2.0 rev 1.1 */
13 #define OFFSET_LENGTH_MULTIPLIER 8 /* offsets/lengths are multiples of 8 */
14 #define NUM_DATA_BYTES(t) (t & 0x3f) /* Encoded in type/length byte */
15 #define FRU_END_OF_FIELDS 0xc1 /* type/length byte encoded to indicate no more info fields */
17 static enum cb_err
ipmi_read_fru(const int port
, struct ipmi_read_fru_data_req
*req
,
23 struct ipmi_read_fru_data_rsp rsp
;
26 if (req
== NULL
|| fru_data
== NULL
) {
27 printk(BIOS_ERR
, "%s failed, null pointer parameter\n",
32 total_size
= req
->count
;
34 if (req
->count
> CONFIG_IPMI_FRU_SINGLE_RW_SZ
)
35 req
->count
= CONFIG_IPMI_FRU_SINGLE_RW_SZ
;
37 while (retry_count
<= MAX_FRU_BUSY_RETRY
) {
38 ret
= ipmi_message(port
, IPMI_NETFN_STORAGE
, 0x0,
39 IPMI_READ_FRU_DATA
, (const unsigned char *)req
,
40 sizeof(*req
), (unsigned char *)&rsp
, sizeof(rsp
));
41 if (rsp
.resp
.completion_code
== 0x81) {
43 if (retry_count
== MAX_FRU_BUSY_RETRY
) {
44 printk(BIOS_ERR
, "IPMI: %s command failed, "
45 "device busy timeout\n", __func__
);
48 printk(BIOS_ERR
, "IPMI: FRU device is busy, "
49 "retry count:%d\n", retry_count
);
51 mdelay(READ_FRU_DATA_RETRY_INTERVAL_MS
);
52 } else if (ret
< sizeof(struct ipmi_rsp
) || rsp
.resp
.completion_code
) {
53 printk(BIOS_ERR
, "IPMI: %s command failed (ret=%d resp=0x%x)\n",
54 __func__
, ret
, rsp
.resp
.completion_code
);
60 memcpy(fru_data
+ offset
, rsp
.data
, rsp
.count
);
62 total_size
-= rsp
.count
;
63 req
->fru_offset
+= rsp
.count
;
64 req
->count
= total_size
;
65 } while (total_size
> 0);
70 /* data: data to check, offset: offset to checksum. */
71 static uint8_t checksum(uint8_t *data
, int offset
)
74 for (; offset
> 0; offset
--, data
++)
79 static uint8_t data2str(const uint8_t *frudata
, char *stringdata
, uint8_t length
)
83 /* bit[7:6] is the type code. */
84 type
= ((frudata
[0] & 0xc0) >> 6);
85 if (type
!= ASCII_8BIT
) {
86 printk(BIOS_ERR
, "%s typecode %d is unsupported, FRU string only "
87 "supports 8-bit ASCII + Latin 1 for now.\n", __func__
, type
);
90 /* In the spec the string data is always the next byte to the type/length byte. */
91 memcpy(stringdata
, frudata
+ 1, length
);
92 stringdata
[length
] = '\0';
97 * Read data string from data_ptr and store it to string, return the
98 * length of the string or 0 when it's failed.
100 static int read_data_string(const uint8_t *data_ptr
, char **string
)
104 length
= NUM_DATA_BYTES(data_ptr
[0]);
106 printk(BIOS_DEBUG
, "%s:%d - failed due to length is zero\n", __func__
,
111 *string
= malloc(length
+ 1);
113 printk(BIOS_ERR
, "%s failed to malloc %d bytes for string data.\n", __func__
,
117 if (!data2str((const uint8_t *)data_ptr
, *string
, length
)) {
118 printk(BIOS_ERR
, "%s:%d - data2str failed\n", __func__
, __LINE__
);
126 static enum cb_err
read_fru_chassis_info_area(const int port
, const uint8_t id
,
127 uint8_t offset
, struct fru_chassis_info
*info
)
130 struct ipmi_read_fru_data_req req
;
131 uint8_t *data_ptr
, *end
, *custom_data_ptr
;
132 int ret
= CB_SUCCESS
;
137 offset
= offset
* OFFSET_LENGTH_MULTIPLIER
;
138 req
.fru_device_id
= id
;
139 /* Read Chassis Info Area length first. */
140 req
.fru_offset
= offset
+ 1;
141 req
.count
= sizeof(length
);
142 if (ipmi_read_fru(port
, &req
, &length
) != CB_SUCCESS
|| !length
) {
143 printk(BIOS_ERR
, "%s failed, length: %d\n", __func__
, length
);
146 length
= length
* OFFSET_LENGTH_MULTIPLIER
;
147 data_ptr
= (uint8_t *)malloc(length
);
149 printk(BIOS_ERR
, "malloc %d bytes for chassis info failed\n", length
);
152 end
= data_ptr
+ length
;
153 /* Read Chassis Info Area data. */
154 req
.fru_offset
= offset
;
156 if (ipmi_read_fru(port
, &req
, data_ptr
) != CB_SUCCESS
) {
157 printk(BIOS_ERR
, "%s failed to read fru\n", __func__
);
161 if (checksum(data_ptr
, length
)) {
162 printk(BIOS_ERR
, "Bad FRU chassis info checksum.\n");
166 /* Read chassis type. */
167 info
->chassis_type
= data_ptr
[CHASSIS_TYPE_OFFSET
];
169 printk(BIOS_DEBUG
, "Read chassis part number string.\n");
170 length
= read_data_string(data_ptr
+ CHASSIS_TYPE_OFFSET
+ 1,
171 &info
->chassis_partnumber
);
173 printk(BIOS_DEBUG
, "Read chassis serial number string.\n");
174 data_ptr
+= CHASSIS_TYPE_OFFSET
+ 1 + length
+ 1;
175 length
= read_data_string(data_ptr
, &info
->serial_number
);
177 printk(BIOS_DEBUG
, "Read custom chassis info fields.\n");
178 data_ptr
+= length
+ 1;
179 /* Check how many valid custom fields first. */
180 info
->custom_count
= 0;
181 custom_data_ptr
= data_ptr
;
182 while ((data_ptr
< end
) && ((data_ptr
[0] != FRU_END_OF_FIELDS
))) {
183 length
= NUM_DATA_BYTES(data_ptr
[0]);
185 info
->custom_count
++;
186 data_ptr
+= length
+ 1;
188 if (!info
->custom_count
)
191 info
->chassis_custom
= malloc(info
->custom_count
* sizeof(char *));
192 if (!info
->chassis_custom
) {
193 printk(BIOS_ERR
, "%s failed to malloc %zu bytes for "
194 "chassis custom data array.\n", __func__
,
195 info
->custom_count
* sizeof(char *));
200 /* Start reading custom chassis data. */
201 data_ptr
= custom_data_ptr
;
203 while ((data_ptr
< end
) && ((data_ptr
[0] != FRU_END_OF_FIELDS
))) {
204 length
= NUM_DATA_BYTES(data_ptr
[0]);
206 length
= read_data_string(data_ptr
, info
->chassis_custom
+ count
);
209 data_ptr
+= length
+ 1;
217 static enum cb_err
read_fru_board_info_area(const int port
, const uint8_t id
,
218 uint8_t offset
, struct fru_board_info
*info
)
221 struct ipmi_read_fru_data_req req
;
222 uint8_t *data_ptr
, *end
, *custom_data_ptr
;
223 int ret
= CB_SUCCESS
;
228 offset
= offset
* OFFSET_LENGTH_MULTIPLIER
;
229 req
.fru_device_id
= id
;
230 /* Read Board Info Area length first. */
231 req
.fru_offset
= offset
+ 1;
232 req
.count
= sizeof(length
);
233 if (ipmi_read_fru(port
, &req
, &length
) != CB_SUCCESS
|| !length
) {
234 printk(BIOS_ERR
, "%s failed, length: %d\n", __func__
, length
);
237 length
= length
* OFFSET_LENGTH_MULTIPLIER
;
238 data_ptr
= (uint8_t *)malloc(length
);
240 printk(BIOS_ERR
, "malloc %d bytes for board info failed\n", length
);
243 end
= data_ptr
+ length
;
244 /* Read Board Info Area data. */
245 req
.fru_offset
= offset
;
247 if (ipmi_read_fru(port
, &req
, data_ptr
) != CB_SUCCESS
) {
248 printk(BIOS_ERR
, "%s failed to read fru\n", __func__
);
252 if (checksum(data_ptr
, length
)) {
253 printk(BIOS_ERR
, "Bad FRU board info checksum.\n");
257 printk(BIOS_DEBUG
, "Read board manufacturer string\n");
258 length
= read_data_string(data_ptr
+ BOARD_MAN_TYPE_LEN_OFFSET
,
259 &info
->manufacturer
);
261 printk(BIOS_DEBUG
, "Read board product name string.\n");
262 data_ptr
+= BOARD_MAN_TYPE_LEN_OFFSET
+ length
+ 1;
263 length
= read_data_string(data_ptr
, &info
->product_name
);
265 printk(BIOS_DEBUG
, "Read board serial number string.\n");
266 data_ptr
+= length
+ 1;
267 length
= read_data_string(data_ptr
, &info
->serial_number
);
269 printk(BIOS_DEBUG
, "Read board part number string.\n");
270 data_ptr
+= length
+ 1;
271 length
= read_data_string(data_ptr
, &info
->part_number
);
273 printk(BIOS_DEBUG
, "Read board FRU file ID string.\n");
274 data_ptr
+= length
+ 1;
275 length
= read_data_string(data_ptr
, &info
->fru_file_id
);
277 /* Check how many valid custom fields first. */
278 data_ptr
+= length
+ 1;
279 info
->custom_count
= 0;
280 custom_data_ptr
= data_ptr
;
281 while ((data_ptr
< end
) && ((data_ptr
[0] != FRU_END_OF_FIELDS
))) {
282 length
= NUM_DATA_BYTES(data_ptr
[0]);
284 info
->custom_count
++;
285 data_ptr
+= length
+ 1;
287 if (!info
->custom_count
)
290 info
->board_custom
= malloc(info
->custom_count
* sizeof(char *));
291 if (!info
->board_custom
) {
292 printk(BIOS_ERR
, "%s failed to malloc %zu bytes for "
293 "board custom data array.\n", __func__
,
294 info
->custom_count
* sizeof(char *));
299 /* Start reading custom board data. */
300 data_ptr
= custom_data_ptr
;
302 while ((data_ptr
< end
) && ((data_ptr
[0] != FRU_END_OF_FIELDS
))) {
303 length
= NUM_DATA_BYTES(data_ptr
[0]);
305 length
= read_data_string(data_ptr
, info
->board_custom
+ count
);
308 data_ptr
+= length
+ 1;
316 static enum cb_err
read_fru_product_info_area(const int port
, const uint8_t id
,
317 uint8_t offset
, struct fru_product_info
*info
)
320 struct ipmi_read_fru_data_req req
;
321 uint8_t *data_ptr
, *end
, *custom_data_ptr
;
322 int ret
= CB_SUCCESS
;
327 offset
= offset
* OFFSET_LENGTH_MULTIPLIER
;
328 req
.fru_device_id
= id
;
329 /* Read Product Info Area length first. */
330 req
.fru_offset
= offset
+ 1;
331 req
.count
= sizeof(length
);
332 if (ipmi_read_fru(port
, &req
, &length
) != CB_SUCCESS
|| !length
) {
333 printk(BIOS_ERR
, "%s failed, length: %d\n", __func__
, length
);
336 length
= length
* OFFSET_LENGTH_MULTIPLIER
;
337 data_ptr
= (uint8_t *)malloc(length
);
339 printk(BIOS_ERR
, "malloc %d bytes for product info failed\n", length
);
342 end
= data_ptr
+ length
;
343 /* Read Product Info Area data. */
344 req
.fru_offset
= offset
;
346 if (ipmi_read_fru(port
, &req
, data_ptr
) != CB_SUCCESS
) {
347 printk(BIOS_ERR
, "%s failed to read fru\n", __func__
);
351 if (checksum(data_ptr
, length
)) {
352 printk(BIOS_ERR
, "Bad FRU product info checksum.\n");
356 printk(BIOS_DEBUG
, "Read product manufacturer string.\n");
357 length
= read_data_string(data_ptr
+ PRODUCT_MAN_TYPE_LEN_OFFSET
,
358 &info
->manufacturer
);
360 data_ptr
+= PRODUCT_MAN_TYPE_LEN_OFFSET
+ length
+ 1;
361 printk(BIOS_DEBUG
, "Read product_name string.\n");
362 length
= read_data_string(data_ptr
, &info
->product_name
);
364 data_ptr
+= length
+ 1;
365 printk(BIOS_DEBUG
, "Read product part/model number.\n");
366 length
= read_data_string(data_ptr
, &info
->product_partnumber
);
368 data_ptr
+= length
+ 1;
369 printk(BIOS_DEBUG
, "Read product version string.\n");
370 length
= read_data_string(data_ptr
, &info
->product_version
);
372 data_ptr
+= length
+ 1;
373 printk(BIOS_DEBUG
, "Read serial number string.\n");
374 length
= read_data_string(data_ptr
, &info
->serial_number
);
376 data_ptr
+= length
+ 1;
377 printk(BIOS_DEBUG
, "Read asset tag string.\n");
378 length
= read_data_string(data_ptr
, &info
->asset_tag
);
380 printk(BIOS_DEBUG
, "Read product FRU file ID string.\n");
381 data_ptr
+= length
+ 1;
382 length
= read_data_string(data_ptr
, &info
->fru_file_id
);
384 /* Check how many valid custom fields first. */
385 data_ptr
+= length
+ 1;
386 info
->custom_count
= 0;
387 custom_data_ptr
= data_ptr
;
388 while ((data_ptr
< end
) && ((data_ptr
[0] != FRU_END_OF_FIELDS
))) {
389 length
= NUM_DATA_BYTES(data_ptr
[0]);
391 info
->custom_count
++;
392 data_ptr
+= length
+ 1;
394 if (!info
->custom_count
)
397 info
->product_custom
= malloc(info
->custom_count
* sizeof(char *));
398 if (!info
->product_custom
) {
399 printk(BIOS_ERR
, "%s failed to malloc %zu bytes for "
400 "product custom data array.\n", __func__
,
401 info
->custom_count
* sizeof(char *));
406 /* Start reading custom product data. */
407 data_ptr
= custom_data_ptr
;
409 while ((data_ptr
< end
) && ((data_ptr
[0] != FRU_END_OF_FIELDS
))) {
410 length
= NUM_DATA_BYTES(data_ptr
[0]);
412 length
= read_data_string(data_ptr
, info
->product_custom
+ count
);
415 data_ptr
+= length
+ 1;
423 void read_fru_areas(const int port
, const uint8_t id
, uint16_t offset
,
424 struct fru_info_str
*fru_info_str
)
426 struct ipmi_read_fru_data_req req
;
427 struct ipmi_fru_common_hdr fru_common_hdr
;
429 /* Set all the char pointers to 0 first, to avoid mainboard
430 * overwriting SMBIOS string with any non-NULL char pointer
432 memset(fru_info_str
, 0, sizeof(*fru_info_str
));
433 req
.fru_device_id
= id
;
434 req
.fru_offset
= offset
;
435 req
.count
= sizeof(fru_common_hdr
);
436 /* Read FRU common header first */
437 if (ipmi_read_fru(port
, &req
, (uint8_t *)&fru_common_hdr
) == CB_SUCCESS
) {
438 if (checksum((uint8_t *)&fru_common_hdr
, sizeof(fru_common_hdr
))) {
439 printk(BIOS_ERR
, "Bad FRU common header checksum.\n");
442 printk(BIOS_DEBUG
, "FRU common header: format_version: %x\n"
443 "product_area_offset: %x\n"
444 "board_area_offset: %x\n"
445 "chassis_area_offset: %x\n",
446 fru_common_hdr
.format_version
,
447 fru_common_hdr
.product_area_offset
,
448 fru_common_hdr
.board_area_offset
,
449 fru_common_hdr
.chassis_area_offset
);
451 printk(BIOS_ERR
, "Read FRU common header failed\n");
455 read_fru_product_info_area(port
, id
, fru_common_hdr
.product_area_offset
,
456 &fru_info_str
->prod_info
);
457 read_fru_board_info_area(port
, id
, fru_common_hdr
.board_area_offset
,
458 &fru_info_str
->board_info
);
459 read_fru_chassis_info_area(port
, id
, fru_common_hdr
.chassis_area_offset
,
460 &fru_info_str
->chassis_info
);
463 void read_fru_one_area(const int port
, const uint8_t id
, uint16_t offset
,
464 struct fru_info_str
*fru_info_str
, enum fru_area fru_area
)
466 struct ipmi_read_fru_data_req req
;
467 struct ipmi_fru_common_hdr fru_common_hdr
;
469 req
.fru_device_id
= id
;
470 req
.fru_offset
= offset
;
471 req
.count
= sizeof(fru_common_hdr
);
472 if (ipmi_read_fru(port
, &req
, (uint8_t *)&fru_common_hdr
) == CB_SUCCESS
) {
473 if (checksum((uint8_t *)&fru_common_hdr
, sizeof(fru_common_hdr
))) {
474 printk(BIOS_ERR
, "Bad FRU common header checksum.\n");
477 printk(BIOS_DEBUG
, "FRU common header: format_version: %x\n"
478 "product_area_offset: %x\n"
479 "board_area_offset: %x\n"
480 "chassis_area_offset: %x\n",
481 fru_common_hdr
.format_version
,
482 fru_common_hdr
.product_area_offset
,
483 fru_common_hdr
.board_area_offset
,
484 fru_common_hdr
.chassis_area_offset
);
486 printk(BIOS_ERR
, "Read FRU common header failed\n");
491 case PRODUCT_INFO_AREA
:
492 memset(&fru_info_str
->prod_info
, 0, sizeof(fru_info_str
->prod_info
));
493 read_fru_product_info_area(port
, id
, fru_common_hdr
.product_area_offset
,
494 &fru_info_str
->prod_info
);
496 case BOARD_INFO_AREA
:
497 memset(&fru_info_str
->board_info
, 0, sizeof(fru_info_str
->board_info
));
498 read_fru_board_info_area(port
, id
, fru_common_hdr
.board_area_offset
,
499 &fru_info_str
->board_info
);
501 case CHASSIS_INFO_AREA
:
502 memset(&fru_info_str
->chassis_info
, 0, sizeof(fru_info_str
->chassis_info
));
503 read_fru_chassis_info_area(port
, id
, fru_common_hdr
.chassis_area_offset
,
504 &fru_info_str
->chassis_info
);
507 printk(BIOS_ERR
, "Invalid fru_area: %d\n", fru_area
);
512 void print_fru_areas(struct fru_info_str
*fru_info_str
)
515 if (fru_info_str
== NULL
) {
516 printk(BIOS_ERR
, "FRU data is null pointer\n");
519 struct fru_product_info prod_info
= fru_info_str
->prod_info
;
520 struct fru_board_info board_info
= fru_info_str
->board_info
;
521 struct fru_chassis_info chassis_info
= fru_info_str
->chassis_info
;
523 printk(BIOS_DEBUG
, "Printing Product Info Area...\n");
524 if (prod_info
.manufacturer
!= NULL
)
525 printk(BIOS_DEBUG
, "manufacturer: %s\n", prod_info
.manufacturer
);
526 if (prod_info
.product_name
!= NULL
)
527 printk(BIOS_DEBUG
, "product name: %s\n", prod_info
.product_name
);
528 if (prod_info
.product_partnumber
!= NULL
)
529 printk(BIOS_DEBUG
, "product part number: %s\n", prod_info
.product_partnumber
);
530 if (prod_info
.product_version
!= NULL
)
531 printk(BIOS_DEBUG
, "product version: %s\n", prod_info
.product_version
);
532 if (prod_info
.serial_number
!= NULL
)
533 printk(BIOS_DEBUG
, "serial number: %s\n", prod_info
.serial_number
);
534 if (prod_info
.asset_tag
!= NULL
)
535 printk(BIOS_DEBUG
, "asset tag: %s\n", prod_info
.asset_tag
);
536 if (prod_info
.fru_file_id
!= NULL
)
537 printk(BIOS_DEBUG
, "FRU file ID: %s\n", prod_info
.fru_file_id
);
539 for (count
= 0; count
< prod_info
.custom_count
; count
++) {
540 if (*(prod_info
.product_custom
+ count
) != NULL
)
541 printk(BIOS_DEBUG
, "product custom data %i: %s\n", count
,
542 *(prod_info
.product_custom
+ count
));
545 printk(BIOS_DEBUG
, "Printing Board Info Area...\n");
546 if (board_info
.manufacturer
!= NULL
)
547 printk(BIOS_DEBUG
, "manufacturer: %s\n", board_info
.manufacturer
);
548 if (board_info
.product_name
!= NULL
)
549 printk(BIOS_DEBUG
, "product name: %s\n", board_info
.product_name
);
550 if (board_info
.serial_number
!= NULL
)
551 printk(BIOS_DEBUG
, "serial number: %s\n", board_info
.serial_number
);
552 if (board_info
.part_number
!= NULL
)
553 printk(BIOS_DEBUG
, "part number: %s\n", board_info
.part_number
);
554 if (board_info
.fru_file_id
!= NULL
)
555 printk(BIOS_DEBUG
, "FRU file ID: %s\n", board_info
.fru_file_id
);
557 for (count
= 0; count
< board_info
.custom_count
; count
++) {
558 if (*(board_info
.board_custom
+ count
) != NULL
)
559 printk(BIOS_DEBUG
, "board custom data %i: %s\n", count
,
560 *(board_info
.board_custom
+ count
));
563 printk(BIOS_DEBUG
, "Printing Chassis Info Area...\n");
564 printk(BIOS_DEBUG
, "chassis type: 0x%x\n", chassis_info
.chassis_type
);
565 if (chassis_info
.chassis_partnumber
!= NULL
)
566 printk(BIOS_DEBUG
, "part number: %s\n", chassis_info
.chassis_partnumber
);
567 if (chassis_info
.serial_number
!= NULL
)
568 printk(BIOS_DEBUG
, "serial number: %s\n", chassis_info
.serial_number
);
570 for (count
= 0; count
< chassis_info
.custom_count
; count
++) {
571 if (*(chassis_info
.chassis_custom
+ count
) != NULL
)
572 printk(BIOS_DEBUG
, "chassis custom data %i: %s\n", count
,
573 *(chassis_info
.chassis_custom
+ count
));