blob: 844eb8e8a3c024c7dfffe13d5531caebee88ace3 [file] [log] [blame]
Angel Pons8a3453f2020-04-02 23:48:19 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Johnny Linb9e84482019-12-02 19:44:04 +08002
3#include <console/console.h>
4#include <string.h>
5#include <delay.h>
Elyes HAOUASf07d7dc2019-12-21 07:24:22 +01006#include <stdlib.h>
7
Sergii Dmytrukef7dd5d2021-10-22 01:02:32 +03008#include "ipmi_if.h"
Johnny Linb9e84482019-12-02 19:44:04 +08009#include "ipmi_ops.h"
10
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 */
Johnny Lind6a47722020-01-22 16:36:17 +080015#define FRU_END_OF_FIELDS 0xc1 /* type/length byte encoded to indicate no more info fields */
Johnny Linb9e84482019-12-02 19:44:04 +080016
17static enum cb_err ipmi_read_fru(const int port, struct ipmi_read_fru_data_req *req,
18 uint8_t *fru_data)
19{
20 int ret;
21 uint8_t total_size;
22 uint16_t offset = 0;
23 struct ipmi_read_fru_data_rsp rsp;
24 int retry_count = 0;
25
26 if (req == NULL || fru_data == NULL) {
27 printk(BIOS_ERR, "%s failed, null pointer parameter\n",
28 __func__);
29 return CB_ERR;
30 }
31
32 total_size = req->count;
33 do {
34 if (req->count > CONFIG_IPMI_FRU_SINGLE_RW_SZ)
35 req->count = CONFIG_IPMI_FRU_SINGLE_RW_SZ;
36
37 while (retry_count <= MAX_FRU_BUSY_RETRY) {
Sergii Dmytrukef7dd5d2021-10-22 01:02:32 +030038 ret = ipmi_message(port, IPMI_NETFN_STORAGE, 0x0,
Elyes Haouas1ef547e2022-11-18 15:05:39 +010039 IPMI_READ_FRU_DATA, (const unsigned char *)req,
40 sizeof(*req), (unsigned char *)&rsp, sizeof(rsp));
Johnny Linb9e84482019-12-02 19:44:04 +080041 if (rsp.resp.completion_code == 0x81) {
42 /* Device is busy */
43 if (retry_count == MAX_FRU_BUSY_RETRY) {
44 printk(BIOS_ERR, "IPMI: %s command failed, "
45 "device busy timeout\n", __func__);
46 return CB_ERR;
47 }
48 printk(BIOS_ERR, "IPMI: FRU device is busy, "
49 "retry count:%d\n", retry_count);
50 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);
55 return CB_ERR;
56 }
57 break;
58 }
59 retry_count = 0;
60 memcpy(fru_data + offset, rsp.data, rsp.count);
61 offset += rsp.count;
62 total_size -= rsp.count;
63 req->fru_offset += rsp.count;
64 req->count = total_size;
65 } while (total_size > 0);
66
67 return CB_SUCCESS;
68}
69
70/* data: data to check, offset: offset to checksum. */
71static uint8_t checksum(uint8_t *data, int offset)
72{
73 uint8_t c = 0;
74 for (; offset > 0; offset--, data++)
75 c += *data;
76 return -c;
77}
78
79static uint8_t data2str(const uint8_t *frudata, char *stringdata, uint8_t length)
80{
81 uint8_t type;
82
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);
88 return 0;
89 }
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';
93 return length;
94}
95
Johnny Lin496bd152020-04-23 09:49:35 +080096/*
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.
99 */
100static int read_data_string(const uint8_t *data_ptr, char **string)
101{
102 uint8_t length;
103
104 length = NUM_DATA_BYTES(data_ptr[0]);
105 if (length == 0) {
106 printk(BIOS_DEBUG, "%s:%d - failed due to length is zero\n", __func__,
107 __LINE__);
108 return 0;
109 }
110
111 *string = malloc(length + 1);
112 if (!*string) {
113 printk(BIOS_ERR, "%s failed to malloc %d bytes for string data.\n", __func__,
114 length + 1);
115 return 0;
116 }
117 if (!data2str((const uint8_t *)data_ptr, *string, length)) {
118 printk(BIOS_ERR, "%s:%d - data2str failed\n", __func__, __LINE__);
119 free(*string);
120 return 0;
121 }
122
123 return length;
124}
Johnny Lind6a47722020-01-22 16:36:17 +0800125
126static enum cb_err read_fru_chassis_info_area(const int port, const uint8_t id,
127 uint8_t offset, struct fru_chassis_info *info)
128{
129 uint8_t length;
130 struct ipmi_read_fru_data_req req;
131 uint8_t *data_ptr, *end, *custom_data_ptr;
132 int ret = CB_SUCCESS;
133
134 if (!offset)
135 return CB_ERR;
136
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);
144 return CB_ERR;
145 }
146 length = length * OFFSET_LENGTH_MULTIPLIER;
147 data_ptr = (uint8_t *)malloc(length);
148 if (!data_ptr) {
149 printk(BIOS_ERR, "malloc %d bytes for chassis info failed\n", length);
150 return CB_ERR;
151 }
152 end = data_ptr + length;
153 /* Read Chassis Info Area data. */
154 req.fru_offset = offset;
155 req.count = length;
156 if (ipmi_read_fru(port, &req, data_ptr) != CB_SUCCESS) {
157 printk(BIOS_ERR, "%s failed to read fru\n", __func__);
158 ret = CB_ERR;
159 goto out;
160 }
161 if (checksum(data_ptr, length)) {
162 printk(BIOS_ERR, "Bad FRU chassis info checksum.\n");
163 ret = CB_ERR;
164 goto out;
165 }
166 /* Read chassis type. */
167 info->chassis_type = data_ptr[CHASSIS_TYPE_OFFSET];
168
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);
172
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);
176
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]);
184 if (length > 0)
185 info->custom_count++;
186 data_ptr += length + 1;
187 }
188 if (!info->custom_count)
189 goto out;
190
191 info->chassis_custom = malloc(info->custom_count * sizeof(char *));
192 if (!info->chassis_custom) {
Paul Menzel7be44d22021-11-09 08:36:52 +0100193 printk(BIOS_ERR, "%s failed to malloc %zu bytes for "
Johnny Lind6a47722020-01-22 16:36:17 +0800194 "chassis custom data array.\n", __func__,
195 info->custom_count * sizeof(char *));
196 ret = CB_ERR;
197 goto out;
198 }
199
200 /* Start reading custom chassis data. */
201 data_ptr = custom_data_ptr;
202 int count = 0;
203 while ((data_ptr < end) && ((data_ptr[0] != FRU_END_OF_FIELDS))) {
204 length = NUM_DATA_BYTES(data_ptr[0]);
205 if (length > 0) {
206 length = read_data_string(data_ptr, info->chassis_custom + count);
207 count++;
208 }
209 data_ptr += length + 1;
210 }
211
212out:
213 free(data_ptr);
214 return ret;
215}
216
Johnny Lindb654ea2020-04-20 17:32:47 +0800217static enum cb_err read_fru_board_info_area(const int port, const uint8_t id,
Johnny Linb9e84482019-12-02 19:44:04 +0800218 uint8_t offset, struct fru_board_info *info)
219{
220 uint8_t length;
221 struct ipmi_read_fru_data_req req;
Johnny Lindb654ea2020-04-20 17:32:47 +0800222 uint8_t *data_ptr, *end, *custom_data_ptr;
223 int ret = CB_SUCCESS;
224
225 if (!offset)
226 return CB_ERR;
Johnny Linb9e84482019-12-02 19:44:04 +0800227
228 offset = offset * OFFSET_LENGTH_MULTIPLIER;
Johnny Linb9e84482019-12-02 19:44:04 +0800229 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);
Johnny Lindb654ea2020-04-20 17:32:47 +0800235 return CB_ERR;
Johnny Linb9e84482019-12-02 19:44:04 +0800236 }
237 length = length * OFFSET_LENGTH_MULTIPLIER;
238 data_ptr = (uint8_t *)malloc(length);
239 if (!data_ptr) {
240 printk(BIOS_ERR, "malloc %d bytes for board info failed\n", length);
Johnny Lindb654ea2020-04-20 17:32:47 +0800241 return CB_ERR;
Johnny Linb9e84482019-12-02 19:44:04 +0800242 }
Johnny Lindb654ea2020-04-20 17:32:47 +0800243 end = data_ptr + length;
Johnny Linb9e84482019-12-02 19:44:04 +0800244 /* Read Board Info Area data. */
245 req.fru_offset = offset;
246 req.count = length;
247 if (ipmi_read_fru(port, &req, data_ptr) != CB_SUCCESS) {
248 printk(BIOS_ERR, "%s failed to read fru\n", __func__);
Johnny Lindb654ea2020-04-20 17:32:47 +0800249 ret = CB_ERR;
Johnny Linb9e84482019-12-02 19:44:04 +0800250 goto out;
251 }
252 if (checksum(data_ptr, length)) {
253 printk(BIOS_ERR, "Bad FRU board info checksum.\n");
Johnny Lindb654ea2020-04-20 17:32:47 +0800254 ret = CB_ERR;
Johnny Linb9e84482019-12-02 19:44:04 +0800255 goto out;
256 }
Johnny Lin496bd152020-04-23 09:49:35 +0800257 printk(BIOS_DEBUG, "Read board manufacturer string\n");
258 length = read_data_string(data_ptr + BOARD_MAN_TYPE_LEN_OFFSET,
259 &info->manufacturer);
Johnny Linb9e84482019-12-02 19:44:04 +0800260
Johnny Lin496bd152020-04-23 09:49:35 +0800261 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);
Johnny Linb9e84482019-12-02 19:44:04 +0800264
Johnny Lin496bd152020-04-23 09:49:35 +0800265 printk(BIOS_DEBUG, "Read board serial number string.\n");
Johnny Linb9e84482019-12-02 19:44:04 +0800266 data_ptr += length + 1;
Johnny Lin496bd152020-04-23 09:49:35 +0800267 length = read_data_string(data_ptr, &info->serial_number);
Johnny Linb9e84482019-12-02 19:44:04 +0800268
Johnny Lin496bd152020-04-23 09:49:35 +0800269 printk(BIOS_DEBUG, "Read board part number string.\n");
Johnny Linb9e84482019-12-02 19:44:04 +0800270 data_ptr += length + 1;
Johnny Lin496bd152020-04-23 09:49:35 +0800271 length = read_data_string(data_ptr, &info->part_number);
Johnny Linb9e84482019-12-02 19:44:04 +0800272
Johnny Lindb654ea2020-04-20 17:32:47 +0800273 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);
276
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]);
283 if (length > 0)
284 info->custom_count++;
285 data_ptr += length + 1;
286 }
287 if (!info->custom_count)
288 goto out;
289
290 info->board_custom = malloc(info->custom_count * sizeof(char *));
291 if (!info->board_custom) {
Paul Menzel7be44d22021-11-09 08:36:52 +0100292 printk(BIOS_ERR, "%s failed to malloc %zu bytes for "
Johnny Lindb654ea2020-04-20 17:32:47 +0800293 "board custom data array.\n", __func__,
294 info->custom_count * sizeof(char *));
295 ret = CB_ERR;
296 goto out;
297 }
298
299 /* Start reading custom board data. */
300 data_ptr = custom_data_ptr;
301 int count = 0;
302 while ((data_ptr < end) && ((data_ptr[0] != FRU_END_OF_FIELDS))) {
303 length = NUM_DATA_BYTES(data_ptr[0]);
304 if (length > 0) {
305 length = read_data_string(data_ptr, info->board_custom + count);
306 count++;
307 }
308 data_ptr += length + 1;
309 }
310
Johnny Linb9e84482019-12-02 19:44:04 +0800311out:
312 free(data_ptr);
Johnny Lindb654ea2020-04-20 17:32:47 +0800313 return ret;
Johnny Linb9e84482019-12-02 19:44:04 +0800314}
315
Johnny Lindb654ea2020-04-20 17:32:47 +0800316static enum cb_err read_fru_product_info_area(const int port, const uint8_t id,
Johnny Linb9e84482019-12-02 19:44:04 +0800317 uint8_t offset, struct fru_product_info *info)
318{
319 uint8_t length;
320 struct ipmi_read_fru_data_req req;
Johnny Lindb654ea2020-04-20 17:32:47 +0800321 uint8_t *data_ptr, *end, *custom_data_ptr;
322 int ret = CB_SUCCESS;
323
324 if (!offset)
325 return CB_ERR;
Johnny Linb9e84482019-12-02 19:44:04 +0800326
327 offset = offset * OFFSET_LENGTH_MULTIPLIER;
Johnny Linb9e84482019-12-02 19:44:04 +0800328 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);
Johnny Lindb654ea2020-04-20 17:32:47 +0800334 return CB_ERR;
Johnny Linb9e84482019-12-02 19:44:04 +0800335 }
336 length = length * OFFSET_LENGTH_MULTIPLIER;
337 data_ptr = (uint8_t *)malloc(length);
338 if (!data_ptr) {
339 printk(BIOS_ERR, "malloc %d bytes for product info failed\n", length);
Johnny Lindb654ea2020-04-20 17:32:47 +0800340 return CB_ERR;
Johnny Linb9e84482019-12-02 19:44:04 +0800341 }
Johnny Lindb654ea2020-04-20 17:32:47 +0800342 end = data_ptr + length;
Johnny Linb9e84482019-12-02 19:44:04 +0800343 /* Read Product Info Area data. */
344 req.fru_offset = offset;
345 req.count = length;
346 if (ipmi_read_fru(port, &req, data_ptr) != CB_SUCCESS) {
347 printk(BIOS_ERR, "%s failed to read fru\n", __func__);
Johnny Lindb654ea2020-04-20 17:32:47 +0800348 ret = CB_ERR;
Johnny Linb9e84482019-12-02 19:44:04 +0800349 goto out;
350 }
351 if (checksum(data_ptr, length)) {
352 printk(BIOS_ERR, "Bad FRU product info checksum.\n");
Johnny Lindb654ea2020-04-20 17:32:47 +0800353 ret = CB_ERR;
Johnny Linb9e84482019-12-02 19:44:04 +0800354 goto out;
355 }
Johnny Lin496bd152020-04-23 09:49:35 +0800356 printk(BIOS_DEBUG, "Read product manufacturer string.\n");
357 length = read_data_string(data_ptr + PRODUCT_MAN_TYPE_LEN_OFFSET,
358 &info->manufacturer);
Johnny Linb9e84482019-12-02 19:44:04 +0800359
Johnny Lin496bd152020-04-23 09:49:35 +0800360 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);
Johnny Linb9e84482019-12-02 19:44:04 +0800363
Johnny Linb9e84482019-12-02 19:44:04 +0800364 data_ptr += length + 1;
Johnny Lin496bd152020-04-23 09:49:35 +0800365 printk(BIOS_DEBUG, "Read product part/model number.\n");
366 length = read_data_string(data_ptr, &info->product_partnumber);
Johnny Linb9e84482019-12-02 19:44:04 +0800367
Johnny Linb9e84482019-12-02 19:44:04 +0800368 data_ptr += length + 1;
Johnny Lin496bd152020-04-23 09:49:35 +0800369 printk(BIOS_DEBUG, "Read product version string.\n");
370 length = read_data_string(data_ptr, &info->product_version);
Johnny Linb9e84482019-12-02 19:44:04 +0800371
Johnny Linb9e84482019-12-02 19:44:04 +0800372 data_ptr += length + 1;
Johnny Lin496bd152020-04-23 09:49:35 +0800373 printk(BIOS_DEBUG, "Read serial number string.\n");
374 length = read_data_string(data_ptr, &info->serial_number);
Johnny Linb9e84482019-12-02 19:44:04 +0800375
Johnny Linb9e84482019-12-02 19:44:04 +0800376 data_ptr += length + 1;
Johnny Lin496bd152020-04-23 09:49:35 +0800377 printk(BIOS_DEBUG, "Read asset tag string.\n");
378 length = read_data_string(data_ptr, &info->asset_tag);
Johnny Linb9e84482019-12-02 19:44:04 +0800379
Johnny Lindb654ea2020-04-20 17:32:47 +0800380 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);
383
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]);
390 if (length > 0)
391 info->custom_count++;
392 data_ptr += length + 1;
393 }
394 if (!info->custom_count)
395 goto out;
396
397 info->product_custom = malloc(info->custom_count * sizeof(char *));
398 if (!info->product_custom) {
Paul Menzel7be44d22021-11-09 08:36:52 +0100399 printk(BIOS_ERR, "%s failed to malloc %zu bytes for "
Johnny Lindb654ea2020-04-20 17:32:47 +0800400 "product custom data array.\n", __func__,
401 info->custom_count * sizeof(char *));
402 ret = CB_ERR;
403 goto out;
404 }
405
406 /* Start reading custom product data. */
407 data_ptr = custom_data_ptr;
408 int count = 0;
409 while ((data_ptr < end) && ((data_ptr[0] != FRU_END_OF_FIELDS))) {
410 length = NUM_DATA_BYTES(data_ptr[0]);
411 if (length > 0) {
412 length = read_data_string(data_ptr, info->product_custom + count);
413 count++;
414 }
415 data_ptr += length + 1;
416 }
417
Johnny Linb9e84482019-12-02 19:44:04 +0800418out:
419 free(data_ptr);
Johnny Lindb654ea2020-04-20 17:32:47 +0800420 return ret;
Johnny Linb9e84482019-12-02 19:44:04 +0800421}
422
423void read_fru_areas(const int port, const uint8_t id, uint16_t offset,
424 struct fru_info_str *fru_info_str)
425{
426 struct ipmi_read_fru_data_req req;
427 struct ipmi_fru_common_hdr fru_common_hdr;
428
429 /* Set all the char pointers to 0 first, to avoid mainboard
430 * overwriting SMBIOS string with any non-NULL char pointer
431 * by accident. */
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");
440 return;
441 }
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);
450 } else {
451 printk(BIOS_ERR, "Read FRU common header failed\n");
452 return;
453 }
454
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);
Johnny Lind6a47722020-01-22 16:36:17 +0800459 read_fru_chassis_info_area(port, id, fru_common_hdr.chassis_area_offset,
460 &fru_info_str->chassis_info);
Johnny Linb9e84482019-12-02 19:44:04 +0800461}
462
463void 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)
465{
466 struct ipmi_read_fru_data_req req;
467 struct ipmi_fru_common_hdr fru_common_hdr;
468
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");
475 return;
476 }
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);
485 } else {
486 printk(BIOS_ERR, "Read FRU common header failed\n");
487 return;
488 }
489
490 switch (fru_area) {
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);
495 break;
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);
500 break;
Johnny Lind6a47722020-01-22 16:36:17 +0800501 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);
505 break;
Johnny Linb9e84482019-12-02 19:44:04 +0800506 default:
507 printk(BIOS_ERR, "Invalid fru_area: %d\n", fru_area);
508 break;
509 }
510}
Johnny Lindb654ea2020-04-20 17:32:47 +0800511
512void print_fru_areas(struct fru_info_str *fru_info_str)
513{
514 int count = 0;
515 if (fru_info_str == NULL) {
516 printk(BIOS_ERR, "FRU data is null pointer\n");
517 return;
518 }
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;
522
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)
Martin Roth0949e732021-10-01 14:28:22 -0600529 printk(BIOS_DEBUG, "product part number: %s\n", prod_info.product_partnumber);
Johnny Lindb654ea2020-04-20 17:32:47 +0800530 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);
538
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));
543 }
544
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);
556
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));
561 }
562
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);
569
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));
574 }
Johnny Lindb654ea2020-04-20 17:32:47 +0800575}