summaryrefslogtreecommitdiff
path: root/util/oem_kontron.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/oem_kontron.c')
-rw-r--r--util/oem_kontron.c1107
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 */