1/* SPDX-License-Identifier: GPL-2.0+ */ 2/* 3 * Copyright (C) 2012 CERN (www.cern.ch) 4 * Author: Alessandro Rubini <rubini@gnudd.com> 5 * 6 * This work is part of the White Rabbit project, a research effort led 7 * by CERN, the European Institute for Nuclear Research. 8 */ 9#ifndef __LINUX_IPMI_FRU_H__ 10#define __LINUX_IPMI_FRU_H__ 11#ifdef __KERNEL__ 12# include <linux/types.h> 13# include <linux/string.h> 14#else 15# include <stdint.h> 16# include <string.h> 17#endif 18 19/* 20 * These structures match the unaligned crap we have in FRU1011.pdf 21 * (http://download.intel.com/design/servers/ipmi/FRU1011.pdf) 22 */ 23 24/* chapter 8, page 5 */ 25struct fru_common_header { 26 uint8_t format; /* 0x01 */ 27 uint8_t internal_use_off; /* multiple of 8 bytes */ 28 uint8_t chassis_info_off; /* multiple of 8 bytes */ 29 uint8_t board_area_off; /* multiple of 8 bytes */ 30 uint8_t product_area_off; /* multiple of 8 bytes */ 31 uint8_t multirecord_off; /* multiple of 8 bytes */ 32 uint8_t pad; /* must be 0 */ 33 uint8_t checksum; /* sum modulo 256 must be 0 */ 34}; 35 36/* chapter 9, page 5 -- internal_use: not used by us */ 37 38/* chapter 10, page 6 -- chassis info: not used by us */ 39 40/* chapter 13, page 9 -- used by board_info_area below */ 41struct fru_type_length { 42 uint8_t type_length; 43 uint8_t data[0]; 44}; 45 46/* chapter 11, page 7 */ 47struct fru_board_info_area { 48 uint8_t format; /* 0x01 */ 49 uint8_t area_len; /* multiple of 8 bytes */ 50 uint8_t language; /* I hope it's 0 */ 51 uint8_t mfg_date[3]; /* LSB, minutes since 1996-01-01 */ 52 struct fru_type_length tl[0]; /* type-length stuff follows */ 53 54 /* 55 * the TL there are in order: 56 * Board Manufacturer 57 * Board Product Name 58 * Board Serial Number 59 * Board Part Number 60 * FRU File ID (may be null) 61 * more manufacturer-specific stuff 62 * 0xc1 as a terminator 63 * 0x00 pad to a multiple of 8 bytes - 1 64 * checksum (sum of all stuff module 256 must be zero) 65 */ 66}; 67 68enum fru_type { 69 FRU_TYPE_BINARY = 0x00, 70 FRU_TYPE_BCDPLUS = 0x40, 71 FRU_TYPE_ASCII6 = 0x80, 72 FRU_TYPE_ASCII = 0xc0, /* not ascii: depends on language */ 73}; 74 75/* 76 * some helpers 77 */ 78static inline struct fru_board_info_area *fru_get_board_area( 79 const struct fru_common_header *header) 80{ 81 /* we know for sure that the header is 8 bytes in size */ 82 return (struct fru_board_info_area *)(header + header->board_area_off); 83} 84 85static inline int fru_type(struct fru_type_length *tl) 86{ 87 return tl->type_length & 0xc0; 88} 89 90static inline int fru_length(struct fru_type_length *tl) 91{ 92 return (tl->type_length & 0x3f) + 1; /* len of whole record */ 93} 94 95/* assume ascii-latin1 encoding */ 96static inline int fru_strlen(struct fru_type_length *tl) 97{ 98 return fru_length(tl) - 1; 99} 100 101static inline char *fru_strcpy(char *dest, struct fru_type_length *tl) 102{ 103 int len = fru_strlen(tl); 104 memcpy(dest, tl->data, len); 105 dest[len] = '\0'; 106 return dest; 107} 108 109static inline struct fru_type_length *fru_next_tl(struct fru_type_length *tl) 110{ 111 return tl + fru_length(tl); 112} 113 114static inline int fru_is_eof(struct fru_type_length *tl) 115{ 116 return tl->type_length == 0xc1; 117} 118 119/* 120 * External functions defined in fru-parse.c. 121 */ 122extern int fru_header_cksum_ok(struct fru_common_header *header); 123extern int fru_bia_cksum_ok(struct fru_board_info_area *bia); 124 125/* All these 4 return allocated strings by calling fru_alloc() */ 126extern char *fru_get_board_manufacturer(struct fru_common_header *header); 127extern char *fru_get_product_name(struct fru_common_header *header); 128extern char *fru_get_serial_number(struct fru_common_header *header); 129extern char *fru_get_part_number(struct fru_common_header *header); 130 131/* This must be defined by the caller of the above functions */ 132extern void *fru_alloc(size_t size); 133 134#endif /* __LINUX_IMPI_FRU_H__ */ 135