diff options
Diffstat (limited to 'util/ihealth.c')
-rw-r--r-- | util/ihealth.c | 1153 |
1 files changed, 1153 insertions, 0 deletions
diff --git a/util/ihealth.c b/util/ihealth.c new file mode 100644 index 0000000..6f6f0e1 --- /dev/null +++ b/util/ihealth.c @@ -0,0 +1,1153 @@ +/* + * ihealth.c (was bmchealth.c) + * + * This tool checks the health of the BMC via IPMI. + * + * Author: Andy Cress arcress at users.sourceforge.net + * Copyright (c) 2006 Intel Corporation. + * Copyright (c) 2009 Kontron America, Inc. + * + * 03/22/06 Andy Cress - created + * 06/20/06 Andy Cress 0.6 - more vendor strings, add ping_node() stub for now + * 10/20/06 Andy Cress 1.1 - added -g for guid + * 01/10/07 Andy Cress 1.4 - added product strings + * 02/25/07 Andy Cress 2.8 - added more Chassis Status decoding + */ +/*M* +Copyright (c) 2006, Intel Corporation +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 Intel Corporation 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*/ +#ifdef WIN32 +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include "getopt.h" +#elif defined(DOS) +#include <dos.h> +#include <stdio.h> +#include <stdlib.h> +#include "getopt.h" +#else +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#else +#include <getopt.h> +#endif +#endif +#include <string.h> +#include "ipmicmd.h" +#include "oem_intel.h" + +#define SELFTEST_STATUS 0x04 +#define GET_POWER_STATE 0x07 +extern int get_BiosVersion(char *str); +extern int get_SystemGuid(uchar *guid); +extern int GetSDR(int id, int *next, uchar *recdata, int srecdata, int *rlen); +extern int get_device_guid(char *pbuf, int *sz); /*subs.c*/ +extern int oem_supermicro_get_health(char *pstr, int sz); /*oem_supermicro.c*/ +extern int oem_supermicro_get_firmware_str(char *pstr, int sz); /*oem_supermicro.c*/ + +/* + * Global variables + */ +static char * progname = "ihealth"; +static char * progver = "2.93"; +static char fdebug = 0; +static char fipmilan = 0; +static char fcanonical = 0; +static char do_hsc = 0; +static char do_me = 0; +static char do_frusdr = 0; +static char do_guid = 0; +static char do_powerstate = 1; +static char do_lanstats = 0; +static char do_session = 0; +static char do_systeminfo = 0; +static char set_restore = 0; +static char set_name = 0; +static char set_os = 0; +static char set_os2 = 0; +static uchar restore_policy = 0; +static uchar bChan = 0x0e; +static char fmBMC = 0; +static char bdelim = '='; /*delimiter to separate name/value pairs*/ +static char bcomma = ','; /*comma delimiter, may change if CSV*/ +static char lan_ch_restrict = 0; +static int kcs_loops = 0; +static int vend_id = 0; +static int prod_id = 0; +static char *pname = NULL; +static char *pos = NULL; +static char *pos2 = NULL; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = BMC_SA; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; + + +int oem_get_health(char *pstr, int sz) +{ + int rv; + switch(vend_id) { + case VENDOR_PEPPERCON: + case VENDOR_SUPERMICRO: + rv = oem_supermicro_get_health(pstr, sz); + break; + case VENDOR_SUPERMICROX: + rv = oem_supermicro_get_firmware_str(pstr,sz); + break; + default: + rv = LAN_ERR_NOTSUPPORT; + break; + } + if (fdebug) printf("oem_get_health rv = %d\n",rv); + return rv; +} + +int get_lan_stats(uchar chan) +{ + uchar idata[2]; + uchar rdata[20]; + int rlen, rv; + uchar cc; + ushort *rw; + + /* get BMC LAN Statistics */ + idata[0] = chan; + idata[1] = 0x00; /*do not clear stats*/ + rlen = sizeof(rdata); + rv = ipmi_cmd(GET_LAN_STATS, idata,2, rdata,&rlen, &cc, fdebug); + if (fdebug) printf("get_lan_stats: rv = %d, cc = %02x\n",rv,cc); + if (rv == 0) { + if (cc == 0) { /*success, show BMC LAN stats*/ + rw = (ushort *)&rdata[0]; + printf("IPMI LAN channel %d statistics: \n",chan); + printf(" \tReceived IP Packets %c %d\n",bdelim,rw[0]); + printf(" \tRecvd IP Header errors %c %d\n",bdelim,rw[1]); + printf(" \tRecvd IP Address errors %c %d\n",bdelim,rw[2]); + printf(" \tRecvd IP Fragments %c %d\n",bdelim,rw[3]); + printf(" \tTransmitted IP Packets %c %d\n",bdelim,rw[4]); + printf(" \tReceived UDP Packets %c %d\n",bdelim,rw[5]); + printf(" \tReceived Valid RMCP Pkts %c %d\n",bdelim,rw[6]); + printf(" \tReceived UDP Proxy Pkts %c %d\n",bdelim,rw[7]); + printf(" \tDropped UDP Proxy Pkts %c %d\n",bdelim,rw[8]); + } else if (cc == 0xc1) { + printf("IPMI LAN channel %d statistics: not supported\n",chan); + } + } + return(rv); +} + +int get_session_info(uchar idx, int hnd, uchar *rdata, int *len) +{ + uchar idata[5]; + int ilen, rlen, rv; + uchar cc; + + ilen = 1; + idata[0] = idx; + if (idx == 0xFE) { + idata[1] = (uchar)hnd; + ilen = 2; + } else if (idx == 0xFF) { + idata[1] = (uchar)(hnd & 0x000000FF); + idata[2] = (uchar)((hnd & 0x0000FF00) >> 8); + idata[3] = (uchar)((hnd & 0x00FF0000) >> 16); + idata[4] = (uchar)((hnd & 0xFF000000) >> 24); + ilen = 5; + } + rlen = *len; + *len = 0; + rv = ipmi_cmdraw(CMD_GET_SESSION_INFO,NETFN_APP, + g_sa, g_bus, g_lun, + idata,ilen, rdata,&rlen,&cc, fdebug); + if (fdebug) printf("get_lan_stats: rv = %d, cc = %02x\n",rv,cc); + if (rv == 0) *len = rlen; + if ((rv == 0) && (cc != 0)) rv = cc; + return(rv); +} + +static char *sesstype_str(uchar c) +{ + uchar b; + char *s; + b = ((c & 0xf0) >> 4); + switch(b) { + case 0: s = "IPMIv1.5"; break; + case 1: s = "IPMIv2/RMCP+"; break; + default: s = "Other"; break; + } + return s; +} + +static void show_session_info(uchar idx, uchar *sinfo,int len) +{ + int i; + char lan_type = 1; + if (fdebug) { + printf("Raw Session Info[%d]: ",idx); + for (i = 0; i < len; i++) printf("%02x ",sinfo[i]); + printf("\n"); + } + + printf("Session Info[%d]:\n",idx); + printf("\tSession Handle %c %d\n",bdelim,sinfo[0]); + printf("\tSession Slot Count %c %d\n",bdelim,(sinfo[1] & 0x3f)); + printf("\tActive Sessions %c %d\n",bdelim,(sinfo[2] & 0x3f)); + if (len <= 3) return; + printf("\tUser ID %c %d\n",bdelim,(sinfo[3] & 0x3f)); + printf("\tPrivilege Level %c %d\n",bdelim,(sinfo[4] & 0x0f)); + printf("\tSession Type %c %s\n",bdelim,sesstype_str(sinfo[5])); + printf("\tChannel Number %c %d\n",bdelim,(sinfo[5] & 0x0f)); + if (len <= 6) return; + if (lan_type) { + printf("\tConsole IP %c %d.%d.%d.%d\n",bdelim, + sinfo[6],sinfo[7],sinfo[8],sinfo[9]); + printf("\tConsole MAC %c %02x:%02x:%02x:%02x:%02x:%02x\n",bdelim, + sinfo[10], sinfo[11], sinfo[12], + sinfo[13], sinfo[14], sinfo[15]); + printf("\tConsole Port %c %d\n",bdelim, + sinfo[16]+ (sinfo[17] << 8)); + } +} + +int get_session_info_all(void) +{ + int rv, len, nslots, i; + uchar sinfo[24]; + nslots = 1; + for (i = 1; i <= nslots; i++) { + len = sizeof(sinfo); + rv = get_session_info(i,0,sinfo,&len); + if (fdebug) printf("get_session_info(%d): rv = %d\n",i,rv); + if (rv != 0) { + if ((rv == 0xCB) || (rv == 0xCC)) { + if (len >= 3) show_session_info(i,sinfo,len); + if (i > 1) rv = 0; /*no such idx, end */ + } + break; + } + nslots = (sinfo[1] & 0x3F); + show_session_info(i,sinfo,len); + } + return(rv); +} + +static int get_selftest_status(uchar *rdata, int rlen) +{ + uchar idata[4]; + uchar ccode; + int ret; + + ret = ipmi_cmdraw( SELFTEST_STATUS, NETFN_APP, + g_sa, g_bus, g_lun, + idata,0, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + return(ret); +} /*end get_selftest_status()*/ + +static int get_last_selftest(uchar *val, int vlen) +{ + uchar idata[4]; + uchar rdata[16]; + int rlen; + uchar ccode; + int ret; + + if (val == NULL) return(ERR_BAD_PARAM); + idata[0] = 0; /*0=first, 1=next*/ + memset(rdata,0xFF,2); /*initial value = end-of-list*/ + rlen = sizeof(rdata); + ret = ipmi_cmdraw( 0x16, 0x30, g_sa, g_bus, g_lun, + idata,1, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + if (ret == 0) { + if (rlen <= 0) ret = LAN_ERR_BADLENGTH; + else { + if (rlen > vlen) rlen = vlen; /*truncate if too long*/ + memcpy(val,rdata,rlen); + } + } + return(ret); +} + +static int get_chassis_status(uchar *rdata, int *rsz) +{ + uchar idata[4]; + uchar ccode; + int rlen; + int ret; + + rlen = *rsz; + ret = ipmi_cmdraw( CHASSIS_STATUS, NETFN_CHAS, + g_sa, g_bus, g_lun, + idata,0, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + if (ret == 0) *rsz = rlen; + return(ret); +} /*end chassis_status()*/ + +static void show_chs_status(uchar *sbuf, int slen) +{ + char chs_strbuf[80]; + char *pstr; + uchar state, b2, b3, b4; + + pstr = &chs_strbuf[0]; + state = sbuf[0] & 0x7f; + b2 = sbuf[1]; + b3 = sbuf[2]; + sprintf(pstr,"%s",(state & 0x01) ? "on" : "off"); + printf("Chassis Status %c %02x %02x %02x %02x (%s, see below)\n", + bdelim,state,sbuf[1],sbuf[2],sbuf[3],pstr); + sprintf(pstr,"\tchassis_power %c ",bdelim); + if (state & 0x01) strcat(pstr,"on"); + else strcat(pstr,"off"); + if (state & 0x02) strcat(pstr,", overload"); + if (state & 0x04) strcat(pstr,", interlock"); + if (state & 0x08) strcat(pstr,", fault"); + if (state & 0x10) strcat(pstr,", control error"); + printf("%s\n",pstr); + + sprintf(pstr,"\tpwr_restore_policy %c ",bdelim); + if (state & 0x20) strcat(pstr,"last_state"); + else if (state & 0x40) strcat(pstr,"turn_on"); + else strcat(pstr,"stay_off"); + printf("%s\n",pstr); + + if (b2 != 0) { + sprintf(pstr,"\tlast_power_event %c ",bdelim); + if (b2 & 0x10) strcat(pstr,"IPMI "); + if (b2 & 0x08) strcat(pstr,"fault "); + if (b2 & 0x04) strcat(pstr,"interlock "); + if (b2 & 0x02) strcat(pstr,"overload "); + if (b2 & 0x01) strcat(pstr,"ACfailed"); + printf("%s\n",pstr); + } + printf("\tchassis_intrusion %c %s\n", bdelim, + (b3 & 0x01) ? "active":"inactive"); + printf("\tfront_panel_lockout %c %s\n", bdelim, + (b3 & 0x02) ? "active":"inactive"); + printf("\tdrive_fault %c %s\n", bdelim, + (b3 & 0x04) ? "true":"false"); + printf("\tcooling_fan_fault %c %s\n", bdelim, + (b3 & 0x08) ? "true":"false"); + if (slen > 3) { + b4 = sbuf[3]; + if (b4 & 0x80) { + printf("\tFP sleep_button_disable %c allowed, button %s\n",bdelim, + (b4 & 0x08) ? "disabled":"enabled"); + } + if (b4 & 0x40) { + printf("\tFP diag_button_disable %c allowed, button %s\n",bdelim, + (b4 & 0x04) ? "disabled":"enabled"); + } + if (b4 & 0x20) { + printf("\tFP reset_button_disable %c allowed, button %s\n",bdelim, + (b4 & 0x02) ? "disabled":"enabled"); + } + if (b4 & 0x10) { + printf("\tFP power_button_disable %c allowed, button %s\n",bdelim, + (b4 & 0x01) ? "disabled":"enabled"); + } + } + return; +} + +static int get_power_state(uchar *rdata, int rlen) +{ + uchar idata[4]; + uchar ccode; + int ret; + + ret = ipmi_cmdraw( GET_POWER_STATE, NETFN_APP, + g_sa, g_bus, g_lun, + idata,0, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + return(ret); +} /*end get_power_state()*/ + +static char *pwr_string(uchar pstate) +{ + char *pstr; + switch(pstate) { + case 0x00: pstr = "S0: working"; break; + case 0x01: pstr = "S1: clock stopped, context ok"; break; + case 0x02: pstr = "S2: clock stopped, context lost"; break; + case 0x03: pstr = "S3: suspend-to-RAM"; break; + case 0x04: pstr = "S4: suspend-to-Disk"; break; + case 0x05: pstr = "S5: soft off"; break; + case 0x06: pstr = "S4/S5: soft off, either S4 or S5"; break; + case 0x07: pstr = "G3: mechanical off"; break; + case 0x08: pstr = "S1-S3: sleeping"; break; + case 0x09: pstr = "S1-S4: sleeping"; break; + case 0x0A: pstr = "S5/o: soft off by override"; break; + case 0x20: pstr = "legacy on"; break; + case 0x21: pstr = "legacy soft-off"; break; + case 0x2a: /* not initialized or device lost track of state */ + default: pstr = "unknown"; break; + } + return(pstr); +} + +#ifdef PING_OK +extern int ping_bmc(char *node, char fdebug); + +static int ping_node(char *node) +{ + int rv = 0; + /* verify that the BMC LAN channel is configured & active */ + /* send rmcp_ping to node's BMC */ + rv = ping_bmc(node,fdebug); + return(rv); +} +#endif + +#define MIN_SDR_SZ 8 +static int get_frusdr_version(char *pver, int sver) +{ + ushort recid; + int recnext; + int ret, sz, i, len; + uchar sdr[MAX_BUFFER_SIZE]; + char verstr[30]; + char fIntel; + int verlen; + + recid = 0; + verstr[0] = 0; + verlen = 0; + while (recid != 0xffff) + { + memset(sdr,0,sizeof(sdr)); + ret = GetSDR(recid,&recnext,sdr,sizeof(sdr),&sz); + if (fdebug) + printf("GetSDR[%04x]: ret = %x, next=%x\n",recid,ret,recnext); + if (ret != 0) { + if (ret > 0) { /* ret is a completion code error */ + if (fdebug) + printf("%04x GetSDR error 0x%02x %s, rlen=%d\n",recid,ret, + decode_cc((ushort)0,(uchar)ret),sz); + } else printf("%04x GetSDR error %d, rlen = %d\n", recid,ret,sz); + if (sz < MIN_SDR_SZ) { /* don't have recnext, so abort */ + break; + } /* else fall through & continue */ + } else { /*got SDR */ + len = sdr[4] + 5; + if (sdr[3] == 0xC0) { /* OEM SDR */ + /* check for Intel mfg id */ + if ((sdr[5] == 0x57) && (sdr[6] == 0x01) && (sdr[7] == 0x00)) + fIntel = 1; + else fIntel = 0; + if (sdr[8] == 0x53) { /*Intel OEM subtype, ASCII 'S' */ + verlen = 0; + for (i = 8; i < len; i++) { + if (sdr[i] == 0) break; + if (i >= sizeof(verstr)) break; + verstr[verlen++] = sdr[i]; + } + verstr[verlen] = 0; /*stringify*/ + /* continue on past SDR File, get SDR Package version */ + // break; + } + } /*endif OEM SDR*/ + } + if (recnext == recid) recid = 0xffff; /*break;*/ + else recid = (ushort)recnext; + } + if (verlen > sver) verlen = sver; + if (fdebug) + printf("get_frusdr_version: verstr=%s, verlen=%d\n",verstr,verlen); + strncpy(pver,verstr,verlen); + return(ret); +} + +static int get_hsc_devid(uchar *rdata, int rlen) +{ + uchar ccode; + int ret; + + ret = ipmi_cmdraw( 0x01, /*(GET_DEVICEID & 0x00ff)*/ + NETFN_APP, 0xC0,PUBLIC_BUS,BMC_LUN, + NULL,0, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + return(ret); +} /*end get_hsc_devid*/ + +static int get_chan_auth(uchar chan, uchar *rdata, int rlen) +{ + uchar idata[4]; + uchar ccode; + int ret; + + idata[0] = chan; /*0x0e = this channel*/ + idata[1] = 0x02; /*priv level = user*/ + ret = ipmi_cmdraw( 0x38, NETFN_APP, /*CMD_GET_CHAN_AUTH_CAP*/ + g_sa, g_bus, g_lun, + idata,2, rdata,&rlen,&ccode, fdebug); + if (ret == 0 && ccode != 0) ret = ccode; + return(ret); +} /*end get_chan_auth*/ + +void show_chan_auth(char *tag, uchar *rec, int srec) +{ + char pstr[40]; + pstr[0] = 0; + if (rec[1] & 0x01) strcat(pstr,"None "); + if (rec[1] & 0x02) strcat(pstr,"MD2 "); + if (rec[1] & 0x04) strcat(pstr,"MD5 "); + if (rec[1] & 0x10) strcat(pstr,"Straight_Passwd "); + if (rec[1] & 0x20) strcat(pstr,"OEM "); + printf("Chan %d AuthTypes %c %s\n",rec[0],bdelim,pstr); + if (do_hsc) /*only show this if extra output*/ + printf("Chan %d Status %c %02x, OEM ID %02x%02x%02x OEM Aux %02x\n", + rec[0],bdelim,rec[2],rec[4],rec[5],rec[6],rec[7]); +} + +#define BMC 1 +#define HSC 2 + +#ifdef MOVED +/* moved to subs.c*/ +#define N_MFG 41 +struct { int val; char *pstr; } mfgs[N_MFG] = { }; +char * get_iana_str(int mfg); +#endif + +char * get_mfg_str(uchar *rgmfg, int *pmfg) +{ + char *mfgstr = ""; + int mfg; + mfg = rgmfg[0] + (rgmfg[1] << 8) + (rgmfg[2] << 16); + if (pmfg != NULL) *pmfg = mfg; /*vend_id*/ + mfgstr = get_iana_str(mfg); + return(mfgstr); +} + +/* int get_system_info(uchar parm, char *pbuf, int *szbuf); *see subs.c*/ +/* int set_system_info(uchar parm, uchar *pbuf, int *szbuf); *see subs.c*/ + +void show_devid_all(int dtype, uchar *devrec, int sdevrec) +{ + uchar ipmi_maj = 0; + uchar ipmi_min = 0; + char *tag; + int mfg, prod; + char *mfgstr = ""; + char *prodstr = ""; + char prodoem[40]; + char extraver[32]; + int i, j, k, l, rv; + + ipmi_maj = devrec[4] & 0x0f; + ipmi_min = devrec[4] >> 4; + prod = devrec[9] + (devrec[10] << 8); + mfgstr = get_mfg_str(&devrec[6],&mfg); + vend_id = mfg; + prod_id = prod; + extraver[0] = 0; + if (dtype == HSC) tag = "HSC"; + else { + tag = "BMC"; + /* The product ids below only apply to BMCs */ + switch(mfg) { + case VENDOR_NSC: /*=0x000322*/ + fmBMC = 1; + if (dtype == BMC) tag="mBMC"; + if (prod == 0x4311) prodstr = "(TIGPT1U)"; /*Intel*/ + break; + case VENDOR_SUN: /*=0x00002a*/ + if (prod == 0x4701) prodstr = "(X4140)"; + break; + case VENDOR_TYAN: /*=0x0019fd*/ + switch(prod) { /* show product names for some */ + case 0x0b41: prodstr = "(M3289)"; break; + case 0x0f98: prodstr = "(M3291)"; break; + case 0x137d: prodstr = "(S4989)"; break; + case 0x13ee: prodstr = "(S5102)"; break; + case 0x14fc: prodstr = "(S5372)"; break; + default: prodstr = ""; break; + } + break; + case VENDOR_FUJITSU: /*=0x002880*/ + if (prod >= 0x200) prodstr = "(iRMC S2)"; + else prodstr = ""; + break; + case VENDOR_CISCO: /*=0x00168b*/ + if (prod == 0x0005) prodstr = "(UCS C200)"; + else prodstr = ""; + if (fipmilan) lan_ch_restrict = 1; /*fw bug, gets 0xC1 on ipmilan*/ + break; + case VENDOR_INTEL: /*=0x000157*/ + if (do_hsc && (dtype == BMC)) /*if HSC option, also show extra*/ + sprintf(extraver," (Boot %x.%x PIA %x.%x)", /*BMC extra*/ + devrec[11],devrec[12],devrec[13],devrec[14]); + switch(prod) { /* show product names for some */ + case 0x000C: prodstr = "(TSRLT2)"; /*SCB2*/ + bChan = 7; break; + case 0x001B: prodstr = "(TIGPR2U)"; /*SWV2*/ + bChan = 7; break; + case 0x0022: prodstr = "(TIGI2U)"; break; /*SJR2*/ + case 0x0026: prodstr = "(Bridgeport)"; break; + case 0x0028: prodstr = "(S5000PAL)"; break; /*Alcolu*/ + case 0x0029: prodstr = "(S5000PSL)"; break; /*StarLake*/ + case 0x002B: prodstr = "(S5000VSA)"; break; + case 0x002D: prodstr = "(MFSYS25)"; break; /*ClearBay*/ + case 0x003E: prodstr = "(S5520UR)"; /*CG2100 or NSN2U*/ + do_me = 1; kcs_loops = URNLOOPS; + bChan = 1; break; + case 0x0040: prodstr = "(QSSC-S4R)"; /*Stoutland*/ + do_me = 1; kcs_loops = URNLOOPS; + bChan = 1; break; + case 0x0100: prodstr = "(Tiger4)"; break; + case 0x0103: prodstr = "(McCarran)"; /*BladeCenter*/ + do_powerstate = 0; break; + case 0x0800: prodstr = "(ZT5504)"; /*ZiaTech*/ + do_powerstate = 0; break; + case 0x0808: prodstr = "(MPCBL0001)"; /*ATCA Blade*/ + do_powerstate = 0; break; + case 0x0841: prodstr = "(MPCMM0001)"; /*ATCA CMM*/ + do_powerstate = 0; break; + case 0x0811: prodstr = "(TIGW1U)"; break; /*S5000PHB*/ + case 0x4311: prodstr = "(NSI2U)"; /*SE7520JR23*/ + if (dtype == BMC) tag="mBMC"; + fmBMC = 1; break; + default: prodstr = ""; break; + } + if (is_romley(mfg,prod)) { + intel_romley_desc(mfg,prod,&prodstr); + snprintf(prodoem,sizeof(prodoem),"(%s)",prodstr); + prodstr = prodoem; + do_me = 1; kcs_loops = URNLOOPS; + do_hsc = 1; /*the HSC is embedded, so not the same*/ + sprintf(extraver,".%d (Boot %x.%x)", /*BMC extra*/ + (devrec[13] + (devrec[14] << 8)),devrec[11],devrec[12]); + } + break; + case VENDOR_KONTRON: /*=0x003A98=15000.*/ + i = devrec[11] + (devrec[12] << 8); + j = devrec[13] + (devrec[14] << 8); + k = 0; l = 0; + { /* get Kontron firmware version with OEM cmd */ + int rlen; + uchar idata[4]; + uchar rdata[16]; + uchar cc; + rlen = sizeof(rdata); + idata[0] = 0; + idata[1] = 0; + idata[2] = 1; + rv = ipmi_cmdraw(0x2f, 0x2c, g_sa, g_bus, g_lun, + idata,3,rdata,&rlen,&cc,fdebug); + if (rv == 0 && cc == 0) { + k = rdata[1]; + l = rdata[2]; + } + } + sprintf(extraver,".%02d.%02d (FW %x.%x)",i,j,k,l); + switch(prod) { /* show product names for some */ + case 0x1590: prodstr = "(KTC5520)"; break; + default: prodstr = ""; break; + } + break; + case VENDOR_PEPPERCON: /*=0x0028c5 Peppercon/Raritan */ + if (prod == 0x0004) prodstr = "(AOC-IPMI20)"; /*SuperMicro*/ + else if (prod == 0x0007) prodstr = "(RMM2)"; /*Intel RMM2*/ + break; + case VENDOR_HP: /*=0x00000B*/ + switch(prod) { /* show product names for some */ + case 0x2000: prodstr = "(Proliant ML/DL)"; break; /*DL380*/ + case 0x2020: prodstr = "(Proliant BL)"; break; + default: if ((prod & 0xff00) == 0x8300) + prodstr = "(Proliant SL)"; + else prodstr = ""; + break; + } + do_powerstate = 0; /*HP does not support get_power_state cmd*/ + break; + case VENDOR_DELL: /*=0x0002A2*/ + switch(prod) { /* show product names for some */ + case 0x0100: prodstr = "(PE R610)"; break; + default: prodstr = ""; break; + } + break; + case VENDOR_MAGNUM: /* =5593. used by SuperMicro*/ + switch(prod) { /* show product names for some */ + case 6: prodstr = "(X8DTL)"; break; + default: prodstr = ""; break; + } + break; + case VENDOR_SUPERMICRO: /* =10876. used by SuperMicro*/ + case VENDOR_SUPERMICROX: /* =47488. used by Winbond/SuperMicro*/ + switch(prod) { /* decode some SuperMicro product ids */ + case 4: prodstr = "(X7DBR)"; break; + case 6: prodstr = "(X8DTL)"; break; + case 1037: prodstr = "(X8SIE)"; break; + case 1541: prodstr = "(X8SIL)"; break; + case 1547: prodstr = "(X8SIA)"; break; /*0x060b*/ + case 1549: prodstr = "(X8DTU)"; break; + case 1551: prodstr = "(X8DTN)"; break; + case 1562: prodstr = "(X8SIU-F)"; break; /*0x061a*/ + case 1572: prodstr = "(X9SCM)"; break; /*or X9SCL*/ + case 1576: prodstr = "(X9DRi)"; break; + case 1585: prodstr = "(X9SCA)"; break; + case 1603: prodstr = "(X9SPU)"; break; /*0x0643*/ + case 1643: prodstr = "(X9SRL)"; break; /*0x066b*/ + case 1797: prodstr = "(X9DR7)"; break; /*0x0705*/ + case 43025: prodstr = "(H8DGU)"; break; + case 43707: prodstr = "(X8DTH)"; break; + default: prodstr = ""; break; + } + if (!fipmilan) lan_ch_restrict = 1; /*fw bug, gets 0xd4 locally*/ + break; + case VENDOR_QUANTA: /*=7244.*/ + switch(prod) { /* show product names for some */ + case 21401: prodstr = "(S99Q)"; break; + default: prodstr = ""; break; + } + break; + default: + prodstr = ""; + break; + } /*end switch(prod)*/ + if (kcs_loops != 0) set_max_kcs_loops(kcs_loops); + } /*end-else BMC*/ + + printf("%s manufacturer %c %06x (%s)%c product %c %04x %s\n", + tag, bdelim,mfg,mfgstr,bcomma,bdelim,prod,prodstr); + { /* BMC version */ + printf("%s version %c %x.%02x%s%c IPMI v%d.%d\n", tag,bdelim, + devrec[2],devrec[3],extraver,bcomma,ipmi_maj,ipmi_min); + } + /* could show product rev, if available (sdevrec > 14) */ + return; +} + +int GetPowerOnHours(unsigned int *val) +{ + uchar resp[MAX_BUFFER_SIZE]; + int sresp = MAX_BUFFER_SIZE; + uchar cc; + int rc = -1; + int i; + unsigned int hrs; + + *val = 0; + if (fmBMC) return(rc); + sresp = MAX_BUFFER_SIZE; + memset(resp,0,6); /* default response size is 5 */ + rc = ipmi_cmd_mc(GET_POWERON_HOURS, NULL, 0, resp, &sresp, &cc, fdebug); + if (rc == 0 && cc == 0) { + /* show the hours (32-bits) */ + hrs = resp[1] | (resp[2] << 8) | (resp[3] << 16) | (resp[4] << 24); + if (resp[0] == 60) /*normal*/ i = 1; + else { + i = 60 / resp[0]; + hrs = hrs / i; + } + *val = hrs; + } + return(rc); +} + +char *decode_selftest(int stat) +{ + uchar *s; + uchar b; + if (stat == 0x0055) s = "(OK)"; + else { + s = "(Error)"; + if ((stat & 0x00ff) == 0x0057) { + b = ((stat & 0xff00) >> 8); + if (b & 0x80) s = "(No SEL Access)"; + if (b & 0x40) s = "(No SDR Access)"; + if (b & 0x20) s = "(No FRU Access)"; + if (b & 0x10) s = "(IPMB Error)"; + if (b & 0x08) s = "(SDR Empty)"; + if (b & 0x02) s = "(BootCode Corrupt)"; + if (b & 0x01) s = "(OpCode Corrupt)"; + } + } + return(s); +} + +#ifdef METACOMMAND +int i_health(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int ret = 0; + int c; + uchar selfbuf[16]; + uchar devrec[30]; + char biosver[80]; + uchar cc; + int selfstatus; + uchar pwr_state; + char selfstr[36]; + char *s; + char *s1; + int i, sresp; + uint n; + int rlen, len; + uchar idata[4]; + uchar rdata[16]; + + printf("%s ver %s\n", progname,progver); + + while ( (c = getopt( argc, argv,"cfghiln:o:p:q:sT:V:J:YEF:P:N:R:U:Z:x?")) != EOF ) + switch(c) { + case 'c': fcanonical = 1; + bdelim = BDELIM; break; /* canonical output */ + case 'f': do_frusdr = 1; break; /* check the FRUSDR too */ + case 'g': do_guid = 1; break; /* get the System GUID also */ + case 'h': do_hsc = 1; break; /* check the HSC too */ + case 'i': do_systeminfo = 1; break; /* get system info too */ + case 'l': do_lanstats = 1; break; /* get the LAN stats too */ + case 'm': /* specific IPMB MC, 3-byte address, e.g. "409600" */ + g_bus = htoi(&optarg[0]); /*bus/channel*/ + g_sa = htoi(&optarg[2]); /*device slave address*/ + g_lun = htoi(&optarg[4]); /*LUN*/ + g_addrtype = ADDR_IPMB; + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + printf("Use MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'n': set_name = 1; /* set the system name*/ + pname = optarg; + break; + case 'o': set_os = 1; /* set the Operating System*/ + pos = optarg; + break; + case 'q': set_os2 = 1; /* set the Operating System*/ + pos2 = optarg; + break; + case 'p': set_restore = 1; /* set the restore policy */ + restore_policy = atob(optarg); + if (restore_policy > 2) restore_policy = 1; + break; + case 's': do_session = 1; break; /* get session info too */ + case 'x': fdebug = 1; break; /* debug messages */ + case 'N': /* nodename */ + case 'U': /* remote username */ + case 'P': /* remote password */ + case 'R': /* remote password */ + case 'E': /* get password from IPMI_PASSWORD environment var */ + case 'F': /* force driver type */ + case 'T': /* auth type */ + case 'J': /* cipher suite */ + case 'V': /* priv level */ + case 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + default: + printf("Usage: %s [-cfghilnopsx -N node -U user -P/-R pswd -EFTVY]\n", progname); + printf(" where -x show eXtra debug messages\n"); + printf(" -c canonical output\n"); + printf(" -f get the FRUSDR version also\n"); + printf(" -g get the System GUID also\n"); + printf(" -h check the HotSwap Controller also\n"); + printf(" -i get System Info also: Name and OS\n"); + printf(" -l get the IPMI LAN statistics also\n"); + printf(" -n set System Name to this string \n"); + printf(" -o set Operating System to this string\n"); + printf(" -p1 set restore policy: 0=off, 1=last, 2=on\n"); + printf(" -s get the IPMI Session info also\n"); + print_lan_opt_usage(); + ret = ERR_USAGE; + goto health_end; + } + + fipmilan = is_remote(); + if (fipmilan && set_restore) + parse_lan_options('V',"4",0); /*if set, request admin priv*/ + + ret = ipmi_getdeviceid(devrec,16,fdebug); + if (ret != 0) { + goto health_end; + } else { + show_devid_all(BMC,devrec,16); + } + + if (!fipmilan) { /*get local BIOS version*/ + biosver[0] = 0; + ret = get_BiosVersion(biosver); + if (ret == 0) printf("BIOS Version %c %s\n",bdelim,biosver); + } + if (do_me) { /* ME version for Intel S5500 motherboards */ + rlen = sizeof(rdata); + ret = ipmi_cmdraw((GET_DEVICE_ID & 0xff), NETFN_APP,ME_SA,ME_BUS,0x00, + idata,0,rdata,&rlen,&cc,fdebug); + if (ret == 0 && cc != 0) ret = cc; + if (ret == 0) { + uchar m,n; + m = (rdata[3] & 0xf0) >> 4; + n = (rdata[3] & 0x0f); + printf("ME Firmware Ver %c %02x.%02x.%02x.%02x%02x\n",bdelim, + rdata[2],m,n,rdata[12],rdata[13]); + /* If rdata[2] has 0x80 bit on, ME is in update/recovery mode. + That can be cleared by removing input power. */ + } else + if (fdebug) printf("GetDeviceID(ME) error ret = %d\n",ret); + } + + if (do_hsc) { + if (fmBMC) printf("No HSC present\n"); + else { + /* Get HSC status */ + if (is_romley(vend_id, prod_id)) { + uchar maj, min; + ret = get_hsbp_version_intel(&maj, &min); + if (fdebug) printf("get_hsbp_version_intel ret = %d\n",ret); + if (ret == 0) + printf("HSC version %c %d.%02d\n", bdelim,maj,min); + } else { + ret = get_hsc_devid(&devrec[0],sizeof(devrec)); + if (fdebug) printf("get_hsc_devid ret = %d\n",ret); + if (ret == 0) /* only if HSC is detected */ + show_devid_all(HSC,devrec,14); + } + } + } + + i = get_driver_type(); + printf("IPMI driver type %c %d (%s)\n",bdelim,i,show_driver_type(i)); + + if (do_powerstate) + { /* Some BMCs dont support get_power_state*/ + ret = get_power_state(selfbuf,4); + if (ret != 0) { + printf("ipmi_getpowerstate error, ret = %d\n",ret); + goto health_end; + } else { + pwr_state = selfbuf[0] & 0x7f; + printf("Power State %c %02x (%s)\n", + bdelim,pwr_state,pwr_string(pwr_state)); + } + } + + ret = get_selftest_status(&selfbuf[0],sizeof(selfbuf)); + if (ret != 0) { + printf("get_selftest_status error, ret = %x\n",ret); + goto health_end; + } else { + selfstatus = selfbuf[0] + (selfbuf[1] << 8); + s = decode_selftest(selfstatus); + if (fmBMC) { + sprintf(selfstr,"%s",s); + } else { + ret = get_last_selftest(&selfbuf[0],sizeof(selfbuf)); + if (fdebug) printf("get_last_selftest ret = %x, %02x%02x\n", + ret, selfbuf[1],selfbuf[0]); + if (ret == 0 && (selfbuf[0] != 0xFF)) { + sprintf(selfstr,"%s, last = %02x%02x",s,selfbuf[1],selfbuf[0]); + } else sprintf(selfstr,"%s",s); + ret = 0; /*ignore any errors with get_last_selftest*/ + } + printf("Selftest status %c %04x %s\n",bdelim,selfstatus,selfstr); + } + + ret = oem_get_health(&selfstr[0],sizeof(selfstr)); + if (ret == 0) { + printf("%s\n",selfstr); + } + + rlen = 4; + ret = get_chassis_status(selfbuf,&rlen); + if (ret != 0) { + printf("Cannot do get_chassis_status, ret = %d\n",ret); + goto health_end; + } else { + show_chs_status(selfbuf,rlen); + } + + if (vend_id == VENDOR_INTEL) { + int pwr_delay = 0; + ret = get_power_restore_delay_intel(&pwr_delay); + if (fdebug) printf("get_power_restore_delay_intel ret = %d\n",ret); + if (ret == 0) { + printf("PowerRestoreDelay %c %d seconds\n",bdelim,pwr_delay); + } else ret = 0; + } + + if (do_guid) { + sresp = sizeof(devrec); + ret = ipmi_cmd(GET_SYSTEM_GUID,NULL,0,devrec,&sresp,&cc,fdebug); + if (ret != 0) { + if (!is_remote()) { /* get UUID from SMBIOS */ + cc = 0; sresp = 16; + ret = get_SystemGuid(devrec); + } else { + cc = 0; + sresp = sizeof(devrec); + ret = get_device_guid(devrec,&sresp); + } + } + if (fdebug) printf("system_guid: ret = %d, cc = %x\n",ret,cc); + if (ret == 0 && cc == 0) { + printf("System GUID %c ",bdelim); + for (i=0; i<16; i++) { + if ((i == 4) || (i == 6) || (i == 8) || (i == 10)) s = "-"; + else s = ""; + printf("%s%02x",s,devrec[i]); + } + printf("\n"); + } + } + + if (bChan != 7) /* do not get first lan chan if set above */ + ret = get_lan_channel(1,&bChan); + + if (fmBMC == 0) { + ret = GetPowerOnHours(&n); + if (ret == 0) + printf("Power On Hours %c %d hours (%d days)\n",bdelim,n,(n/24)); + if (ret == 0xC1) ret = 0; /* not supporting poweron hours is ok. */ + + printf("BMC LAN Channels %c ",bdelim); + for (i = 1; i<= 16; ) { + c = get_lan_channel(i,&cc); + if (c != 0) break; + printf("%d ",cc); + i = cc+1; + } + printf("\n"); + + if (lan_ch_restrict) ; /*skip if vendor fw bug*/ + else { + ret = get_chan_auth(bChan,&devrec[0],sizeof(devrec)); + if (ret == 0) + show_chan_auth("Channel Auth Cap",devrec,8); + else + printf("get_chan_auth error: ret = %x\n",ret); + } + } + + if (do_systeminfo) { + char infostr[64]; + len = sizeof(infostr); + ret = get_system_info(1,infostr,&len); /*Firmware Version*/ + len = sizeof(infostr); + ret = get_system_info(2,infostr,&len); + if (ret == 0) { + printf("System Name %c %s\n",bdelim,infostr); + len = sizeof(infostr); + ret = get_system_info(3,infostr,&len); + if (ret == 0) printf("Pri Operating System %c %s\n",bdelim,infostr); + len = sizeof(infostr); + ret = get_system_info(4,infostr,&len); + if (ret == 0) printf("Sec Operating System %c %s\n",bdelim,infostr); + } else { + if (ret == 0xC1) /*only supported on later IPMI 2.0 firmware */ + printf("GetSystemInfo not supported on this platform\n"); + } + } + + if (do_frusdr) { + ret = get_frusdr_version((char *)&devrec[0],sizeof(devrec)); + if (ret == 0) printf("FRU/SDR Version %c %s\n",bdelim,devrec); + else printf("FRU/SDR Version %c error %d\n",bdelim,ret); + } + + if (do_lanstats) { + ret = get_lan_stats(bChan); + } + + if (do_session) { + i = get_session_info_all(); + if (i != 0) printf("get_session_info error %d, %s\n",i,decode_rv(i)); + } + +#ifdef PING_OK + { + char *node; + /* Currently some problems with this: + * works first time, but locks up BMC LAN on subsequent attempts. + */ + node = get_nodename(); + ret = ping_node(node); + printf("ping_node(%s): ret = %d\n",node,ret); + } +#endif + + if (set_name) { + len = (int)strlen(pname); + ret = set_system_info(2,pname,len); + printf("Set System Name to '%s', ret = %d\n",pname,ret); + if (ret == 0xC1) /*only supported on later IPMI 2.0 firmware */ + printf("SetSystemInfo not supported on this platform\n"); + } + + if (set_os) { + len = (int)strlen(pos); + ret = set_system_info(3,pos,len); + printf("Set Pri Operating System to '%s', ret = %d\n",pos,ret); + if (ret == 0xC1) /*only supported on later IPMI 2.0 firmware */ + printf("SetSystemInfo not supported on this platform\n"); + } + + if (set_os2) { + len = (int)strlen(pos2); + ret = set_system_info(4,pos2,len); + printf("Set Sec Operating System to '%s', ret = %d\n",pos2,ret); + if (ret == 0xC1) /*only supported on later IPMI 2.0 firmware */ + printf("SetSystemInfo not supported on this platform\n"); + } + + if (set_restore) { + idata[0] = restore_policy; /* 1=last_state, 2=turn_on, 0=stay_off*/ + rlen = sizeof(rdata); + ret = ipmi_cmdraw(0x06 , NETFN_CHAS, g_sa, g_bus, g_lun, + idata,1,rdata,&rlen,&cc,fdebug); + if (ret == 0 && cc != 0) ret = cc; + printf("set_restore_policy(%x): ret = %d\n",restore_policy,ret); + } + +health_end: + ipmi_close_(); + // show_outcome(progname,ret); + return (ret); +} /* end main()*/ + +/* end bmchealth.c */ |