diff options
Diffstat (limited to 'util/oem_kontron.c')
-rw-r--r-- | util/oem_kontron.c | 1107 |
1 files changed, 1107 insertions, 0 deletions
diff --git a/util/oem_kontron.c b/util/oem_kontron.c new file mode 100644 index 0000000..263560f --- /dev/null +++ b/util/oem_kontron.c @@ -0,0 +1,1107 @@ +/* + * oem_kontron.c + * This code implements Kontron OEM proprietary commands. + * + * Change history: + * 08/25/2010 ARCress - included in source tree + * + *--------------------------------------------------------------------- + */ +/* + * Copyright (c) 2004 Kontron Canada, Inc. All Rights Reserved. + * + * Base on code from + * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. + * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. + * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING + * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL + * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, + * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR + * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF + * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, + * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +/* + * Tue Mar 7 14:36:12 2006 + * <stephane.filion@ca.kontron.com> + * + * This code implements an Kontron OEM proprietary commands. + */ + +#ifdef WIN32 +#include <windows.h> +#include <winsock.h> +#include <time.h> +#define uint8_t unsigned char +#define uint16_t unsigned short +#define uint32_t unsigned int +typedef uint32_t socklen_t; +#else +#include <arpa/inet.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <netinet/in.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "ipmicmd.h" +#include "ievents.h" +#include "oem_kontron.h" + +#define FRU_TYPE_COMPONENT 0x01 +#define FRU_TYPE_BASEBOARD 0x07 + +const struct valstr ktc5520_post[] = { /*from EAS*/ + { 0x0003, "Start POST Init" }, + { 0x0004, "Check CMOS" }, + { 0x0005, "Init interrupt HW" }, + { 0x0006, "Init INT1Ch" }, + { 0x0008, "Init CPUs" }, + { 0x000A, "Init 8042 Keyboard" }, + { 0x000B, "Detect PS2 Mouse" }, + { 0x000C, "Detect KBC Keyboard" }, + { 0x000E, "Test Input Devices" }, + { 0x0013, "PreInit chipset regs" }, + { 0x0024, "Init platform modules" }, + { 0x002A, "Init PCI devices" }, + { 0x002C, "Init Video" }, + { 0x002E, "Init Output devices" }, + { 0x0030, "Init SMI" }, + { 0x0031, "Init ADM module" }, + { 0x0033, "Init Silent boot" }, + { 0x0037, "Show first message" }, + { 0x0038, "Init Buses" }, + { 0x0039, "Init DMAC" }, + { 0x003A, "Init RTC" }, + { 0x003B, "Memory Test" }, + { 0x003C, "MidInit chipset regs" }, + { 0x0040, "Detect Ports" }, + { 0x0050, "Adjust RAM size" }, + { 0x0052, "Update CMOS size" }, + { 0x0060, "Init Kbd Numlock" }, + { 0x0075, "Init Int13" }, + { 0x0078, "Init IPL" }, + { 0x007A, "Init OpRoms" }, + { 0x007C, "Write ESCD to NV" }, + { 0x0084, "Log errors" }, + { 0x0085, "Display errors" }, + { 0x0087, "Run BIOS Setup" }, + { 0x008C, "LateInit chipset regs" }, + { 0x008D, "Build ACPI Tables" }, + { 0x008E, "Program peripherals" }, + { 0x0090, "LateInit SMI" }, + { 0x00A0, "Check Boot password" }, + { 0x00A1, "PreBoot Cleanup" }, + { 0x00A2, "Init Runtime image" }, + { 0x00A4, "Init Runtime lang" }, + { 0x00A7, "Show Config, Init MTRR" }, + { 0x00A8, "Prep CPU for OS boot" }, + { 0x00A9, "Wait for input" }, + { 0x00AA, "Deinit ADM, Int1C" }, + { 0x00AB, "Prepare BBS" }, + { 0x00AC, "EndInit chipse regs" }, + { 0x00B1, "Save context for ACPI" }, + { 0x00C0, "EarlyCPU Init APIC" }, + { 0x00C1, "Setup BSP info" }, + { 0x00C2, "Setup BSP for POST" }, + { 0x00C5, "Setup App Processors" }, + { 0x00C6, "Setup BSP cache" }, + { 0x00C7, "EarlyCPU Init exit" }, + { 0x0000, "OS Loader" }, + { 0xffff , NULL } /*end of list*/ +}; +/* +61-70, OEM POST Error. This range is reserved for chipset vendors & system manufacturers. The error associated with this value may be different from one platform to the next. +DD-DE, OEM PCI init debug POST code during DIMM init, See DIM Code Checkpoints section of document for more information. +DD-DE, OEM PCI init debug POST code during DIMM init. DEh during BUS number +*/ + +extern int verbose; /*ipmilanplus.c*/ +#ifdef METACOMMAND +extern int load_fru(uchar sa, uchar frudev, uchar frutype, uchar **pfrubuf); +extern int write_fru_data(uchar id, ushort offset, uchar *data, int dlen, + char fdebug); /*ifru.c*/ +#endif + +/* local function prototypes */ +static void ipmi_kontron_help(void); +static int ipmi_kontron_set_serial_number(void * intf); +static int ipmi_kontron_set_mfg_date (void * intf); + +static void print_buf( uint8_t * buf, int len, char * desc) +{ + dump_buf(desc,buf,len,0); +} + +#ifdef METACOMMAND +/* get_fru_area_str - Parse FRU area string from raw data + * @data: raw FRU data + * @offset: offset into data for area + * returns pointer to FRU area string + */ +static char * get_fru_area_str(uint8_t * data, uint32_t * offset) +{ + static const char bcd_plus[] = "0123456789 -.:,_"; + char * str; + int len, off, size, i, j, k, typecode; + union { + uint32_t bits; + char chars[4]; + } u; + + size = 0; + off = *offset; + /* bits 6:7 contain format */ + typecode = ((data[off] & 0xC0) >> 6); + + /* bits 0:5 contain length */ + len = data[off++]; + len &= 0x3f; + + switch (typecode) { + case 0: /* 00b: binary/unspecified */ + /* hex dump -> 2x length */ + size = (len*2); + break; + case 2: /* 10b: 6-bit ASCII */ + /* 4 chars per group of 1-3 bytes */ + size = ((((len+2)*4)/3) & ~3); + break; + case 3: /* 11b: 8-bit ASCII */ + case 1: /* 01b: BCD plus */ + /* no length adjustment */ + size = len; + break; + } + + if (size < 1) { + *offset = off; + return NULL; + } + str = malloc(size+1); + if (str == NULL) + return NULL; + memset(str, 0, size+1); + + if (len == 0) { + str[0] = '\0'; + *offset = off; + return str; + } + + switch (typecode) { + case 0: /* Binary */ + strncpy(str, buf2str(&data[off], len), len*2); + break; + + case 1: /* BCD plus */ + for (k=0; k<len; k++) + str[k] = bcd_plus[(data[off+k] & 0x0f)]; + str[k] = '\0'; + break; + + case 2: /* 6-bit ASCII */ + for (i=j=0; i<len; i+=3) { + u.bits = 0; + k = ((len-i) < 3 ? (len-i) : 3); +#if WORDS_BIGENDIAN + u.chars[3] = data[off+i]; + u.chars[2] = (k > 1 ? data[off+i+1] : 0); + u.chars[1] = (k > 2 ? data[off+i+2] : 0); +#define CHAR_IDX 3 +#else + memcpy((void *)&u.bits, &data[off+i], k); +#define CHAR_IDX 0 +#endif + for (k=0; k<4; k++) { + str[j++] = ((u.chars[CHAR_IDX] & 0x3f) + 0x20); + u.bits >>= 6; + } + } + str[j] = '\0'; + break; + + case 3: + memcpy(str, &data[off], len); + str[len] = '\0'; + break; + } + + off += len; + *offset = off; + + return str; +} +#endif + +static char *bootdev[] = {"BIOS", "FDD", "HDD", "CDROM", "network", 0}; + +static void +ipmi_kontron_nextboot_help(void) +{ + int i; + printf("nextboot <device>\n" + "Supported devices:\n"); + for (i = 0; bootdev[i] != 0; i++) { + printf("- %s\n", bootdev[i]); + } +} + +/* ipmi_kontron_next_boot_set - Select the next boot order on CP6012 + * + * @intf: ipmi interface + * @id: fru id + * + * returns -1 on error + * returns 1 if successful + */ +static int +ipmi_kontron_nextboot_set(void * intf, int argc, char **argv) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + uint8_t msg_data[8]; + int i; + + memset(msg_data, 0, sizeof(msg_data)); + msg_data[0] = 0xb4; + msg_data[1] = 0x90; + msg_data[2] = 0x91; + msg_data[3] = 0x8b; + msg_data[4] = 0x9d; + msg_data[5] = 0xFF; + msg_data[6] = 0xFF; /* any */ + + for (i = 0; bootdev[i] != 0; i++) { + if (strcmp(argv[0], bootdev[i]) == 0) { + msg_data[5] = (uchar)i; + break; + } + } + + /* Invalid device selected? */ + if (msg_data[5] == 0xFF) { + printf("Unknown boot device: %s\n", argv[0]); + return -1; + } + + memset(&req, 0, sizeof(req)); + req.msg.netfn = 0x3E; + req.msg.cmd = 0x02; + req.msg.data = msg_data; + req.msg.data_len = 7; + + /* Set Lun temporary, necessary for this oem command */ + req.msg.lun = 0x03; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv < 0) + { + printf(" Device not present (No Response)\n"); + return (rv); + } + if (rv > 0) { + printf(" NextBoot Device error (%s)\n",decode_cc(0,rv)); + return(rv); + } + return (rv); +} + +#ifdef METACOMMAND +int +ipmi_kontronoem_main(void * intf, int argc, char ** argv) +{ + int rc = 0; + + if (argc == 0) + ipmi_kontron_help(); + else if (strncmp(argv[0], "help", 4) == 0) + ipmi_kontron_help(); + + else if(!strncmp(argv[0], "setsn", 5)) + { + if(argc >= 1) + { + rc = ipmi_kontron_set_serial_number(intf); + if(rc == 0) { + printf("FRU serial number set successfully\n"); + } else { + printf("FRU serial number set failed\n"); + } + } + else + { + printf("fru setsn\n"); + } + } + else if(!strncmp(argv[0], "setmfgdate", 5)) + { + if(argc >= 1) + { + rc = ipmi_kontron_set_mfg_date(intf); + if (rc == 0) { + printf("FRU manufacturing date set successfully\n"); + } else { + printf("FRU manufacturing date set failed\n"); + } + } + else + { + printf("fru setmfgdate\n"); + } + + } + else if (!strncmp(argv[0], "nextboot", sizeof("nextboot")-1)) + { + if (argc > 1) + { + if ((rc = ipmi_kontron_nextboot_set(intf, argc-1, argv+1)) == 0) + { + printf("Nextboot set successfully\n"); + } else { + printf("Nextboot set failed\n"); + } + } else { + ipmi_kontron_nextboot_help(); + } + } + + else + { + printf("Invalid Kontron command: %s", argv[0]); + ipmi_kontron_help(); + rc = ERR_USAGE; + } + + return rc; +} + +static void ipmi_kontron_help(void) +{ + printf("Kontron Commands: setsn setmfgdate nextboot\n"); +} + +/* ipmi_fru_set_serial_number - Set the Serial Number in FRU + * + * @intf: ipmi interface + * @id: fru id + * + * returns -1 on error + * returns 1 if successful + */ +static int +ipmi_kontron_set_serial_number(void * intf) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + struct fru_info fru; + struct fru_header header; + uint8_t msg_data[4]; + char *sn; + uint8_t sn_size, checksum; + uint8_t *fru_data; + char *fru_area; + uint32_t fru_data_offset, fru_data_offset_tmp, board_sec_len, prod_sec_len, i; + uint8_t bus, sa, lun, mtype; + + sn = NULL; + fru_data = NULL; + + ipmi_get_mc(&bus, &sa, &lun, &mtype); + + memset(msg_data, 0, 4); + msg_data[0] = 0xb4; + msg_data[1] = 0x90; + msg_data[2] = 0x91; + msg_data[3] = 0x8b; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = 0x3E; + req.msg.cmd = 0x0C; + req.msg.data = msg_data; + req.msg.data_len = 4; + + /* Set Lun, necessary for this oem command */ + req.msg.lun = 0x03; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv < 0) + { + printf(" Device not present (No Response)\n"); + return (rv); + } + + if (rv > 0) + { + if (verbose) printf("sernum cmd ccode = %02x\n",rv); + printf(" This option is not implemented for this board\n"); +#ifdef TEST + strcpy(rsp,"serialnumber"); + rsp_len = 12; +#else + return (rv); +#endif + } + + sn_size = (uchar)rsp_len; + if (sn_size < 1) + { + printf(" Original serial number is zero length, was cleared.\n"); + return(ERR_BAD_LENGTH); + } + sn = malloc(sn_size + 1); + if(sn == NULL) + { + printf("Out of memory!"); + return(-1); + } + + memset(sn, 0, sn_size + 1); + memcpy(sn, rsp, sn_size); + + if(verbose >= 1) + { + printf("Original serial number is : [%s]\n", sn); + } + + memset(msg_data, 0, 4); + msg_data[0] = 0; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_STORAGE; + req.msg.cmd = GET_FRU_INFO; + req.msg.data = msg_data; + req.msg.data_len = 1; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv < 0) { + printf(" Device not present (No Response)\n"); + free(sn); + return (rv); + } + if (rv > 0) { + printf(" Device not present (%s)\n",decode_cc(0,rv)); + free(sn); + return (rv); + } + + fru.size = (rsp[1] << 8) | rsp[0]; + fru.access = rsp[2] & 0x1; + + if (fru.size < 1) { + printf(" Invalid FRU size %d", fru.size); + free(sn); + return(ERR_BAD_LENGTH); + } + + /* + * retrieve the FRU header + */ + msg_data[0] = 0; + msg_data[1] = 0; + msg_data[2] = 0; + msg_data[3] = 8; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_STORAGE; + req.msg.cmd = GET_FRU_DATA; + req.msg.data = msg_data; + req.msg.data_len = 4; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv < 0) + { + printf(" Device not present (No Response)\n"); + free(sn); + return(rv); + } + if (rv > 0) + { + printf(" Device not present (%s)\n",decode_cc(0,rv)); + free(sn); + return(rv); + } + + if (verbose >= 1) + print_buf(rsp, rsp_len, "FRU DATA"); + + memcpy(&header, rsp + 1, 8); + + if (header.version != 1) + { + printf(" Unknown FRU header version 0x%02x\n", header.version); + free(sn); + return(-1); + } + + /* Set the Board Section */ + board_sec_len = (header.offset.product * 8) - (header.offset.board * 8); + + rv = load_fru(sa,0, FRU_TYPE_BASEBOARD, &fru_data); + if (rv != 0) + { + printf(" Cannot Read FRU, error %d\n",rv); + free(sn); + if (fru_data != NULL) free(fru_data); + return(rv); + } + + if (verbose >= 1) + print_buf(fru_data, fru.size, "FRU BUFFER"); + + /*Position at Board Manufacturer*/ + fru_data_offset = (header.offset.board * 8) + 6; + fru_area = &fru_data[fru_data_offset]; + if (verbose) + printf("board_area: offset=0x%x len=%d\n",fru_data_offset,board_sec_len); + + fru_area = get_fru_area_str(fru_data, &fru_data_offset); + + /*Position at Board Product Name*/ + fru_area = get_fru_area_str(fru_data, &fru_data_offset); + + fru_data_offset_tmp = fru_data_offset; + + /*Position at Serial Number*/ + fru_area = get_fru_area_str(fru_data, &fru_data_offset_tmp); + if (fru_area == NULL) { + printf("Bad FRU area data read.\n"); + free(sn); + free(fru_data); + return(-1); + } + + fru_data_offset ++; + if (verbose) + printf("%x: Old board sernum [%s], New board sernum [%s]\n", + fru_data_offset,fru_area,sn); + + if (strlen(fru_area) != sn_size) + { + printf("The length of the serial number in the FRU Board Area is wrong.\n"); + free(sn); + free(fru_data); + return(ERR_BAD_LENGTH); + } + + /* Copy the new serial number in the board section saved in memory*/ + memcpy(fru_data + fru_data_offset, sn, sn_size); + + /* Calculate Header Checksum */ + checksum = 0; + for( i = (header.offset.board * 8); i < (((header.offset.board * 8)+board_sec_len) - 2) ; i ++ ) + { + checksum += fru_data[i]; + } + checksum = (~checksum) + 1; + fru_data[(header.offset.board * 8)+board_sec_len - 1] = checksum; + +#ifdef TEST + if (verbose >= 1) + print_buf(fru_data, fru.size, "FRU BUFFER, New"); + + /* Write the new FRU Board section */ + rv = write_fru_data(0, 0, fru_data, fru.size, verbose); + // if(write_fru_area(intf, &fru, 0, (header.offset.board * 8), (header.offset.board * 8), board_sec_len, fru_data) < 0) + if ( rv != 0 ) + { + printf(" Cannot Write FRU, error %d\n",rv); + free(sn); + free(fru_data); + return(rv); + } + + if (fru_data != NULL) { free(fru_data); fru_data = NULL; } + rv = load_fru(sa,0, FRU_TYPE_BASEBOARD, &fru_data); + if (rv != 0) + { + printf(" Cannot Read FRU, error %d\n",rv); + free(sn); + if (fru_data != NULL) free(fru_data); + return(rv); + } +#endif + + /* Set the Product Section */ + prod_sec_len = (header.offset.multi * 8) - (header.offset.product * 8); + + /*Position at Product Manufacturer*/ + fru_data_offset = (header.offset.product * 8) + 3; + fru_area = get_fru_area_str(fru_data, &fru_data_offset); + + /*Position at Product Name*/ + fru_area = get_fru_area_str(fru_data, &fru_data_offset); + + /*Position at Product Part*/ + fru_area = get_fru_area_str(fru_data, &fru_data_offset); + + /*Position at Product Version*/ + fru_area = get_fru_area_str(fru_data, &fru_data_offset); + + + + fru_data_offset_tmp = fru_data_offset; + + /*Position at Serial Number*/ + fru_area = get_fru_area_str(fru_data, &fru_data_offset_tmp); + + fru_data_offset ++; + if (verbose) + printf("%x: Old product sernum [%s], New product sernum [%s]\n", + fru_data_offset,fru_area,sn); + + if(strlen(fru_area) != sn_size) + { + free(sn); + free(fru_data); + printf("The length of the serial number in the FRU Product Area is wrong.\n"); + return(ERR_BAD_LENGTH); + } + + /* Copy the new serial number in the product section saved in memory*/ + memcpy(fru_data + fru_data_offset, sn, sn_size); + + /* Calculate Header Checksum */ + checksum = 0; + for( i = (header.offset.product * 8); i < (((header.offset.product * 8)+prod_sec_len) - 2) ; i ++ ) + { + checksum += fru_data[i]; + } + checksum = (~checksum) + 1; + fru_data[(header.offset.product * 8)+prod_sec_len - 1] = checksum; + + if (verbose >= 1) + print_buf(fru_data, fru.size, "FRU BUFFER, New"); + + /* Write the new FRU Board section */ + rv = write_fru_data(0, 0, fru_data, fru.size, (char)verbose); + if ( rv != 0 ) + { + printf(" Cannot Write FRU, error %d\n",rv); + /* fall through and free(sn); free(fru_data); return(rv); */ + } + + free(sn); + free(fru_data); + return(rv); +} + + +/* ipmi_fru_set_mfg_date - Set the Manufacturing Date in FRU + * + * @intf: ipmi interface + * @id: fru id + * + * returns -1 on error + * returns 1 if successful + */ +static int +ipmi_kontron_set_mfg_date (void * intf) +{ + uchar rsp[IPMI_RSPBUF_SIZE]; + int rsp_len, rv; + struct ipmi_rq req; + struct fru_info fru; + struct fru_header header; + uint8_t msg_data[4]; + uint8_t mfg_date[3]; + + uint32_t board_sec_len, i; + uint8_t *fru_data, checksum; + uint8_t bus, sa, lun, mtype; + + ipmi_get_mc(&bus, &sa, &lun, &mtype); + + memset(msg_data, 0, 4); + msg_data[0] = 0xb4; + msg_data[1] = 0x90; + msg_data[2] = 0x91; + msg_data[3] = 0x8b; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = 0x3E; + req.msg.cmd = 0x0E; + req.msg.data = msg_data; + req.msg.data_len = 4; + + /* Set Lun temporary, necessary for this oem command */ + req.msg.lun = 0x03; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv < 0) + { + printf("Device not present (No Response)\n"); + return(rv); + } + + if (rv > 0) + { + printf("This option is not implemented for this board\n"); + return(rv); + } + + if(rsp_len != 3) + { + printf("Invalid response for the Manufacturing date\n"); + return(ERR_BAD_LENGTH); + } + if(rsp[0] == 0 && rsp[1] == 0 && rsp[2] == 0) + { + printf("Manufacturing date is zero, has been cleared\n"); + return(ERR_BAD_FORMAT); + } + + memset(mfg_date, 0, 3); + memcpy(mfg_date, rsp, 3); + + memset(msg_data, 0, 4); + msg_data[0] = 0; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_STORAGE; + req.msg.cmd = GET_FRU_INFO; + req.msg.data = msg_data; + req.msg.data_len = 1; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv < 0) { + printf(" Device not present (No Response)\n"); + return(rv); + } + if (rv > 0) { + printf(" Device not present (%s)\n",decode_cc(0,rv)); + return(rv); + } + + fru.size = (rsp[1] << 8) | rsp[0]; + fru.access = rsp[2] & 0x1; + + if (fru.size < 1) { + printf(" Invalid FRU size %d", fru.size); + return(ERR_BAD_LENGTH); + } + + /* + * retrieve the FRU header + */ + msg_data[0] = 0; + msg_data[1] = 0; + msg_data[2] = 0; + msg_data[3] = 8; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_STORAGE; + req.msg.cmd = GET_FRU_DATA; + req.msg.data = msg_data; + req.msg.data_len = 4; + + rv = ipmi_sendrecv(&req, &rsp[0], &rsp_len); + if (rv < 0) + { + printf(" Device not present (No Response)\n"); + return(rv); + } + if (rv > 0) + { + printf(" Device not present (%s)\n",decode_cc(0,rv)); + return(rv); + } + + if (verbose > 1) + print_buf(rsp, rsp_len, "FRU DATA"); + + memcpy(&header, &rsp[1], 8); + + if (header.version != 1) + { + printf(" Unknown FRU header version 0x%02x", + header.version); + return(ERR_BAD_FORMAT); + } + + + board_sec_len = (header.offset.product * 8) - (header.offset.board * 8); + + rv = load_fru(sa,0, FRU_TYPE_BASEBOARD, &fru_data); + if (rv != 0) +#ifdef NOT + /* do not re-read the same fru buffer */ + fru_data = malloc( fru.size); + if(fru_data == NULL) + { + printf("Out of memory!"); + return(-1); + } + + memset(fru_data, 0, fru.size); + rv = read_fru_area(intf ,&fru ,0 ,(header.offset.board * 8) ,board_sec_len , fru_data); + if(rv < 0) +#endif + { + if (fru_data != NULL) free(fru_data); + return(rv); + } + + /* Copy the new manufacturing date in the board section saved in memory*/ + memcpy(fru_data + (header.offset.board * 8) + 3, mfg_date, 3); + + checksum = 0; + /* Calculate Header Checksum */ + for( i = (header.offset.board * 8); i < (((header.offset.board * 8)+board_sec_len) - 2) ; i ++ ) + { + checksum += fru_data[i]; + } + checksum = (~checksum) + 1; + + fru_data[(header.offset.board * 8)+board_sec_len - 1] = checksum; + + /* Write the new FRU Board section */ +#ifdef NOT + if(write_fru_area(intf, &fru, 0, (header.offset.board * 8), (header.offset.board * 8), board_sec_len, fru_data) < 0) +#endif + rv = write_fru_data(0, 0, fru_data, fru.size, (char)verbose); + if ( rv != 0 ) + { + printf(" Cannot Write FRU, error %d\n",rv); + /* fall through and free(fru_data); return(rv); */ + } + + free(fru_data); + return(rv); +} +#endif + +static char *assert_str(uchar val) +{ + char *pstr; + if ((val & 0x0f) == 0) pstr = "Deasserted"; + else pstr = "Asserted"; + return(pstr); +} + +/* + * decode_sel_kontron + * inputs: + * evt = the 16-byte IPMI SEL event + * outbuf = points to the output string buffer + * outsz = size of the output buffer + * outputs: + * rv = 0 if this event was successfully interpreted here, + * non-zero otherwise, to use default interpretations. + * outbuf = will contain the interpreted event text string (if rv==0) + */ +int decode_sel_kontron(uint8_t *evt, char *outbuf, int outsz, char fdesc, + char fdebug) +{ + int rv = -1; + uint16_t id; + uint8_t rectype; + int oemid; + uint32_t timestamp; + char timestr[40]; + char mybuf[64]; + char oembuf[64]; + char *type_str = NULL; + char *gstr = NULL; + char *pstr = NULL; + int sevid; + ushort genid; + uchar snum; + int isdr = 0; + char *p1, *p2; + + sevid = SEV_INFO; + id = evt[0] + (evt[1] << 8); + /* instead try to decode some events manually */ + rectype = evt[2]; + timestamp = evt[3] + (evt[4] << 8) + (evt[5] << 16) + (evt[6] << 24); + genid = evt[7] | (evt[8] << 8); + snum = evt[11]; + if (rectype == 0xc1) { /* OEM type C1 */ + oemid = evt[7] + (evt[8] << 8) + (evt[9] << 16); + if (oemid == VENDOR_KONTRON) { + fmt_time(timestamp, timestr, sizeof(timestr)); + type_str = "Kontron"; + gstr = "BMC "; + switch(evt[10]) { + case 0x01: + default: + sprintf(mybuf,"OEM Event %02x %02x %02x %02x %02x %02x", + evt[10], evt[11], evt[12], evt[13], evt[14], evt[15]); + break; + } + snprintf(outbuf, outsz, "%04x %s %s %s %s %s\n", + id,timestr,get_sev_str(sevid), gstr, type_str, mybuf); + rv = 0; + } /*endif kontron*/ + } else if (rectype == 0x02) { + type_str = ""; + gstr = "BMC "; + sprintf(mybuf,"%02x [%02x %02x %02x]", evt[12],evt[13],evt[14],evt[15]); + switch(evt[10]) { /*sensor type*/ + /* TODO: 0xC0, 0xC2, 0xC6 */ + case 0xCF: /* Board Reset */ + type_str = "Board Reset"; + if (evt[12] == 0x03) { /*event trigger/type = discrete [de]assert */ + pstr = ""; /*default*/ + switch(evt[13]) { /*data1/offset*/ + case 0x01: + pstr = "Asserted"; + break; + case 0xa1: /*data2,3 bytes have meaning*/ + /* data2: usually 0x01 */ + /* data3: 05, 08, ff */ + switch(evt[14]) { /*data2*/ + case 0x00: p1 = "warm reset"; break; + case 0x01: p1 = "cold reset"; break; + case 0x02: p1 = "forced cold"; break; + case 0x03: p1 = "soft reset"; break; + case 0x04: p1 = "hard reset"; break; + case 0x05: p1 = "forced hard"; break; + default: p1 = "other"; break; + } + switch(evt[15]) { /*data3*/ + case 0x00: p2 = "IPMI watchdog"; break; + case 0x01: p2 = "IPMI command"; break; + case 0x02: p2 = "Proc check stop"; break; /*internal*/ + case 0x03: p2 = "Proc reset request"; break; /*internal*/ + case 0x04: p2 = "Reset button"; break; + case 0x05: p2 = "Power up"; break; + case 0x06: p2 = "Legacy int watchdog"; break; /*internal*/ + case 0x07: p2 = "Legacy prg watchdog"; break; /*programmable*/ + case 0x08: p2 = "Software initiated"; break; + case 0x09: p2 = "Setup reset"; break; + case 0x0a: p2 = "Power cycle"; break; + default: p2 = "Other"; break; + } + sprintf(oembuf,"%s/%s",p1,p2); + pstr = oembuf; + break; + default: break; + } + rv = 0; + } + break; + case 0x12: /* System Event */ + /* snum 38, 6f 00, or ef 00 */ + /* if (snum == 0x38) */ + type_str = "System Event"; + if (evt[12] == 0x6f) pstr = assert_str(1); /*asserted*/ + else pstr = assert_str(0); /*0xef means deasserted*/ + rv = 0; + break; + case 0x24: /* Platform Alert */ + /* usu 03 01 */ + type_str = "Platform Alert"; + pstr = assert_str(evt[13]); /*data1*/ + rv = 0; + break; + case 0x2B: /* Version Change */ + /* 6f c1 02 ff */ + type_str = "Version Change"; + if ((evt[13] & 0x80) == 0) pstr = ""; + else switch(evt[14]) { /*data2*/ + case 0x01: pstr = "HW Changed"; break; + case 0x02: pstr = "SW Changed"; break; + case 0x03: pstr = "HW incompatible"; break; + default: pstr = "Change failed"; break; /*TODO: add detail here*/ + } + rv = 0; + break; + case 0x70: + type_str = "OEM Firmware Info 1"; + pstr = assert_str(evt[13]); /*data1*/ + rv = 0; + break; + case 0x71: + type_str = "OEM Firmware Info 2"; + pstr = assert_str(evt[13]); /*data1*/ + rv = 0; + break; + default: break; + } + if (rv == 0) { + format_event(id,timestamp, sevid, genid, type_str, + snum,NULL,pstr,mybuf,outbuf,outsz); + } + } + return rv; +} /*end decode_sel_kontron*/ + +int decode_sensor_kontron(uchar *sdr,uchar *reading,char *pstring, int slen) +{ + int rv = -1; + uchar stype; + char *pstr = NULL; + int rdval; + + if (sdr == NULL || reading == NULL) return(rv); + if (pstring == NULL || slen == 0) return(rv); + if (sdr[3] != 0x02) return(rv); /*skip if not compact sensor*/ + stype = sdr[12]; + rdval = reading[2] | ((reading[3] & 0x7f) << 8); + /* usually reading3 == 0x80 */ + switch(stype) { + case 0x08: /* Power Supply or PwrGood ... */ + if (sdr[14] == 0x02) { + if (reading[2] & 0x02) pstr = "Failed"; + else pstr = "OK"; + rv = 0; + } + break; + case 0xC0: /* IPMI Info-N */ + if (reading[2] == 0) pstr = "OK"; + else pstr = "Asserted"; + rv = 0; + break; + case 0xC2: /* IniAgent Err */ + if ((reading[2] & 0x01) == 1) pstr = "OK"; + else pstr = "Error"; /*could be 0x02*/ + rv = 0; + break; + case 0xC6: /* POST Value */ + pstr = (char *)val2str((ushort)rdval,ktc5520_post); + if (pstr == NULL) { + if (rdval >= 0x61 && rdval <= 0x71) pstr = "Error"; + else if (rdval >= 0xDD && rdval <= 0xDE) pstr = "DIMM Debug"; + else pstr = "Other"; + } + rv = 0; + break; + case 0xCF: /* Board Reset */ + if ((reading[2] & 0x01) == 1) pstr = "OK"; + else pstr = "Asserted"; + rv = 0; + break; + default: + break; + } + if (rv == 0) strncpy(pstring, pstr, slen); + return(rv); +} + +/* end oem_kontron.c */ |