/*
 * oem_intel.c
 *
 * This module handles code specific to Intel platforms, 
 * including the Intel/Kontron Telco Alarms panel.  
 * 
 * Note that the Intel BMC TAM will set these alarms
 * based on firmware-detected thresholds and events.
 * 
 * Author:  Andy Cress  arcress at users.sourceforge.net
 * Copyright (c) 2010 Kontron America, Inc.
 *
 * 09/02/10 Andy Cress - separated from ialaems.c
 */
/*M*
Copyright (c) 2010 Kontron America, 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:

  a.. Redistributions of source code must retain the above copyright notice, 
      this list of conditions and the following disclaimer. 
  b.. Redistributions 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. 
  c.. Neither the name of Kontron nor the names of its contributors 
      may be used to endorse or promote products derived from this software 
      without specific prior written permission. 

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *M*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#if defined(DOS)
#include <dos.h>
#endif
#include "ipmicmd.h"
#include "oem_intel.h"
 
extern char  fdebug;   /*ipmicmd.c*/ 
#ifdef METACOMMAND
extern int   sens_verbose;  /*isensor.c*/
extern char *get_sensor_type_desc(uchar stype);  /*ievents.c*/
#else
static int   sens_verbose = 0; 
static char *get_sensor_type_desc(uchar stype) 
{ 
    static char tstr[12];
    sprintf(tstr,"%02x",stype);
    return(tstr); 
}
#endif

/*
 * Global variables 
 */
#ifdef WIN32
/* Windows tamutil is installed by the ipmirastools package from Kontron. */
static char *tam1cmd = "\"\"%ProgramFiles%\"\\Intel\\ipmirastools\\tamutil\" >NUL: 2>NUL:";
static char *tam2cmd = "\"\"%ProgramFiles%\"\\Intel\\ipmirastools\\tamutil\" |findstr TAM.Status >NUL:";
//static char * tam3cmd = "ipmiutil sensor |findstr BMC_TAM >NUL:"; 
//static char * tambcmd = "bmcTamActive"; /*old*/
#define RET_NOT_FOUND  1  /*command not found (%ERRORLEVE%=9009)*/
#else
/* Linux tamutil is installed by the ipmimisc package from Kontron. */
static char *tam1cmd = "/usr/share/ipmimisc/tamutil >/dev/null 2>&1";
static char *tam2cmd = "/usr/share/ipmimisc/tamutil 2>/dev/null |grep TAM.Status >/dev/null";
//static char * tam3cmd = "ipmiutil sensor |grep BMC_TAM  >/dev/null"; 
//static char * tambcmd = "/usr/local/tam/bin/bmcTamActive 2>/dev/null"; /*old*/
//#define RET_TAMB_ACTIVE 256   /*from bmcTamActive, if BMC TAM is enabled*/
#define RET_NOT_FOUND 32512   /*command not found ($?=127 if shell)*/ 
#endif

#ifdef NOT
#define PRIVATE_BUS_ID      0x03 // w Sahalee,  the 8574 is on Private Bus 1
#define PRIVATE_BUS_ID5     0x05 // for Intel TIGI2U
#define PRIVATE_BUS_ID7     0x07 // for Intel S5000
#define PERIPHERAL_BUS_ID   0x24 // w mBMC, the 8574 is on the Peripheral Bus
#define ALARMS_PANEL_WRITE  0x40 
#define ALARMS_PANEL_READ   0x41
#define DISK_LED_WRITE      0x44 // only used for Chesnee mBMC
#define DISK_LED_READ       0x45 // only used for Chesnee mBMC
#endif

uchar get_nsc_diskleds(uchar busid)
{
	uchar inputData[4];
	uchar responseData[16];
	int responseLength = 4;
	uchar completionCode;
	int ret;

	inputData[0] = busid;
	inputData[1] = DISK_LED_READ;
	inputData[2] = 0x1;   // return one byte of LED data
	inputData[3] = 0x00;  // init data to zero
        ret = ipmi_cmd(MASTER_WRITE_READ, inputData, 3, responseData,
                        &responseLength, &completionCode, fdebug);
	if (ret != 0) {
           printf("get_nsc_diskleds: ret = %d, ccode %02x, leds = %02x\n",
                    ret, completionCode, responseData[0]);
	   return(0);
	   }
	return(responseData[0]);
}  /*end get_nsc_diskleds()*/

int set_nsc_diskleds(uchar val, uchar busid)
{
	uchar inputData[4];
	uchar responseData[16];
	int responseLength = 4;
	uchar completionCode;
	int ret;

	inputData[0] = busid;
	inputData[1] = DISK_LED_WRITE;
	inputData[2] = 0x01;   // len = one byte of LED data
	inputData[3] = val;    
        ret = ipmi_cmd(MASTER_WRITE_READ, inputData, 4, responseData,
                        &responseLength, &completionCode, fdebug);
	if (ret != 0) {
           printf("set_nsc_diskleds: ret = %d, ccode %02x, leds = %02x\n",
                    ret, completionCode, val);
	   return(0);
	   }
	return(ret);
}  /*end set_nsc_diskleds()*/

void show_nsc_diskleds(uchar val)
{
	if (fdebug) printf("diskled = %02x\n",val);
	printf("disk A: ");
	if ((val & 0x20) == 0) printf("present");
	else printf("not present");
	if ((val & 0x02) == 0) printf("/faulted ");
	printf("\ndisk B: ");
	if ((val & 0x10) == 0) printf("present");
	else printf("not present");
	if ((val & 0x01) == 0) printf("/faulted ");
	printf("\n");
}

uchar get_alarms_intel(uchar busid)
{
	uchar inputData[4];
	uchar responseData[16];
	int responseLength = 4;
	uchar completionCode;
	int ret;

	inputData[0] = busid;
	inputData[1] = ALARMS_PANEL_READ;
	inputData[2] = 0x1;   // return one byte of alarms data
	inputData[3] = 0x00;  // init data to zero
        ret = ipmi_cmd(MASTER_WRITE_READ, inputData, 3, responseData,
                        &responseLength, &completionCode, fdebug);
	if (ret != 0 || completionCode != 0) {
           printf("get_alarms: ret = %d, ccode %02x, alarms = %02x\n",
                    ret, completionCode, responseData[0]);
	   return(0);
	   }
	return(responseData[0]);
}  /*end get_alarms()*/

int set_alarms_intel(uchar val, uchar busid)
{
	uchar inputData[4];
	uchar responseData[16];
	int responseLength = 4;
	uchar completionCode;
	int ret;

	inputData[0] = busid; 
	inputData[1] = ALARMS_PANEL_WRITE;
	inputData[2] = 0x1;   // one byte of alarms data
	inputData[3] = val;  
        ret = ipmi_cmd(MASTER_WRITE_READ, inputData, 4, responseData,
                        &responseLength, &completionCode, fdebug);
	if (ret != 0) {
           printf("set_alarms: ret = %d, ccode %02x, value = %02x\n",
                    ret, completionCode, val);
	   return(ret);
	   }
	if (completionCode != 0) ret = completionCode;
	return(ret);
}  /*end set_alarms()*/

/* 
 * show_alarms
 *
 * The alarm control/status byte is decoded as follows:
 * bit
 * 7 = reserved, always write 1
 * 6 = LED colors, 1 = amber (default), 0 = red
 *     Colors were added in some later firmware versions, but
 *     not for all platforms.
 * 5 = Minor Relay bit, 0 = on, 1 = off, always write 1
 * 4 = Major Relay bit, 0 = on, 1 = off, always write 1
 * 3 = Minor LED bit, 0 = on, 1 = off
 * 2 = Major LED bit, 0 = on, 1 = off
 * 1 = Critical LED bit, 0 = on, 1 = off
 * 0 = Power LED bit, 0 = on, 1 = off
 *
 * Note that the Power LED is also wired to the System Fault LED 
 * in the back of the system, so this state may be off for Power,
 * but the LED could be lit for a System Fault reason instead.
 */
void show_alarms_intel(uchar val)
{
   char *scrit = "ON ";
   char *smaj = "ON ";
   char *smin = "ON ";
   char *spow = "ON ";
   char *rmaj = "ON";
   char *rmin = "ON";
   if (fdebug) printf("alarms = %02x\n",val);
    
   if (val & 0x01) spow = "off";
   if (val & 0x02) scrit = "off";
   if (val & 0x04) smaj = "off";
   if (val & 0x08) smin = "off";
   printf("Alarm LEDs:   critical = %s major = %s minor = %s power = %s\n",
           scrit,smaj,smin,spow);
   if (val & 0x10) rmaj = "off ";
   if (val & 0x20) rmin = "off ";
   printf("Alarm Relays: major = %s minor = %s\n", rmaj, rmin);
}


int detect_capab_intel(int vend_id, int prod_id, int *cap, char fdbg)
{
     int busid = PRIVATE_BUS_ID;
     int f = 0;
     char fbmctam = 0;
     char fHasAlarms = 1;
     char fHasEnc = 0; 
     char fpicmg = 0;
     char fChesnee = 0;

     fdebug = fdbg;
     if (vend_id == VENDOR_NSC)  { /*NSC mBMC, Chesnee*/
	  busid = PERIPHERAL_BUS_ID;
          fHasAlarms = 1;
          fChesnee = 1;
     } else if (vend_id == VENDOR_INTEL) { /*Intel BMC*/
          switch (prod_id) {
             case 0x0022:   
		busid = PRIVATE_BUS_ID5;  /* Intel TIGI2U */
		fbmctam = 1;  /* Intel TIGI2U may have bmc tam */
                fHasAlarms = 1;
                fHasEnc = 1;
                break;
             case 0x001B:   
	        busid = PRIVATE_BUS_ID;
		fbmctam = 1;  /* Intel TIGPR2U may have bmc tam */
                fHasAlarms = 1;
                break;
             case 0x0808:   
             case 0x0841:   
	        fpicmg = 1;   /* Intel ATCA platform, supports PICMG */
                fHasAlarms = 1;
                break;
             case 0x4311:  
	        busid = PERIPHERAL_BUS_ID; /* SJR2 (NSI2U) mBMC */
                break;
             case 0x0026:   
             case 0x0028:
             case 0x0811:   
		busid = PRIVATE_BUS_ID7;  /* Intel Harbision */
		fbmctam = 1;  /* Intel TIGW1U may have bmc tam */
                fHasAlarms = 1;
                fHasEnc = 1;
                break;
             case 0x003E:     /*S5520UR*/
	        busid = PRIVATE_BUS_ID;
		fbmctam = 1;  /* CG2100 has bmc tam */
                fHasAlarms = 1;
                fHasEnc = 1;
#ifdef LINUX
	        set_max_kcs_loops(1000); /*longer for cmds (default 300)*/
#endif
                break;
             default:
	        busid = PRIVATE_BUS_ID;
                break;
          }
   } 
   if (fHasAlarms) f |= HAS_ALARMS_MASK;
   if (fbmctam)    f |= HAS_BMCTAM_MASK;
   if (fHasEnc)    f |= HAS_ENCL_MASK;
   if (fpicmg)     f |= HAS_PICMG_MASK;
   if (fChesnee)   f |= HAS_NSC_MASK;
   *cap = f;
   return(busid); 
}

int check_bmctam_intel(void)
{
   int ret;

   /* Check if BMC TAM is enabled */
   ret = system(tam1cmd);
   if (fdebug) printf("%s ret = %d\n",tam1cmd,ret);
   if (ret == RET_NOT_FOUND) { /*command not found, no such file*/
	      /* Could also do "ipmiutil sensor |grep BMC_TAM" (tam3cmd),
	       * but this would take a while to complete. */
	      printf("Warning: BMC TAM may be active and managing the LEDs.\n"
		  "If so, use tamutil to set the alarm LEDs instead.\n");
   } else if (ret == 0) {  
	      /*the command was found, check if BMC TAM enabled*/
	      ret = system(tam2cmd);
	      if (fdebug) printf("%s ret = %d\n",tam2cmd,ret);
	      if (ret == 0) {
	         /*If so, print warning, use Intel tamutil instead.*/
	         printf("Warning: BMC TAM is active and managing the LEDs.\n"
		   "Use tamutil or the Intel TAM API to set alarms instead.\n"
		   "Aborting.\n");
	         return(LAN_ERR_ABORT);
	      }
   } 
   /* else tamutil was there but did not show BMC TAM active, so
    *	assume BMC TAM is not active and do nothing. */
    return(ret);
}

#define NTAMSEV  8
static char *tam_sev[] = {
/*0*/ "OFF",
/*1*/ "MNR",
/*2*/ "MNR+P",
/*3*/ "MJR",
/*4*/ "MJR+P",
/*5*/ "CRT",
/*6*/ "CRT+P",
/*7*/ "UNK"
};

/* 
 * show_oemsdr_intel
 */
void show_oemsdr_intel(uchar *sdr)
{
    uchar idx, len, c, i, n, j, k, t;
    int vend;

    len = sdr[4] + 5;
    /*double-check that this is an Intel OEM SDR*/
    vend = sdr[5] | (sdr[6] << 8) | (sdr[7] << 16);
    if (vend != VENDOR_INTEL) return;
    printf("Intel: "); 
    switch(sdr[8]) {  /*OEM subtype*/
    case 0x53:   /* SDR version subtype (has ASCII) */
       for (i = 8; i < len; i++) {
           c = sdr[i];
           if (c < 0x20 || c > 0x7f) printf("[%02x]",c);
           else printf("%c",c);
       }
       printf("\n");
       break;
    case 0x60:  /* BMC TAM subtype */
       idx = (sdr[10] & 0xf0) >> 4;
       n = (sdr[10] & 0x0f) + 1;  /*number of TAM records*/
       printf("BMC_TAM%d ",idx);
       for (i = 8; i < len; i++) 
   	printf("%02x ",sdr[i]);
       if (idx == 0) {
           printf(" nrec=%d cfg=%02x",n,sdr[11]);
       }
       printf("\n");
       if (fdebug || sens_verbose) {
         /* show decoded BMC_TAM rules */
         if (idx > 0) {
           uchar map, off, sev, sa;
           const char *tstr;
           sa = sdr[12];
           for (i = 13; i < len; ) {
              k = (sdr[i] & 0xf0) >> 4;
              t = sdr[i+1];
	      tstr = get_sensor_type_desc(t); 
              printf("\tBMC_TAM%d sa=%02x %s (",idx,sa,tstr);
              for (j = 0; j < k; j++) {
                 map = sdr[i+3+j];
                 off = (map & 0xf0) >> 4;
                 sev = map & 0x0f;
                 if (sev >= NTAMSEV) sev = NTAMSEV - 1;
                 printf("%d=%s ",off,tam_sev[sev]);
              }
              printf(")\n");
              i += 3 + k;
           }
         }
       }
       break;
    case 0x02: /*S5500 Power Unit Redundancy subtype*/
    case 0x05: /*S5500 Fan Redundancy subtype*/
    case 0x09: /*S5500 Voltage sensor scaling*/
    case 0x0A: /*S5500 Fan sensor scaling*/
    case 0x0B: /*S5500 Thermal Profile data*/
    case 0x06: /*S5000 System Information/Capab */
    case 0x0C: /*S5000 Fan Speed Control*/
    default:   /* other subtypes 02,06,07, etc. */
       for (i = 8; i < len; i++)
            printf("%02x ",sdr[i]);
       printf("\n");
       break;
    } /*end switch*/
} /*end show_oemsdr_intel*/

int decode_sensor_intel(uchar *sdr,uchar *reading,char *pstring, int slen)
{
   int rv = -1;
   uchar stype;
   char *pstr = NULL;

   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];
   switch(stype) {
	case 0xC0:	/* SMI State, NMI State */
	case 0xC7:	/* FanBoost */
	case 0xCC:	/* Debug Info */
	case 0xD8:	/* BIST */
	case 0xF0:	/* ATCA HotSwap, TODO: refine this */
	case 0xF3:	/* SMI Timeout, etc. */
	case 0xF6:	/* Sensor Failure */
	case 0xF7:	/* FSB Mismatch */
	   if (reading[2] & 0x01) pstr = "Asserted"; /*Asserted, error*/
           else pstr = "OK";               /*deasserted*/
	   rv = 0;
	   break;
	default:
	   break;
   }
   if (rv == 0) strncpy(pstring, pstr, slen);
   return(rv);
}

const struct valstr intel_s5000_post[] = {  /*from S5000 TPS*/
 { 0x004C, "Keyboard/interface error" },
 { 0x0012, "CMOS date/time not set" },
 { 0x0048, "Password check failed" },
 { 0x0141, "PCI resource conflict" },
 { 0x0146, "Insufficient memory to shadow PCI ROM" },
 { 0x0192, "L3 cache size mismatch" },
 { 0x0194, "CPUID, processor family are different" },
 { 0x0195, "Front side bus mismatch" },
 { 0x0197, "Processor speeds mismatched" },
 { 0x5220, "Configuration cleared by jumper" },
 { 0x5221, "Passwords cleared by jumper" },
 { 0x5223, "Configuration default loaded" },
 { 0x8110, "Proc1 internal error (IERR) on last boot" },
 { 0x8111, "Proc2 internal error (IERR) on last boot" },
 { 0x8120, "Proc1 thermal trip error on last boot" },
 { 0x8121, "Proc2 thermal trip error on last boot" },
 { 0x8130, "Proc1 disabled" },
 { 0x8131, "Proc2 disabled" },
 { 0x8160, "Proc1 unable to apply BIOS update" },
 { 0x8161, "Proc2 unable to apply BIOS update" },
 { 0x8170, "Proc1 failed Self Test (BIST)" },
 { 0x8171, "Proc2 failed Self Test (BIST)" },
 { 0x8180, "Proc1 BIOS does not support current CPU stepping" },
 { 0x8181, "Proc2 BIOS does not support current CPU stepping" },
 { 0x8190, "Watchdog timer failed on last boot" },
 { 0x8198, "OS boot watchdog timer expired on last boot" },
 { 0x8300, "Baseboard management controller failed self-test" },
 { 0x8306, "Front panel controller locked" },
 { 0x8305, "Hot swap controller failed" },
 { 0x84F2, "Baseboard management controller failed to respond" },
 { 0x84F3, "Baseboard management controller in update mode" },
 { 0x84F4, "Sensor data record empty" },
 { 0x84FF, "System event log full" },
 { 0x8500, "Memory could not be configured in the selected RAS mode" },
 { 0x8510, "Memory above 16GB maximum" }, /*S5000V only*/
 { 0x8520, "DIMM_A1 failed Self Test (BIST)" },
 { 0x8521, "DIMM_A2 failed Self Test (BIST)" },
 { 0x8522, "DIMM_A3 failed Self Test (BIST)" },
 { 0x8523, "DIMM_A4 failed Self Test (BIST)" },
 { 0x8524, "DIMM_B1 failed Self Test (BIST)" },
 { 0x8525, "DIMM_B2 failed Self Test (BIST)" },
 { 0x8526, "DIMM_B3 failed Self Test (BIST)" },
 { 0x8527, "DIMM_B4 failed Self Test (BIST)" },
 { 0x8528, "DIMM_C1 failed Self Test (BIST)" },
 { 0x8529, "DIMM_C2 failed Self Test (BIST)" },
 { 0x852A, "DIMM_C3 failed Self Test (BIST)" },
 { 0x852B, "DIMM_C4 failed Self Test (BIST)" },
 { 0x852C, "DIMM_D1 failed Self Test (BIST)" },
 { 0x852D, "DIMM_D2 failed Self Test (BIST)" },
 { 0x852E, "DIMM_D3 failed Self Test (BIST)" },
 { 0x852F, "DIMM_D4 failed Self Test (BIST)" },
 { 0x8540, "Memory lost redundancy during last boot" },
 { 0x8580, "DIMM_A1 Correctable ECC error" },
 { 0x8581, "DIMM_A2 Correctable ECC error" },
 { 0x8582, "DIMM_A3 Correctable ECC error" },
 { 0x8583, "DIMM_A4 Correctable ECC error" },
 { 0x8584, "DIMM_B1 Correctable ECC error" },
 { 0x8585, "DIMM_B2 Correctable ECC error" },
 { 0x8586, "DIMM_B3 Correctable ECC error" },
 { 0x8587, "DIMM_B4 Correctable ECC error" },
 { 0x8588, "DIMM_C1 Correctable ECC error" },
 { 0x8589, "DIMM_C2 Correctable ECC error" },
 { 0x858A, "DIMM_C3 Correctable ECC error" },
 { 0x858B, "DIMM_C4 Correctable ECC error" },
 { 0x858C, "DIMM_D1 Correctable ECC error" },
 { 0x858D, "DIMM_D2 Correctable ECC error" },
 { 0x858E, "DIMM_D3 Correctable ECC error" },
 { 0x858F, "DIMM_D4 Correctable ECC error" },
 { 0x8600, "Primary and secondary BIOS IDs do not match" },
 { 0x8601, "BIOS Bank Override jumper set to lower bank" },
 { 0x8602, "WatchDog timer expired (check secondary BIOS bank)" },
 { 0x8603, "Secondary BIOS checksum fail" },
 { 0xffff , NULL }  /*end of list*/
};
const struct valstr intel_s5500_post[] = {  /*from S5520UR TPS*/
 { 0x0012, "CMOS date/time not set" },
 { 0x0048, "Password check failed" },
 { 0x0108, "Keyboard locked error" },
 { 0x0109, "Keyboard stuck key error" },
 { 0x0113, "The SAS RAID firmware cannot run properly" },
 { 0x0140, "PCI PERR detected" },
 { 0x0141, "PCI resource conflict" },
 { 0x0146, "PCI out of resources error" },
 { 0x0192, "L3 cache size mismatch" },
 { 0x0194, "CPUID/processor family are different" },
 { 0x0195, "Front side bus mismatch" },
 { 0x0196, "Processor Model mismatch" },
 { 0x0197, "Processor speeds mismatched" },
 { 0x0198, "Processor family is unsupported" },
 { 0x019F, "Processor/chipset stepping configuration is unsupported" },
 { 0x5220, "CMOS/NVRAM Configuration Cleared" },
 { 0x5221, "Passwords cleared by jumper" },
 { 0x5224, "Password clear Jumper is Set" },
 { 0x8110, "Proc1 internal error (IERR) on last boot" },
 { 0x8111, "Proc2 internal error (IERR) on last boot" },
 { 0x8120, "Proc1 thermal trip error on last boot" },
 { 0x8121, "Proc2 thermal trip error on last boot" },
 { 0x8130, "Proc1 disabled" },
 { 0x8131, "Proc2 disabled" },
 { 0x8140, "Proc1 Failed FRB-3 Timer" },
 { 0x8141, "Proc2 Failed FRB-3 Timer" },
 { 0x8160, "Proc1 unable to apply BIOS update" },
 { 0x8161, "Proc2 unable to apply BIOS update" },
 { 0x8170, "Proc1 failed Self Test (BIST)" },
 { 0x8171, "Proc2 failed Self Test (BIST)" },
 { 0x8180, "Proc1 BIOS does not support current CPU stepping" },
 { 0x8181, "Proc2 BIOS does not support current CPU stepping" },
 { 0x8190, "Watchdog timer failed on last boot" },
 { 0x8198, "OS boot watchdog timer expired on last boot" },
 { 0x8300, "iBMC failed self-test" },
 { 0x84F2, "iBMC failed to respond" },
 { 0x84F3, "iBMC in update mode" },
 { 0x84F4, "Sensor data record empty" },
 { 0x84FF, "System event log full" },
 { 0x8500, "Memory could not be configured in the selected RAS mode" },
 { 0x8520, "DIMM_A1 failed Self Test (BIST)" },
 { 0x8521, "DIMM_A2 failed Self Test (BIST)" },
 { 0x8522, "DIMM_A3 failed Self Test (BIST)" },
 { 0x8523, "DIMM_A4 failed Self Test (BIST)" },
 { 0x8524, "DIMM_B1 failed Self Test (BIST)" },
 { 0x8525, "DIMM_B2 failed Self Test (BIST)" },
 { 0x8526, "DIMM_B3 failed Self Test (BIST)" },
 { 0x8527, "DIMM_B4 failed Self Test (BIST)" },
 { 0x8528, "DIMM_C1 failed Self Test (BIST)" },
 { 0x8529, "DIMM_C2 failed Self Test (BIST)" },
 { 0x852A, "DIMM_C3 failed Self Test (BIST)" },
 { 0x852B, "DIMM_C4 failed Self Test (BIST)" },
 { 0x852C, "DIMM_D1 failed Self Test (BIST)" },
 { 0x852D, "DIMM_D2 failed Self Test (BIST)" },
 { 0x852E, "DIMM_D3 failed Self Test (BIST)" },
 { 0x852F, "DIMM_D4 failed Self Test (BIST)" },
 { 0x8540, "DIMM_A1 Disabled" },
 { 0x8541, "DIMM_A2 Disabled" },
 { 0x8542, "DIMM_A3 Disabled" },
 { 0x8543, "DIMM_A4 Disabled" },
 { 0x8544, "DIMM_B1 Disabled" },
 { 0x8545, "DIMM_B2 Disabled" },
 { 0x8546, "DIMM_B3 Disabled" },
 { 0x8547, "DIMM_B4 Disabled" },
 { 0x8548, "DIMM_C1 Disabled" },
 { 0x8549, "DIMM_C2 Disabled" },
 { 0x854A, "DIMM_C3 Disabled" },
 { 0x854B, "DIMM_C4 Disabled" },
 { 0x854C, "DIMM_D1 Disabled" },
 { 0x854D, "DIMM_D2 Disabled" },
 { 0x854E, "DIMM_D3 Disabled" },
 { 0x854F, "DIMM_D4 Disabled" },
 { 0x8560, "DIMM_A1 SPD fail error." },
 { 0x8561, "DIMM_A2 SPD fail error" },
 { 0x8562, "DIMM_A3 SPD fail error" },
 { 0x8563, "DIMM_A4 SPD fail error" },
 { 0x8564, "DIMM_B1 SPD fail error" },
 { 0x8565, "DIMM_B2 SPD fail error" },
 { 0x8566, "DIMM_B3 SPD fail error" },
 { 0x8567, "DIMM_B4 SPD fail error" },
 { 0x8568, "DIMM_C1 SPD fail error" },
 { 0x8569, "DIMM_C2 SPD fail error" },
 { 0x856A, "DIMM_C3 SPD fail error" },
 { 0x856B, "DIMM_C4 SPD fail error" },
 { 0x856C, "DIMM_D1 SPD fail error" },
 { 0x856D, "DIMM_D2 SPD fail error" },
 { 0x856E, "DIMM_D3 SPD fail error" },
 { 0x856F, "DIMM_D4 SPD fail error" },
 { 0x8580, "DIMM_A1 Correctable ECC error" },
 { 0x8581, "DIMM_A2 Correctable ECC error" },
 { 0x8582, "DIMM_A3 Correctable ECC error" },
 { 0x8583, "DIMM_A4 Correctable ECC error" },
 { 0x8584, "DIMM_B1 Correctable ECC error" },
 { 0x8585, "DIMM_B2 Correctable ECC error" },
 { 0x8586, "DIMM_B3 Correctable ECC error" },
 { 0x8587, "DIMM_B4 Correctable ECC error" },
 { 0x8588, "DIMM_C1 Correctable ECC error" },
 { 0x8589, "DIMM_C2 Correctable ECC error" },
 { 0x858A, "DIMM_C3 Correctable ECC error" },
 { 0x858B, "DIMM_C4 Correctable ECC error" },
 { 0x858C, "DIMM_D1 Correctable ECC error" },
 { 0x858D, "DIMM_D2 Correctable ECC error" },
 { 0x858E, "DIMM_D3 Correctable ECC error" },
 { 0x858F, "DIMM_D4 Correctable ECC error" },
 { 0x85A0, "DIMM_A1 Uncorrectable ECC error" },
 { 0x85A1, "DIMM_A2 Uncorrectable ECC error" },
 { 0x85A2, "DIMM_A3 Uncorrectable ECC error" },
 { 0x85A3, "DIMM_A4 Uncorrectable ECC error" },
 { 0x85A4, "DIMM_B1 Uncorrectable ECC error" },
 { 0x85A5, "DIMM_B2 Uncorrectable ECC error" },
 { 0x85A6, "DIMM_B3 Uncorrectable ECC error" },
 { 0x85A7, "DIMM_B4 Uncorrectable ECC error" },
 { 0x85A8, "DIMM_C1 Uncorrectable ECC error" },
 { 0x85A9, "DIMM_C2 Uncorrectable ECC error" },
 { 0x85AA, "DIMM_C3 Uncorrectable ECC error" },
 { 0x85AB, "DIMM_C4 Uncorrectable ECC error" },
 { 0x85AC, "DIMM_D1 Uncorrectable ECC error" },
 { 0x85AD, "DIMM_D2 Uncorrectable ECC error" },
 { 0x85AE, "DIMM_D3 Uncorrectable ECC error" },
 { 0x85AF, "DIMM_D4 Uncorrectable ECC error" },
 { 0x8601, "BIOS Bank Override jumper set to lower bank" },
 { 0x8602, "WatchDog timer expired (check secondary BIOS bank)" },
 { 0x8603, "Secondary BIOS checksum fail" },
 { 0x8604, "Chipset Reclaim of non critical variables complete" },
 { 0x9000, "Unspecified processor component error" },
 { 0x9223, "Keyboard was not detected" },
 { 0x9226, "Keyboard controller error" },
 { 0x9243, "Mouse was not detected" },
 { 0x9246, "Mouse controller error" },
 { 0x9266, "Local Console controller error" },
 { 0x9268, "Local Console output error" },
 { 0x9269, "Local Console resource conflict error" },
 { 0x9286, "Remote Console controller error" },
 { 0x9287, "Remote Console input error" },
 { 0x9288, "Remote Console output error" },
 { 0x92A3, "Serial port was not detected" },
 { 0x92A9, "Serial port resource conflict error" },
 { 0x92C6, "Serial Port controller error" },
 { 0x92C7, "Serial Port input error" },
 { 0x92C8, "Serial Port output error" },
 { 0x94C6, "LPC controller error" },
 { 0x94C9, "LPC resource conflict error" },
 { 0x9506, "ATA/ATPI controller error" },
 { 0x95A6, "PCI controller error" },
 { 0x95A7, "PCI read error" },
 { 0x95A8, "PCI write error" },
 { 0x9609, "Unspecified software start error" },
 { 0x9641, "PEI Core load error" },
 { 0x9667, "PEI module Illegal software state error" },
 { 0x9687, "DXE core Illegal software state error" },
 { 0x96A7, "DXE driver Illegal software state error" },
 { 0x96AB, "DXE driver Invalid configuration" },
 { 0x96E7, "SMM driver Illegal software state error" },
 { 0xA022, "Processor mismatch error" },
 { 0xA027, "Processor low voltage error" },
 { 0xA028, "Processor high voltage error" },
 { 0xA421, "PCI SERR detected" },
 { 0xA500, "ATA/ATPI ATA bus SMART not supported" },
 { 0xA501, "ATA/ATPI ATA SMART is disabled" },
 { 0xA5A0, "PCI Express PERR" },
 { 0xA5A1, "PCI Express SERR" },
 { 0xA5A4, "PCI Express IBIST error" },
 { 0xA6A0, "DXE driver Not enough memory to shadow legacy OpROM" },
 { 0xffff , NULL }  /*end of list*/
};

/* decode Intel POST codes for some platforms*/
int decode_post_intel(int prod, ushort code, char *outbuf,int szbuf)
{
   int rv = -1;
   const char *poststr = NULL;
   switch(prod) {
      case 0x0028:   /*S5000PAL*/
      case 0x0029:   /*S5000PSL*/
      case 0x0811:   /*S5000PHB*/
	  poststr = val2str(code,intel_s5000_post);
	  break;
      case 0x003E:   /*S5520UR/T5520UR (CG2100 or NSN2U)*/
	  poststr = val2str(code,intel_s5500_post);
	  break;
      default:   break;
   }
   if (poststr != NULL) {
      strncpy(outbuf, poststr, szbuf);
      rv = 0;
   }
   return(rv);
}
/* end oem_intel.c */
