diff options
Diffstat (limited to 'util/oem_supermicro.c')
-rw-r--r-- | util/oem_supermicro.c | 595 |
1 files changed, 595 insertions, 0 deletions
diff --git a/util/oem_supermicro.c b/util/oem_supermicro.c new file mode 100644 index 0000000..528e4f7 --- /dev/null +++ b/util/oem_supermicro.c @@ -0,0 +1,595 @@ +/* + * oem_supermicro.c + * Handle SuperMicro OEM command functions + * + * Change history: + * 12/06/2010 ARCress - included in source tree + * + *--------------------------------------------------------------------- + */ +/*M* +Copyright (c) 2010 Kontron America, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a.. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b.. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + c.. Neither the name of Kontron nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *M*/ +#ifdef WIN32 +#include <windows.h> +#include "getopt.h" +#else +#if defined(HPUX) +/* getopt is defined in stdio.h */ +#elif defined(MACOS) +/* getopt is defined in unistd.h */ +#include <unistd.h> +#include <sys/time.h> +#else +#include <getopt.h> +#endif +#endif +#include <stdio.h> +#include <string.h> +#include <time.h> +#include "ipmicmd.h" +#include "ievents.h" +#include "oem_supermicro.h" + +#ifdef MOVED /*moved to oem_supermicro.h*/ +#define SUPER_NETFN_OEM 0x30 +#define SUPER_CMD_BMCSTATUS 0x70 +#define SUPER_CMD_RESET_INTRUSION 0x03 +#define SUPER_NETFN_OEMFW 0x3C +#define SUPER_CMD_OEMFWINFO 0x20 +#endif + +void set_loglevel(int level); /*prototype */ +extern char fsm_debug; /*mem_if.c*/ + +static char * progver = "2.93"; +static char * progname = "ismcoem"; +static int verbose = 0; +static char fdebug = 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; +static int vend_id = 0; +static int prod_id = 0; + +int oem_supermicro_get_bmc_status(uchar *sts) +{ + int rv; + int rlen, ilen; + uchar rdata[16]; + uchar idata[16]; + uchar cc; + + if (sts == NULL) return(LAN_ERR_INVPARAM); + if ((vend_id == VENDOR_SUPERMICROX) || + (vend_id == VENDOR_SUPERMICRO)) { + /* subfunc 0xF0 is invalid for newer SMC systems */ + idata[0] = 0x02; /* action: get status */ + ilen = 1; + } else { + idata[0] = 0xF0; /* subfunction */ + idata[1] = 0x02; /* action: get status */ + // idata[2] = 0; + ilen = 2; + } + rlen = sizeof(rdata); + rv = ipmi_cmdraw(SUPER_CMD_BMCSTATUS, SUPER_NETFN_OEM, + BMC_SA, PUBLIC_BUS, BMC_LUN, + idata, ilen, rdata, &rlen, &cc, fdebug); + if ((rv == 0) && (cc != 0)) rv = cc; + if (rv == 0) { *sts = rdata[0]; } + return(rv); +} + +int oem_supermicro_set_bmc_status(uchar sts) +{ + int rv; + int rlen, ilen; + uchar rdata[16]; + uchar idata[16]; + uchar cc; + + if (sts > 1) sts = 1; /* actions: 0=disable, 1=enable, 2=status*/ + if ((vend_id == VENDOR_SUPERMICROX) || + (vend_id == VENDOR_SUPERMICRO)) { + idata[0] = sts; + ilen = 1; + } else { + idata[0] = 0xF0; /* subfunction */ + idata[1] = sts; + ilen = 2; + } + rlen = sizeof(rdata); + rv = ipmi_cmdraw(SUPER_CMD_BMCSTATUS, SUPER_NETFN_OEM, + BMC_SA, PUBLIC_BUS, BMC_LUN, + idata, ilen, rdata, &rlen, &cc, fdebug); + if ((rv == 0) && (cc != 0)) rv = cc; + return(rv); +} + +int oem_supermicro_get_lan_port(uchar *val) +{ + int rv; + int rlen, ilen; + uchar rdata[16]; + uchar idata[16]; + uchar cc; + + idata[0] = 0x0c; /* subfunction */ + idata[1] = 0x00; /* get */ + ilen = 2; + rlen = sizeof(rdata); + rv = ipmi_cmdraw(SUPER_CMD_BMCSTATUS, SUPER_NETFN_OEM, + BMC_SA, PUBLIC_BUS, BMC_LUN, + idata, ilen, rdata, &rlen, &cc, fdebug); + if ((rv == 0) && (cc != 0)) rv = cc; + if (rv == 0) { *val = rdata[0]; } + return(rv); +} + +int oem_supermicro_set_lan_port(uchar val) +{ + int rv; + int rlen, ilen; + uchar rdata[16]; + uchar idata[16]; + uchar cc; + + idata[0] = 0x0c; /* subfunction */ + idata[1] = 0x01; /* set */ + idata[2] = val; + ilen = 3; + rlen = sizeof(rdata); + rv = ipmi_cmdraw(SUPER_CMD_BMCSTATUS, SUPER_NETFN_OEM, + BMC_SA, PUBLIC_BUS, BMC_LUN, + idata, ilen, rdata, &rlen, &cc, fdebug); + if ((rv == 0) && (cc != 0)) rv = cc; + return(rv); +} + +char *oem_supermicro_lan_port_string(uchar val) +{ + char *p; + switch(val) { + case 0: p = "Dedicated"; break; + case 1: p = "Onboard_LAN1"; break; + case 2: p = "Failover"; break; + default: p = "unknown"; break; + } + return(p); +} + +static void oem_supermicro_show_lan_port(uchar val) +{ + printf("Current LAN interface is %s\n", + oem_supermicro_lan_port_string(val)); +} + +int oem_supermicro_get_health(char *pstr, int sz) +{ + int rv; + uchar bsts; + char *str; + + rv = oem_supermicro_get_bmc_status(&bsts); + if (rv == 0) { + if (bsts == 0x01) str = "BMC status = enabled"; + else str = "BMC status = disabled"; + strncpy(pstr, str, sz); + } + return(rv); +} + +/* + * oem_supermicro_get_firmware_info + * + * From post by ipmitool developer. + * http://sourceforge.net/mailarchive/message.php?msg_name=49ABCCC3.4040004%40cern.ch + * + * Request + * 0x3C - OEM network function + * 0x20 - OEM cmd (SUPER_CMD_OEMFWINFO) + * + * Response data: + * 4 bytes - firmware major version (LSB first) + * 4 bytes - firmware minor version (LSB first) + * 4 bytes - firmware sub version (LSB first) + * 4 bytes - firmware build number (LSB first) + * 1 byte - hardware ID + * ? bytes - firmware tag, null terminated string + */ +int oem_supermicro_get_firmware_info(uchar *info) +{ + int rv; + int rlen; + uchar rdata[32]; + uchar idata[16]; + uchar cc; + + if (info == NULL) return(LAN_ERR_INVPARAM); + rlen = sizeof(rdata); + rv = ipmi_cmdraw(SUPER_CMD_OEMFWINFO, SUPER_NETFN_OEM, + BMC_SA, PUBLIC_BUS, BMC_LUN, + idata, 0, rdata, &rlen, &cc, fdebug); + if ((rv == 0) && (cc != 0)) rv = cc; + if (rv == 0) { memcpy(info,rdata,rlen); } + return(rv); +} + +int oem_supermicro_get_firmware_str(char *pstr, int sz) +{ + int rv; + uchar info[32]; + uint32 fwmaj; + uint32 fwmin; + uint32 fwsub; + uint32 fwbld; + uchar hwid; + rv = oem_supermicro_get_firmware_info(info); + if (rv == 0) { + fwmaj = info[0] + (info[1] << 8) + (info[2] << 16) + (info[3] << 24); + fwmin = info[4] + (info[5] << 8) + (info[6] << 16) + (info[7] << 24); + fwsub = info[8] + (info[9] << 8) + (info[10] << 16) + (info[11] << 24); + fwbld = info[12] +(info[13] << 8) + (info[14] << 16) + (info[15] << 24); + hwid = info[16]; + /*info[17] = fw tag string */ + snprintf(pstr,sz,"Firmware %d.%d.%d.%d HW %d %s\n",fwmaj,fwmin,fwsub, + fwbld,hwid,&info[17]); + } + return(rv); +} + + +int oem_supermicro_reset_intrusion(void) +{ + int rv; + int rlen; + uchar rdata[32]; + uchar idata[16]; + uchar cc; + // if (state == NULL) return(LAN_ERR_INVPARAM); + rlen = sizeof(rdata); + rv = ipmi_cmdraw(SUPER_CMD_RESET_INTRUSION, SUPER_NETFN_OEM, + BMC_SA, PUBLIC_BUS, BMC_LUN, + idata, 0, rdata, &rlen, &cc, fdebug); + if ((rv == 0) && (cc != 0)) rv = cc; + if (rv == 0) { /* check rdata for more info */ } + return(rv); +} + +/* + * decode_sensor_supermicro + * 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_supermicro(uchar *sdr,uchar *reading,char *pstring, int slen) +{ + int rv = -1; + uchar stype; + uchar bval; + char *pstr = NULL; + + if (sdr == NULL || reading == NULL) return(rv); + if (pstring == NULL || slen == 0) return(rv); + /* sdr[3] is 0x01 for Full, 0x02 for Compact */ + bval = reading[2]; + stype = sdr[12]; + switch(stype) { + case 0xC0: /* CPU Temp Sensor, EvTyp=0x70 (Full) */ + //if (dbg) printf("supermicro %x sensor reading %x\n",stype,reading); + rv = 0; + switch(bval) { + case 0x0000: pstr = "00 Low"; break; + case 0x0001: pstr = "01 Medium"; break; + case 0x0002: pstr = "02 High"; break; + case 0x0004: pstr = "04 Overheat"; break; + case 0x0007: pstr = "07 Not Installed"; break; + default: rv = -1; break; + } + break; + case 0x08: /* Power Supply Status (Full/Discrete) Table 42-3 */ + rv = 0; + switch(bval) { + case 0x00: pstr = "00 Absent"; break; /*bit 0*/ + case 0x01: pstr = "01 Present"; break; /*bit 0*/ + case 0x02: pstr = "02 Failure"; break; /*bit 1*/ + case 0x04: pstr = "04 Predict Fail"; break; /*bit 2*/ + case 0x08: pstr = "08 Input Lost"; break; /*bit 3*/ + default: rv = -1; break; + } + break; + default: + break; + } + if (rv == 0) strncpy(pstring, pstr, slen); + return(rv); +} + +int decode_mem_supermicro(int prod, uchar b2, uchar b3, char *desc, int *psz) +{ + int array, dimm, n; + int rv = -1; + uchar bdata; + if ((desc == NULL) || (psz == NULL)) return -1; + if (b2 == 0xff) bdata = b3; /*ff is reserved*/ + else bdata = b2; /* normal case */ + array = (bdata & 0xc0) >> 6; + dimm = bdata & 0x3f; + /* bdata = 0x10 (16.) means CPU 1, DIMM 6 */ + array = bdata / 10; + dimm = bdata % 10; + +#ifdef DMIOK + /* Use DMI if we get confirmation about array/dimm indices. */ + if (! is_remote()) { + fsm_debug = fdebug; + rv = get_MemDesc(array,dimm,desc,psz); + /* if (rv != 0) desc has "DIMM[%d}" */ + } +#endif + + if (rv != 0) { + n = sprintf(desc,"DIMM%d/CPU%d",dimm,array); + *psz = n; + rv = 0; + } + return(rv); +} /*end decode_mem_supermicro*/ + +/* + * decode_sel_supermicro + * 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_supermicro(uchar *evt, char *outbuf, int outsz, char fdesc, + char fdbg) +{ + int rv = -1; + ushort id; + uchar rectype; + ulong timestamp; + char mybuf[64]; + char *type_str = ""; + char *pstr = NULL; + int sevid; + ushort genid; + uchar snum; + + fdebug = fdbg; + 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 == 0x02) + { + sprintf(mybuf,"%02x [%02x %02x %02x]", evt[12],evt[13],evt[14],evt[15]); + switch(evt[10]) { /*sensor type*/ + case 0xC0: /* CPU Temp Sensor */ + type_str = "OEM_CpuTemp"; + switch((evt[13] &0x0f)) { /*offset/data1 l.o. nibble*/ + case 0x02: /* CPU Temp Sensor Overheat event offset */ + if (evt[12] & 0x80) { /*EvTyp==0xF0 if deassert*/ + pstr = "CpuTemp Overheat OK"; sevid = SEV_INFO; + } else { /* EvTyp=0x70 assert */ + pstr = "CpuTemp Overheat "; sevid = SEV_MAJ; + } + rv = 0; + break; + default: pstr = "CpuTemp Event"; break; + } + break; + case 0xC2: /* CPLD Event */ + type_str = "OEM_CPLD"; + switch((evt[13] & 0x0f)) { /* data1 usu 0xa0*/ + case 0x00: + if (evt[14] == 0x1c) + { pstr = "CPLD CATERR Asserted"; sevid = SEV_CRIT; } + else { pstr = "CPLD Event Asserted"; sevid = SEV_MIN; } + rv = 0; + break; + default: pstr = "CPLD Event"; break; + } + break; + default: /*other sensor types*/ + break; + } + } + if (rv == 0) { + format_event(id,timestamp, sevid, genid, type_str, + snum,NULL,pstr,mybuf,outbuf,outsz); + } + return(rv); +} + +static void usage(void) +{ + printf("Usage: %s <command> [arg]\n",progname); + printf(" intrusion = reset chassis intrusion\n"); + printf(" bmcstatus [enable| disable] = get/set BMC status\n"); + printf(" firmware = get extra firmware info\n"); + printf(" lanport [dedicated| lan1| failover] = get/set IPMI LAN port\n"); + printf("These commands may not work on all SuperMicro systems\n"); +} + +static int ipmi_smcoem_main(int argc, char **argv) +{ + int rv = 0; + char msg[80]; + uchar val; + + if (strncmp(argv[0],"intrusion",9) == 0) { + printf("Clearing Chassis Intrusion ...\n"); + rv = oem_supermicro_reset_intrusion(); + } else if (strncmp(argv[0],"bmcstatus",9) == 0) { + printf("Getting BMC status ...\n"); + rv = oem_supermicro_get_health(msg, sizeof(msg)); + if (rv != 0) return(rv); + printf("%s\n",msg); + if (argv[1] != NULL) { + if (strncmp(argv[1],"disable",7) == 0) { + val = 0; + } else if (strncmp(argv[1],"enable",6) == 0) { + val = 1; + } else { + usage(); + return(ERR_USAGE); + } + printf("Setting BMC status to %s ...\n",argv[1]); + rv = oem_supermicro_set_bmc_status(val); + if (rv != 0) return(rv); + rv = oem_supermicro_get_health(msg, sizeof(msg)); + if (rv == 0) printf("%s\n",msg); + } + } else if (strncmp(argv[0],"firmware",8) == 0) { + printf("Getting SMC Firmare Information ...\n"); + rv = oem_supermicro_get_firmware_str(msg, sizeof(msg)); + if (rv == 0) printf("%s\n",msg); + } else if (strncmp(argv[0],"lanport",9) == 0) { + rv = oem_supermicro_get_lan_port(&val); + if (rv == 0) { + oem_supermicro_show_lan_port(val); + if (argv[1] != NULL) { + if (strncmp(argv[1],"dedicated",9) == 0) { + val = 0; + } else if (strncmp(argv[1],"lan1",4) == 0) { + val = 1; + } else if (strncmp(argv[1],"failover",8) == 0) { + val = 2; + } else { + usage(); + return(ERR_USAGE); + } + printf("Setting LAN interface to %s ...\n",argv[1]); + rv = oem_supermicro_set_lan_port(val); + if (rv != 0) return(rv); + rv = oem_supermicro_get_lan_port(&val); + if (rv == 0) oem_supermicro_show_lan_port(val); + } + } + } else { + usage(); + rv = ERR_USAGE; + } + return(rv); +} + +#ifdef METACOMMAND +int i_smcoem(int argc, char **argv) +#else +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#endif +{ + int rv = 0; + uchar devrec[16]; + int c, i; + char *s1; + + printf("%s ver %s\n", progname,progver); + set_loglevel(LOG_NOTICE); + parse_lan_options('V',"4",0); /*default to admin priv*/ + + while ( (c = getopt( argc, argv,"m:xzEF:J:N:P:R:T:U:V:YZ:?")) != EOF ) + switch(c) { + 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 'x': fdebug = 2; /* normal (dbglog if isol) */ + verbose = 1; + break; + case 'z': fdebug = 3; /*full debug (for isol)*/ + verbose = 1; + break; + 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: + usage(); + return(ERR_USAGE); + break; + } + for (i = 0; i < optind; i++) { argv++; argc--; } + if (argc == 0) { + usage(); + return(ERR_USAGE); + } + + rv = ipmi_getdeviceid(devrec,16,fdebug); + if (rv == 0) { + char ipmi_maj, ipmi_min; + ipmi_maj = devrec[4] & 0x0f; + ipmi_min = devrec[4] >> 4; + vend_id = devrec[6] + (devrec[7] << 8) + (devrec[8] << 16); + prod_id = devrec[9] + (devrec[10] << 8); + show_devid( devrec[2], devrec[3], ipmi_maj, ipmi_min); + } + + rv = ipmi_smcoem_main(argc, argv); + + ipmi_close_(); + return(rv); +} +/* end oem_supermicro.c */ |