diff options
Diffstat (limited to 'util/oem_intel.c')
-rw-r--r-- | util/oem_intel.c | 1842 |
1 files changed, 1842 insertions, 0 deletions
diff --git a/util/oem_intel.c b/util/oem_intel.c new file mode 100644 index 0000000..f568300 --- /dev/null +++ b/util/oem_intel.c @@ -0,0 +1,1842 @@ +/* + * 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) 2005 Intel Corporation + * Copyright (c) 2010 Kontron America, Inc. + * + * Compile flags for oem_intel.c: + * NO_CMD would be defined if linking with ievents.c only (no ipmicmd code) + * NO_EVENTS would be defined if linking with ialarms.c (no ievents code) + * + * 09/02/10 Andy Cress - separated from ialarms.c + */ +/*M* +Copyright (c) 2005 Intel Corporation +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" + +#ifdef METACOMMAND +#include "ievents.h" +extern char fsm_debug; /*mem_if.c*/ +extern int sens_verbose; /*isensor.c*/ +extern int get_sensdesc(uchar sa, int snum, char *sdesc, int *pstyp, int *pidx); +extern int get_MemDesc(int array, int dimm, char *desc, int *psz); /*mem_if.c*/ +#else +static char fsm_debug = 0; +static int sens_verbose = 0; +static int get_MemDesc(int array, int dimm, char *desc, int *psz) { return -1;} +#if !defined(NO_CMD) +int get_sensdesc(uchar sa, int snum, char *sensdesc, int *pstyp, int *pidx) +{ return(-1); } +#endif +static char *get_sensor_type_desc(uchar stype) +{ + static char tstr[12]; + sprintf(tstr,"%02x",stype); + return(tstr); +} +#endif +extern char fdebug; /*ipmicmd.c*/ + +/* + * Global variables + */ +static char fRelayBits = 0; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = BMC_SA; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; + +#ifdef OLD +#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 +#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 + +#if defined(NO_CMD) +const char * val2str(ushort val, const struct valstr *vs) +{ + static char un_str[32]; + int i; + for (i = 0; vs[i].str != NULL; i++) + if (vs[i].val == val) return vs[i].str; + memset(un_str, 0, 32); + snprintf(un_str, 32, "Unknown (0x%x)", val); + return un_str; +} +#else +uchar get_nsc_diskleds(uchar busid) +{ + uchar inputData[4]; + uchar rdata[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, rdata, + &responseLength, &completionCode, fdebug); + if (ret != 0) { + printf("get_nsc_diskleds: ret = %d, ccode %02x, leds = %02x\n", + ret, completionCode, rdata[0]); + return(0); + } + return(rdata[0]); +} /*end get_nsc_diskleds()*/ + +int set_nsc_diskleds(uchar val, uchar busid) +{ + uchar inputData[4]; + uchar rdata[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, rdata, + &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 rdata[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, rdata, + &responseLength, &completionCode, fdebug); + if (ret != 0 || completionCode != 0) { + printf("get_alarms: ret = %d, ccode %02x, alarms = %02x\n", + ret, completionCode, rdata[0]); + return(0); + } + return(rdata[0]); +} /*end get_alarms()*/ + +int set_alarms_intel(uchar val, uchar busid) +{ + uchar inputData[4]; + uchar rdata[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, rdata, + &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 (fRelayBits == 1) { /*CG2100 platforms have Relay bits reversed*/ + if (val & 0x10) rmin = "off "; + if (val & 0x20) rmaj = "off "; + } else { + if (val & 0x10) rmaj = "off "; + if (val & 0x20) rmin = "off "; + } + printf("Alarm Relays: major = %s minor = %s\n", rmaj, rmin); +} + +/* + * get_led_status_intel + * uses Intel OEM command to get the status of the ID LED. + * if success, rv=0, pstate: 0=off, 1=on, 2=blinking + */ +int get_led_status_intel(uchar *pstate) +{ + uchar rdata[64]; + int rv, rlen; + uchar cc, b_leds, bstate; + + /* This command is only supported on Intel S5000 motherboards */ + rlen = sizeof(rdata); + rv = ipmi_cmdraw(0x40,0x32, g_sa,g_bus,g_lun, + NULL, 0, rdata, &rlen, &cc, fdebug); + if (fdebug) printf("get_led_status_intel: rv = %d, cc=%02x\n", rv,cc); + if (rv == 0 && cc != 0) rv = cc; + if (rv == 0) { + b_leds = rdata[0]; + bstate = 0; /*off*/ + if (b_leds & 0x80) { bstate = 1; /*on*/ } + else if (b_leds & 0x40) { bstate = 2; /*blink*/ } + if (pstate != NULL) *pstate = bstate; + } + return(rv); +} + + +int detect_capab_intel(int vend_id,int prod_id, int *cap, int *ndisk,char fdbg) +{ + int busid = PRIVATE_BUS_ID; + int f = 0; + char fbmctam = 0; + char fHasAlarms = 0; + char fHasEnc = 0; + char fpicmg = 0; + char fChesnee = 0; + int styp, idx, rv; + char desc[20]; + + 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 = 2; + break; + case 0x000C: /* TSRLT2 or TSRMT2 */ + busid = PRIVATE_BUS_ID; + fbmctam = 0; /* no BMC TAM */ + fHasAlarms = 1; + fHasEnc = 0; + 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: /*BridgePort*/ + case 0x0028: /*S5000PAL*/ + case 0x0029: /*S5000PSL*/ + case 0x0811: /*S5000PHB*/ + busid = PRIVATE_BUS_ID7; /* Intel Harbision (TIGW1U/NSW1U) */ + /* Check for SAS Drv Pres sensor on HSC, if TIGW1U */ + rv = get_sensdesc(0xC0,0x09,desc,&styp, &idx); + if (fdebug) printf("get_sensdesc rv = %d\n",rv); + if (rv == ERR_NOT_FOUND) { /* NSW1U does not have alarm panel*/ + fHasAlarms = 0; + fHasEnc = 0; + } else { /* has HSC, like TIGW1U */ + fbmctam = 1; /* TIGW1U may have bmc tam */ + fHasAlarms = 1; + if (prod_id == 0x0811) fHasEnc = 3; + else fHasEnc = 6; + } + break; + case 0x003E: /*S5520UR*/ + busid = PRIVATE_BUS_ID; + fbmctam = 1; /* CG2100 has bmc tam */ + fHasAlarms = 1; + fHasEnc = 8; /* CG2100 has 8 disks */ + fRelayBits = 1; + set_max_kcs_loops(URNLOOPS); /*longer for cmds (default 300)*/ + break; + case 0x005D: /* Copper Pass, CG2200*/ + busid = PRIVATE_BUS_ID; + fbmctam = 1; /* CG2200 has bmc tam */ + fHasAlarms = 1; + fRelayBits = 1; + fHasEnc = 6; /* 6 disks */ + set_max_kcs_loops(URNLOOPS); /*longer for cmds (default 300)*/ + break; + case 0x0051: /* Eagle Pass */ + busid = PRIVATE_BUS_ID; + fbmctam = 1; /* CG1200 has bmc tam */ + fHasAlarms = 1; + fRelayBits = 1; + fHasEnc = 4; /* 4 disks */ + set_max_kcs_loops(URNLOOPS); /*longer for cmds (default 300)*/ + break; + case 0x0048: /* "(S1200BT)" *BearTooth Pass*/ + case 0x004A: /* "(S2600CP)" *Canoe Pass*/ + case 0x0055: /* Iron Pass */ + case 0x005C: /* Lizard Head Pass */ + fHasEnc = 8; + set_max_kcs_loops(URNLOOPS); /*longer for cmds (default 300)*/ + break; + default: + busid = PRIVATE_BUS_ID; + fHasEnc = 8; + break; + } + } + if (fHasAlarms) f |= HAS_ALARMS_MASK; + if (fbmctam) f |= HAS_BMCTAM_MASK; + if (fHasEnc > 0) { + f |= HAS_ENCL_MASK; + if (ndisk != NULL) *ndisk = fHasEnc; + } + if (fpicmg) f |= HAS_PICMG_MASK; + if (fChesnee) f |= HAS_NSC_MASK; + if (is_romley(vend_id,prod_id)) { + if (prod_id == 0x005D) fHasEnc = 6; /*CG2200*/ + fHasEnc = 8; + set_max_kcs_loops(URNLOOPS); /*longer for cmds (default 300)*/ + f |= HAS_ROMLEY_MASK; + } + *cap = f; + return(busid); +} + +int check_bmctam_intel(void) +{ + int ret, rlen; + uchar rdata[16]; + uchar cc; + + /* Check if BMC TAM is enabled */ + rlen = sizeof(rdata); + ret = ipmi_cmdraw(0x00, 0x36, g_sa,g_bus,g_lun, + NULL, 0, rdata, &rlen, &cc, fdebug); + if ((ret == 0) && (cc == 0)) { + printf("Warning: BMC TAM is active and managing the LEDs.\n" + "Use tamutil (from ipmimisc rpm) to set alarms instead.\n"); + return(LAN_ERR_ABORT); + } else return(0); +#ifdef OLD + 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); +#endif +} + +int soft_reset_intel(uchar func) +{ + int ret, rlen; + uchar idata[16]; + uchar rdata[16]; + uchar cc; + + /* Do an Intel S5000 soft reset, via an OS bridge agent (ipmiutil_asy) */ + rlen = sizeof(rdata); + idata[0] = func; /* 0=read, 1=shutdown, 2=reset */ + ret = ipmi_cmdraw(0x70, 0x30, g_sa,g_bus,g_lun, + idata, 1, rdata, &rlen, &cc, fdebug); + if ((ret == 0) && (cc != 0)) ret = cc; + return(ret); +} + +int lan_failover_intel(uchar func, uchar *mode) +{ + int ret, rlen; + uchar idata[16]; + uchar rdata[16]; + uchar cc; + + /* Do an Intel S2600 LAN Failover command, where func is: + * 0x00=disable, + * 0x01=enable with leash monitor, + * 0x02=enable with ARP monitor if blade, + * 0xFF=no set, just get current mode + */ + rlen = sizeof(rdata); + idata[0] = func; /* 0=read, 1=shutdown, 2=reset */ + ret = ipmi_cmdraw(0x40, 0x3E, g_sa,g_bus,g_lun, + idata, 1, rdata, &rlen, &cc, fdebug); + if ((ret == 0) && (cc != 0)) ret = cc; + if (ret == 0 && mode != NULL) *mode = rdata[0]; + return(ret); +} + +int get_power_restore_delay_intel(int *delay) +{ + int ret, rlen; + uchar idata[16]; + uchar rdata[16]; + uchar cc; + + rlen = sizeof(rdata); + ret = ipmi_cmdraw(0x55, 0x30, g_sa,g_bus,g_lun, + idata, 0, rdata, &rlen, &cc, fdebug); + if ((ret == 0) && (cc != 0)) ret = cc; + if (ret == 0 && delay != NULL) + *delay = ( rdata[1] + ((rdata[0] & 0x07) << 8) ); + return(ret); +} + +/* end-else NO_CMD not defined */ +#endif + +#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" +}; + +int decode_sensor_intel_nm(uchar *sdr,uchar *reading,char *pstring, int slen) +{ + int rv = -1; + uchar stype; + char mystr[60]; + uchar nm_sa, chan, lun; + + if (sdr == NULL) return(rv); + if (pstring == NULL || slen == 0) return(rv); + switch(sdr[3]) { /*SDR type*/ + case 0xC0: /*OEM sensor*/ + if (sdr[8] == 0x0D) { /* OEM NM Reference SDR, no reading */ + nm_sa = sdr[10]; + chan = (sdr[11] & 0xf0) >> 4; + lun = (sdr[11] & 0x0f); + /* show NM location and sensor numbers for NM sensors */ + sprintf(mystr,"NM(%x,%x,%x) health=%x excep=%x capab=%x thresh=%x", + chan,nm_sa,lun, sdr[12],sdr[13],sdr[14],sdr[15]); + strncpy(pstring, mystr, slen); + if ((int)strlen(mystr) > slen) pstring[slen-1] = 0; /*string*/ + rv = 0; + } + break; + case 0x02: /*compact sensor*/ + if (reading == NULL) return(rv); + stype = sdr[12]; /*sensor type*/ + if (stype == 0xDC) { /* NM Capabilities sensor, usu snum 0x1a (26.)*/ + mystr[0] = 0; + if (reading[2] == 0x00) strcat(mystr,"None"); + else { + if (reading[2] & 0x01) strcat(mystr,"Policy "); + if (reading[2] & 0x02) strcat(mystr,"Monitor "); + if (reading[2] & 0x04) strcat(mystr,"Power "); + } + strncpy(pstring, mystr, slen); + if ((int)strlen(mystr) > slen) pstring[slen-1] = 0; /*string*/ + rv = 0; + } + break; + default: + break; + } + return(rv); +} + +static void show_oem_hex(uchar *sdr, int slen) +{ + int i; + for (i = 8; i < slen; i++) + printf("%02x ",sdr[i]); + printf("\n"); +} + +void show_oemsdr_nm(uchar *sdr) +{ + int rv, len; + char mystr[60]; + + /* vendor id has already been shown */ + len = sdr[4] + 5; + rv = decode_sensor_intel_nm(sdr,NULL,mystr,sizeof(mystr)); + if (rv == 0) printf("%s\n",mystr); + else show_oem_hex(sdr, len); + return; +} + +/* + * 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) { + if (fdebug) printf("show_oemsdr_intel: vendor %x != %x (Intel)\n", + 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 0x0C: /* Fan Speed Control */ + printf("FanCtl "); + show_oem_hex(sdr, len); + break; + case 0x0D: /* ME NM Reference SDR */ + show_oemsdr_nm(sdr); + break; + case 0x02: /*S5500 Power Unit Redundancy subtype*/ + case 0x05: /*S5500 Fan Redundancy subtype*/ + case 0x06: /*S5000 System Information/Capab */ + case 0x09: /*S5500 Voltage sensor scaling*/ + case 0x0A: /*S5500 Fan sensor scaling*/ + case 0x0B: /*S5500 Thermal Profile data*/ + default: /* other subtypes 07,0e,15 etc. */ + show_oem_hex(sdr, len); + break; + } /*end switch*/ +} /*end show_oemsdr_intel*/ + +#ifdef NO_EVENTS +/* if not linking with ievents.c, need to skip decode_sel_intel because it + * would have unresolved externals for fmt_time, get_sev_str, get_sensor_tag */ +#else +/* + * decode_sel_intel + * 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_intel(uchar *evt, char *outbuf, int outsz, char fdesc, + char fdebug) +{ + int rv = -1; + ushort id; + uchar rectype; + ulong timestamp; + char mybuf[64]; + char oembuf[64]; + char *type_str = NULL; + char *pstr = NULL; + int sevid; + ushort genid; + uchar snum; + char *p1; + int d, f; + + sevid = SEV_INFO; + id = evt[0] + (evt[1] << 8); + rectype = evt[2]; + snum = evt[11]; + timestamp = evt[3] + (evt[4] << 8) + (evt[5] << 16) + (evt[6] << 24); + genid = evt[7] | (evt[8] << 8); + if (rectype == 0x00) { + if (snum == 0x0A && evt[12] == 0x03) rectype = 0x02; /*internal wdog*/ + } + if (rectype == 0x02) { + type_str = ""; + sprintf(mybuf,"%02x [%02x %02x %02x]", evt[12],evt[13],evt[14],evt[15]); + pstr = ""; /*default*/ + switch(evt[10]) { /*sensor type*/ + case 0x00: /* type undefined */ + // type_str = get_sensor_type_desc(0x28); + type_str = "Management Subsystem Health"; + if (snum == 0x0A && evt[12] == 0x03) { /*internal wd event*/ + pstr = "BMC wd restart"; + sevid = SEV_CRIT; + rv = 0; + } + break; + case 0x13: /* Critical Interrupt */ + type_str = "Critical Interrupt"; + if (evt[12] == 0x70) { /*event trigger/type = OEM AER events */ + /* AER doc uses 'Fatal' here, but they are not really fatal.*/ + pstr = &oembuf[0]; + switch(evt[13]) { /*data1/offset*/ + case 0xA0: p1 = "PCIe Data Link Protocol Error"; break; + case 0xA1: p1 = "PCIe Surprise Link Down"; break; + case 0xA2: p1 = "PCIe Unexpected Completion"; break; + case 0xA3: p1 = "PCIe Unsupported Request"; break; + case 0xA4: p1 = "PCIe Poisoned TLP"; break; + case 0xA5: p1 = "PCIe Flow Control Protocol"; break; + case 0xA6: p1 = "PCIe Completion Timeout"; break; + case 0xA7: p1 = "PCIe Completer Abort"; break; + case 0xA8: p1 = "PCIe Recv Buffer Overflow"; break; + case 0xA9: p1 = "PCIe ACS Violation"; break; + case 0xAA: p1 = "PCIe Malformed TLP"; break; + case 0xAB: p1 = "PCIe Recvd Fatal Message"; break; + case 0xAC: p1 = "PCIe Unexpected Completion Error"; break; + case 0xAD: p1 = "PCIe Recvd Warning Message"; break; + default: p1 = "PCIe Other AER"; break; + } + rv = 0; + sevid = SEV_MAJ; + /* also include the bus dev/func bytes (as shown by lspci) */ + d = (evt[15] & 0xF8) >> 3; + f = (evt[15] & 0x07); + snprintf(oembuf,sizeof(oembuf),"%s on (%02x:%02x.%d)", + p1,evt[14],d,f); + } + if (evt[12] == 0x71) { /*event trigger/type = OEM AER warnings */ + pstr = &oembuf[0]; + switch(evt[13]) { /*data1/offset*/ + case 0xA0: p1 = "PCIe Warn Receiver Error"; break; + case 0xA1: p1 = "PCIe Warn Bad DLLP"; break; + case 0xA2: p1 = "PCIe Warn Bad TLLP"; break; + case 0xA3: p1 = "PCIe Warn Replay Num Rollover"; break; + case 0xA4: p1 = "PCIe Warn Replay Timeout"; break; + case 0xA5: p1 = "PCIe Warn Advisory Non-Fatal"; break; + case 0xA6: p1 = "PCIe Warn Link BW Changed"; break; + default: p1 = "PCIe Warn Other AER"; break; + } + rv = 0; + sevid = SEV_MIN; + /* also include the bus dev/func bytes (as shown by lspci) */ + d = (evt[15] & 0xF8) >> 3; + f = (evt[15] & 0x07); + snprintf(oembuf,sizeof(oembuf),"%s on (%02x:%02x.%d)", + p1,evt[14],d,f); + } + break; + case 0x2B: /* Version Change */ + type_str = "Version Change"; + if (evt[12] == 0x70) { /*event trigger/type */ + switch(evt[13]) { /*data1/offset*/ + case 0x00: pstr = "Update started"; break; + case 0x01: pstr = "Update completed"; break; + case 0x02: pstr = "Update failed"; sevid = SEV_MIN; break; + default: pstr = "-"; break; + } + 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_intel*/ +#endif + +const struct valstr intel_mem_s2600[] = { + { 0, "DIMM_A1" }, + { 1, "DIMM_A2" }, + { 2, "DIMM_A3" }, + { 3, "DIMM_B1" }, + { 4, "DIMM_B2" }, + { 5, "DIMM_B3" }, + { 6, "DIMM_C1" }, + { 7, "DIMM_C2" }, + { 8, "DIMM_C3" }, + { 9, "DIMM_D1" }, + { 10, "DIMM_D2" }, + { 11, "DIMM_D3" }, + { 12, "DIMM_E1" }, + { 13, "DIMM_E2" }, + { 14, "DIMM_E3" }, + { 15, "DIMM_F1" }, + { 16, "DIMM_F2" }, + { 17, "DIMM_F3" }, + { 18, "DIMM_G1" }, + { 19, "DIMM_G2" }, + { 20, "DIMM_G3" }, + { 21, "DIMM_H1" }, + { 22, "DIMM_H2" }, + { 23, "DIMM_H3" }, + { 24, "DIMM_I1" }, + { 25, "DIMM_I2" }, + { 26, "DIMM_I3" }, + { 27, "DIMM_J1" }, + { 28, "DIMM_J2" }, + { 29, "DIMM_J3" }, + { 30, "DIMM_K1" }, + { 31, "DIMM_K2" }, + { 32, "DIMM_K3" }, + { 33 , NULL } /*end of list*/ +}; + +const struct valstr intel_mem_s5520ur[] = { + { 0, "DIMM_A1" }, + { 1, "DIMM_A2" }, + { 2, "DIMM_B1" }, + { 3, "DIMM_B2" }, + { 4, "DIMM_C1" }, + { 5, "DIMM_C2" }, + { 6, "DIMM_D1" }, + { 7, "DIMM_D2" }, + { 8, "DIMM_E1" }, + { 9, "DIMM_E2" }, + { 10, "DIMM_F1" }, + { 11, "DIMM_F2" }, + { 12 , NULL } /*end of list*/ +}; +const struct valstr intel_mem_s5000phb[] = { + { 0, "DIMM_A1" }, + { 1, "DIMM_A2" }, + { 2, "DIMM_A3" }, + { 3, "DIMM_B1" }, + { 4, "DIMM_B2" }, + { 5, "DIMM_B3" }, + { 6 , NULL } /*end of list*/ +}; +const struct valstr intel_mem_s5000pal[] = { + { 0, "DIMM_A1" }, + { 1, "DIMM_A2" }, + { 2, "DIMM_B1" }, + { 3, "DIMM_B2" }, + { 4, "DIMM_C1" }, + { 5, "DIMM_C2" }, + { 6, "DIMM_D1" }, + { 7, "DIMM_D2" }, + { 8 , NULL } /*end of list*/ +}; +const struct valstr intel_mem_tigi2u[] = { + { 0, "DIMM_1B" }, + { 1, "DIMM_1A" }, + { 2, "DIMM_2B" }, + { 3, "DIMM_2A" }, + { 4, "DIMM_3B" }, + { 5, "DIMM_3A" }, + { 6 , NULL } /*end of list*/ +}; + +#define LIDS 8 +ushort lan2i_ids[LIDS] = { /*Intel prod_ids that use lan2i, rest use lan2*/ + 0x0000, /*uninitialized */ + 0x0022, /*TIGI2U */ + 0x0026, /*Bridgeport */ + 0x0028, /*S5000PAL, Alcolu*/ + 0x0029, /*S5000PSL, StarLake*/ + 0x002B, /*S5000VSA */ + 0x002D, /*ClearBay*/ + 0x0811 /*S5000PHB, TIGW1U*/ }; + +#define RIDS 21 /* Intel Romley product ids: */ +struct { ushort id; char *desc; } romleys[RIDS] = { + { 0x0048, "S1200BT" }, /* S1200BT, BearTooth Pass */ + { 0x0049, "S2600GL" }, /* S2600GL, S2600GZ */ + { 0x004A, "S2600CP" }, /* S2600CP, Canoe Pass */ + { 0x004D, "S2600JF" }, /* S2600JF, Jefferson Pass, Appro 512X */ + { 0x004E, "S2600WP" }, /* S2600WP */ + { 0x004F, "S2400SC" }, /* S2400SC */ + { 0x0050, "S2400LP" }, /* S2400LP */ + { 0x0051, "S2400EP" }, /* S2400EP, Eagle Pass */ + { 0x0052, "S1400FP" }, /* S1400FP */ + { 0x0053, "S1400SP" }, /* S1400SP */ + { 0x0054, "S2600KI" }, /* S2600KI */ + { 0x0055, "S2600IP" }, /* S2600IP, Iron Pass */ + { 0x0056, "W2600CR" }, /* W2600CR */ + { 0x0057, "S2400GP" }, /* S2400GP */ + { 0x0058, "Badger Pass" }, /* Badger Pass */ + { 0x0059, "S2400BB" }, /* S2400BB */ + { 0x005A, "Taylor Pass" }, /* Taylor Pass */ + { 0x005B, "S1600JP" }, /* S1600JP */ + { 0x005C, "S4600LH" }, /* S4600LH, Lizard Head Pass */ + { 0x005D, "CG2200" }, /* S2600CO, Copper Pass, Kontron CG2200 */ + { 0x005E, "Big Ridge"} /* Big Ridge */ +}; + +#define TIDS 5 +ushort thurley_ids[TIDS] = { /* Intel Thurley product ids: */ + 0x003A, /* Snow Hill */ + 0x003B, /* Shoffner */ + 0x003D, /* Melstone */ + 0x003E, /* S5520UR, S5500WB, Kontron CG2100, Penguin Computing Relion 700 */ + 0x0040 }; /* Stoutland, Quanta QSSC-S4R/Appro GB812X-CN (Nehalem-EX) */ + +int is_romley(int vend, int prod) +{ + int ret = 0; + int i; + if (vend != VENDOR_INTEL) return(ret); + for (i = 0; i < RIDS; i++) + if ((ushort)prod == romleys[i].id) { ret = 1; break; } + return(ret); +} + +int intel_romley_desc(int vend, int prod, char **pdesc) +{ + int ret = -1; + int i; + if (vend != VENDOR_INTEL) return(ret); + if (pdesc == NULL) return(ret); + for (i = 0; i < RIDS; i++) { + if ((ushort)prod == romleys[i].id) { + *pdesc = romleys[i].desc; + ret = 0; + break; + } + } + return(ret); +} + +int is_thurley(int vend, int prod) +{ + int ret = 0; + int i; + if (vend != VENDOR_INTEL) return(ret); + for (i = 0; i < TIDS; i++) + if ((ushort)prod == thurley_ids[i]) { ret = 1; break; } + return(ret); +} + +int is_lan2intel(int vend, int prod) +{ + int ret = 0; + int i; + if (vend != VENDOR_INTEL) return(ret); + if (is_thurley(vend,prod) || is_romley(vend,prod)) + ret = 0; /*iBMC does not use lan2i*/ + else { + for (i = 0; i < LIDS; i++) + if ((ushort)prod == lan2i_ids[i]) { ret = 1; break; } + } + return(ret); +} + +int decode_mem_intel(int prod, uchar b2, uchar b3, char *desc, int *psz) +{ + const char *pstr = NULL; + int array, dimm; + int node, chan, sock, n; + int rv = -1; + uchar bdata; + int vend; + int iBMC = 0; + + if ((desc == NULL) || (psz == NULL)) return -1; + + vend = VENDOR_INTEL; + if (is_thurley(vend,prod)) iBMC = 1; + if (is_romley(vend,prod)) iBMC = 2; + if (iBMC != 0) { + /* custom DIMM decoding for iBMC on Intel S5500 and S2600 */ + // rank = (b2 & 0x03); /* psel->event_data2 & 0x03; */ + node = (b3 & 0xE0) >> 5; /*socket*/ + chan = (b3 & 0x18) >> 3; + sock = (b3 & 0x07); + array = 0; /* is 0 for Thurley & Romley currently, else see b2. */ + if (iBMC == 1) dimm = (node * 6) + (chan * 2) + sock; + else dimm = (node * 12) + (chan * 3) + sock; + if (fdebug) printf("iBMC DIMM (%d,%d,%d) = idx %d\n", + node,chan,sock,dimm); + } else { /* use straight DIMM index */ + /* for mini-BMC, data2 is dimm index, data3 is syndrome */ + if (prod == 0x4311) bdata = b2; /*mini-BMC*/ + else if (b3 == 0xff) bdata = b2; /*ff is reserved*/ + else bdata = b3; /* normal case */ + /* (data3 & 0xc0) = SMBIOS type 16 mem array */ + array = (bdata & 0xc0) >> 6; + /* (data3 & 0x3f) = SMBIOS type 17 dimm index */ + dimm = bdata & 0x3f; + } + + if (! is_remote()) { + fsm_debug = fdebug; + rv = get_MemDesc(array,dimm,desc,psz); + /* if (rv != 0) desc has "DIMM[%d}" */ + } + if (rv != 0) { + /* either remote, or get_MemDesc failed, use common product defaults*/ + switch(prod) { + case 0x0811: /*S5000PHB*/ + pstr = val2str(dimm,intel_mem_s5000phb); + break; + case 0x0028: /*S5000PAL*/ + pstr = val2str(dimm,intel_mem_s5000pal); + break; + case 0x0022: /*TIGI2U*/ + pstr = val2str(dimm,intel_mem_tigi2u); + break; + default: + if (iBMC == 1) pstr = val2str(dimm,intel_mem_s5520ur); + else if (iBMC == 2) pstr = val2str(dimm,intel_mem_s2600); + else rv = -2; /*do not guess, use raw index below*/ + break; + } + if (pstr != NULL) rv = 0; + if (rv == 0) { + /* These strings are usually 7 chars, desc is 80 chars */ + n = strlen_(pstr); + strncpy(desc, pstr, n+1); + } else { + n = sprintf(desc,"DIMM[%d]",dimm); + } + *psz = n; + } + return(rv); +} /*end decode_mem_intel*/ + +/* + * decode_sensor_intel + * inputs: + * sdr = the SDR buffer + * reading = the 3 or 4 bytes of data from GetSensorReading + * pstring = points to the output string buffer + * slen = size of the output buffer + * outputs: + * rv = 0 if this sensor was successfully interpreted here, + * non-zero otherwise, to use default interpretations. + * pstring = contains the sensor reading interpretation string (if rv==0) + */ +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) { /*Compact SDR*/ + 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*/ + strncpy(pstring, pstr, slen); + rv = 0; + break; + case 0xDC: /* NM Capabilities sensor */ + rv = decode_sensor_intel_nm(sdr,reading,pstring,slen); + break; + default: + break; + } + } else if (sdr[3] == 0xC0) { /*OEM SDR*/ + rv = decode_sensor_intel_nm(sdr,reading,pstring,slen); + } + return(rv); +} + +const struct valstr intel_s5000_post[] = { /*from S5000 TPS*/ + { 0x0012, "CMOS date/time not set" }, + { 0x0048, "Password check failed" }, + { 0x004C, "Keyboard/interface error" }, + { 0x0108, "Keyboard locked error" }, + { 0x0109, "Keyboard stuck key error" }, + { 0x0113, "The SAS RAID firmware cannot run properly, reflash" }, + { 0x0140, "PCI PERR detected" }, + { 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, "Processor cache size mismatch" }, + { 0x0194, "Processor family mismatch" }, + { 0x0195, "Processor QPI speed 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" }, /*not used*/ + { 0x8111, "Proc2 internal error (IERR) on last boot" }, /*not used*/ + { 0x8120, "Proc1 thermal trip error on last boot" }, /*not used*/ + { 0x8121, "Proc2 thermal trip error on last boot" }, /*not used*/ + { 0x8130, "Proc1 disabled" }, /*not used*/ + { 0x8131, "Proc2 disabled" }, /*not used*/ + { 0x8140, "Proc1 Failed FRB-3 Timer" }, /*not used*/ + { 0x8141, "Proc2 Failed FRB-3 Timer" }, /*not used*/ + { 0x8160, "Proc1 unable to apply microcode update" }, + { 0x8161, "Proc2 unable to apply microcode update" }, + { 0x8170, "Proc1 failed Self Test (BIST)" }, /*not used*/ + { 0x8171, "Proc2 failed Self Test (BIST)" }, /*not used*/ + { 0x8180, "Processor microcode update not found" }, + { 0x8190, "Watchdog timer failed on last boot" }, + { 0x8198, "OS boot watchdog timer expired on last boot" }, + { 0x8300, "iBMC failed self-test" }, + { 0x8305, "Hotswap controller failure" }, + { 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_B1 failed Self Test (BIST)" }, + { 0x8523, "DIMM_B2 failed Self Test (BIST)" }, + { 0x8524, "DIMM_C1 failed Self Test (BIST)" }, + { 0x8525, "DIMM_C2 failed Self Test (BIST)" }, + { 0x8526, "DIMM_D1 failed Self Test (BIST)" }, + { 0x8527, "DIMM_D2 failed Self Test (BIST)" }, + { 0x8528, "DIMM_E1 failed Self Test (BIST)" }, + { 0x8529, "DIMM_E2 failed Self Test (BIST)" }, + { 0x852A, "DIMM_F1 failed Self Test (BIST)" }, + { 0x852B, "DIMM_F2 failed Self Test (BIST)" }, + { 0x8540, "DIMM_A1 Disabled" }, + { 0x8541, "DIMM_A2 Disabled" }, + { 0x8542, "DIMM_B1 Disabled" }, + { 0x8543, "DIMM_B2 Disabled" }, + { 0x8544, "DIMM_C1 Disabled" }, + { 0x8545, "DIMM_C2 Disabled" }, + { 0x8546, "DIMM_D1 Disabled" }, + { 0x8547, "DIMM_D2 Disabled" }, + { 0x8548, "DIMM_E1 Disabled" }, + { 0x8549, "DIMM_E2 Disabled" }, + { 0x854A, "DIMM_F1 Disabled" }, + { 0x854B, "DIMM_F2 Disabled" }, + { 0x8560, "DIMM_A1 SPD fail error." }, + { 0x8561, "DIMM_A2 SPD fail error" }, + { 0x8562, "DIMM_B1 SPD fail error" }, + { 0x8563, "DIMM_B2 SPD fail error" }, + { 0x8564, "DIMM_C1 SPD fail error" }, + { 0x8565, "DIMM_C2 SPD fail error" }, + { 0x8566, "DIMM_D1 SPD fail error" }, + { 0x8567, "DIMM_D2 SPD fail error" }, + { 0x8568, "DIMM_E1 SPD fail error" }, + { 0x8569, "DIMM_E2 SPD fail error" }, + { 0x856A, "DIMM_F1 SPD fail error" }, + { 0x856B, "DIMM_F2 SPD fail error" }, + { 0x8580, "DIMM_A1 Correctable ECC error" }, + { 0x8581, "DIMM_A2 Correctable ECC error" }, + { 0x8582, "DIMM_B1 Correctable ECC error" }, + { 0x8583, "DIMM_B2 Correctable ECC error" }, + { 0x8584, "DIMM_C1 Correctable ECC error" }, + { 0x8585, "DIMM_C2 Correctable ECC error" }, + { 0x8586, "DIMM_D1 Correctable ECC error" }, + { 0x8587, "DIMM_D2 Correctable ECC error" }, + { 0x8588, "DIMM_E1 Correctable ECC error" }, + { 0x8589, "DIMM_E2 Correctable ECC error" }, + { 0x858A, "DIMM_F1 Correctable ECC error" }, + { 0x858B, "DIMM_F2 Correctable ECC error" }, + { 0x85A0, "DIMM_A1 Uncorrectable ECC error" }, + { 0x85A1, "DIMM_A2 Uncorrectable ECC error" }, + { 0x85A2, "DIMM_B1 Uncorrectable ECC error" }, + { 0x85A3, "DIMM_B2 Uncorrectable ECC error" }, + { 0x85A4, "DIMM_C1 Uncorrectable ECC error" }, + { 0x85A5, "DIMM_C2 Uncorrectable ECC error" }, + { 0x85A6, "DIMM_D1 Uncorrectable ECC error" }, + { 0x85A7, "DIMM_D2 Uncorrectable ECC error" }, + { 0x85A8, "DIMM_E1 Uncorrectable ECC error" }, + { 0x85A9, "DIMM_E2 Uncorrectable ECC error" }, + { 0x85AA, "DIMM_F1 Uncorrectable ECC error" }, + { 0x85AB, "DIMM_F2 Uncorrectable ECC error" }, + { 0x8601, "BIOS Bank Override jumper set to lower bank" }, /*not used*/ + { 0x8602, "WatchDog timer expired (check secondary BIOS bank)" }, /*not used*/ + { 0x8603, "Secondary BIOS checksum fail" }, /*not used*/ + { 0x8604, "Chipset Reclaim of non critical variables complete" }, + { 0x9000, "Unspecified processor component error" }, + { 0x9223, "Keyboard was not detected" }, /*not used*/ + { 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" }, + { 0xA000, "TPM device not detected" }, + { 0xA001, "TPM device missing" }, + { 0xA002, "TPM device failure" }, + { 0xA003, "TPM device failed self-test" }, + { 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" }, + { 0xB6A3, "DXE driver unrecognized" }, + { 0xffff , NULL } /*end of list*/ +}; +const struct valstr intel_s2600_post[] = { /*from S2600CP 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" }, + { 0x0191, "Processor core/thread count mismatch" }, + { 0x0192, "Processor cache size mismatch" }, + { 0x0194, "Processor family mismatch" }, + { 0x0195, "Processor QPI speed 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" }, /*not used*/ + { 0x8111, "Proc2 internal error (IERR) on last boot" }, /*not used*/ + { 0x8120, "Proc1 thermal trip error on last boot" }, /*not used*/ + { 0x8121, "Proc2 thermal trip error on last boot" }, /*not used*/ + { 0x8130, "Proc1 disabled" }, /*not used*/ + { 0x8131, "Proc2 disabled" }, /*not used*/ + { 0x8140, "Proc1 Failed FRB-3 Timer" }, /*not used*/ + { 0x8141, "Proc2 Failed FRB-3 Timer" }, /*not used*/ + { 0x8160, "Proc1 unable to apply microcode update" }, + { 0x8161, "Proc2 unable to apply microcode update" }, + { 0x8170, "Proc1 failed Self Test (BIST)" }, /*not used*/ + { 0x8171, "Proc2 failed Self Test (BIST)" }, /*not used*/ + { 0x8180, "Processor microcode update not found" }, + { 0x8181, "Proc2 microcode update not found" }, + { 0x8190, "Watchdog timer failed on last boot" }, + { 0x8198, "OS boot watchdog timer expired on last boot" }, + { 0x8300, "iBMC failed self-test" }, + { 0x8305, "Hotswap controller failure" }, + { 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" }, + { 0x8501, "DIMM Population Error" }, + { 0x8520, "DIMM_A1 failed test/initialization" }, + { 0x8521, "DIMM_A2 failed test/initialization" }, + { 0x8522, "DIMM_A3 failed test/initialization" }, + { 0x8523, "DIMM_B1 failed test/initialization" }, + { 0x8524, "DIMM_B2 failed test/initialization" }, + { 0x8525, "DIMM_B3 failed test/initialization" }, + { 0x8526, "DIMM_C1 failed test/initialization" }, + { 0x8527, "DIMM_C2 failed test/initialization" }, + { 0x8528, "DIMM_C3 failed test/initialization" }, + { 0x8529, "DIMM_D1 failed test/initialization" }, + { 0x852A, "DIMM_D2 failed test/initialization" }, + { 0x852B, "DIMM_D3 failed test/initialization" }, + { 0x852C, "DIMM_E1 failed test/initialization" }, + { 0x852D, "DIMM_E2 failed test/initialization" }, + { 0x852E, "DIMM_E3 failed test/initialization" }, + { 0x852F, "DIMM_F1 failed test/initialization" }, + { 0x8530, "DIMM_F2 failed test/initialization" }, + { 0x8531, "DIMM_F3 failed test/initialization" }, + { 0x8532, "DIMM_G1 failed test/initialization" }, + { 0x8533, "DIMM_G2 failed test/initialization" }, + { 0x8534, "DIMM_G3 failed test/initialization" }, + { 0x8535, "DIMM_H1 failed test/initialization" }, + { 0x8536, "DIMM_H2 failed test/initialization" }, + { 0x8537, "DIMM_H3 failed test/initialization" }, + { 0x8538, "DIMM_I1 failed test/initialization" }, + { 0x8539, "DIMM_I2 failed test/initialization" }, + { 0x853A, "DIMM_I3 failed test/initialization" }, + { 0x853B, "DIMM_J1 failed test/initialization" }, + { 0x853C, "DIMM_J2 failed test/initialization" }, + { 0x853D, "DIMM_J3 failed test/initialization" }, + { 0x853E, "DIMM_K1 failed test/initialization" }, + { 0x853F, "DIMM_K2 failed test/initialization" }, + { 0x8540, "DIMM_A1 Disabled" }, + { 0x8541, "DIMM_A2 Disabled" }, + { 0x8542, "DIMM_A3 Disabled" }, + { 0x8543, "DIMM_B1 Disabled" }, + { 0x8544, "DIMM_B2 Disabled" }, + { 0x8545, "DIMM_B3 Disabled" }, + { 0x8546, "DIMM_C1 Disabled" }, + { 0x8547, "DIMM_C2 Disabled" }, + { 0x8548, "DIMM_C3 Disabled" }, + { 0x8549, "DIMM_D1 Disabled" }, + { 0x854A, "DIMM_D2 Disabled" }, + { 0x854B, "DIMM_D3 Disabled" }, + { 0x854C, "DIMM_E1 Disabled" }, + { 0x854D, "DIMM_E2 Disabled" }, + { 0x854E, "DIMM_E3 Disabled" }, + { 0x854F, "DIMM_F1 Disabled" }, + { 0x8550, "DIMM_F2 Disabled" }, + { 0x8551, "DIMM_F3 Disabled" }, + { 0x8552, "DIMM_G1 Disabled" }, + { 0x8553, "DIMM_G2 Disabled" }, + { 0x8554, "DIMM_G3 Disabled" }, + { 0x8555, "DIMM_H1 Disabled" }, + { 0x8556, "DIMM_H1 Disabled" }, + { 0x8557, "DIMM_H1 Disabled" }, + { 0x8558, "DIMM_I1 Disabled" }, + { 0x8559, "DIMM_I2 Disabled" }, + { 0x855A, "DIMM_I3 Disabled" }, + { 0x855B, "DIMM_J1 Disabled" }, + { 0x855C, "DIMM_J2 Disabled" }, + { 0x855D, "DIMM_J3 Disabled" }, + { 0x855E, "DIMM_K1 Disabled" }, + { 0x855F, "DIMM_K2 Disabled" }, + { 0x8560, "DIMM_A1 SPD fail error" }, + { 0x8561, "DIMM_A2 SPD fail error" }, + { 0x8562, "DIMM_A3 SPD fail error" }, + { 0x8563, "DIMM_B1 SPD fail error" }, + { 0x8564, "DIMM_B2 SPD fail error" }, + { 0x8565, "DIMM_B3 SPD fail error" }, + { 0x8566, "DIMM_C1 SPD fail error" }, + { 0x8567, "DIMM_C2 SPD fail error" }, + { 0x8568, "DIMM_C3 SPD fail error" }, + { 0x8569, "DIMM_D1 SPD fail error" }, + { 0x856A, "DIMM_D2 SPD fail error" }, + { 0x856B, "DIMM_D3 SPD fail error" }, + { 0x856C, "DIMM_E1 SPD fail error" }, + { 0x856D, "DIMM_E2 SPD fail error" }, + { 0x856E, "DIMM_E3 SPD fail error" }, + { 0x856F, "DIMM_F1 SPD fail error" }, + { 0x8570, "DIMM_F2 SPD fail error" }, + { 0x8571, "DIMM_F3 SPD fail error" }, + { 0x8572, "DIMM_G1 SPD fail error" }, + { 0x8573, "DIMM_G2 SPD fail error" }, + { 0x8574, "DIMM_G3 SPD fail error" }, + { 0x8575, "DIMM_H1 SPD fail error" }, + { 0x8576, "DIMM_H1 SPD fail error" }, + { 0x8577, "DIMM_H1 SPD fail error" }, + { 0x8578, "DIMM_I1 SPD fail error" }, + { 0x8579, "DIMM_I2 SPD fail error" }, + { 0x857A, "DIMM_I3 SPD fail error" }, + { 0x857B, "DIMM_J1 SPD fail error" }, + { 0x857C, "DIMM_J2 SPD fail error" }, + { 0x857D, "DIMM_J3 SPD fail error" }, + { 0x857E, "DIMM_K1 SPD fail error" }, + { 0x857F, "DIMM_K2 SPD fail error" }, + /* some missing here for DIMM_K3 thru DIMM_P3 */ + { 0x8604, "Chipset Reclaim of non critical variables complete" }, + { 0x8605, "BIOS settings are corrupt" }, + { 0x92A3, "Serial port was not detected" }, + { 0x92A9, "Serial port resource conflict error" }, + { 0xA000, "TPM device not detected" }, + { 0xA001, "TPM device missing" }, + { 0xA002, "TPM device failure" }, + { 0xA003, "TPM device failed self-test" }, + { 0xA100, "BIOS ACM errord" }, + { 0xA421, "PCI SERR detected" }, + { 0xA5A0, "PCI Express PERR" }, + { 0xA5A1, "PCI Express SERR" }, + { 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; + if (is_thurley(VENDOR_INTEL,prod)) /* S5520UR/T5520UR (CG2100 or NSN2U)*/ + poststr = val2str(code,intel_s5500_post); + else if (is_romley(VENDOR_INTEL,prod)) /* S2600CO, CG2200 */ + poststr = val2str(code,intel_s2600_post); + else switch(prod) { + case 0x0028: /*S5000PAL*/ + case 0x0029: /*S5000PSL*/ + case 0x0811: /*S5000PHB*/ + poststr = val2str(code,intel_s5000_post); + break; + default: break; + } + if (poststr != NULL) { + strncpy(outbuf, poststr, szbuf); + rv = 0; + } + return(rv); +} + +#define ENC_LED_SLEEP 50000 +#define ENC_RCMD_SLEEP 500000 + +int get_hsbp_version_intel(uchar *maj, uchar *min) +{ + uchar idata[8]; + uchar rdata[4]; + int rv, rlen, i; + uchar cc; + + *maj = 0; + *min = 0; + /* For Romley/CG2200 get HSBP FW Version */ + for (i = 0; i < 3; i++) { + idata[0] = 0x0A; // 0x0A + idata[1] = 0xD0; + idata[2] = 0x01; // return one byte of LED data + idata[3] = 0x0A; // HSBP Major version + rlen = sizeof(rdata); + rv = ipmi_cmd(MASTER_WRITE_READ, idata, 4, rdata, &rlen, &cc, fdebug); + if (rv == 0 && cc != 0) rv = cc; + os_usleep(0,ENC_LED_SLEEP); /* wait before re-reading values */ + if (rv == 0) { + *maj = rdata[0]; + break; + } + /*else retry reading it*/ + } + for (i = 0; i < 3; i++) { + idata[0] = 0x0A; // 0x0A + idata[1] = 0xD0; + idata[2] = 0x01; // return one byte of LED data + idata[3] = 0x0B; // HSBP Minor version + rlen = sizeof(rdata); + rv = ipmi_cmd(MASTER_WRITE_READ, idata, 4, rdata, &rlen, &cc, fdebug); + if (rv == 0 && cc != 0) rv = cc; + os_usleep(0,ENC_LED_SLEEP); /* wait before re-reading values */ + if (rv == 0) { + *min = rdata[0]; + break; + } + /*else retry reading it*/ + } + return (rv); +} + +static uchar rdisk_led_method = 0; /* 0=initial, 1=rcmd, 2=i2c */ +static uchar rdisk_led_override = 0x00; /*override is off by default*/ + +static int get_enc_leds_i2c(uchar *val) +{ + uchar idata[8]; + uchar rdata[4]; + int rv, rv2, rlen, i; + uchar cc; + + *val = 0; /*make sure to initialize the reading*/ + for (i = 0; i < 3; i++) { + /* For Romley/Patsburg get disk fault LED status */ + idata[0] = 0x0A; // 0x0A + idata[1] = 0xD0; + idata[2] = 0x01; // return one byte of LED data + idata[3] = 0x0E; // LED_Status + rlen = sizeof(rdata); + rv = ipmi_cmd(MASTER_WRITE_READ, idata, 4, rdata, &rlen, &cc, fdebug); + if (rv == 0 && cc != 0) rv = cc; + os_usleep(0,ENC_LED_SLEEP); /* wait before re-reading values */ + if (rv == 0) { + *val = rdata[0]; + break; + } + /*else retry reading the LED Status*/ + } + + /* get & save the override status for use in show() */ + idata[0] = 0x0A; // 0x0A + idata[1] = 0xD0; + idata[2] = 0x01; // return one byte of LED data + idata[3] = 0x0D; // LED_Override + rlen = sizeof(rdata); + rv2 = ipmi_cmd(MASTER_WRITE_READ, idata, 4, rdata, &rlen, &cc, fdebug); + if (rv2 == 0 && cc != 0) rv2 = cc; + if (rv2 == 0) rdisk_led_override = rdata[0]; + + return (rv); +} + +static int set_enc_override_i2c(uchar val) +{ + uchar idata[8]; + uchar rdata[4]; + int rv, rlen, i; + uchar cc; + + if (val != 0) val = 1; + for (i = 0; i < 3; i++) { + /* Set LED Override to 0=off or 1=on */ + idata[0] = 0x0A; // 0x0A bus + idata[1] = 0xD0; + idata[2] = 0x00; // return no data + idata[3] = 0x0D; // LED_Override + idata[4] = val; /* turn on override */ + rlen = sizeof(rdata); + rv = ipmi_cmd(MASTER_WRITE_READ, idata, 5, rdata, &rlen, &cc, fdebug); + if (rv == 0 && cc != 0) rv = cc; + os_usleep(0,ENC_LED_SLEEP); /* wait before next LED cmd */ + if (rv == 0) break; + } + return(rv); +} + +static int set_enc_leds_i2c(uchar val) +{ + uchar idata[8]; + uchar rdata[4]; + int rv, rv2, rlen, i; + uchar cc; + + if ((val != 0) && (rdisk_led_override == 0)) { + /* setting some LED, so set disk led override*/ + rv2 = set_enc_override_i2c(1); + } + + for (i = 0; i < 3; i++) { + /* For Romley/Patsburg set disk fault LED status */ + idata[0] = 0x0A; // 0x0A bus + idata[1] = 0xD0; + idata[2] = 0x00; // return one byte of LED data + idata[3] = 0x0E; // LED_Status + idata[4] = val; + rlen = sizeof(rdata); + rv = ipmi_cmd(MASTER_WRITE_READ, idata, 5, rdata, &rlen, &cc, fdebug); + if ((rv == 0) && (cc != 0)) rv = cc; + os_usleep(0,ENC_LED_SLEEP); /* wait before next LED cmd */ + if (rv == 0) break; + } + + if (val == 0x00) { /* clear the disk led override */ + rv2 = set_enc_override_i2c(0); + } + return (rv); +} + +void show_enc_leds_i2c(uchar val, int numd) +{ + char *enc_pattn = "disk slot %d LED: %s %s\n"; + char *pstat; + char *pover; + uchar mask; + int i; + if (fdebug) printf("leds = %02x override = %02x\n",val,rdisk_led_override); + /* Some backplanes support 6 slots, but max is 8. */ + if (numd > 8) numd = 8; + mask = 0x01; + for (i = 0; i < numd; i++) { + if (val & mask) pstat = "ON"; + else pstat = "off"; + if (rdisk_led_override) pover = "(override)"; + else pover = ""; + printf(enc_pattn,i,pstat,pover); + mask = (mask << 1); + } +} + +static int set_enc_override_rcmd(uchar val) +{ + rdisk_led_override = val; + return(0); +} + +static int get_enc_leds_rcmd(uchar *val) +{ + uchar rdata[8]; + uchar slot[12]; + int rv, rlen, i; + uchar cc; + uchar v = 0; + + /* This command is only supported on Intel Romley w BMC >= 1.10 */ + for (i = 0; i < 12; i++) slot[i] = 0; + rlen = sizeof(rdata); + rv = ipmi_cmdraw(0x65, 0x30, g_sa,g_bus,g_lun, + NULL, 0, rdata, &rlen, &cc, fdebug); + if (fdebug) printf("get_enc_leds_rcmd: rv = %d, cc=%02x\n", rv,cc); + if ((rv == 0) && (cc != 0)) rv = cc; + if (rv == 0) { + rdisk_led_override = (rdata[0] & 0x07); +/* +rdata[1]: Slot 1 to 4 status + [7:6]Slot4 status + 00-Off + 01-Locate (Amber 4HZ) + 10-Fail (Amber solid on) + 11-Rebuild (Amber 1HZ) + [5:4] Slot3 status + 00-Off + 01-Locate (Amber 4HZ) + 10-Fail (Amber solid on) + 11-Rebuild (Amber 1HZ) + [3:2] Slot2 status + 00-Off + 01-Locate (Amber 4HZ) + 10-Fail (Amber solid on) + 11-Rebuild (Amber 1HZ) + [1:0] Slot1 status + 00-Off + 01-Locate (Amber 4HZ) + 10-Fail (Amber solid on) + 11-Rebuild (Amber 1HZ) + */ + if (rdata[1] & 0x02) slot[0] = 1; + if (rdata[1] & 0x08) slot[1] = 1; + if (rdata[1] & 0x20) slot[2] = 1; + if (rdata[1] & 0x80) slot[3] = 1; + if (rdata[2] & 0x02) slot[4] = 1; + if (rdata[2] & 0x08) slot[5] = 1; + if (rdata[2] & 0x20) slot[6] = 1; + if (rdata[2] & 0x80) slot[7] = 1; + if (rdata[3] & 0x02) slot[8] = 1; + if (rdata[3] & 0x08) slot[9] = 1; + if (rdata[3] & 0x20) slot[10] = 1; + if (rdata[3] & 0x80) slot[11] = 1; + } + for (i = 0; i < 8; i++) { + if (slot[i] == 1) v |= (1 << i); + } + *val = v; + return(rv); +} + +static int set_enc_leds_rcmd(uchar val) +{ + uchar idata[8]; + uchar rdata[4]; + int rlen, rv; + uchar cc; + + if ((val != 0) && (rdisk_led_override == 0)) + set_enc_override_rcmd(1); + + /* This command is only supported on Intel Romley w BMC >= 1.10 */ + idata[0] = rdisk_led_override; + idata[1] = val; /*first 8 slots*/ + idata[2] = 0; + idata[3] = 0; + rlen = sizeof(rdata); + rv = ipmi_cmdraw(0x64, 0x30, g_sa,g_bus,g_lun, + idata, 4, rdata, &rlen, &cc, fdebug); + if (fdebug) printf("set_enc_leds_rcmd: rv = %d, cc=%02x\n", rv,cc); + if ((rv == 0) && (cc != 0)) rv = cc; + if (rv == 0) os_usleep(0,ENC_RCMD_SLEEP); + + if ((rv == 0) && (val == 0)) { /*repeat with override off*/ + os_usleep(1,0); /* wait before next LED cmd */ + idata[0] = 0; + idata[1] = val; + idata[2] = 0; + idata[3] = 0; + rlen = sizeof(rdata); + rv = ipmi_cmdraw(0x64, 0x30, g_sa,g_bus,g_lun, + idata, 4, rdata, &rlen, &cc, fdebug); + if (fdebug) printf("set_enc_leds_rcmd0: rv = %d, cc=%02x\n", rv,cc); + if ((rv == 0) && (cc != 0)) rv = cc; + if (rv == 0) os_usleep(0,ENC_RCMD_SLEEP); + set_enc_override_rcmd(0); + } + os_usleep(1,0); /* wait before next LED cmd */ + return(rv); +} + +static void show_enc_leds_rcmd(uchar val, int numd) +{ + char *enc_pattn = "disk slot %d LED: %s %s\n"; + char *pstat; + char *pover; + uchar mask; + int i; + if (fdebug) printf("leds = %02x override = %02x\n",val,rdisk_led_override); + /* Some backplanes support 6 slots, but max is 8. */ + if (numd > 8) numd = 8; + mask = 0x01; + for (i = 0; i < numd; i++) { + if (val & mask) pstat = "ON"; + else pstat = "off"; + if (rdisk_led_override) pover = "(override)"; + else pover = ""; + printf(enc_pattn,i,pstat,pover); + mask = (mask << 1); + } +} + +int set_enc_override_intel(uchar val) +{ + int rv; + if (rdisk_led_method == 1) rv = set_enc_override_rcmd(val); + else rv = set_enc_override_i2c(val); + return(rv); +} + +int get_enc_leds_intel(uchar *val) +{ + int rv = -1; + if (rdisk_led_method < 2) rv = get_enc_leds_rcmd(val); + if ((rv != 0) && (rdisk_led_method == 0)) rdisk_led_method = 2; + if (rdisk_led_method == 2) rv = get_enc_leds_i2c(val); + return(rv); +} + +int set_enc_leds_intel(uchar val) +{ + int rv = -1; + if (rdisk_led_method < 2) rv = set_enc_leds_rcmd(val); + if ((rv != 0) && (rdisk_led_method == 0)) rdisk_led_method = 2; + if (rdisk_led_method == 2) rv = set_enc_leds_i2c(val); + return(rv); +} + +void show_enc_leds_intel(uchar val, int numd) +{ + if (rdisk_led_method == 1) show_enc_leds_rcmd(val, numd); + else show_enc_leds_i2c(val, numd); +} + +/* end oem_intel.c */ |