db654eae79
Tested on OCP Tioga Pass Signed-off-by: Johnny Lin <johnny_lin@wiwynn.com> Change-Id: Ib05fdb34b2b324b6eb766de15727668ce91d2844 Reviewed-on: https://review.coreboot.org/c/coreboot/+/40522 Reviewed-by: Patrick Rudolph <siro@das-labor.org> Reviewed-by: Jonathan Zhang <jonzhang@fb.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
575 lines
18 KiB
C
575 lines
18 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
|
|
#include <console/console.h>
|
|
#include <string.h>
|
|
#include <delay.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "ipmi_ops.h"
|
|
|
|
#define MAX_FRU_BUSY_RETRY 5
|
|
#define READ_FRU_DATA_RETRY_INTERVAL_MS 30 /* From IPMI spec v2.0 rev 1.1 */
|
|
#define OFFSET_LENGTH_MULTIPLIER 8 /* offsets/lengths are multiples of 8 */
|
|
#define NUM_DATA_BYTES(t) (t & 0x3f) /* Encoded in type/length byte */
|
|
#define FRU_END_OF_FIELDS 0xc1 /* type/length byte encoded to indicate no more info fields */
|
|
|
|
static enum cb_err ipmi_read_fru(const int port, struct ipmi_read_fru_data_req *req,
|
|
uint8_t *fru_data)
|
|
{
|
|
int ret;
|
|
uint8_t total_size;
|
|
uint16_t offset = 0;
|
|
struct ipmi_read_fru_data_rsp rsp;
|
|
int retry_count = 0;
|
|
|
|
if (req == NULL || fru_data == NULL) {
|
|
printk(BIOS_ERR, "%s failed, null pointer parameter\n",
|
|
__func__);
|
|
return CB_ERR;
|
|
}
|
|
|
|
total_size = req->count;
|
|
do {
|
|
if (req->count > CONFIG_IPMI_FRU_SINGLE_RW_SZ)
|
|
req->count = CONFIG_IPMI_FRU_SINGLE_RW_SZ;
|
|
|
|
while (retry_count <= MAX_FRU_BUSY_RETRY) {
|
|
ret = ipmi_kcs_message(port, IPMI_NETFN_STORAGE, 0x0,
|
|
IPMI_READ_FRU_DATA, (const unsigned char *) req,
|
|
sizeof(*req), (unsigned char *) &rsp, sizeof(rsp));
|
|
if (rsp.resp.completion_code == 0x81) {
|
|
/* Device is busy */
|
|
if (retry_count == MAX_FRU_BUSY_RETRY) {
|
|
printk(BIOS_ERR, "IPMI: %s command failed, "
|
|
"device busy timeout\n", __func__);
|
|
return CB_ERR;
|
|
}
|
|
printk(BIOS_ERR, "IPMI: FRU device is busy, "
|
|
"retry count:%d\n", retry_count);
|
|
retry_count++;
|
|
mdelay(READ_FRU_DATA_RETRY_INTERVAL_MS);
|
|
} else if (ret < sizeof(struct ipmi_rsp) || rsp.resp.completion_code) {
|
|
printk(BIOS_ERR, "IPMI: %s command failed (ret=%d resp=0x%x)\n",
|
|
__func__, ret, rsp.resp.completion_code);
|
|
return CB_ERR;
|
|
}
|
|
break;
|
|
}
|
|
retry_count = 0;
|
|
memcpy(fru_data + offset, rsp.data, rsp.count);
|
|
offset += rsp.count;
|
|
total_size -= rsp.count;
|
|
req->fru_offset += rsp.count;
|
|
req->count = total_size;
|
|
} while (total_size > 0);
|
|
|
|
return CB_SUCCESS;
|
|
}
|
|
|
|
/* data: data to check, offset: offset to checksum. */
|
|
static uint8_t checksum(uint8_t *data, int offset)
|
|
{
|
|
uint8_t c = 0;
|
|
for (; offset > 0; offset--, data++)
|
|
c += *data;
|
|
return -c;
|
|
}
|
|
|
|
static uint8_t data2str(const uint8_t *frudata, char *stringdata, uint8_t length)
|
|
{
|
|
uint8_t type;
|
|
|
|
/* bit[7:6] is the type code. */
|
|
type = ((frudata[0] & 0xc0) >> 6);
|
|
if (type != ASCII_8BIT) {
|
|
printk(BIOS_ERR, "%s typecode %d is unsupported, FRU string only "
|
|
"supports 8-bit ASCII + Latin 1 for now.\n", __func__, type);
|
|
return 0;
|
|
}
|
|
/* In the spec the string data is always the next byte to the type/length byte. */
|
|
memcpy(stringdata, frudata + 1, length);
|
|
stringdata[length] = '\0';
|
|
return length;
|
|
}
|
|
|
|
/*
|
|
* Read data string from data_ptr and store it to string, return the
|
|
* length of the string or 0 when it's failed.
|
|
*/
|
|
static int read_data_string(const uint8_t *data_ptr, char **string)
|
|
{
|
|
uint8_t length;
|
|
|
|
length = NUM_DATA_BYTES(data_ptr[0]);
|
|
if (length == 0) {
|
|
printk(BIOS_DEBUG, "%s:%d - failed due to length is zero\n", __func__,
|
|
__LINE__);
|
|
return 0;
|
|
}
|
|
|
|
*string = malloc(length + 1);
|
|
if (!*string) {
|
|
printk(BIOS_ERR, "%s failed to malloc %d bytes for string data.\n", __func__,
|
|
length + 1);
|
|
return 0;
|
|
}
|
|
if (!data2str((const uint8_t *)data_ptr, *string, length)) {
|
|
printk(BIOS_ERR, "%s:%d - data2str failed\n", __func__, __LINE__);
|
|
free(*string);
|
|
return 0;
|
|
}
|
|
|
|
return length;
|
|
}
|
|
|
|
static enum cb_err read_fru_chassis_info_area(const int port, const uint8_t id,
|
|
uint8_t offset, struct fru_chassis_info *info)
|
|
{
|
|
uint8_t length;
|
|
struct ipmi_read_fru_data_req req;
|
|
uint8_t *data_ptr, *end, *custom_data_ptr;
|
|
int ret = CB_SUCCESS;
|
|
|
|
if (!offset)
|
|
return CB_ERR;
|
|
|
|
offset = offset * OFFSET_LENGTH_MULTIPLIER;
|
|
req.fru_device_id = id;
|
|
/* Read Chassis Info Area length first. */
|
|
req.fru_offset = offset + 1;
|
|
req.count = sizeof(length);
|
|
if (ipmi_read_fru(port, &req, &length) != CB_SUCCESS || !length) {
|
|
printk(BIOS_ERR, "%s failed, length: %d\n", __func__, length);
|
|
return CB_ERR;
|
|
}
|
|
length = length * OFFSET_LENGTH_MULTIPLIER;
|
|
data_ptr = (uint8_t *)malloc(length);
|
|
if (!data_ptr) {
|
|
printk(BIOS_ERR, "malloc %d bytes for chassis info failed\n", length);
|
|
return CB_ERR;
|
|
}
|
|
end = data_ptr + length;
|
|
/* Read Chassis Info Area data. */
|
|
req.fru_offset = offset;
|
|
req.count = length;
|
|
if (ipmi_read_fru(port, &req, data_ptr) != CB_SUCCESS) {
|
|
printk(BIOS_ERR, "%s failed to read fru\n", __func__);
|
|
ret = CB_ERR;
|
|
goto out;
|
|
}
|
|
if (checksum(data_ptr, length)) {
|
|
printk(BIOS_ERR, "Bad FRU chassis info checksum.\n");
|
|
ret = CB_ERR;
|
|
goto out;
|
|
}
|
|
/* Read chassis type. */
|
|
info->chassis_type = data_ptr[CHASSIS_TYPE_OFFSET];
|
|
|
|
printk(BIOS_DEBUG, "Read chassis part number string.\n");
|
|
length = read_data_string(data_ptr + CHASSIS_TYPE_OFFSET + 1,
|
|
&info->chassis_partnumber);
|
|
|
|
printk(BIOS_DEBUG, "Read chassis serial number string.\n");
|
|
data_ptr += CHASSIS_TYPE_OFFSET + 1 + length + 1;
|
|
length = read_data_string(data_ptr, &info->serial_number);
|
|
|
|
printk(BIOS_DEBUG, "Read custom chassis info fields.\n");
|
|
data_ptr += length + 1;
|
|
/* Check how many valid custom fields first. */
|
|
info->custom_count = 0;
|
|
custom_data_ptr = data_ptr;
|
|
while ((data_ptr < end) && ((data_ptr[0] != FRU_END_OF_FIELDS))) {
|
|
length = NUM_DATA_BYTES(data_ptr[0]);
|
|
if (length > 0)
|
|
info->custom_count++;
|
|
data_ptr += length + 1;
|
|
}
|
|
if (!info->custom_count)
|
|
goto out;
|
|
|
|
info->chassis_custom = malloc(info->custom_count * sizeof(char *));
|
|
if (!info->chassis_custom) {
|
|
printk(BIOS_ERR, "%s failed to malloc %ld bytes for "
|
|
"chassis custom data array.\n", __func__,
|
|
info->custom_count * sizeof(char *));
|
|
ret = CB_ERR;
|
|
goto out;
|
|
}
|
|
|
|
/* Start reading custom chassis data. */
|
|
data_ptr = custom_data_ptr;
|
|
int count = 0;
|
|
while ((data_ptr < end) && ((data_ptr[0] != FRU_END_OF_FIELDS))) {
|
|
length = NUM_DATA_BYTES(data_ptr[0]);
|
|
if (length > 0) {
|
|
length = read_data_string(data_ptr, info->chassis_custom + count);
|
|
count++;
|
|
}
|
|
data_ptr += length + 1;
|
|
}
|
|
|
|
out:
|
|
free(data_ptr);
|
|
return ret;
|
|
}
|
|
|
|
static enum cb_err read_fru_board_info_area(const int port, const uint8_t id,
|
|
uint8_t offset, struct fru_board_info *info)
|
|
{
|
|
uint8_t length;
|
|
struct ipmi_read_fru_data_req req;
|
|
uint8_t *data_ptr, *end, *custom_data_ptr;
|
|
int ret = CB_SUCCESS;
|
|
|
|
if (!offset)
|
|
return CB_ERR;
|
|
|
|
offset = offset * OFFSET_LENGTH_MULTIPLIER;
|
|
req.fru_device_id = id;
|
|
/* Read Board Info Area length first. */
|
|
req.fru_offset = offset + 1;
|
|
req.count = sizeof(length);
|
|
if (ipmi_read_fru(port, &req, &length) != CB_SUCCESS || !length) {
|
|
printk(BIOS_ERR, "%s failed, length: %d\n", __func__, length);
|
|
return CB_ERR;
|
|
}
|
|
length = length * OFFSET_LENGTH_MULTIPLIER;
|
|
data_ptr = (uint8_t *)malloc(length);
|
|
if (!data_ptr) {
|
|
printk(BIOS_ERR, "malloc %d bytes for board info failed\n", length);
|
|
return CB_ERR;
|
|
}
|
|
end = data_ptr + length;
|
|
/* Read Board Info Area data. */
|
|
req.fru_offset = offset;
|
|
req.count = length;
|
|
if (ipmi_read_fru(port, &req, data_ptr) != CB_SUCCESS) {
|
|
printk(BIOS_ERR, "%s failed to read fru\n", __func__);
|
|
ret = CB_ERR;
|
|
goto out;
|
|
}
|
|
if (checksum(data_ptr, length)) {
|
|
printk(BIOS_ERR, "Bad FRU board info checksum.\n");
|
|
ret = CB_ERR;
|
|
goto out;
|
|
}
|
|
printk(BIOS_DEBUG, "Read board manufacturer string\n");
|
|
length = read_data_string(data_ptr + BOARD_MAN_TYPE_LEN_OFFSET,
|
|
&info->manufacturer);
|
|
|
|
printk(BIOS_DEBUG, "Read board product name string.\n");
|
|
data_ptr += BOARD_MAN_TYPE_LEN_OFFSET + length + 1;
|
|
length = read_data_string(data_ptr, &info->product_name);
|
|
|
|
printk(BIOS_DEBUG, "Read board serial number string.\n");
|
|
data_ptr += length + 1;
|
|
length = read_data_string(data_ptr, &info->serial_number);
|
|
|
|
printk(BIOS_DEBUG, "Read board part number string.\n");
|
|
data_ptr += length + 1;
|
|
length = read_data_string(data_ptr, &info->part_number);
|
|
|
|
printk(BIOS_DEBUG, "Read board FRU file ID string.\n");
|
|
data_ptr += length + 1;
|
|
length = read_data_string(data_ptr, &info->fru_file_id);
|
|
|
|
/* Check how many valid custom fields first. */
|
|
data_ptr += length + 1;
|
|
info->custom_count = 0;
|
|
custom_data_ptr = data_ptr;
|
|
while ((data_ptr < end) && ((data_ptr[0] != FRU_END_OF_FIELDS))) {
|
|
length = NUM_DATA_BYTES(data_ptr[0]);
|
|
if (length > 0)
|
|
info->custom_count++;
|
|
data_ptr += length + 1;
|
|
}
|
|
if (!info->custom_count)
|
|
goto out;
|
|
|
|
info->board_custom = malloc(info->custom_count * sizeof(char *));
|
|
if (!info->board_custom) {
|
|
printk(BIOS_ERR, "%s failed to malloc %ld bytes for "
|
|
"board custom data array.\n", __func__,
|
|
info->custom_count * sizeof(char *));
|
|
ret = CB_ERR;
|
|
goto out;
|
|
}
|
|
|
|
/* Start reading custom board data. */
|
|
data_ptr = custom_data_ptr;
|
|
int count = 0;
|
|
while ((data_ptr < end) && ((data_ptr[0] != FRU_END_OF_FIELDS))) {
|
|
length = NUM_DATA_BYTES(data_ptr[0]);
|
|
if (length > 0) {
|
|
length = read_data_string(data_ptr, info->board_custom + count);
|
|
count++;
|
|
}
|
|
data_ptr += length + 1;
|
|
}
|
|
|
|
out:
|
|
free(data_ptr);
|
|
return ret;
|
|
}
|
|
|
|
static enum cb_err read_fru_product_info_area(const int port, const uint8_t id,
|
|
uint8_t offset, struct fru_product_info *info)
|
|
{
|
|
uint8_t length;
|
|
struct ipmi_read_fru_data_req req;
|
|
uint8_t *data_ptr, *end, *custom_data_ptr;
|
|
int ret = CB_SUCCESS;
|
|
|
|
if (!offset)
|
|
return CB_ERR;
|
|
|
|
offset = offset * OFFSET_LENGTH_MULTIPLIER;
|
|
req.fru_device_id = id;
|
|
/* Read Product Info Area length first. */
|
|
req.fru_offset = offset + 1;
|
|
req.count = sizeof(length);
|
|
if (ipmi_read_fru(port, &req, &length) != CB_SUCCESS || !length) {
|
|
printk(BIOS_ERR, "%s failed, length: %d\n", __func__, length);
|
|
return CB_ERR;
|
|
}
|
|
length = length * OFFSET_LENGTH_MULTIPLIER;
|
|
data_ptr = (uint8_t *)malloc(length);
|
|
if (!data_ptr) {
|
|
printk(BIOS_ERR, "malloc %d bytes for product info failed\n", length);
|
|
return CB_ERR;
|
|
}
|
|
end = data_ptr + length;
|
|
/* Read Product Info Area data. */
|
|
req.fru_offset = offset;
|
|
req.count = length;
|
|
if (ipmi_read_fru(port, &req, data_ptr) != CB_SUCCESS) {
|
|
printk(BIOS_ERR, "%s failed to read fru\n", __func__);
|
|
ret = CB_ERR;
|
|
goto out;
|
|
}
|
|
if (checksum(data_ptr, length)) {
|
|
printk(BIOS_ERR, "Bad FRU product info checksum.\n");
|
|
ret = CB_ERR;
|
|
goto out;
|
|
}
|
|
printk(BIOS_DEBUG, "Read product manufacturer string.\n");
|
|
length = read_data_string(data_ptr + PRODUCT_MAN_TYPE_LEN_OFFSET,
|
|
&info->manufacturer);
|
|
|
|
data_ptr += PRODUCT_MAN_TYPE_LEN_OFFSET + length + 1;
|
|
printk(BIOS_DEBUG, "Read product_name string.\n");
|
|
length = read_data_string(data_ptr, &info->product_name);
|
|
|
|
data_ptr += length + 1;
|
|
printk(BIOS_DEBUG, "Read product part/model number.\n");
|
|
length = read_data_string(data_ptr, &info->product_partnumber);
|
|
|
|
data_ptr += length + 1;
|
|
printk(BIOS_DEBUG, "Read product version string.\n");
|
|
length = read_data_string(data_ptr, &info->product_version);
|
|
|
|
data_ptr += length + 1;
|
|
printk(BIOS_DEBUG, "Read serial number string.\n");
|
|
length = read_data_string(data_ptr, &info->serial_number);
|
|
|
|
data_ptr += length + 1;
|
|
printk(BIOS_DEBUG, "Read asset tag string.\n");
|
|
length = read_data_string(data_ptr, &info->asset_tag);
|
|
|
|
printk(BIOS_DEBUG, "Read product FRU file ID string.\n");
|
|
data_ptr += length + 1;
|
|
length = read_data_string(data_ptr, &info->fru_file_id);
|
|
|
|
/* Check how many valid custom fields first. */
|
|
data_ptr += length + 1;
|
|
info->custom_count = 0;
|
|
custom_data_ptr = data_ptr;
|
|
while ((data_ptr < end) && ((data_ptr[0] != FRU_END_OF_FIELDS))) {
|
|
length = NUM_DATA_BYTES(data_ptr[0]);
|
|
if (length > 0)
|
|
info->custom_count++;
|
|
data_ptr += length + 1;
|
|
}
|
|
if (!info->custom_count)
|
|
goto out;
|
|
|
|
info->product_custom = malloc(info->custom_count * sizeof(char *));
|
|
if (!info->product_custom) {
|
|
printk(BIOS_ERR, "%s failed to malloc %ld bytes for "
|
|
"product custom data array.\n", __func__,
|
|
info->custom_count * sizeof(char *));
|
|
ret = CB_ERR;
|
|
goto out;
|
|
}
|
|
|
|
/* Start reading custom product data. */
|
|
data_ptr = custom_data_ptr;
|
|
int count = 0;
|
|
while ((data_ptr < end) && ((data_ptr[0] != FRU_END_OF_FIELDS))) {
|
|
length = NUM_DATA_BYTES(data_ptr[0]);
|
|
if (length > 0) {
|
|
length = read_data_string(data_ptr, info->product_custom + count);
|
|
count++;
|
|
}
|
|
data_ptr += length + 1;
|
|
}
|
|
|
|
out:
|
|
free(data_ptr);
|
|
return ret;
|
|
}
|
|
|
|
void read_fru_areas(const int port, const uint8_t id, uint16_t offset,
|
|
struct fru_info_str *fru_info_str)
|
|
{
|
|
struct ipmi_read_fru_data_req req;
|
|
struct ipmi_fru_common_hdr fru_common_hdr;
|
|
|
|
/* Set all the char pointers to 0 first, to avoid mainboard
|
|
* overwriting SMBIOS string with any non-NULL char pointer
|
|
* by accident. */
|
|
memset(fru_info_str, 0, sizeof(*fru_info_str));
|
|
req.fru_device_id = id;
|
|
req.fru_offset = offset;
|
|
req.count = sizeof(fru_common_hdr);
|
|
/* Read FRU common header first */
|
|
if (ipmi_read_fru(port, &req, (uint8_t *)&fru_common_hdr) == CB_SUCCESS) {
|
|
if (checksum((uint8_t *)&fru_common_hdr, sizeof(fru_common_hdr))) {
|
|
printk(BIOS_ERR, "Bad FRU common header checksum.\n");
|
|
return;
|
|
}
|
|
printk(BIOS_DEBUG, "FRU common header: format_version: %x\n"
|
|
"product_area_offset: %x\n"
|
|
"board_area_offset: %x\n"
|
|
"chassis_area_offset: %x\n",
|
|
fru_common_hdr.format_version,
|
|
fru_common_hdr.product_area_offset,
|
|
fru_common_hdr.board_area_offset,
|
|
fru_common_hdr.chassis_area_offset);
|
|
} else {
|
|
printk(BIOS_ERR, "Read FRU common header failed\n");
|
|
return;
|
|
}
|
|
|
|
read_fru_product_info_area(port, id, fru_common_hdr.product_area_offset,
|
|
&fru_info_str->prod_info);
|
|
read_fru_board_info_area(port, id, fru_common_hdr.board_area_offset,
|
|
&fru_info_str->board_info);
|
|
read_fru_chassis_info_area(port, id, fru_common_hdr.chassis_area_offset,
|
|
&fru_info_str->chassis_info);
|
|
}
|
|
|
|
void read_fru_one_area(const int port, const uint8_t id, uint16_t offset,
|
|
struct fru_info_str *fru_info_str, enum fru_area fru_area)
|
|
{
|
|
struct ipmi_read_fru_data_req req;
|
|
struct ipmi_fru_common_hdr fru_common_hdr;
|
|
|
|
req.fru_device_id = id;
|
|
req.fru_offset = offset;
|
|
req.count = sizeof(fru_common_hdr);
|
|
if (ipmi_read_fru(port, &req, (uint8_t *)&fru_common_hdr) == CB_SUCCESS) {
|
|
if (checksum((uint8_t *)&fru_common_hdr, sizeof(fru_common_hdr))) {
|
|
printk(BIOS_ERR, "Bad FRU common header checksum.\n");
|
|
return;
|
|
}
|
|
printk(BIOS_DEBUG, "FRU common header: format_version: %x\n"
|
|
"product_area_offset: %x\n"
|
|
"board_area_offset: %x\n"
|
|
"chassis_area_offset: %x\n",
|
|
fru_common_hdr.format_version,
|
|
fru_common_hdr.product_area_offset,
|
|
fru_common_hdr.board_area_offset,
|
|
fru_common_hdr.chassis_area_offset);
|
|
} else {
|
|
printk(BIOS_ERR, "Read FRU common header failed\n");
|
|
return;
|
|
}
|
|
|
|
switch (fru_area) {
|
|
case PRODUCT_INFO_AREA:
|
|
memset(&fru_info_str->prod_info, 0, sizeof(fru_info_str->prod_info));
|
|
read_fru_product_info_area(port, id, fru_common_hdr.product_area_offset,
|
|
&fru_info_str->prod_info);
|
|
break;
|
|
case BOARD_INFO_AREA:
|
|
memset(&fru_info_str->board_info, 0, sizeof(fru_info_str->board_info));
|
|
read_fru_board_info_area(port, id, fru_common_hdr.board_area_offset,
|
|
&fru_info_str->board_info);
|
|
break;
|
|
case CHASSIS_INFO_AREA:
|
|
memset(&fru_info_str->chassis_info, 0, sizeof(fru_info_str->chassis_info));
|
|
read_fru_chassis_info_area(port, id, fru_common_hdr.chassis_area_offset,
|
|
&fru_info_str->chassis_info);
|
|
break;
|
|
default:
|
|
printk(BIOS_ERR, "Invalid fru_area: %d\n", fru_area);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void print_fru_areas(struct fru_info_str *fru_info_str)
|
|
{
|
|
int count = 0;
|
|
if (fru_info_str == NULL) {
|
|
printk(BIOS_ERR, "FRU data is null pointer\n");
|
|
return;
|
|
}
|
|
struct fru_product_info prod_info = fru_info_str->prod_info;
|
|
struct fru_board_info board_info = fru_info_str->board_info;
|
|
struct fru_chassis_info chassis_info = fru_info_str->chassis_info;
|
|
|
|
printk(BIOS_DEBUG, "Printing Product Info Area...\n");
|
|
if (prod_info.manufacturer != NULL)
|
|
printk(BIOS_DEBUG, "manufacturer: %s\n", prod_info.manufacturer);
|
|
if (prod_info.product_name != NULL)
|
|
printk(BIOS_DEBUG, "product name: %s\n", prod_info.product_name);
|
|
if (prod_info.product_partnumber != NULL)
|
|
printk(BIOS_DEBUG, "product part numer: %s\n", prod_info.product_partnumber);
|
|
if (prod_info.product_version != NULL)
|
|
printk(BIOS_DEBUG, "product version: %s\n", prod_info.product_version);
|
|
if (prod_info.serial_number != NULL)
|
|
printk(BIOS_DEBUG, "serial number: %s\n", prod_info.serial_number);
|
|
if (prod_info.asset_tag != NULL)
|
|
printk(BIOS_DEBUG, "asset tag: %s\n", prod_info.asset_tag);
|
|
if (prod_info.fru_file_id != NULL)
|
|
printk(BIOS_DEBUG, "FRU file ID: %s\n", prod_info.fru_file_id);
|
|
|
|
for (count = 0; count < prod_info.custom_count; count++) {
|
|
if (*(prod_info.product_custom + count) != NULL)
|
|
printk(BIOS_DEBUG, "product custom data %i: %s\n", count,
|
|
*(prod_info.product_custom + count));
|
|
}
|
|
|
|
printk(BIOS_DEBUG, "Printing Board Info Area...\n");
|
|
if (board_info.manufacturer != NULL)
|
|
printk(BIOS_DEBUG, "manufacturer: %s\n", board_info.manufacturer);
|
|
if (board_info.product_name != NULL)
|
|
printk(BIOS_DEBUG, "product name: %s\n", board_info.product_name);
|
|
if (board_info.serial_number != NULL)
|
|
printk(BIOS_DEBUG, "serial number: %s\n", board_info.serial_number);
|
|
if (board_info.part_number != NULL)
|
|
printk(BIOS_DEBUG, "part number: %s\n", board_info.part_number);
|
|
if (board_info.fru_file_id != NULL)
|
|
printk(BIOS_DEBUG, "FRU file ID: %s\n", board_info.fru_file_id);
|
|
|
|
for (count = 0; count < board_info.custom_count; count++) {
|
|
if (*(board_info.board_custom + count) != NULL)
|
|
printk(BIOS_DEBUG, "board custom data %i: %s\n", count,
|
|
*(board_info.board_custom + count));
|
|
}
|
|
|
|
printk(BIOS_DEBUG, "Printing Chassis Info Area...\n");
|
|
printk(BIOS_DEBUG, "chassis type: 0x%x\n", chassis_info.chassis_type);
|
|
if (chassis_info.chassis_partnumber != NULL)
|
|
printk(BIOS_DEBUG, "part number: %s\n", chassis_info.chassis_partnumber);
|
|
if (chassis_info.serial_number != NULL)
|
|
printk(BIOS_DEBUG, "serial number: %s\n", chassis_info.serial_number);
|
|
|
|
for (count = 0; count < chassis_info.custom_count; count++) {
|
|
if (*(chassis_info.chassis_custom + count) != NULL)
|
|
printk(BIOS_DEBUG, "chassis custom data %i: %s\n", count,
|
|
*(chassis_info.chassis_custom + count));
|
|
}
|
|
|
|
}
|