Commit aecd624a authored by Benoit Rat's avatar Benoit Rat

fmceeprom: adding fru-generator and ipmi library

parent e65079b1
#! /usr/bin/env python
#-*-python-*-
# Copyright CERN, 2011, 2012
# Author: Matthieu Cattin <matthieu.cattin@cern.ch>
# Modified and broken by Alessandro Rubini, still learning python
# Import system modules
import sys
import getopt
import time
import datetime
import os
from libipmi.fmc_eeprom import *
"""
Creates a FRU binary file to be written into FMC EEPROM
"""
def main (argv0, argv):
# Defaults
FRU_VENDOR = "fmc-example"
FRU_NAME = "mezzanine"
FRU_SERIAL = "0001"
FRU_PART = "sample-part"
FRU_OUTPUT = "/dev/stdout"
verbose = 0
# Override defaults with environment variables
try:
FRU_VENDOR = os.environ['FRU_VENDOR']
except:
pass
try:
FRU_NAME = os.environ['FRU_NAME']
except:
pass
try:
FRU_SERIAL = os.environ['FRU_SERIAL']
except:
pass
try:
FRU_PART = os.environ['FRU_PART']
except:
pass
try:
FRU_OUTPUT = os.environ['FRU_OUTPUT']
except:
pass
if os.getenv("FRU_VERBOSE") is not None:
verbose = 1
# Override defaults with command line arguments
try:
opts, args = getopt.getopt(argv,"v:n:s:p:o:",["--help"])
except getopt.GetoptError:
print "fru-generator: wrong arguments"
sys.exit(2)
for opt, arg in opts:
if opt == "--help":
print "fru-generator: no help yet"
sys.exit(1)
if opt == '-v':
FRU_VENDOR = arg
if opt == '-n':
FRU_NAME = arg
if opt == '-s':
FRU_SERIAL = arg
if opt == '-p':
FRU_PART = arg
if opt == '-o':
FRU_OUTPUT = arg
if verbose:
print "VENDOR = " + FRU_VENDOR
print "NAME = " + FRU_NAME
print "SERIAL = " + FRU_SERIAL
print "PART = " + FRU_PART
print "OUTPUT = " + FRU_OUTPUT
#==================================================
# Calculate number of minutes since 0:00 1/1/96
now_date = datetime.datetime.now()
ref_date = datetime.datetime(1996, 1, 1)
diff_date = now_date - ref_date
total_seconds = diff_date.days * 86400 + diff_date.seconds
current_date = int(total_seconds//60)
mfg_date = current_date
#==================================================
# Create Board Info Area
# FRU field is used to store the date of generation of the eeprom content
# This could be used later to determine if the content has to be udated (bug fix, ...)
fru = "%s" % now_date
bia = BoardInfoArea(mfg_date, FRU_VENDOR, FRU_NAME, FRU_SERIAL, FRU_PART, fru)
#==================================================
# Multirecords Area
# output number, vnom, vmin, vmax, ripple, imin, imax
dcload0 = DCLoadRecord(0, 2.5, 2.375, 2.625, 0.0, 0, 4000) # VADJ
dcload1 = DCLoadRecord(1, 3.3, 3.135, 3.465, 0.0, 0, 3000) # P3V3
dcload2 = DCLoadRecord(2, 12.0, 11.4, 12.6, 0.0, 0, 1000) # P12V
dcload = [ dcload0, dcload1, dcload2 ]
# output number, vnom, vmin, vmax, ripple, imin, imax
dcout0 = DCOutputRecord(3, 0.0, 0.0, 0.0, 0.0, 0, 0) # VIO_B_M2C
dcout1 = DCOutputRecord(4, 0.0, 0.0, 0.0, 0.0, 0, 0) # VREF_A_M2C
dcout2 = DCOutputRecord(5, 0.0, 0.0, 0.0, 0.0, 0, 0) # VREF_B_M2C
dcout = [ dcout0, dcout1, dcout2 ]
# module size : 0=single width, 1=double width
# P1 size : 0=LPC, 1=HPC
# P2 size : 0=LPC, 1=HPC, 3=not fitted
# clock dir : 0=M2C, 1=C2M
# nb sig P1 A : number
# nb sig P1 B : number
# nb sig P2 A : number
# nb sig P2 B : number
# nb GBT P1 : number
# nb GBT P2 : number
# max TCK freq : frequency in MHz
oem = OEMRecord(0, 1, 3, 1, 68, 0, 0, 0, 0, 0, 0)
#==================================================
# Write eeprom content to a binary file
ipmi_open_file(FRU_OUTPUT)
#ipmi_set(bia, dcload, dcout, oem, iua)
ipmi_set(bia, dcload, dcout, oem)
ipmi_write()
ipmi_close_file()
if __name__ == '__main__' :
main(sys.argv[0], sys.argv[1:])
OBJ=ipmi.o
OUT=libipmi.a
OUT_SO=libipmi.so
CFLAGS+=-fPIC -shared -Wall -Wextra -ggdb
all: $(OUT) $(OUT_SO)
$(OUT): $(OBJ)
ar rcs $(OUT) $(OBJ)
$(OUT_SO): $(OBJ)
$(CC) $< $(CFLAGS) -shared -fPIC -L. -Wl,-soname,$@ -o $@
clean:
rm -rf $(OBJ) $(OUT) $(OUT_SO)
#!/usr/bin/python
from ctypes import *
import array
import struct
import os
lib = cdll.LoadLibrary(os.path.dirname(__file__) + "/libipmi.so")
class c_CommonHeader(Structure):
_fields_ = [
("format", c_ubyte),
("internal_use_off", c_ubyte),
("chassis_info_off", c_ubyte),
("board_area_off", c_ubyte),
("product_area_off", c_ubyte),
("multirecord_off", c_ubyte),
("pad", c_ubyte),
("checksum", c_ubyte)
]
class c_BoardInfoArea(Structure):
_fields_ = [
("format", c_ubyte),
("area_len", c_ubyte),
("language", c_ubyte),
("mfg_date0", c_ubyte),
("mfg_date1", c_ubyte),
("mfg_date2", c_ubyte),
("mfgr_typelen", c_ubyte),
("mfgr_data", c_char_p),
("product_typelen", c_ubyte),
("product_data", c_char_p),
("serial_typelen", c_ubyte),
("serial_data", c_char_p),
("partnum_typelen", c_ubyte),
("partnum_data", c_char_p),
("fru_fid_typelen", c_ubyte),
("fru_fid_data", c_char_p),
("typelen_end", c_ubyte),
("pad_len", c_ubyte),
("checksum", c_ubyte)
]
class c_DCLoadRecord(Structure):
_fields_ = [
("voltage_required", c_ubyte),
("nominal_voltage", c_ushort),
("min_voltage", c_ushort),
("max_voltage", c_ushort),
("spec_ripple", c_ushort),
("min_current", c_ushort),
("max_current", c_ushort)
]
class c_DCOutputRecord(Structure):
_fields_ = [
("output_info", c_ubyte),
("nominal_voltage", c_ushort),
("max_neg_voltage_dev", c_ushort),
("max_pos_voltage_dev", c_ushort),
("ripple", c_ushort),
("min_current_draw", c_ushort),
("max_current_draw", c_ushort)
]
class c_InternalUseArea(Structure):
_fields_ = [
("format", c_ubyte),
("len", c_int),
("data", c_char_p)
]
class InternalUseArea:
def __init__(self, data):
self.struct = c_InternalUseArea()
self._as_parameter_ = byref(self.struct)
self.struct.format = 0x1
self.set_data(data)
def set_data(self, data):
self.struct.data = c_char_p(array.array('B', data).tostring())
self.struct.len = c_int(len(data))
class CommonHeader:
def __init__(self):
self.struct = c_CommonHeader()
self._as_parameter_ = byref(self.struct)
self.struct.format = 0x1
self.struct.chassis_info_off = 0
self.struct.product_area_off = 0
self.struct.pad = 0
def set_internal_use_offset(self, off):
self.struct.internal_use_off = off
def set_board_info_area_offset(self, off):
self.struct.board_area_off = off
def set_multirecord_area_offset(self, off):
self.multirecord_off = off
class BoardInfoArea:
def __init__(self, date, mfgr, product, serial, partnum, fru):
self.struct = c_BoardInfoArea()
self._as_parameter_ = byref(self.struct)
self.struct.format = 0x1
self.struct.area_len = 0
self.struct.language = 0 # English
self.set_manufacture_date(date)
self.set_manufacturer(mfgr)
self.set_product_name(product)
self.set_serial_number(serial)
self.set_part_number(partnum)
self.set_fru_file_id(fru)
def set_manufacture_date(self, date):
val = bytearray(struct.pack('>I', date))
self.struct.mfg_date2 = c_ubyte(val[1])
self.struct.mfg_date1 = c_ubyte(val[2])
self.struct.mfg_date0 = c_ubyte(val[3])
def set_manufacturer(self, data):
self.struct.mfgr_data = c_char_p(data)
self.struct.mfgr_typelen = (len(bytearray(data)) & 0x3f) | (0x3 << 6)
def set_product_name(self, data):
self.struct.product_data = c_char_p(data)
self.struct.product_typelen = (len(bytearray(data)) & 0x3f) | (0x3 << 6)
def set_serial_number(self, data):
self.struct.serial_data = c_char_p(data)
self.struct.serial_typelen = (len(bytearray(data)) & 0x3f) | (0x3 << 6)
def set_part_number(self, data):
self.struct.partnum_data = c_char_p(data)
self.struct.partnum_typelen = (len(bytearray(data)) & 0x3f) | (0x3 << 6)
def set_fru_file_id(self, data):
self.struct.fru_fid_data = c_char_p(data)
self.struct.fru_fid_typelen = (len(bytearray(data)) & 0x3f) | (0x3 << 6)
class DCLoadRecord:
def __init__(self, rec_num, nom, vmin, vmax, ripple, imin, imax):
self.struct = c_DCLoadRecord()
self._as_parameter_ = byref(self.struct)
self.struct.voltage_required = 0
self.struct.nominal_voltage = 0
self.struct.min_voltage = 0
self.struct.max_voltage = 0
self.struct.spec_ripple = 0
self.struct.min_current = 0
self.struct.max_current = 0
self.set_record_number(rec_num)
self.set_nominal_voltage(nom*100)
self.set_min_voltage(vmin*100)
self.set_max_voltage(vmax*100)
self.set_spec_ripple(ripple*1000)
self.set_min_current(imin)
self.set_max_current(imax)
def set_record_number(self, val):
self.struct.voltage_required = int(val)
def set_nominal_voltage(self, val):
self.struct.nominal_voltage = int(val)
def set_min_voltage(self, val):
self.struct.min_voltage = int(val)
def set_max_voltage(self, val):
self.struct.max_voltage = int(val)
def set_spec_ripple(self, val):
self.struct.spec_ripple = int(val)
def set_min_current(self, val):
self.struct.min_current = int(val)
def set_max_current(self, val):
self.struct.max_current = int(val)
class DCOutputRecord:
def __init__(self, rec_num, nom, max_neg, max_pos, ripple, imin, imax):
self.struct = c_DCOutputRecord()
self._as_parameter_ = byref(self.struct)
self.struct.output_info = 0
self.struct.nominal_voltage = 0
self.struct.max_net_voltage_dev = 0
self.struct.max_pos_voltage_dev = 0
self.struct.ripple = 0
self.struct.min_current_draw = 0
self.struct.max_current_draw = 0
self.set_record_number(rec_num)
self.set_nominal_voltage(nom*100)
self.set_max_negative_voltage_deviation(max_neg*100)
self.set_max_positive_voltage_deviation(max_pos*100)
self.set_ripple(ripple*1000)
self.set_min_current_draw(imin)
self.set_max_current_draw(imax)
def set_record_number(self, val):
self.struct.output_info = val
def set_nominal_voltage(self, val):
self.struct.nominal_voltage = int(val)
def set_max_negative_voltage_deviation(self, val):
self.struct.max_neg_voltage_dev = int(val)
def set_max_positive_voltage_deviation(self, val):
self.struct.max_pos_voltage_dev = int(val)
def set_ripple(self, val):
self.struct.ripple = int(val)
def set_min_current_draw(self, val):
self.struct.min_current_draw = int(val)
def set_max_current_draw(self, val):
self.struct.max_current_draw = int(val)
class c_FMCOEMData(Structure):
_fields_ = [
("subtype_version", c_ubyte),
("other", c_ubyte),
("p1_a_nsig", c_ubyte),
("p1_b_nsig", c_ubyte),
("p2_a_nsig", c_ubyte),
("p2_b_nsig", c_ubyte),
("p1_p2_gbt_ntran", c_ubyte),
("max_clock", c_ubyte)
]
class c_OEMRecord(Structure):
_fields_ = [
("mfg_id0", c_ubyte),
("mfg_id1", c_ubyte),
("mfg_id2", c_ubyte),
("data", c_FMCOEMData)
]
class OEMRecord:
def __init__(self, msize, p1, p2, clockdir, pa_b1_nsig, pa_b2_nsig, pb_b1_nsig, pb_b2_nsig, pa_ngbt, pb_ngbt, maxclk):
self.struct = c_OEMRecord()
self._as_parameter_ = byref(self.struct)
self.struct.data.subtype_version = 0
self.struct.data.other = 0
self.struct.data.p1_a_nsig = 0
self.struct.data.p1_b_nsig = 0
self.struct.data.p2_a_nsig = 0
self.struct.data.p2_b_nsig = 0
self.struct.data.p1_gbt_ntran = 0
self.struct.data.p2_gbt_ntran = 0
self.struct.data.max_clock = 0
self.set_module_size(msize)
self.set_p1_connector_size(p1)
self.set_p2_connector_size(p2)
self.set_clock_direction(clockdir)
self.set_nsignals(1, 1, pa_b1_nsig)
self.set_nsignals(1, 2, pa_b2_nsig)
self.set_nsignals(2, 1, pb_b1_nsig)
self.set_nsignals(2, 2, pb_b2_nsig)
self.set_num_gbt_transceivers(1, pa_ngbt)
self.set_num_gbt_transceivers(2, pb_ngbt)
self.set_max_clock(maxclk)
def set_module_size(self, val):
self.struct.data.other &= ~(0xc0)
self.struct.data.other |= (val << 6) & 0xc0
def set_p1_connector_size(self, val):
self.struct.data.other &= ~(0x30)
self.struct.data.other |= (val << 4) & 0x30
def set_p2_connector_size(self, val):
self.struct.data.other &= ~(0xc)
self.struct.data.other |= (val << 2) & 0xc
def set_clock_direction(self, val):
self.struct.data.other &= ~(0x2)
self.struct.data.other |= (val << 1) & 0x2
def set_nsignals(self, port, bank, num):
if (port == 1):
if (bank == 1):
self.struct.data.p1_a_nsig = num
elif (bank == 2):
self.struct.data.p1_b_nsig = num
elif (port == 2):
if (bank == 1):
self.struct.data.p2_a_nsig = num
elif (bank == 2):
self.struct.data.p2_b_nsig = num
def set_num_gbt_transceivers(self, port, num):
if (port == 1):
self.struct.data.p1_p2_gbt_ntran &= ~(0xf0)
self.struct.data.p1_p2_gbt_ntran |= (num << 4) & 0xf0
elif (port == 2):
self.struct.data.p1_p2_gbt_ntran &= ~(0xf)
self.struct.data.p1_p2_gbt_ntran |= num & 0xf
def set_max_clock(self, clock):
self.struct.data.max_clock = clock
def ipmi_open_file(name):
lib.ipmi_file_open(c_char_p(name))
def ipmi_close_file():
lib.ipmi_file_close()
def ipmi_set(bia, dcload, dcout, oem, iua=None):
lib.ipmi_set_board_info_area(bia)
for r in dcload:
lib.ipmi_add_dc_load_record(r)
for r in dcout:
lib.ipmi_add_dc_output_record(r)
lib.ipmi_set_oem_record(oem)
if iua != None:
lib.ipmi_set_internal_use_area(iua)
def ipmi_write():
lib.ipmi_write()
def ipmi_get_mfg_date(data):
return lib.ipmi_get_mfg_date(c_char_p(data))
def ipmi_get_internal_use_data(data):
l = c_int()
d = c_void_p(lib.ipmi_get_internal_use_data(c_char_p(data), byref(l)))
q = cast(d, POINTER(l.value*c_ubyte))
return q.contents
def main():
bia = BoardInfoArea(12345678, "CERN", "ADC100M", "1234567890", "ADC100M", "abcde")
dcload0 = DCLoadRecord(0, 2.5, 2.4, 2.6, 0.0, 0, 4000)
dcload1 = DCLoadRecord(1, 2.5, 2.4, 2.6, 0.0, 0, 4000)
dcload2 = DCLoadRecord(2, 2.5, 2.4, 2.6, 0.0, 0, 4000)
dcload3 = DCLoadRecord(3, 2.5, 2.4, 2.6, 0.0, 0, 4000)
dcload4 = DCLoadRecord(4, 2.5, 2.4, 2.6, 0.0, 0, 4000)
dcload5 = DCLoadRecord(5, 2.5, 2.4, 2.6, 0.0, 0, 4000)
dcload = [ dcload0, dcload1, dcload2, dcload3, dcload4, dcload5 ]
dcout0 = DCOutputRecord(0, 2.5, 2.4, 2.6, 0.0, 0, 4000)
dcout1 = DCOutputRecord(1, 2.5, 2.4, 2.6, 0.0, 0, 4000)
dcout2 = DCOutputRecord(2, 2.5, 2.4, 2.6, 0.0, 0, 4000)
dcout3 = DCOutputRecord(3, 2.5, 2.4, 2.6, 0.0, 0, 4000)
dcout4 = DCOutputRecord(4, 2.5, 2.4, 2.6, 0.0, 0, 4000)
dcout5 = DCOutputRecord(5, 2.5, 2.4, 2.6, 0.0, 0, 4000)
dcout = [ dcout0, dcout1, dcout2, dcout3, dcout4, dcout5 ]
# oem = OEMRecord(single width, LPC, not fitted, mezz to carrier, 68, 0, 0, 0, 0, 0, 0)
oem = OEMRecord(0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0)
iudata = [0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 ]
iua = InternalUseArea(iudata)
# Open, set, write, close!
ipmi_open_file("test.out")
ipmi_set(bia, dcload, dcout, oem, iua)
ipmi_write()
ipmi_close_file()
test = open('test.out', 'r').read()
print ipmi_get_mfg_date(test)
d = ipmi_get_internal_use_data(test)
for v in d:
print hex(v)
if __name__ == "__main__":
main()
#include "ipmi.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static FILE *f = NULL;
struct common_header *ch = NULL;
struct board_info_area *bia = NULL;
struct oem_record *oem = NULL;
struct internal_use_area *iua = NULL;
struct dc_load_list *dcll = NULL;
struct dc_output_list *dcol = NULL;
int ipmi_file_open(const char *name)
{
if (f)
fclose(f);
f = fopen(name, "w");
if (!f)
return -1;
return 0;
}
void ipmi_file_close(void)
{
if (f)
fclose(f);
}
uint8_t checksum(uint8_t *data, int len)
{
int i;
int sum = 0;
for (i = 0; i < len; i++)
sum += data[i];
return (-sum)&0xff;
}
int board_info_area_get_size(uint8_t *pad)
{
int size = 13 +
(bia->mfgr_typelen & 0x3f) +
(bia->product_typelen & 0x3f) +
(bia->serial_typelen & 0x3f) +
(bia->partnum_typelen & 0x3f) +
(bia->fru_fid_typelen & 0x3f);
if (size & 0x7) {
if (pad) {
*pad = 8 - (size & 0x7);
}
size -= size % 8;
size += 8;
}
return size;
}
int internal_use_area_get_size(void)
{
return 1 + iua->len;
}
int ipmi_common_header_write(void)
{
int ret;
if (!ch || !f)
return -1;
ch->checksum = checksum((uint8_t *)ch, sizeof(struct common_header) - 1);
ret = fwrite(ch, 1, sizeof(struct common_header), f);
return 0;
}
void ipmi_set_board_info_area(struct board_info_area *d)
{
bia = d;
}
void ipmi_add_dc_load_record(struct dc_load_record *d)
{
struct dc_load_list *l = malloc(sizeof(struct dc_load_list));
l->rec = d;
l->next = NULL;
if (!dcll) {
dcll = l;
} else {
l->next = dcll;
dcll = l;
}
}
void ipmi_add_dc_output_record(struct dc_output_record *d)
{
struct dc_output_list *l = malloc(sizeof(struct dc_output_list));
l->rec = d;
l->next = NULL;
if (!dcol) {
dcol = l;
} else {
l->next = dcol;
dcol = l;
}
}
void ipmi_set_oem_record(struct oem_record *d)
{
oem = d;
}
int ipmi_board_info_area_write(void)
{
int i;
int len;
int ret;
uint8_t pad = 0;
uint8_t checksum;
if (!bia || !f)
return -1;
/* Write upto the mfgr_data */
ret = fwrite(bia, 6, 1, f);
len = bia->mfgr_typelen & 0x3f;
ret = fwrite(&bia->mfgr_typelen, 1, sizeof(uint8_t), f);
ret = fwrite(bia->mfgr_data, len, 1, f);
len = bia->product_typelen & 0x3f;
ret = fwrite(&bia->product_typelen, 1, sizeof(uint8_t), f);
ret = fwrite(bia->product_data, len, 1, f);
len = bia->serial_typelen & 0x3f;
ret = fwrite(&bia->serial_typelen, 1, sizeof(uint8_t), f);
ret = fwrite(bia->serial_data, len, 1, f);
len = bia->partnum_typelen & 0x3f;
ret = fwrite(&bia->partnum_typelen, 1, sizeof(uint8_t), f);
ret = fwrite(bia->partnum_data, len, 1, f);
len = bia->fru_fid_typelen & 0x3f;
ret = fwrite(&bia->fru_fid_typelen, 1, sizeof(uint8_t), f);
ret = fwrite(bia->fru_fid_data, len, 1, f);
bia->typelen_end = 0xc1;
ret = fwrite(&bia->typelen_end, 1, sizeof(uint8_t), f);
/* calculate checksum here */
checksum = 0;
checksum +=
bia->format +
bia->area_len +
bia->language +
bia->mfg_date0 +
bia->mfg_date1 +
bia->mfg_date2 +
bia->mfgr_typelen +
bia->product_typelen +
bia->serial_typelen +
bia->partnum_typelen +
bia->fru_fid_typelen +
bia->typelen_end;
for (i = 0; i < (bia->mfgr_typelen & 0x3f); i++)
checksum += bia->mfgr_data[i];
for (i = 0; i < (bia->product_typelen & 0x3f); i++)
checksum += bia->product_data[i];
for (i = 0; i < (bia->serial_typelen & 0x3f); i++)
checksum += bia->serial_data[i];
for (i = 0; i < (bia->partnum_typelen & 0x3f); i++)
checksum += bia->partnum_data[i];
for (i = 0; i < (bia->fru_fid_typelen & 0x3f); i++)
checksum += bia->fru_fid_data[i];
checksum = -checksum;
checksum &= 0xff;
bia->checksum = checksum;
uint8_t nul = 0;
board_info_area_get_size(&pad);
for (i = 0; i < pad; i++)
ret = fwrite(&nul, 1, sizeof(uint8_t), f);
ret = fwrite(&bia->checksum, 1, sizeof(uint8_t), f);
return 0;
}
int ipmi_dc_load_record_write(int end)
{
int ret;
struct dc_load_list *t;
if (!dcll || !f)
return -1;
t = dcll;
while (t) {
struct multirecord_header head;
head.record_typeid = 0x2; /* DC load type */
head.extra = 0x2;
if (end)
head.extra |= (1 << 7);
head.record_len = 13;
head.record_checksum = checksum((uint8_t *)t->rec,
sizeof(struct dc_load_record));
head.header_checksum = checksum((uint8_t *)&head,
sizeof(struct multirecord_header) - 1);
ret = fwrite(&head, 1, sizeof(struct multirecord_header), f);
ret = fwrite(&t->rec->voltage_required, 1, 1, f);
ret = fwrite(&t->rec->nominal_voltage, 1, 12, f);
t = t->next;
}
return 0;
}
int ipmi_dc_output_record_write(int end)
{
int ret;
struct dc_output_list *t;
if (!dcol || !f)
return -1;
t = dcol;
while (t) {
struct multirecord_header head;
head.record_typeid = 0x1; /* DC output type */
head.extra = 0x2;
if (end)
head.extra |= (1 << 7);
head.record_len = 13;
head.record_checksum = checksum((uint8_t *)t->rec,
sizeof(struct dc_output_record));
head.header_checksum = checksum((uint8_t *)&head,
sizeof(struct multirecord_header) - 1);
ret = fwrite(&head, 1, sizeof(struct multirecord_header), f);
ret = fwrite(&t->rec->output_info, 1, 1, f);
ret = fwrite(&t->rec->nominal_voltage, 1, 12, f);
t = t->next;
}
return 0;
}
int ipmi_oem_record_write(int end)
{
int ret;
struct multirecord_header head;
if (!oem || !f)
return -1;
/* VITA ID: 0x0012a2 (LS Byte first) */
oem->mfg_id0 = 0xa2;
oem->mfg_id1 = 0x12;
oem->mfg_id2 = 0x00;
head.record_typeid = 0xfa; /* OEM record type */
head.extra = 0x2;
if (end)
head.extra |= (1 << 7);
head.record_len = sizeof(struct oem_record);
head.record_checksum = checksum((uint8_t *)oem,
sizeof(struct oem_record));
head.header_checksum = checksum((uint8_t *)&head,
sizeof(struct multirecord_header) - 1);
ret = fwrite(&head, 1, sizeof(struct multirecord_header), f);
ret = fwrite(oem, 1, sizeof(struct oem_record), f);
return 0;
}
int multirecord_area_get_size(int *diff)
{
struct dc_load_list *l1 = dcll;
struct dc_output_list *l2 = dcol;
int sum = 0;
while (l1) {
sum += sizeof(struct multirecord_header);
sum += 13;
l1 = l1->next;
}
while (l2) {
sum += sizeof(struct multirecord_header);
sum += 13;
l2 = l2->next;
}
sum += sizeof(struct multirecord_header) + sizeof(struct oem_record);
if (sum % 8) {
if (diff) {
*diff = 8 - (sum % 8);
}
sum += 8;
sum &= ~7;
}
return sum;
}
int ipmi_write(void)
{
int pad = 0;
int padlen = 0;
ch = malloc(sizeof(struct common_header));
memset(ch, 0, sizeof(struct common_header));
ch->format = 1; // Format version
/*
* IPMI areas arrangement in memory
*
* +------------------------------+
* | Common header |
* +------------------------------+
* | Board area |
* +------------------------------+
* | Multi-record area |
* | +------------------------+
* | | 3x DC load records |
* | +------------------------+
* | | 3x DC output records |
* | +------------------------+
* | | OEM record |
* +-----+------------------------+
* | Internal use area (optional) |
* +------------------------------+
*/
// Compute area offsets
ch->board_area_off = sizeof(struct common_header)/8; // always 1
ch->multirecord_off = (sizeof(struct common_header) + board_info_area_get_size(NULL))/8;
if (iua)
ch->internal_use_off = (sizeof(struct common_header) + board_info_area_get_size(NULL) + multirecord_area_get_size(NULL))/8;
else
ch->internal_use_off = 0;
// Write common heade
ipmi_common_header_write();
// Write board info area, padding (to 8 byte multiple) is done inside the write function
bia->area_len = board_info_area_get_size(NULL)/8;
ipmi_board_info_area_write();
// Write multi-record area
ipmi_dc_load_record_write(0);
ipmi_dc_output_record_write(0);
ipmi_oem_record_write(1);
// Padding after multi-record area
multirecord_area_get_size(&padlen);
if (padlen) {
int i;
for (i = 0; i < padlen; i++)
fwrite(&pad, 1, 1, f);
}
// Write Internal Use area, if exists
if (iua)
ipmi_internal_use_area_write();
return 0;
}
void ipmi_set_internal_use_area(struct internal_use_area *d)
{
iua = d;
}
int ipmi_internal_use_area_write(void)
{
if (!iua || !f)
return -1;
fwrite(&iua->format, 1, 1, f);
fwrite(&iua->len, 1, 4, f);
fwrite(iua->data, 1, iua->len, f);
return 0;
}
unsigned char *ipmi_get_internal_use_data(char *data, int *l)
{
unsigned char *buf;
struct common_header *ch = (struct common_header *)data;
unsigned char *d = (unsigned char *)data + ch->internal_use_off*8;
int len = (int)d[1];
buf = malloc(sizeof(uint8_t) * (len + 1));
memcpy(buf, d+5, len);
buf[len] = 0;
*l = len;
return buf;
}
int ipmi_get_mfg_date(char *data)
{
int i;
int ret = 0;
struct common_header *ch = (struct common_header *)data;
unsigned char *date = (unsigned char *)data + ch->board_area_off*8 + 3;
for (i = 0; i < 3; i++)
ret |= (date[i] << (i*8));
return ret;
}
#ifndef IPMI_H
#define IPMI_H
#include <stdint.h>
#include <stdio.h>
/* 8 bytes */
struct common_header {
uint8_t format;
uint8_t internal_use_off;
uint8_t chassis_info_off;
uint8_t board_area_off;
uint8_t product_area_off;
uint8_t multirecord_off;
uint8_t pad;
uint8_t checksum;
};
struct board_info_area {
uint8_t format;
uint8_t area_len;
uint8_t language;
uint8_t mfg_date0;
uint8_t mfg_date1;
uint8_t mfg_date2;
uint8_t mfgr_typelen;
uint8_t *mfgr_data;
uint8_t product_typelen;
uint8_t *product_data;
uint8_t serial_typelen;
uint8_t *serial_data;
uint8_t partnum_typelen;
uint8_t *partnum_data;
uint8_t fru_fid_typelen;
uint8_t *fru_fid_data;
/* uint8_t *custom; */
uint8_t typelen_end;
uint8_t pad_len;
uint8_t checksum;
};
/* 5 bytes */
struct multirecord_header {
uint8_t record_typeid;
uint8_t extra;
uint8_t record_len;
uint8_t record_checksum;
uint8_t header_checksum;
};
struct dc_output_list {
struct dc_output_record *rec;
struct dc_output_list *next;
};
/* 13 bytes */
struct dc_load_record {
uint8_t voltage_required;
uint16_t nominal_voltage;
uint16_t min_voltage;
uint16_t max_voltage;
uint16_t spec_ripple;
uint16_t min_current;
uint16_t max_current;
};
struct dc_load_list {
struct dc_load_record *rec;
struct dc_load_list *next;
};
/* 13 bytes */
struct dc_output_record {
uint8_t output_info;
uint16_t nominal_voltage;
uint16_t max_neg_voltage_dev;
uint16_t max_pos_voltage_dev;
uint16_t ripple;
uint16_t min_current_draw;
uint16_t max_current_draw;
};
struct fmc_oem_data {
uint8_t subtype_version;
uint8_t other;
uint8_t p1_a_nsig;
uint8_t p1_b_nsig;
uint8_t p2_a_nsig;
uint8_t p2_b_nsig;
uint8_t p1_p2_gbt_ntran;
uint8_t max_clock;
};
/* 12 bytes */
struct oem_record {
uint8_t mfg_id0;
uint8_t mfg_id1;
uint8_t mfg_id2;
struct fmc_oem_data data;
};
struct internal_use_area {
uint8_t format;
int len;
char *data;
};
int ipmi_file_open(const char *name);
void ipmi_file_close(void);
int ipmi_write(void);
int ipmi_common_header_write(void);
void ipmi_set_board_info_area(struct board_info_area *);
int ipmi_board_info_area_write(void);
void ipmi_set_internal_use_area(struct internal_use_area *);
int ipmi_internal_use_area_write(void);
void ipmi_add_dc_load_record(struct dc_load_record *);
int ipmi_dc_load_record_write(int);
void ipmi_add_dc_output_record(struct dc_output_record *);
int ipmi_dc_output_record_write(int);
void ipmi_set_oem_record(struct oem_record *);
int ipmi_oem_record_write(int);
unsigned char *ipmi_get_internal_use_data(char *data, int *l);
int ipmi_get_mfg_date(char *data);
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment