diff options
Diffstat (limited to 'util/isensor.c')
-rw-r--r-- | util/isensor.c | 3680 |
1 files changed, 3680 insertions, 0 deletions
diff --git a/util/isensor.c b/util/isensor.c new file mode 100644 index 0000000..ac93411 --- /dev/null +++ b/util/isensor.c @@ -0,0 +1,3680 @@ +/* + * isensor.c + * + * This tool reads the SDR records to return sensor information. + * It can use either the Intel /dev/imb driver or VALinux /dev/ipmikcs. + * + * Author: arcress at users.sourceforge.net + * Copyright (c) 2002-2006 Intel Corporation. + * Copyright (c) 2009 Kontron America, Inc. + * + * 07/25/02 Andy Cress created + * 10/09/02 Andy Cress v1.1 added decodeValue(RawToFloat) routine + * 10/11/02 Andy Cress v1.2 added expon routine + * 10/30/02 Andy Cress v1.3 added SDR types 08 & 14 + * 12/04/02 Andy Cress v1.4 changed dstatus descriptions + * 01/29/03 Andy Cress v1.5 added MV OpenIPMI driver support + * Hannes Schulz <schulz@schwaar.com> + * 1) correct raw readings to floatval + * 2) allow extra SDR bytes returned from HP netserver 1000r + * Guo Min <guo.min@intel.com> + * add -l option for simpler list display + * 02/25/03 Andy Cress v1.6 misc cleanup + * 05/02/03 Andy Cress v1.7 add PowerOnHours + * 07/28/03 Andy Cress v1.8 added -t option for threshold values, + * added sample Discovery routine (unfinished), + * added ipmi_getdeviceid for completeness. + * 09/05/03 Andy Cress v1.9 show SDR OEM subtypes, + * fix GetSDR multi-part get for OEM SDRs + * stop if SDR Repository is empty + * 09/23/03 Andy Cress v1.10 Add options to set thresholds + * 10/14/03 Andy Cress v1.11 Fixed sdr offset for ShowThreshold values + * 01/15/04 Andy Cress v1.12 Fixed SetThreshold to set hysteresis, + * Fixed sens_cap testing in ShowThresh(Full) + * 01/30/04 Andy Cress v1.13 Changed field display order, added header, + * check for sdr sz below min, added WIN32. + * 02/19/04 Andy Cress v1.14 Added SDR type 3 parsing for mBMC + * 02/27/04 Andy Cress v1.15 Added check for superuser, more mBMC logic + * 03/11/04 Andy Cress v1.16 Added & removed private mBMC code for set + * thresholds due to licensing issues + * 04/13/04 Andy Cress v1.17 Added -r to show raw SDRs also + * 05/05/04 Andy Cress v1.18 call ipmi_close before exit, + * fix sresp in GetSDR for WIN32. + * 07/07/04 Andy Cress v1.19 Added -a to reArm sensor, + * show debug raw reading values only in hex + * 08/18/04 Andy Cress v1.20 Added decoding for DIMM status + * 11/01/04 Andy Cress v1.21 add -N / -R for remote nodes, + * added -U for remote username + * 11/19/04 Andy Cress v1.22 added more decoding for compact reading types, + * added -w option to wrap thresholds + * 11/24/04 ARCress v1.23 added sens_type to display output + * 12/10/04 ARCress v1.24 added support for device sdrs also, + * fixed sens_cap byte, + * 01/10/05 ARCress v1.25 change ShowThresh order, highest to lowest, + * change signed exponent type in RawToFloat + * 01/13/05 ARCress v1.26 added time display if fwrap + * 01/28/05 ARCress v1.27 mod for Power Redundancy SDR status + * 02/15/05 ARCress v1.28 added FloatToRaw for -h/-l threshold set funcs, + * always take -n sensor_num as hex (like displayed) + * 03/07/05 ARCress v1.29 added "LAN Leash Lost" decoding in decode_comp_ + * added -v to show max/min & hysteresis. + * 03/22/05 ARCress v1.30 added OEM subtype 0x60 for BMC TAM + * 03/26/05 ARCress v1.31 added battery type to decode_comp_reading + * 04/21/05 ARCress v1.32 added error message if -n sensor_num not found, + * added more decoding for Power Redund sensor + * 06/20/05 ARCress v1.33 if GetSDRRepository cc=0xc1 switch fdevsdrs mode, + * also detect fdevsdrs better for ATCA. + * 07/28/05 ARCress v1.34 check for Reading init state, + * add extra byte to decode_comp_reading() + * 09/12/05 ARCress v1.35 don't check superuser for fipmi_lan + * 01/26/06 ARCress v1.36 added -i option to only show one sensor index + * 03/14/06 ARCress v1.37 added -p option to save persistent thresholds + * 04/06/06 ARCress v1.38 show auto/manual rearm + * 07/17/06 ARCress v1.39 add -V, add -L, handle RepInfo rc=0xc1 + * 11/28/06 ARCress v1.46 added -c -m for ATCA child MCs + * 08/15/07 ARCress v1.58 filter display if -n sensor_num + * 08/29/07 ARCress v1.59 fixed Battery sensor interpretation + * 10/31/07 ARCress v2.3 retry GetSDR if cc=0xC5 (lost reservationID) + * 01/14/08 ARCress v2.6 add -u param for setting unique thresholds, + * always show float when setting thresholds, + * fixup in decoding Proc,PS Comp readings + * 01/25/08 ARCress v2.7 allow float input with -u thresholds, + * add -p persist logic for -u thresholds. + */ +/*M* +Copyright (c) 2002-2006 Intel Corporation. +Copyright (c) 2009 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 Intel 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 <math.h> // for: double pow(double x, double y); +#include <string.h> +#include <time.h> +#ifdef WIN32 +#include <windows.h> +#include "getopt.h" +#elif defined(DOS) +#include <dos.h> +#include "getopt.h" +#else +#include <sys/stat.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 +#if defined(LINUX) +#include <unistd.h> +#include <sys/types.h> +#endif +#include "ipmicmd.h" +#include "isensor.h" + +#define PICMG_CHILD 1 /* show child MCs if -b */ +#define MIN_SDR_SZ 8 +#define SZCHUNK 16 /* SDR chunksize was 8, now 16 */ +#define INIT_SNUM 0xff +#define N_SGRP 16 +#define THR_EMPTY 999 + +extern int get_LastError( void ); /* ipmilan.c */ +extern int use_devsdrs(int picmg); /* ipmicmd.c */ +extern int get_MemDesc(int array, int dimm, char *desc, int *psz); /*mem_if.c*/ +extern char *get_sensor_type_desc(uchar stype); /*ievents.c*/ +#ifdef METACOMMAND +#include "oem_intel.h" +/* void show_oemsdr_intel(uchar *sdr); in oem_intel.h */ +/* int decode_sensor_intel(); in oem_intel.h */ +/* int is_romley(int vend, int prod); in oem_intel.h */ +extern int decode_sensor_kontron(uchar *sdr,uchar *reading,char *pstring, + int slen); /*see oem_kontron.c*/ +extern int decode_sensor_fujitsu(uchar *sdr,uchar *reading,char *pstring, + int slen); /*see oem_fujitsu.c*/ +extern int decode_sensor_sun(uchar *sdr,uchar *reading,char *pstring, + int slen); /*see oem_sun.c*/ +extern int decode_sensor_supermicro(uchar *sdr,uchar *reading,char *pstring, + int slen); /*see oem_supermicro.c*/ +extern int decode_sensor_quanta(uchar *sdr,uchar *reading,char *pstring, + int slen); /*see oem_quanta.c*/ +extern int decode_sensor_hp(uchar *sdr,uchar *reading,char *pstring, + int slen); /*see oem_hp.c*/ +extern int decode_sensor_dell(uchar *sdr,uchar *reading,char *pstring, + int slen); /*see oem_dell.c*/ +extern void show_oemsdr_hp(uchar *sdr); +#else +int is_romley(int vend, int prod) { + if ((vend == VENDOR_INTEL) && ((prod >= 0x0048) && (prod <= 0x005e))) + return(1); + return(0); +} +int is_thurley(int vend, int prod) { + if ((vend == VENDOR_INTEL) && ((prod >= 0x003A) && (prod <= 0x0040))) + return(1); + return(0); +} +#endif +#ifdef ALONE +#define NENTID 53 +static char *entity_id_str[NENTID] = { +/* 00 */ "unspecified", +/* 01 */ "other", +/* 02 */ "unknown", +/* 03 */ "processor", +/* 04 */ "disk", +/* 05 */ "peripheral bay", +/* 06 */ "management module", +/* 07 */ "system board", +/* 08 */ "memory module", +/* 09 */ "processor module", +/* 10 */ "power supply", +/* 11 */ "add-in card", +/* 12 */ "front panel bd", +/* 13 */ "back panel board", +/* 14 */ "power system bd", +/* 15 */ "drive backplane", +/* 16 */ "expansion board", +/* 17 */ "Other system board", +/* 18 */ "processor board", +/* 19 */ "power unit", +/* 20 */ "power module", +/* 21 */ "power distr board", +/* 22 */ "chassis back panel bd", +/* 23 */ "system chassis", +/* 24 */ "sub-chassis", +/* 25 */ "Other chassis board", +/* 26 */ "Disk Drive Bay", +/* 27 */ "Peripheral Bay", +/* 28 */ "Device Bay", +/* 29 */ "fan", +/* 30 */ "cooling unit", +/* 31 */ "cable/interconnect", +/* 32 */ "memory device ", +/* 33 */ "System Mgt Software", +/* 34 */ "BIOS", +/* 35 */ "Operating System", +/* 36 */ "system bus", +/* 37 */ "Group", +/* 38 */ "Remote Mgt Comm Device", +/* 39 */ "External Environment", +/* 40 */ "battery", +/* 41 */ "Processing blade", +/* 43 */ "Processor/memory module", +/* 44 */ "I/O module", +/* 45 */ "Processor/IO module", +/* 46 */ "Mgt Controller Firmware", +/* 47 */ "IPMI Channel", +/* 48 */ "PCI Bus", +/* 49 */ "PCI Express Bus", +/* 50 */ "SCSI Bus", +/* 51 */ "SATA/SAS bus", +/* 52 */ "Processor FSB" +}; +char *decode_entity_id(int id) { + if (id < NENTID) return (""); + else return(entity_id_str[id]); } +#else +/* char *decode_entity_id(int id); *isensor.h, from ievents.c*/ +#endif +/************************ + * Global Data + ************************/ +static char *progname = "isensor"; +static char *progver = "2.93"; +#ifdef WIN32 +static char savefile[] = "%ipmiutildir%\\thresholds.cmd"; +#else +static char savefile[] = "/var/lib/ipmiutil/thresholds.sh"; +// static char savefile[] = "/usr/share/ipmiutil/thresholds.sh"; +#endif +extern char fdebug; /*from ipmicmd.c*/ +int sens_verbose = 0; /* =1 show max/min & hysteresis also */ +static int fdevsdrs = 0; +static int fReserveOK = 1; +static int fDoReserve = 1; +static int fsimple = 0; /*=1 simple, canonical output*/ +static int fshowthr = 0; /* =1 show thresholds, =2 show thr in ::: fmt */ +static int fwrap = 0; +static int frawsdr = 0; +static int frearm = 0; +static int fshowidx = 0; /* only show a specific SDR index/range */ +static int fshowgrp = 0; /* =1 show group of sensors by sensor type */ +static int fdoloop = 0; /* =1 if user specified number of loops */ +static int fpicmg = 0; +static int fchild = 0; /* =1 show child SDRs */ +static int fset_mc = 0; /* =1 -m to set_mc */ +static int fdump = 0; +static int frestore = 0; +static int fjumpstart = 0; +static int fgetmem = 0; +static int fprivset = 0; +static char fremote = 0; +static int nloops = 1; /* num times to show repeated sensor readings */ +static char bdelim = BDELIM; /* delimiter for canonical output */ +static char tmpstr[20]; /* temp string */ +static char *binfile = NULL; +static int fsetthresh = 0; +static int fsavethresh = 0; +static uchar sensor_grps[N_SGRP] = {0, 0}; /*sensor type groups*/ +static ushort sensor_idx1 = 0xffff; +static ushort sensor_idxN = 0xffff; +static uchar sensor_num = INIT_SNUM; +static uchar sensor_hi = 0xff; +static uchar sensor_lo = 0xff; +static uchar sensor_thr[6] = {0,0,0,0,0,0}; +static double sensor_thrf[6] = {0,0,0,0,0,0}; +static double sensor_hi_f = 0; +static double sensor_lo_f = 0; +static int fmBMC = 0; +static int fRomley = 0; +static char chEol = '\n'; /* newline by default, space if option -w */ +static uchar resid[2] = {0,0}; +static uchar g_bus = PUBLIC_BUS; +static uchar g_sa = 0; +static uchar g_lun = BMC_LUN; +static uchar g_addrtype = ADDR_SMI; +static int vend_id = 0; +static int prod_id; + +/* sensor_dstatus + * This is used to decode the sensor reading types and meanings. + * Use IPMI Table 36-1 and 36-2 for this. + */ +#define N_DSTATUS 82 +#define STR_CUSTOM 58 +#define STR_OEM 71 +#define STR_AC_LOST 76 +#define STR_PS_FAIL 77 +#define STR_PS_CONFIG 78 +#define STR_HSC_OFF 79 +#define STR_REBUILDING 80 +#define STR_OTHER 81 +static char oem_string[50] = "OEM"; +static char *sensor_dstatus[N_DSTATUS] = { +/* 0 00h */ "OK ", +/* Threshold event states */ +/* 1 01h */ "Warn-lo", // "Warning-lo", +/* 2 02h */ "Crit-lo", // "Critical-lo", +/* 3 04h */ "BelowCrit", // "BelowCrit-lo", +/* 4 08h */ "Warn-hi", // "Warning-hi", +/* 5 10h */ "Crit-hi", // "Critical-hi", +/* 6 20h */ "AboveCrit", // "AboveCrit-hi", +/* 7 40h */ "Init ", /*in init state, no reading*/ +/* 8 80h */ "OK* ", +/* Hotswap Controller event states, also Availability */ +/* 9 HSC */ "Present", /*present,inserted*/ +/*10 HSC */ "Absent", /*absent,removed,empty,missing*/ +/*11 HSC */ "Ready", +/*12 HSC */ "Faulty", +/* Digital/Discrete event states */ +/*13 D-D */ "Asserted", +/*14 D-D */ "Deassert", +/*15 D-D */ "Predict ", +/* Availability event states */ +/*16 Avl */ "Disabled", +/*17 Avl */ "Enabled ", +/*18 Avl */ "Redundant", +/*19 Avl */ "RedunLost", +/*20 Avl */ "RedunDegr", +/* ACPI Device Power States */ +/*21 ACPI*/ "Off ", +/*22 ACPI*/ "Working", +/*23 ACPI*/ "Sleeping", /*D2/S2*/ +/*24 ACPI*/ "On", +/* Critical Interrupt event states */ +/*25 CrI */ "FP_NMI ", +/*26 CrI */ "Bus_TimOut", +/*27 CrI */ "IOch_NMI", +/*28 CrI */ "SW_NMI ", +/*29 CrI */ "PCI_PERR", +/*30 CrI */ "PCI_SERR", +/*31 CrI */ "EISA_TimOut", +/*32 CrI */ "Bus_Warn ", /*Correctable*/ +/*33 CrI */ "Bus_Error", /*Uncorrectable*/ +/*34 CrI */ "Fatal_NMI", +/*35 CrI */ "Bus_Fatal", /*0x0A*/ +/*36 CrI */ "Bus_Degraded", /*0x0B*/ +/* Physical Security event states */ +/*37 Phys*/ "LanLeashLost", +/*38 Phys*/ "ChassisIntrus", +/* Memory states */ +/*39 Mem */ "ECCerror", +/*40 Mem */ "ParityErr", +/* Discrete sensor invalid readings (error or init state) */ +/*41 D-D */ "Unknown", +/*42 D-D */ "NotAvailable", +/* Discrete sensor OEM reading states */ +/*43 OEM */ "Enabled ", +/*44 OEM */ "Disabled", +/* Session Audit states */ +/*45 OEM */ "Activated ", +/*46 OEM */ "Deactivated", +/*47 HSC */ "Unused ", +/* Processor event states */ +/*48 Proc*/ "IERR", +/*49 Proc*/ "ThermalTrip", +/*50 Proc*/ "FRB1Failure", +/*51 Proc*/ "FRB2Failure", +/*52 Proc*/ "FRB3Failure", +/*53 Proc*/ "ConfigError", +/*54 Proc*/ "SMBIOSError", +/*55 Proc*/ "ProcPresent", +/*56 Proc*/ "ProcDisabled", +/*57 Proc*/ "TermPresent", +/* Custom data string, 15 bytes */ +/*58 Custom*/ "CustomData12345", +/* Event Log */ +/*59 EvLog*/ "MemLogDisab", +/*60 EvLog*/ "TypLogDisab", +/*61 EvLog*/ "LogCleared", +/*62 EvLog*/ "AllLogDisab", +/*63 EvLog*/ "SelFull", +/*64 EvLog*/ "SelNearFull", +/* more Digital Discrete */ +/*65 D-D */ "Exceeded", +/*66 Alert*/ "AlertPage", +/*67 Alert*/ "AlertLAN", +/*68 Alert*/ "AlertPET", +/*69 Alert*/ "AlertSNMP", +/*70 Alert*/ "None", +/*71 OEM str*/ &oem_string[0], +/* Version Change */ +/*72 Change*/ "HW Changed", +/*73 Change*/ "SW Changed", +/*74 Change*/ "HW incompatibility", +/*75 Change*/ "Change Error", +/* Power Supply event states */ +/*76 PS */ "AC_Lost ", +/*77 PS */ "PS_Failed", +/* Power Supply event states */ +/*78 PS */ "Config_Err", +/*79 HSC */ "Offline", +/*80 HSC */ "Rebuilding", +/*81 other*/ " _ " +}; + +static char *raid_states[9] = { /*for sensor type 0x0d drive status */ + "Faulty", + "Rebuilding", + "InFailedArray", + "InCriticalArray", + "ParityCheck", + "PredictedFault", + "Un-configured", + "HotSpare", + "NoRaid" }; + +#define NSENSTYPES 0x2a +#ifdef OLD +/* see ievents.c */ +static const char *sensor_types[NSENSTYPES] = { /*IPMI 2.0 Table 42-3*/ +/* 00h */ "reserved", +/* 01h */ "Temperature", +/* 02h */ "Voltage", +/* 03h */ "Current", +/* 04h */ "Fan", +/* 05h */ "Platform Chassis Intrusion", +/* 06h */ "Platform Security Violation", +/* 07h */ "Processor", +/* 08h */ "Power Supply", +/* 09h */ "Power Unit", +/* 0Ah */ "Cooling Device", +/* 0Bh */ "FRU Sensor", +/* 0Ch */ "Memory", +/* 0Dh */ "Drive Slot", +/* 0Eh */ "POST Memory Resize", +/* 0Fh */ "System Firmware", +/* 10h */ "SEL Disabled", +/* 11h */ "Watchdog 1", +/* 12h */ "System Event", /* offset 0,1,2 */ +/* 13h */ "Critical Interrupt", /* offset 0,1,2 */ +/* 14h */ "Button", /* offset 0,1,2 */ +/* 15h */ "Board", +/* 16h */ "Microcontroller", +/* 17h */ "Add-in Card", +/* 18h */ "Chassis", +/* 19h */ "Chip Set", +/* 1Ah */ "Other FRU", +/* 1Bh */ "Cable / Interconnect", +/* 1Ch */ "Terminator", +/* 1Dh */ "System Boot Initiated", +/* 1Eh */ "Boot Error", +/* 1Fh */ "OS Boot", +/* 20h */ "OS Critical Stop", +/* 21h */ "Slot / Connector", +/* 22h */ "ACPI Power State", +/* 23h */ "Watchdog 2", +/* 24h */ "Platform Alert", +/* 25h */ "Entity Presence", +/* 26h */ "Monitor ASIC", +/* 27h */ "LAN", +/* 28h */ "Management Subsystem Health", +/* 29h */ "Battery", +}; +#endif + +#define NUNITS 30 +static char *unit_types[] = { +/* 00 */ "unspecified", +/* 01 */ "degrees C", +/* 02 */ "degrees F", +/* 03 */ "degrees K", +/* 04 */ "Volts", +/* 05 */ "Amps", +/* 06 */ "Watts", +/* 07 */ "Joules", +/* 08 */ "Coulombs", +/* 09 */ "VA", +/* 10 */ "Nits", +/* 11 */ "lumen", +/* 12 */ "lux", +/* 13 */ "Candela", +/* 14 */ "kPa", +/* 15 */ "PSI", +/* 16 */ "Newton", +/* 17 */ "CFM", +/* 18 */ "RPM", +/* 19 */ "Hz", +/* 20 */ "microseconds", +/* 21 */ "milliseconds", +/* 22 */ "seconds", +/* 23 */ "minutes", +/* 24 */ "hours", +/* 25 */ "days", +/* 26 */ "weeks", +/* 27 */ "mil", +/* 28 */ "inches", +/* 29 */ "feet", +/* 42 */ "cycles" +}; +/* 68 * "megabit", */ +/* 72 * "megabyte", */ +/* 90 * "uncorrectable error" (last defined)*/ +static char *unit_types_short[] = { +/* 00 */ "?", /*unknown, not specified*/ +/* 01 */ "C", +/* 02 */ "F", +/* 03 */ "K", +/* 04 */ "V", +/* 05 */ "A", +/* 06 */ "W", +/* 07 */ "J", +/* 08 */ "Coul", +/* 09 */ "VA", +/* 10 */ "Nits", +/* 11 */ "lumen", +/* 12 */ "lux", +/* 13 */ "Cand", +/* 14 */ "kPa", +/* 15 */ "PSI", +/* 16 */ "Newton", +/* 17 */ "CFM", +/* 18 */ "RPM", +/* 19 */ "Hz", +/* 20 */ "usec", +/* 21 */ "msec", +/* 22 */ "sec", +/* 23 */ "min", +/* 24 */ "hrs", +/* 25 */ "days", +/* 26 */ "wks", +/* 27 */ "mil", +/* 28 */ "in", +/* 29 */ "ft", +/* 42 */ "cyc" +}; + +ushort parse_idx(char *str) +{ + int i, n; + char istr[5]; + if (strncmp(str,"0x",2) == 0) str += 2; + n = strlen_(str); + if (n == 4) { + i = (htoi(str) << 8) + htoi(&str[2]); + } else if (n == 3) { + istr[0] = '0'; + memcpy(&istr[1],str,3); + i = (htoi(istr) << 8) + htoi(&istr[2]); + } else i = htoi(str); /*was atoi()*/ + printf("idx = 0x%x\n",i); + return((ushort)i); +} + +int get_idx_range(char *str) +{ + // int i = 0; + char *p; + p = strchr(str,'-'); + if (p == NULL) p = strchr(str,','); + if (p != NULL) { + *p = 0; + p++; + sensor_idx1 = parse_idx(str); + sensor_idxN = parse_idx(p); + } else { + sensor_idx1 = parse_idx(str); + sensor_idxN = sensor_idx1; + } + return(0); +} + +char *get_unit_type(int iunits, int ibase, int imod, int fshort) +{ + char *pstr = NULL; + char **punittypes; + static char unitstr[32]; + int jbase, jmod; + uchar umod; + + punittypes = unit_types; + if (fshort) punittypes = unit_types_short; + if (fdebug) printf("get_unit_type(%x,%d,%d,%d)\n",iunits,ibase,imod,fshort); + umod = (iunits & 0x06) >> 1; + if (ibase < NUNITS) jbase = ibase; + else { + if (fdebug) printf("units base %02x > %d\n",ibase,NUNITS); + if (ibase == 42) jbase = NUNITS; /*"cycles"*/ + else jbase = 0; + } + if (imod < NUNITS) jmod = imod; + else { + if (fdebug) printf("units mod %02x > %d\n",imod,NUNITS); + jmod = 0; + } + switch (umod) { + case 2: + snprintf(unitstr,sizeof(unitstr),"%s * %s", + punittypes[jbase],punittypes[jmod]); + pstr = unitstr; + break; + case 1: + snprintf(unitstr,sizeof(unitstr),"%s/%s", + punittypes[jbase],punittypes[jmod]); + pstr = unitstr; + break; + case 0: + default: + pstr = punittypes[jbase]; + break; + } + if ((umod == 0) && (iunits > 0)) { + /* special cases for other SensorUnits1 bits */ + if ((iunits & 0x01) != 0) { /*percentage*/ + if (fshort) pstr = "%"; + else pstr = "percent"; + } else if (iunits == 0xC0) { /*no analog reading*/ + pstr = "na"; + } else if (iunits == 0x18) { + /* For Tyan fans: base=42, units=24.(0x18) -> cycles/hour */ + snprintf(unitstr,sizeof(unitstr),"%s/hour",punittypes[jbase]); + pstr = unitstr; + } + } + return(pstr); +} + +char *decode_capab(uchar c) +{ + static char cstr[50]; + char *arm; + char *thr; + char *evt; + // char *hys; + uchar b; + /* decode sens_capab bits */ + if ((c & 0x40) == 0) arm = "man"; /*manual rearm*/ + else arm = "auto"; /*automatic rearm*/ + /* skip hysteresis bits (0x30) */ + b = ((c & 0x0c) >> 2); + switch(b) { + case 0x00: thr = "none"; break; /*no thresholds*/ + case 0x01: thr = "read"; break; + case 0x02: thr = "write"; break; /*read & write*/ + case 0x03: + default: thr = "fixed"; break; + } + b = (c & 0x03) ; + switch(b) { + case 0x00: evt = "state"; break; /*threshold or discrete state*/ + case 0x01: evt = "entire"; break; /*entire sensor only*/ + case 0x02: evt = "disab"; break; /*global disable only*/ + case 0x03: + default: evt = "none"; break; /*no events*/ + } + sprintf(cstr,"arm=%s thr=%s evts=%s",arm,thr,evt); + return(cstr); +} + + +int get_group_id(char *pstr) +{ + int i, j, n, sz, len; + char *p; + int rv = -1; + + sz = strlen_(pstr); + p = &pstr[0]; + n = 0; + for (i = 0; i <= sz; i++) { + if (n >= N_SGRP) break; + switch(pstr[i]) { + case ',': /*delimiter*/ + case '\n': + case '\0': + pstr[i] = 0; /*stringify this word*/ + len = strlen_(p); + for (j = 0; j < NSENSTYPES; j++) { + if (strncasecmp(get_sensor_type_desc(j),p,len) == 0) { + sensor_grps[n++] = (uchar)j; + rv = 0; + break; + } + } /*endfor(j)*/ + if (i+1 < sz) p = &pstr[i+1]; /*set p for next word*/ + if (j >= NSENSTYPES) { /* sensor type not found */ + rv = -1; + i = sz; /*exit loop*/ + } + break; + default: + break; + } /*end switch*/ + } /*end for(i)*/ + if (rv == 0) rv = n; + else rv = -1; + return(rv); +} + +static int validate_thresholds(void *pthrs, char flag, uchar *sdr) +{ + double *thrf; + uchar *thr; + int rv = 0; + uchar bits; + + if (sdr == NULL) bits = 0xff; /*assume all are used*/ + else bits = sdr[18]; /*18=indicates which are readable/used */ + + if (bits == 0) { + printf("No threshold values can be set for this sensor.\n"); + return(3); + } + if (flag == 1) { /*float*/ + thrf = (double *)pthrs; + if (fdebug) + printf("validate_thresh: bits=%02x, values: %f>=%f>=%f, %f<=%f<=%f\n", + bits, thrf[0],thrf[1],thrf[2], thrf[3],thrf[4],thrf[5]); + if ((bits & 0x02) != 0) { /*thrf[1] lo-crit is valid*/ + if ((thrf[1] > thrf[0]) && ((bits & 0x01) != 0)) rv = 1; + if ((thrf[2] > thrf[1]) && ((bits & 0x04) != 0)) rv = 1; /*lo is wrong*/ + } + if ((bits & 0x10) != 0) { /*thrf[4] hi-crit is valid*/ + if ((thrf[4] < thrf[3]) && ((bits & 0x08) != 0)) rv = 2; + if ((thrf[5] < thrf[4]) && ((bits & 0x20) != 0)) rv = 2; /*hi is wrong*/ + } + if (rv != 0) { + printf("Threshold values: %f>=%f>=%f, %f<=%f<=%f\n", + thrf[0], thrf[1], thrf[2], thrf[3], thrf[4], thrf[5]); + printf("Invalid threshold order in %s range.\n", + ((rv == 1)? "lo": "hi")); + } + } else { + thr = (uchar *)pthrs; + if ((bits & 0x02) != 0) { /*thr[1] lo-crit is valid*/ + if ((thr[1] > thr[0]) && ((bits & 0x01) != 0)) rv = 1; + if ((thr[2] > thr[1]) && ((bits & 0x04) != 0)) rv = 1; /*lo is wrong*/ + } + if ((bits & 0x10) != 0) { /*thr[4] hi-crit is valid*/ + if ((thr[4] < thr[3]) && ((bits & 0x08) != 0)) rv = 2; + if ((thr[5] < thr[4]) && ((bits & 0x20) != 0)) rv = 2; /*hi is wrong*/ + } + if (rv != 0) { + printf("Threshold values: %02x>=%02x>=%02x %02x<=%02x<=%02x\n", + thr[0], thr[1], thr[2], thr[3], thr[4], thr[5]); + printf("Invalid threshold order within -u (%s)\n", + ((rv == 1)? "lo": "hi")); + } + } + return(rv); +} + +int +GetSDRRepositoryInfo(int *nret, int *fdev) +{ + uchar resp[MAX_BUFFER_SIZE]; + int sresp = MAX_BUFFER_SIZE; + int rc; + int nSDR; + int freespace; + ushort cmd; + uchar cc = 0; + int i; + + memset(resp,0,6); /* init first part of buffer */ + if (nret != NULL) *nret = 0; + if (fdev != NULL) fdevsdrs = *fdev; + if (fdevsdrs) cmd = GET_DEVSDR_INFO; + else cmd = GET_SDR_REPINFO; + rc = ipmi_cmd_mc(cmd, NULL, 0, resp,&sresp, &cc, fdebug); + if (fdebug) printf("ipmi_cmd[%04x] repinf(%d) status=%d cc=%x\n", + cmd, fdevsdrs,rc,cc); + /* some drivers return cc in rc */ + if ((rc == 0xc1) || (rc == 0xd4)) cc = rc; + else if (rc != 0) return(rc); + if (cc != 0) { + if ((cc == 0xc1) || /*0xC1 (193.) means unsupported command */ + (cc == 0xd4)) /*0xD4 means insufficient privilege (Sun/HP)*/ + { + /* Must be reporting wrong bit for fdevsdrs, + * so switch & retry */ + if (fdevsdrs) { + fdevsdrs = 0; + cmd = GET_SDR_REPINFO; + } else { + fdevsdrs = 1; + cmd = GET_DEVSDR_INFO; + } + sresp = MAX_BUFFER_SIZE; + rc = ipmi_cmd_mc(cmd, NULL, 0, resp,&sresp, &cc, fdebug); + if (fdebug) + printf("ipmi_cmd[%04x] repinf status=%d cc=%x\n",cmd,rc,cc); + if (rc != ACCESS_OK) return(rc); + if (cc != 0) return(cc); + } else return(cc); + } + + if (fdevsdrs) { + nSDR = resp[0]; + freespace = 1; + fReserveOK = 1; + } else { + nSDR = resp[1] + (resp[2] << 8); + freespace = resp[3] + (resp[4] << 8); + if ((resp[13] & 0x02) == 0) fReserveOK = 0; + else fReserveOK = 1; + } + if (nret != NULL) *nret = nSDR; + if (fdev != NULL) *fdev = fdevsdrs; + if (fdebug) { + //successful, show data + printf("SDR Repository (len=%d): ",sresp); + for (i = 0; i < sresp; i++) printf("%02x ",resp[i]); + printf("\n"); + printf("SDR Info: fdevsdrs=%d nSDRs=%d free space = %x ReserveOK=%d\n", + fdevsdrs,nSDR,freespace,fReserveOK); + } + + return(0); +} /*end GetSDRRepositoryInfo()*/ + + +int +GetSensorThresholds(uchar sens_num, uchar *thr_data) +{ + uchar resp[MAX_BUFFER_SIZE]; + int sresp = MAX_BUFFER_SIZE; + uchar inputData[6]; + int rc; + uchar cc = 0; + + inputData[0] = sens_num; + rc = ipmi_cmd_mc(GET_SENSOR_THRESHOLD, inputData,1, resp,&sresp, &cc,fdebug); + if (fdebug) + printf("GetSensorThreshold[%02x] rc = %d, resp(%d) %02x %02x %02x %02x %02x %02x %02x\n", + sens_num,rc, sresp,resp[0],resp[1],resp[2],resp[3], + resp[4],resp[5],resp[6]); + if (rc != ACCESS_OK) return(rc); + if (cc != 0) return(cc); + if (sresp == 0) return(-2); + memcpy(thr_data,resp,sresp); + return(0); +} + +int +RearmSensor(uchar sens_num) +{ + uchar resp[MAX_BUFFER_SIZE]; + int sresp = MAX_BUFFER_SIZE; + uchar inputData[8]; + int rc; + uchar cc = 0; + + memset(inputData,0,6); + memset(resp,0,6); + inputData[0] = sens_num; + rc = ipmi_cmd_mc(GET_SEVT_ENABLE, inputData, 1, resp,&sresp, &cc, fdebug); + if (rc == 0 && cc != 0) rc = cc; + if (rc != 0 || fdebug) + printf("GetSensorEventEnable(%02x) rc = %d, cc = %x %02x %02x %02x\n", + sens_num,rc,cc,resp[0],resp[1],resp[3]); + if (rc == 0 && resp[0] != 0xc0) { + printf("EventEnable(%02x) = %02x, is not 0xc0\n", + sens_num,resp[0]); + memset(inputData,0,6); + inputData[0] = sens_num; + inputData[1] = resp[0] | 0xc0; + inputData[2] = resp[1]; + inputData[3] = resp[2]; + inputData[4] = resp[3]; + inputData[5] = resp[4]; + rc = ipmi_cmd_mc(SET_SEVT_ENABLE, inputData, 6, resp,&sresp, + &cc, fdebug); + if (rc == 0 && cc != 0) rc = cc; + if (rc != 0 || fdebug) + printf("SetSensorEventEnable(%02x) rc = %d, cc = %x\n", + sens_num,rc,cc); + } + + memset(inputData,0,6); + inputData[0] = sens_num; + inputData[1] = 0; /* rearm all events for this sensor */ + rc = ipmi_cmd_mc(REARM_SENSOR, inputData, 6, resp,&sresp, &cc, fdebug); + if (fdebug) + printf("RearmSensor(%02x) rc = %d, cc = %x %02x %02x\n", + sens_num,rc,cc,resp[0],resp[1]); + if (rc == 0 && cc != 0) rc = cc; + + /* Could also do a global rearm via SetEventReceiver. */ + + return(rc); +} /*end RearmSensor*/ + +int +SetSensorThresholds(uchar sens_num, uchar hi, uchar lo, + uchar *thr_data, uchar *thr_set) +{ + uchar resp[MAX_BUFFER_SIZE]; + int sresp = MAX_BUFFER_SIZE; + uchar inputData[8]; + int rc; + uchar cc = 0; + uchar sets = 0; + int i; + + /* + * Set the sensor Hysteresis before setting the threshold. + */ + memset(inputData,0,8); + inputData[0] = sens_num; + inputData[1] = 0xff; + rc = ipmi_cmd_mc(GET_SENSOR_HYSTERESIS,inputData,2, resp,&sresp, &cc,fdebug); + if (fdebug) + printf("GetSensorHysteresis(%02x) rc = %d, cc = %x %02x %02x\n", + sens_num,rc,cc,resp[0],resp[1]); + if (rc != ACCESS_OK) return(rc); + inputData[0] = sens_num; + inputData[1] = 0xff; + inputData[2] = resp[0]; + inputData[3] = resp[1]; + rc = ipmi_cmd_mc(SET_SENSOR_HYSTERESIS,inputData,4, resp,&sresp, &cc,fdebug); + if (fdebug) + printf("SetSensorHysteresis(%02x) rc = %d, cc = %x\n", + sens_num,rc,cc); + if (rc != ACCESS_OK) return(rc); + + /* + * The application should validate that values are ordered, + * e.g. upper critical should be greater than upper + * non-critical. + * Due to the limited command line parameter interface, + * use the hi & lo values to set each of the thresholds. + * For a full implemenation, these thresholds should be set + * individually. + */ + memset(inputData,0,8); + inputData[0] = sens_num; + sets = thr_data[0]; + if (thr_set != NULL) { /* use specific thr_set values */ + memcpy(&inputData[2],thr_set,6); + } else { /*default, use hi/lo params */ + if (lo == 0xff) sets &= 0x38; /* don't set lowers */ + else { + inputData[2] = lo; /* lower non-crit (& 0x01) */ + inputData[3] = lo - 1; /* lower critical (& 0x02) */ + inputData[4] = lo - 2; /* lower non-recov (& 0x04) */ + } + if (hi == 0xff) sets &= 0x07; /* don't set uppers */ + else { + inputData[5] = hi; /* upper non-crit (& 0x08) */ + inputData[6] = hi + 1; /* upper critical (& 0x10) */ + inputData[7] = hi + 2; /* upper non-recov (& 0x20) */ + } + } + inputData[1] = sets; /* which ones to set */ + { /* show from/to changes */ + printf("GetThreshold[%02x]: %02x ",sens_num,sens_num); + for (i = 0; i < 7; i++) printf("%02x ",thr_data[i]); + printf("\n"); + printf("SetThreshold[%02x]: ",sens_num); + for (i = 0; i < 8; i++) printf("%02x ",inputData[i]); + printf("\n"); + } + rc = ipmi_cmd_mc(SET_SENSOR_THRESHOLD, inputData, 8, resp,&sresp, &cc, fdebug); + if (fdebug) + printf("SetSensorThreshold(%02x) rc = %d, cc = %x\n", + sens_num,rc,cc); + if (rc == 0 && cc != 0) rc = cc; + /* mBMC gets cc = 0xD5 (213.) here, setting thresholds disabled. */ + return(rc); +} + +int +GetSensorReading(uchar sens_num, void *psdr, uchar *sens_data) +{ + uchar resp[MAX_BUFFER_SIZE]; + int sresp = MAX_BUFFER_SIZE; + uchar inputData[6]; + SDR02REC *sdr = NULL; + int mc; + int rc; + uchar cc = 0; + uchar lun = 0; + uchar chan = 0; + + if (psdr != NULL) { + sdr = (SDR02REC *)psdr; + mc = sdr->sens_ownid; + if (mc != BMC_SA) { /* not BMC, e.g. HSC or ME sensor */ + uchar a = ADDR_IPMB; + if (mc == HSC_SA) a = ADDR_SMI; + chan = (sdr->sens_ownlun & 0xf0) >> 4; + lun = (sdr->sens_ownlun & 0x03); + ipmi_set_mc(chan,(uchar)mc, lun,a); + } + } else mc = BMC_SA; + inputData[0] = sens_num; + rc = ipmi_cmd_mc(GET_SENSOR_READING,inputData,1, resp,&sresp,&cc,fdebug); + if (fdebug) + printf("GetSensorReading mc=%x,%x,%x status=%d cc=%x sz=%d resp: %02x %02x %02x %02x\n", + chan,mc,lun,rc,cc,sresp,resp[0],resp[1],resp[2],resp[3]); + if (mc != BMC_SA) ipmi_restore_mc(); + if ((rc == 0) && (cc != 0)) { + if (fdebug) printf("GetSensorReading error %x %s\n",cc, + decode_cc((ushort)0,(uchar)cc)); + rc = cc; + } + if (rc != 0) return(rc); + + if (resp[1] & 0x20) { /* init state, reading invalid */ + if (fdebug) + printf("sensor[%x] in init state, no reading\n", sens_num); + sens_data[1] = resp[1]; + sens_data[2] = 0x40; /*set bit num for init state*/ + } else { /*valid reading, copy it*/ + /* only returns 4 bytes, no matter what type */ + memcpy(sens_data,resp,4); + } + return(0); +} /*end GetSensorReading()*/ + +int +GetSensorReadingFactors(uchar snum, uchar raw, int *m, int *b, int * b_exp, + int *r, int *a) +{ + uchar resp[MAX_BUFFER_SIZE]; + int sresp = MAX_BUFFER_SIZE; + uchar inputData[6]; + int rc; + uchar cc = 0; + int toler, a_exp; + + inputData[0] = snum; + inputData[1] = raw; + rc = ipmi_cmd_mc(GET_SENSOR_READING_FACTORS, inputData, 2, + resp,&sresp, &cc, fdebug); + if (fdebug) printf("GetSensorReadingFactors status = %d\n",rc); + if (rc != ACCESS_OK) return(rc); + if (cc != 0) return(cc); + + /* successful, copy values */ + *m = resp[1] + ((resp[2] & 0xc0) << 2); + toler = resp[2] & 0x3f; + *b = resp[3] + ((resp[4] & 0xc0) << 2); + *a = (resp[4] & 0x3f) + ((resp[5] & 0xf0) << 4); + a_exp = (resp[5] & 0xc0) >> 2; + *r = (resp[6] &0xf0) >> 4; + *b_exp = resp[6] & 0x0f; + if (fdebug) { + printf("factors: next=%x m=%d b=%d b_exp=%d a=%d a_exp=%d r=%d\n", + resp[0],*m,*b,*b_exp,*a,a_exp,*r); + } + return(0); +} + +int GetSensorType(uchar snum, uchar *stype, uchar *rtype) +{ + uchar resp[MAX_BUFFER_SIZE]; + int sresp = MAX_BUFFER_SIZE; + uchar inputData[6]; + int rc; + uchar cc = 0; + + inputData[0] = snum; + rc = ipmi_cmd_mc(GET_SENSOR_TYPE, inputData, 1, + resp,&sresp, &cc, fdebug); + if (fdebug) printf("GetSensorType: ipmi_cmd rv = %d, cc = %x\n",rc,cc); + if (rc != ACCESS_OK) return(rc); + if (cc != 0) return(cc); + /* successful, copy values */ + if (stype != NULL) *stype = resp[0]; + if (rtype != NULL) *rtype = resp[1] & 0x7f; + return(rc); +} + +void set_reserve(int val) +{ + fDoReserve = val; +} + +int sdr_get_reservation(uchar *res_id, int fdev) +{ + int sresp; + uchar resp[MAX_BUFFER_SIZE]; + uchar cc = 0; + ushort cmd; + int rc = -1; + + if (fDoReserve == 1) { + fDoReserve = 0; /* only reserve SDR the first time */ + sresp = sizeof(resp);; + if (fdev) cmd = RESERVE_DEVSDR_REP; + else cmd = RESERVE_SDR_REP; + rc = ipmi_cmd_mc(cmd, NULL, 0, resp, &sresp, &cc, fdebug); + if (rc == 0 && cc != 0) rc = cc; + if (rc == 0) { /* ok, so set the reservation id */ + resid[0] = resp[0]; + resid[1] = resp[1]; + } + /* A reservation is cancelled by the next reserve request. */ + if (fdebug) + printf("ipmi_cmd RESERVE status=%d cc=%x id=%02x%02x\n", + rc,cc,resid[0],resid[1]); + } else rc = 0; + /* if not first time, or if error, return existing resid. */ + res_id[0] = resid[0]; + res_id[1] = resid[1]; + return(rc); +} /*end sdr_get_reservation*/ + +int sdr_clear_repo(int fdev) +{ + int sresp; + uchar resp[MAX_BUFFER_SIZE]; + uchar inputData[6]; + uchar cc = 0; + int rc = -1; + ushort cmd; + uchar resv[2] = {0,0}; + + if (fReserveOK) + rc = sdr_get_reservation(resv,fdev); + + cmd = 0x27 + (NETFN_STOR << 8); /*Clear SDR Repository*/ + inputData[0] = resv[0]; /*res id LSB*/ + inputData[1] = resv[1]; /*res id MSB*/ + inputData[2] = 'C'; + inputData[3] = 'L'; + inputData[4] = 'R'; + inputData[5] = 0xAA; + sresp = sizeof(resp);; + rc = ipmi_cmd_mc(cmd, inputData, 6, resp, &sresp,&cc, fdebug); + if (fdebug) printf("sdr_clear_repo: rc = %d, cc = %x, sz=%d\n",rc,cc,sresp); + if (rc == 0 && cc != 0) rc = cc; + + if (rc == 0 && (resp[0] & 1) != 1) { + if (fdebug) printf("Wait for sdr_clear_repo to complete\n"); + os_usleep(1,0); + } + return(rc); +} + +int sdr_add_record(uchar *sdr, int fdev) +{ + int sresp; + uchar resp[MAX_BUFFER_SIZE]; + uchar inputData[6+SZCHUNK]; + uchar cc = 0; + int rc = -1; + ushort cmd; + uchar resv[2] = {0,0}; + int reclen, len, i; + int recid, chunksz; + uchar prog; + + reclen = sdr[4] + 5; + recid = sdr[0] + (sdr[1] << 8); + /* OEM SDRs can be min 8 bytes, less is an error. */ + if (reclen < 8) return(LAN_ERR_BADLENGTH); + if (fReserveOK) + rc = sdr_get_reservation(resv,fdev); + if (fdebug) printf("sdr_add_record[%x]: reclen = %d, reserve rc = %d\n", + recid,reclen,rc); + + cmd = 0x25 + (NETFN_STOR << 8); /*PartialAddSdr*/ + recid = 0; /*first chunk must be added as 0000*/ + chunksz = SZCHUNK; + for (i = 0; i < reclen; ) + { + prog = 0; + len = chunksz; + if ((i+chunksz) >= reclen) { /*last record*/ + len = reclen - i; + prog = 1; + } + inputData[0] = resv[0]; /*res id LSB*/ + inputData[1] = resv[1]; /*res id MSB*/ + inputData[2] = recid & 0x00ff; /*record id LSB*/ + inputData[3] = (recid >> 8) & 0x00ff; /*record id MSB*/ + inputData[4] = (uchar)i; /*offset */ + inputData[5] = prog; /*progress: 1=last record*/ + memcpy(&inputData[6],&sdr[i],len); + sresp = sizeof(resp); + rc = ipmi_cmd_mc(cmd, inputData, 6+len, resp, &sresp,&cc, fdebug); + if (fdebug) + printf("sdr_add_record[%x,%x]: rc = %d, cc = %x, sz=%d\n", + recid,i,rc,cc,sresp); + if (rc == 0 && cc != 0) rc = cc; + if (rc != 0) break; + if (recid == 0 && rc == 0) /*first time, so set recid*/ + recid = resp[0] + (resp[1] << 8); + i += len; + } + return(rc); +} + +int GetSDR(int r_id, int *r_next, uchar *recdata, int srecdata, int *rlen) +{ + int sresp; + uchar resp[MAX_BUFFER_SIZE+SZCHUNK]; + uchar respchunk[SZCHUNK+10]; + uchar inputData[6]; + uchar cc = 0; + int rc = -1; + int i, chunksz, thislen, off; + int reclen; + ushort cmd; + uchar resv[2] = {0,0}; + + chunksz = SZCHUNK; + reclen = srecdata; /*max size of SDR record*/ + off = 0; + *rlen = 0; + *r_next = 0xffff; /*default*/ + if (fReserveOK) + rc = sdr_get_reservation(resv,fdevsdrs); + if (fdevsdrs) cmd = GET_DEVICE_SDR; + else cmd = GET_SDR; + if (reclen == 0xFFFF) { /* get it all in one call */ + inputData[0] = resv[0]; /*res id LSB*/ + inputData[1] = resv[1]; /*res id MSB*/ + inputData[2] = r_id & 0x00ff; /*record id LSB*/ + inputData[3] = (r_id & 0xff00) >> 8; /*record id MSB*/ + inputData[4] = 0; /*offset */ + inputData[5] = 0xFF; /*bytes to read, ff=all*/ + sresp = sizeof(resp);; + if (fdebug) printf("ipmi_cmd SDR id=%d read_all, len=%d\n", + r_id,sresp); + rc = ipmi_cmd_mc(cmd, inputData, 6, recdata, &sresp,&cc, fdebug); + /* This will usually return cc = 0xCA (invalid length). */ + if (fdebug) printf("ipmi_cmd SDR data status = %d, cc = %x, sz=%d\n", + rc,cc,sresp); + reclen = sresp; + *r_next = recdata[0] + (recdata[1] << 8); + } else /* if (reclen > chunksz) do multi-part chunks */ + for (off = 0; off < reclen; ) + { + thislen = chunksz; + if ((off+chunksz) > reclen) thislen = reclen - off; + inputData[0] = resv[0]; /*res id LSB*/ + inputData[1] = resv[1]; /*res id MSB*/ + inputData[2] = r_id & 0x00ff; /*record id LSB*/ + inputData[3] = (r_id & 0xff00) >> 8; /*record id MSB*/ + inputData[4] = (uchar)off; /*offset */ + inputData[5] = (uchar)thislen; /*bytes to read, ff=all*/ + sresp = sizeof(respchunk); + rc = ipmi_cmd_mc(cmd, inputData, 6, respchunk, &sresp,&cc, fdebug); + if (fdebug) + printf("ipmi_cmd SDR[%x] off=%d ilen=%d status=%d cc=%x sz=%d\n", + r_id,off,thislen,rc,cc,sresp); + if (off == 0 && cc == 0xCA && thislen == SZCHUNK) { + /* maybe shorter than SZCHUNK, try again */ + chunksz = 0x06; + if (fdebug) printf("sdr[%x] try again with chunksz=%d\n", + r_id,chunksz); + continue; + } + if (off > chunksz) { + /* already have first part of the SDR, ok to truncate */ + if (rc == -3) { /* if LAN_ERR_RECV_FAIL */ + if (fdebug) printf("sdr[%x] error rc=%d len=%d truncated\n", + r_id,rc,sresp); + sresp = 0; + rc = 0; + } + if (cc == 0xC8 || cc == 0xCA) { /* length errors */ + /* handle certain MCs that report wrong length, + * at least use what we already have (sresp==0) */ + if (fdebug) printf("sdr[%x] error cc=%02x len=%d truncated\n", + r_id,cc,sresp); + cc = 0; + } + } + if (rc != ACCESS_OK) return(rc); + if (cc != 0) return(cc); + /* if here, successful, chunk was read */ + if (sresp < (thislen+2)) { + /* There are some SDRs that may report the wrong length, and + * return less bytes than they reported, so just truncate. */ + if (fdebug) printf("sdr[%x] off=%d, expected %d, got %d\n", + r_id,off,thislen+2,sresp); + if (sresp >= 2) thislen = sresp - 2; + else thislen = 0; + reclen = off + thislen; /* truncate, stop reading */ + } + /* successful */ + memcpy(&resp[off],&respchunk[2],thislen); + if (off == 0 && sresp >= 5) { + *r_next = respchunk[0] + (respchunk[1] << 8); + reclen = respchunk[6] + 5; /*get actual record size*/ + if (reclen > srecdata) { + if (fdebug) printf("sdr[%x] chunk0, reclen=%d srecdata=%d\n", + r_id, reclen, srecdata); + reclen = srecdata; /*truncate*/ + } + } + off += thislen; + *rlen = off; + } + if (fdebug) { + printf("GetSDR[%04x] next=%x (len=%d): ",r_id,*r_next,reclen); + for (i = 0; i < reclen; i++) printf("%02x ",resp[i]); + printf("\n"); + } + memcpy(recdata,&resp[0],reclen); + *rlen = reclen; + return(rc); +} /*end GetSDR*/ + +static int nsdrs = 0; /*number of sdrs*/ +static int sz_sdrs = 0; /*actual size used with sdrs*/ +static uchar *psdrcache = NULL; + +void free_sdr_cache(uchar *ptr) +{ + if (ptr != NULL) free(ptr); + if ((ptr != psdrcache) && (psdrcache != NULL)) + free(psdrcache); + psdrcache = NULL; +} + +int get_sdr_file(char *sdrfile, uchar **sdrlist) +{ + int rv = -1; + FILE *fp = NULL; + int i, n, num, nsdr, isdr, len; + uchar *sdrbuf; + uchar buff[255]; + uchar hbuf[85]; + char fvalid; + + fp = fopen(sdrfile,"r"); + if (fp == NULL) { + printf("Cannot open file %s\n",sdrfile); + return(ERR_FILE_OPEN); + } + /* determine number of SDRs by number of lines in the file */ + num = 0; + while (fgets(buff, 255, fp)) { num++; } + if (fdebug) printf("Reading %d SDRs from file %s\n",num,sdrfile); + sdrbuf = malloc(num * SDR_SZ); + if (sdrbuf == NULL) { + fclose(fp); + return(rv); + } + fseek(fp, 0L, SEEK_SET); + *sdrlist = sdrbuf; + psdrcache = sdrbuf; + nsdrs = num; + isdr = 0; + nsdr = 0; + while (fgets(buff, 255, fp)) { + len = strlen_(buff); + fvalid = 0; + if (buff[0] >= '0' && (buff[0] <= '9')) fvalid = 1; + else if (buff[0] >= 'a' && (buff[0] <= 'f')) fvalid = 1; + else if (buff[0] >= 'A' && (buff[0] <= 'F')) fvalid = 1; + if (fvalid == 0) continue; + i = 0; + for (n = 0; n < len; ) { + if (buff[n] < 0x20) break; /* '\n', etc. */ + hbuf[i++] = htoi(&buff[n]); + n += 3; + } + memcpy(&sdrbuf[isdr],hbuf,i); + isdr += i; + nsdr++; + } /*end while*/ + if (fdebug) printf("Read %d SDRs, %d bytes\n",nsdr,isdr); + fclose(fp); + rv = 0; + return(rv); +} + +int get_sdr_cache(uchar **pret) +{ + int rv = -1; + int i, n, sz, len, asz; + int recid, recnext; + uchar *pcache; + uchar *psdr; + + if (pret == NULL) return(rv); + fdevsdrs = use_devsdrs(fpicmg); + + if ((psdrcache != NULL) && (nsdrs > 0)) { /*already have sdrcache*/ + *pret = psdrcache; + if (fdebug) printf("get_sdr_cache: already have cache (%p)\n",*pret); + return(0); + } + + rv = GetSDRRepositoryInfo(&n,&fdevsdrs); + if (rv != 0) return(rv); + if (n == 0) { + /* this is an error, probably because fdevsdrs is wrong.*/ + if (fdebug) printf("get_sdr_cache: nsdrs=0, retrying\n"); + fdevsdrs = (fdevsdrs ^ 1); + n = 150; /*try some default num SDRs*/ + } + + sz = n * SDR_SZ; /*estimate max size for n sdrs*/ + pcache = malloc(sz); + if (pcache == NULL) return(rv); + psdrcache = pcache; + *pret = pcache; + memset(pcache,0,sz); + recid = 0; + asz = 0; + for (i = 0; i <= n; i++) + { + if (recid == 0xffff) break; + // psdr = &pcache[i * SDR_SZ]; + psdr = &pcache[asz]; + rv = GetSDR(recid,&recnext,psdr,SDR_SZ,&len); + if (fdebug) + printf("GetSDR[%x] rv = %d len=%d next=%x\n",recid,rv,len,recnext); + if (rv != 0) { + if (rv == 0xC5) { set_reserve(1); i--; } /*retry*/ + else break; + } else { /*success*/ + asz += len; + if (recnext == recid) recid = 0xffff; + else recid = recnext; + } + } + nsdrs = n; + sz_sdrs = asz; /* save the size for later*/ + if (fdebug) { + printf("get_sdr_cache, n=%d sz=%d asz=%d\n",n,sz,asz); + if (i < n) printf("get_sdr_cache error, i=%d < n=%d, rv=%d\n",i,n,rv); + } + return(rv); +} + +int find_nsdrs(uchar *pcache) +{ + int num = 0; + int asz = 0; + int i, len; + uchar *sdr; + ushort recid; + + if (pcache == NULL) return(num); + for (i = 0; asz < sz_sdrs; i++) + { + sdr = &pcache[asz]; + len = sdr[4] + 5; + recid = sdr[0] + (sdr[1] << 8); + asz += len; + if (fdebug) printf("SDR[%x] len=%d i=%d\n", recid,len,i); + } + num = i; + return(num); +} + +int find_sdr_by_snum(uchar *psdr, uchar *pcache, uchar snum, uchar sa) +{ + int rv = -1; + uchar *sdr; + int i, k, len; + int asz = 0; + if (psdr == NULL) return(rv); + if (pcache == NULL) return(rv); + for (i = 0; i <= nsdrs; i++) + { + // sdr = &pcache[i * SDR_SZ]; + sdr = &pcache[asz]; + len = sdr[4] + 5; + asz += len; + switch(sdr[3]) { + case 0x01: k = 7; break; /*full sensor*/ + case 0x02: k = 7; break; /*compact sensor*/ + case 0x03: k = 7; break;/*compact sensor*/ + default: k = 0; break; + } + if (k == 0) continue; + else { + if ((sdr[5] == sa) && (sdr[k] == snum)) { + memcpy(psdr,sdr,len); + return(0); + } + } + } + return(rv); +} + +int find_sdr_by_tag(uchar *psdr, uchar *pcache, char *tag, uchar dbg) +{ + int rv = -1; + uchar *sdr; + int i, k, n, len; + int asz = 0; + if (psdr == NULL) return(rv); + if (pcache == NULL) return(rv); + if (tag == NULL) return(rv); + if (dbg) fdebug = 1; + n = strlen_(tag); + if (fdebug) printf("find_sdr_by_tag(%s) nsdrs=%d\n",tag,nsdrs); + for (i = 0; i <= nsdrs; i++) + { + // sdr = &pcache[i * SDR_SZ]; + sdr = &pcache[asz]; + len = sdr[4] + 5; + asz += len; + switch(sdr[3]) { /* set tag offset by SDR type */ + case 0x01: k = 48; break; /*full SDR*/ + case 0x02: k = 32; break; /*compact SDR*/ + case 0x03: k = 17; break; /*event-only SDR*/ + case 0x10: k = 16; break; /*device locator SDR*/ + case 0x11: k = 16; break; /*FRU device locator SDR*/ + case 0x12: k = 16; break; /*IPMB device locator SDR*/ + default: k = 0; break; /*else do not have an ID string/tag*/ + } + if (k == 0) { + if (fdebug) printf("sdr[%d] idx=%02x%02x num=%x type=%x skip\n", + i,sdr[1],sdr[0],sdr[7],sdr[3]); + continue; + } else { + if (len > SDR_SZ) len = SDR_SZ; + if (fdebug) { + char tmp[17]; + memset(tmp,0,sizeof(tmp)); + memcpy(tmp,&sdr[k],(len - k)); + tmp[16] = 0; /*force stringify*/ + printf("sdr[%d] idx=%02x%02x num=%x tag: %s\n",i,sdr[1],sdr[0], + sdr[7],tmp); + } + if (strncmp(tag,&sdr[k],n) == 0) { + memcpy(psdr,sdr,len); + return(0); + } + } + } + return(rv); +} + + +int find_sdr_next(uchar *psdr, uchar *pcache, ushort id) +{ + int rv = -1; + uchar *sdr; + int i, imatch, len; + ushort recid; + int asz = 0; + if (psdr == NULL) return(rv); + if (pcache == NULL) return(rv); + imatch = nsdrs; + for (i = 0; i < nsdrs; i++) + { + // sdr = &pcache[i * SDR_SZ]; + sdr = &pcache[asz]; + len = sdr[4] + 5; + recid = sdr[0] + (sdr[1] << 8); + asz += len; + // if (fdebug) printf("SDR[%x] len=%d id=%x i=%d imatch=%d\n", + // recid,len,id,i,imatch); + if (recid == id) imatch = i + 1; /*matches prev, return next one*/ + if (id == 0) { rv = 0; break; } + if (i == imatch) { rv = 0; break; } + } + if (rv == 0) memcpy(psdr,sdr,len); + return(rv); +} + +int find_sdr_by_id(uchar *psdr, uchar *pcache, ushort id) +{ + int rv = -1; + uchar *sdr; + int i, imatch, len; + ushort recid; + int asz = 0; + if (psdr == NULL) return(rv); + if (pcache == NULL) return(rv); + imatch = nsdrs; + for (i = 0; i < nsdrs; i++) + { + sdr = &pcache[asz]; + len = sdr[4] + 5; + recid = sdr[0] + (sdr[1] << 8); + asz += len; + if (recid == id) { rv = 0; break; } + } + if (rv == 0) memcpy(psdr,sdr,len); + return(rv); +} + +uchar +bitnum(ushort value) +{ + uchar ret = 0; + int i; + /* returns the highest bit number number set in this word. */ + /* Bit numbers are 1-based in this routine, 0 means no bits set. */ + /* scan 15 bits (0x7FFF). */ + for (i = 0; i < 15; i++) { + if (value & 0x01) ret = i+1; /*was ret++;*/ + value = (value >> 1); + } + return(ret); +} + +static double +expon(int x, int y) +{ + double res; + int i; + /* compute exponent: x to the power y */ + res = 1; + if (y > 0) { + for (i = 0; i < y; i++) res = res * x; + } else if (y < 0) { + for (i = 0; i > y; i--) res = res / x; + } /* else if if (y == 0) do nothing, res=1 */ + return(res); +} + +double +RawToFloat(uchar raw, uchar *psdr) +{ + double floatval; + int m, b, a; + uchar ax; + int rx, b_exp; + SDR01REC *sdr; + int signval; + + sdr = (SDR01REC *)psdr; + floatval = (double)raw; /*default*/ + + // if (raw == 0xff) floatval = 0; else + if (sdr->rectype == 0x01) { /* SDR rectype == full */ + if (fdebug) + printf("units=%x base=%d mod=%d (raw=%x, nom_rd=%x)\n", + sdr->sens_units,sdr->sens_base,sdr->sens_mod, + raw, sdr->nom_reading); + m = sdr->m + ((sdr->m_t & 0xc0) << 2); + b = sdr->b + ((sdr->b_a & 0xc0) << 2); + if (b & 0x0200) b = (b - 0x0400); /*negative*/ + if (m & 0x0200) m = (m - 0x0400); /*negative*/ + rx = (sdr->rx_bx & 0xf0) >> 4; + if (rx & 0x08) rx = (rx - 0x10); /*negative, fix sign w ARM compilers*/ + a = (sdr->b_a & 0x3f) + ((sdr->a_ax & 0xf0) << 2); + ax = (sdr->a_ax & 0x0c) >> 2; + b_exp = (sdr->rx_bx & 0x0f); + if (b_exp & 0x08) b_exp = (b_exp - 0x10); /*negative*/ + //b_exp |= 0xf0; /* negative 8-bit */ + if ((sdr->sens_units & 0xc0) == 0) { /*unsigned*/ + floatval = (double)raw; + } else { /*signed*/ + if (raw & 0x80) signval = (raw - 0x100); + else signval = raw; + floatval = (double)signval; + } + floatval *= (double) m; +#ifdef MATH_OK + floatval += (b * pow (10,b_exp)); + floatval *= pow (10,rx); +#else + floatval += (b * expon (10,b_exp)); + floatval *= expon (10,rx); +#endif + if (fdebug) + printf("decode1: m=%d b=%d b_exp=%x rx=%d, a=%d ax=%d l=%x, floatval=%f\n", + m,b,b_exp,rx,a,ax,sdr->linear,floatval); + switch(sdr->linear) { + case 0: /*linear*/ + break; + case 7: /*invert 1/x*/ + /* skip if zero to avoid dividing by zero */ + if (raw != 0) floatval = 1 / floatval; + break; + case 1: /*ln*/ + case 2: /*log10, log2, e, exp10, exp2, */ + case 3: /*log2*/ + case 4: /*e*/ + case 5: /*exp10*/ + case 6: /*exp2*/ + case 8: /*sqr(x)*/ + case 9: /*cube(x)*/ + case 10: /*sqrt(x)*/ + case 11: /*cube-1(x)*/ + default: + if (fdebug) printf("linear mode %x not implemented\n",sdr->linear); + break; + } /*end-switch linear*/ + } + +#ifdef NOT_LINEAR + /* else if (sdr->linear != 7) */ + { + double be, re; + rc = GetSensorType(sdr->sens_num,&stype,&rtype); + if (fdebug) + printf("decode: rc=%x, stype=%x, rtype=%x\n",rc,stype,rtype); + if (rc != 0) return(floatval); + + /* GetSensorReadingFactors */ + rc = GetSensorReadingFactors(sdr->sens_num,raw,&m,&b,&b_exp,&r,&a); + if (rc == 0) { + // floatval = ((m * raw) + (b * be)) * re; + } + if (fdebug) printf("decode: rc=%x, floatval=%f\n",rc,floatval); + } +#endif + + return(floatval); +} + +#define IpmiAnalogDataFormatUnsigned 0 +#define IpmiAnalogDataFormat1Compl 1 +#define IpmiAnalogDataFormat2Compl 2 + +uchar +FloatToRaw(double val, uchar *psdr, int rounding) +{ + double cval; + int lowraw, highraw, raw, maxraw, minraw, next_raw; + int analog_dfmt; + + analog_dfmt = (psdr[20] >> 6) & 0x03; + switch( analog_dfmt ) + { + case IpmiAnalogDataFormat1Compl: + lowraw = -127; + highraw = 127; + minraw = -127; + maxraw = 127; + next_raw = 0; + break; + case IpmiAnalogDataFormat2Compl: + lowraw = -128; + highraw = 127; + minraw = -128; + maxraw = 127; + next_raw = 0; + break; + case IpmiAnalogDataFormatUnsigned: + default: + lowraw = 0; + highraw = 255; + minraw = 0; + maxraw = 255; + next_raw = 128; + break; + } + + /* do a binary search for the right nth root value */ + do { + raw = next_raw; + cval = RawToFloat( (uchar)raw, psdr ); + if ( cval < val ) { + next_raw = ((highraw - raw) / 2) + raw; + lowraw = raw; + } else { + next_raw = ((raw - lowraw) / 2) + lowraw; + highraw = raw; + } + } while ( raw != next_raw ); + + /* Do rounding to get the final value */ + switch( rounding ) { + case 0: /* Round Normal = Round to nearest value */ + if ( val > cval ) { + if ( raw < maxraw ) { + double nval; + nval = RawToFloat((uchar)(raw+1),psdr); + nval = cval + ((nval - cval) / 2.0); + if ( val >= nval ) raw++; + } + } else { + if ( raw > minraw ) { + double pval; + pval = RawToFloat((uchar)(raw-1),psdr); + pval = pval + ((cval - pval) / 2.0); + if ( val < pval ) raw--; + } + } + break; + case 1: /*Round Down*/ + if ((val < cval) && (raw > minraw )) raw--; + break; + case 2: /*Round Up*/ + if ((val > cval) && (raw < maxraw)) raw++; + break; + } + if ( analog_dfmt == IpmiAnalogDataFormat1Compl ) + if ( raw < 0 ) raw -= 1; + return((uchar)raw); +} /*end FloatToRaw()*/ + +static int fill_thresholds(double *thrf, uchar *sdr) +{ + int rv = 0; + uchar *vals; + uchar bits; + + // snum = sdr[7]; + bits = sdr[19]; /*which are settable*/ + vals = &sdr[36]; + if (fdebug) + printf("fill_thresholds: bits=%02x, values: %f>=%f>=%f, %f<=%f<=%f\n", + bits, thrf[0],thrf[1],thrf[2], thrf[3],thrf[4],thrf[5]); + if (thrf[0] == THR_EMPTY) { + if ((bits & 0x01) != 0) { /*lo-noncrit*/ + thrf[0] = RawToFloat(vals[5],sdr); + rv++; + } else thrf[0] = 0; + } + if (thrf[1] == THR_EMPTY) { + if ((bits & 0x02) != 0) { /*lo-crit*/ + thrf[1] = RawToFloat(vals[4],sdr); + rv++; + } else thrf[1] = 0; + } + if (thrf[2] == THR_EMPTY) { + if ((bits & 0x04) != 0) { /*lo-unrec*/ + thrf[2] = RawToFloat(vals[3],sdr); + rv++; + } else thrf[2] = 0; + } + if (thrf[3] == THR_EMPTY) { + if ((bits & 0x08) != 0) { /*hi-noncrit*/ + thrf[3] = RawToFloat(vals[2],sdr); + rv++; + } else thrf[3] = 0; + } + if (thrf[4] == THR_EMPTY) { + if ((bits & 0x10) != 0) { /*hi-crit*/ + thrf[4] = RawToFloat(vals[1],sdr); + rv++; + } else thrf[4] = 0; + } + if (thrf[5] == THR_EMPTY) { + if ((bits & 0x20) != 0) { /*hi-unrec*/ + thrf[5] = RawToFloat(vals[0],sdr); + rv++; + } else thrf[5] = 0; + } + if (fdebug) + printf("fill_thresholds: after rv=%d values: %f>=%f>=%f, %f<=%f<=%f\n", + rv,thrf[0],thrf[1],thrf[2], thrf[3],thrf[4],thrf[5]); + return(rv); +} + +char * +decode_itype(uchar itype) +{ + char *retstr; + int i; + /* Decode the Interrupt Type from Entity Assoc records */ + + retstr = tmpstr; + if (itype <= 0x0f) sprintf(retstr,"IRQ_%d",itype); + else if (itype <= 0x13) { + strcpy(retstr,"PCI-A"); + for (i=0x10;i<itype;i++) retstr[4]++; + } + else if (itype == 0x14) strcpy(retstr,"SMI"); + else if (itype == 0x15) strcpy(retstr,"SCI"); + else if (itype >= 0x20 && itype <= 0x5f) + sprintf(retstr,"SysInt_%d",itype-0x20); + else if (itype == 0x60) strcpy(retstr,"ACPI/PnP"); + else if (itype == 0xFF) strcpy(retstr,"NoInt"); + else strcpy(retstr,"Invalid"); + return(retstr); +} + +int decode_oem_sensor(uchar *sdr,uchar *reading,char *pstring,int slen) +{ + int rv = -1; +#ifdef METACOMMAND + switch(vend_id) { + case VENDOR_INTEL: + rv = decode_sensor_intel(sdr, reading, pstring, slen); + break; + case VENDOR_KONTRON: + rv = decode_sensor_kontron(sdr, reading, pstring, slen); + break; + case VENDOR_FUJITSU: + rv = decode_sensor_fujitsu(sdr,reading,pstring,slen); + break; + case VENDOR_SUN: + rv = decode_sensor_sun(sdr, reading, pstring, slen); + break; + case VENDOR_MAGNUM: + case VENDOR_SUPERMICRO: + case VENDOR_SUPERMICROX: + rv = decode_sensor_supermicro(sdr, reading, pstring, slen); + break; + case VENDOR_QUANTA: + rv = decode_sensor_quanta(sdr, reading, pstring, slen); + break; + case VENDOR_HP: + rv = decode_sensor_hp(sdr, reading, pstring, slen); + break; + case VENDOR_DELL: + rv = decode_sensor_dell(sdr, reading, pstring, slen); + break; + default: + break; + } /*end-switch vend_id*/ + if (fdebug && rv == 0) + printf("decode_oem_sensor rv=%d vend=%x string=%s\n",rv,vend_id,pstring); +#endif + return (rv); +} + +int show_oemsdr(int vend, uchar *sdr) +{ + int rv = -1; + int i, len; + +#ifdef METACOMMAND + if (vend == VENDOR_INTEL) { + show_oemsdr_intel(sdr); /*show subtypes for Intel BMC_TAM*/ + rv = 0; + } else if (vend == 4156) { /*special HP/NewAccess OEM SDR*/ + show_oemsdr_hp(sdr); + rv = 0; + } else if (vend == VENDOR_QUANTA) { + printf("Quanta: "); + show_oemsdr_nm(sdr); + rv = 0; + } +#endif + if (rv != 0) { + len = sdr[4] + 5; + if (vend == VENDOR_FUJITSU) printf("Fujitsu: "); + else if (vend == VENDOR_INTEL) printf("Intel: "); + else printf("manuf=%d: ",vend); + for (i = 8; i < len; i++) printf("%02x ",sdr[i]); + printf("\n"); + } + return(rv); +} + +void +ShowThresh(int flg, uchar bits, uchar *vals, uchar *sdr) +{ + char str[128] = ""; + char part[24]; /* ~15 bytes used */ + double ival; + char sep[4]; + char *tag; + tag = ""; + if (fsimple) { + sprintf(sep,"%c ",bdelim); + tag = "Thresholds"; + } else sep[0] = 0; /*null string*/ + if (fshowthr == 2) { + double i0, i1, i2, i3, i4, i5; + i0 = RawToFloat(vals[0],sdr); + i1 = RawToFloat(vals[1],sdr); + i2 = RawToFloat(vals[2],sdr); + i3 = RawToFloat(vals[3],sdr); + i4 = RawToFloat(vals[4],sdr); + i5 = RawToFloat(vals[5],sdr); + sprintf(str,"%.2f:%.2f:%.2f:%.2f:%.2f:%.2f",i0,i1,i2,i3,i4,i5); + printf("\t%s%s%s%c",sep,"Thresh ",str,chEol); + } else if (flg != 0) { /* Compact, did GetThresholds, reverse order */ + if (bits & 0x20) { + ival = RawToFloat(vals[5],sdr); + sprintf(part,"%shi-unrec %.2f ",sep,ival); + strcat(str,part); + } + if (bits & 0x10) { + ival = RawToFloat(vals[4],sdr); + sprintf(part,"%shi-crit %.2f ", sep,ival); + strcat(str,part); + } + if (bits & 0x08) { + ival = RawToFloat(vals[3],sdr); + sprintf(part,"%shi-noncr %.2f ",sep,ival); + strcat(str,part); + } + if (bits & 0x01) { + ival = RawToFloat(vals[0],sdr); + sprintf(part,"%slo-noncr %.2f ",sep,ival); + strcat(str,part); + } + if (bits & 0x02) { + ival = RawToFloat(vals[1],sdr); + sprintf(part,"%slo-crit %.2f ", sep,ival); + strcat(str,part); + } + if (bits & 0x04) { + ival = RawToFloat(vals[2],sdr); + sprintf(part,"%slo-unrec %.2f ",sep,ival); + strcat(str,part); + } + if (flg == 2) { + if (sens_verbose) tag = "Volatile "; + printf("\t%s%s%s%c",sep,tag,str,chEol); + } else + printf("\t%s%s%s%c",sep,tag,str,chEol); + } else { /*Full SDR*/ + if (fdebug) printf("ShowThresh[%x]: bits=%02x, sdr18=%02x %02x\n", + sdr[7],bits,sdr[18],sdr[19]); + if (bits & 0x20) { + ival = RawToFloat(vals[0],sdr); + sprintf(part,"%shi-unrec %.2f ",sep,ival); + strcat(str,part); + } + if (bits & 0x10) { + ival = RawToFloat(vals[1],sdr); + sprintf(part,"%shi-crit %.2f ",sep,ival); + strcat(str,part); + } + if (bits & 0x08) { + ival = RawToFloat(vals[2],sdr); + sprintf(part,"%shi-noncr %.2f ",sep,ival); + strcat(str,part); + } + if (bits & 0x01) { + ival = RawToFloat(vals[5],sdr); + sprintf(part,"%slo-noncr %.2f ",sep,ival); + strcat(str,part); + } + if (bits & 0x02) { + ival = RawToFloat(vals[4],sdr); + sprintf(part,"%slo-crit %.2f ",sep,ival); + strcat(str,part); + } + if (bits & 0x04) { + ival = RawToFloat(vals[3],sdr); + sprintf(part,"%slo-unrec %.2f ",sep,ival); + strcat(str,part); + } + if (sens_verbose) tag = "SdrThres "; + printf("\t%s%s%s%c",sep,tag,str,chEol); + if (sens_verbose) + { /* show max/min & hysteresis from full sdr */ + str[0] = 0; + ival = RawToFloat(sdr[31],sdr); + sprintf(part,"%snom %.2f ",sep,ival); + strcat(str,part); + ival = RawToFloat(sdr[32],sdr); + sprintf(part,"%snmax %.2f ",sep,ival); + strcat(str,part); + ival = RawToFloat(sdr[33],sdr); + sprintf(part,"%snmin %.2f ",sep,ival); + strcat(str,part); + + ival = RawToFloat(sdr[34],sdr); + sprintf(part,"%ssmax %.2f ",sep,ival); + strcat(str,part); + + ival = RawToFloat(sdr[35],sdr); + sprintf(part,"%ssmin %.2f ",sep,ival); + strcat(str,part); + +#ifdef OLD + ival = RawToFloat(sdr[42],sdr); + sprintf(part,"%s+hyst %.2f ",sep,ival); + strcat(str,part); + + ival = RawToFloat(sdr[43],sdr); + sprintf(part,"%s-hyst %.2f ",sep,ival); + strcat(str,part); +#endif + + printf("\t%s%c",str,chEol); + } + } /*endif full sdr*/ +} + +/* + * decode_comp_reading + * + * Decodes the readings from compact SDR sensors. + * Use sensor_dstatus array for sensor reading types and meaning strings. + * Refer to IPMI Table 36-1 and 36-2 for this. + * + * Note that decoding should be based on sensor type and ev_type only, + * except for end cases. + * + * Note reading1 = sens_reading[2], reading2 = sens_reading[3] + */ +int +decode_comp_reading(uchar type, uchar evtype, uchar num, + uchar reading1, uchar reading2) +{ + int istr = 0; /*string index into sensor_dstatus[] */ + uchar b; + ushort reading; + static char customstr[35]; + + /* usually reading2 has h.o. bit set (0x80). */ + reading = reading1 | ((reading2 & 0x7f) << 8); + + switch(type) + { + case 0x01: /*Discrete Thermal, Temperature*/ + if (fdebug) + printf("Discrete Thermal snum %x evtype=%x reading=%x\n", + num,evtype,reading); + if (evtype == 0x07) { + b = bitnum(reading); + if (b == 0) istr = 8; /*no bits set, "OK*"*/ + else if (b < 3) istr = 0; /*bits 1,2 "OK"*/ + else istr = 65; /*transition to error, Limit Exceeded*/ + } else if (evtype == 0x05) { + /* see CPU1 VRD Temp on S5000, snum 0xc0 thru 0xcf */ + if (reading & 0x01) istr = 65; /* Limit Exceeded*/ + else istr = 0; /* "OK" LimitNotExceeded*/ + } else if (evtype == 0x03) { + if (reading & 0x01) istr = 13; /* Asserted */ + else istr = 0; /* "OK" Deasserted */ + } else { /* evtype == other 0x05 */ + if (reading & 0x01) istr = 0; /* 8="OK*", 0="OK" */ + else istr = 5; /*state asserted, Crit-hi */ + } + break; + case 0x02: /*Discrete Voltage*/ + { /* evtype == 0x05 for VBat, 0x03 for VR Watchdog */ + if (reading & 0x01) istr = 65; /*LimitExceeded, was Crit-hi*/ + else istr = 0; /* "OK" LimitNotExceeded*/ + } + break; + case 0x04: /*Fan*/ + if (evtype == 0x0b) { /*redundancy*/ + b = reading & 0x3f; + if (b == 0x00) istr = 16; /*sensor disabled*/ + else if (b == 0x01) istr = 18; /*fully redundant*/ + else if (b == 0x02) istr = 19; /*redundancy lost*/ + else if (b == 0x0b) istr = STR_AC_LOST; /*ac lost*/ + else istr = 20; /*redundancy degraded*/ + } else if (evtype == 0x08) { /*presence*/ + if (reading & 0x02) istr = 9; /*Present/Inserted*/ + else if (reading & 0x01) istr = 10; /*Absent/Removed*/ + else /*reading==00*/ istr = 47; /*Unused*/ + } else if (evtype == 0x03) { /*PS Fan Fail*/ + if (reading == 0) istr = 0; /*OK*/ + else istr = 12; /*faulty*/ + } else { /*other evtype*/ + b = reading & 0x0f; + if (b == 0) istr = 12; /*faulty*/ + else if (b & 0x01) istr = 11; /*ready*/ + else istr = 41; /*Unknown*/ + } + break; + case 0x05: /*Physical Security, Chassis */ + if (reading == 0) istr = 0; /*OK*/ + else if (reading & 0x01) istr = 38; /*chassis intrusion*/ + /* 0x02 Drive bay intrusion */ + /* 0x04 IO area intrusion */ + /* 0x08 Processor area intrusion */ + else if (reading & 0x10) istr = 37; /*lan leash lost*/ + /* 0x20 Dock/Undock */ + /* 0x40 Fan area intrusion */ + else istr = 41; /* Unknown, was bitnum(reading); */ + break; + case 0x07: /*Processor Status - 0x80 is OK/Present */ + b = bitnum(reading); + if (evtype == 0x03) { + if (b <= 1) istr = 0; /*bit1 Deasserted, OK* */ + else istr = 13; /*bit2 Asserted*/ + } else { /*usu 0x6f*/ + if (b > 10) istr = 41; /*Unknown*/ + else if (b == 0) istr = 0; /*OK*/ + else istr = 47 + b; /*Proc strings 48 thru 57*/ + } + break; + case 0x08: /*Power Supply*/ + b = reading & 0x7f; + if (b == 0) istr = 10; /*absent*/ + else if (b & 0x40) istr = STR_PS_CONFIG; /*Config Err*/ + else if (b & 0x08) istr = STR_AC_LOST; /*AC Lost*/ + else if (b & 0x04) istr = 15; /*Predictive Fail*/ + else if (b & 0x02) istr = STR_PS_FAIL; /*PS Fail*/ + else if (b & 0x01) istr = 9; /*present*/ + break; + case 0x09: /*Power Unit*/ + b = reading & 0x3f; + if (evtype == 0x0b) { /*Power Redundancy*/ + if (b == 0x00) istr = 16; /*sensor disabled*/ + else if (b == 0x01) istr = 18; /*fully redundant*/ + else if (b == 0x02) istr = 19; /*redundancy lost*/ + else if (b == 0x0b) istr = STR_AC_LOST; /*ac lost*/ + else istr = 20; /*redundancy degraded*/ + } else { /* Power Unit (evtype==0x6f or 0xef) */ + if (b == 0) istr = 17; /*enabled*/ + else if ((b & 0x01) == 1) istr = 16; /*disabled*/ + } + break; + case 0x0C: /* Memory */ + b = reading & 0x3f; + if (b == 0) istr = 0; /*OK*/ + else if (b & 0x01) istr = 8; /*Correctable ECC (OK*)*/ + else if ((b & 0x02) || (b & 0x20)) istr = 39; /*ECC Error*/ + else if (b & 0x04) istr = 40; /*Parity Error*/ + else istr = bitnum(b); /* ECC or other error */ + break; + case 0x0D: /* drive slot - usually HSC sens_ownid == 0xc0 */ + if (fRomley) { /* evtype==0x6f, has both status and presence */ + if (reading & 0x02) istr = 12; /*Faulty*/ + else if (reading & 0x80) istr = STR_REBUILDING; /*Rebuilding*/ + else if (reading & 0x01) istr = 9; /*Present (OK)*/ + else istr = 10; /*Absent*/ + } else { + if (evtype == 8) { /* HSC slot presence sensors (num > 8)*/ + if (reading1 & 0x02) istr = 9; /*Present/Inserted*/ + else if (reading1 & 0x01) istr = 10; /*Absent/Removed*/ + else /*reading1==00*/ istr = 47; /*Unused*/ + } else { /* HSC slot status sensors (evtype==0x6f) */ + /* usually reading2 == 0x82 or 0x8E if healthy */ + if (reading2 & 0x01) istr = 12; /*state8=Rebuild stopped*/ + else if (reading2 & 0x02) istr = 11; /*state9=Inserted/Ready */ + else if (reading2 & 0x04) istr = 11; /*state10=Safe_to_Remove*/ + else if (reading2 & 0x08) istr = 11; /*state11=Ready */ + else if (reading2 == 0x80) istr = 47; /*no states, Unused*/ + else istr = 12; /*faulty*/ + b = 8; /*if no bits set, no raid state */ + if (reading1 & 0x01) { b = 0; } /*state0=Faulty*/ + else if (reading1 & 0x02) b = 1; /*state1=Rebuilding*/ + else if (reading1 & 0x04) b = 2; /*state2=InFailedArray*/ + else if (reading1 & 0x08) b = 3; /*state3=InCriticalArray*/ + else if (reading1 & 0x10) b = 4; /*state4=ParityCheck*/ + else if (reading1 & 0x20) b = 5; /*state5=PredictedFault*/ + else if (reading1 & 0x40) b = 6; /*state6=Un-configured*/ + else if (reading1 & 0x80) b = 7; /*state7=HotSpare*/ + if (b < 8) { + /* also include a raid_state, via custom string */ + sprintf(customstr,"%s %s", + sensor_dstatus[istr], raid_states[b]); + istr = STR_CUSTOM; + sensor_dstatus[istr] = customstr; + if (fdebug) printf("dstatus=%s\n",sensor_dstatus[istr]); + } + } /*end-else HSC slot status*/ + } + break; + case 0x10: /*Event Logging*/ + /* usu evtype==0x6f*/ + b = bitnum(reading & 0x3f); + switch (b) { + case 0x00: istr = 0; break; /*OK*/ + case 0x01: istr = 59; break; /*MemLogDisabled*/ + case 0x02: istr = 60; break; /*TypLogDisabled*/ + case 0x03: istr = 61; break; /*LogCleared*/ + case 0x04: istr = 62; break; /*AllLogDisabled*/ + case 0x05: istr = 63; break; /*SelFull*/ + case 0x06: istr = 64; break; /*SelNearFull*/ + default: istr = 41; break; /*Unknown*/ + } + break; + case 0x12: /*System Event*/ + if (reading == 0) istr = 0; + else istr = 13; /*Asserted*/ + break; + case 0x13: /*Critical Interrupt*/ + /* valid bits: 0x03FF */ + if (reading == 0) istr = 0; /*OK*/ + else { + b = bitnum(reading); /* ECC or other error */ + if (b > 10) b = 10; + istr = 24 + b; + } + break; + case 0x14: /*Button*/ + if (reading == 0) istr = 0; /*OK*/ + else istr = 13; /*Asserted*/ + break; + case 0x15: /*Module/ Board */ + if (evtype == 0x08) { /*presence*/ + if (reading & 0x02) istr = 9; /*Present/Inserted*/ + else if (reading & 0x01) istr = 10; /*Absent/Removed*/ + else /*reading==00*/ istr = 47; /*Unused*/ + } + break; + case 0x16: /* HSBP Status (esp. Romley) */ + if (reading & 0x010) istr = STR_HSC_OFF; /*Offline*/ + else istr = 0; /*OK*/ + break; + case 0x17: /* ATCA CDM, Air Filter, Filter Tray */ + if (reading == 0) istr = 0; /*OK*/ + else if (reading & 0x01) istr = 10; /*Absent*/ + else istr = bitnum(reading); /* other error, TODO: fix this */ + break; + case 0x1C: /*Terminator (usu SCSI)*/ + if (reading & 0x01) istr = 9; /*present*/ + else istr = 10; /*missing,absent*/ + break; + case 0x21: /*DIMM memory slot*/ + if ((reading & 0x04) != 0) istr = 9; /*present*/ + else istr = 10; /*absent*/ + sprintf(customstr,"%s", sensor_dstatus[istr]); + if ((reading & 0x01) != 0) strcat(customstr,",Fault"); + if ((reading & 0x0100) != 0) strcat(customstr,",Disabled"); + istr = 58; /*use a custom string*/ + sensor_dstatus[istr] = customstr; + if (fdebug) printf("dstatus=%s\n",sensor_dstatus[istr]); + break; + case 0x22: /*ACPI Power State*/ + b = bitnum(reading); + switch(b) { + case 0: istr = 0; break; /*OK*/ + case 1: istr = 22; break; /*Working*/ + case 2: + case 3: + case 4: + case 5: + case 9: + case 10: istr = 23; break; /*Sleeping*/ + case 6: + case 7: + case 8: + case 11: + case 13: istr = 21; break; /*Off*/ + case 12: istr = 24; break; /*On*/ + default: istr = 41; /*unknown*/ + } + break; + case 0x23: /*Watchdog*/ + if (reading == 0) istr = 0; + else istr = 13; /*Asserted*/ + break; + case 0x24: /*Platform Alert*/ + b = bitnum(reading); + switch(b) { + case 0: istr = 0; break; /*OK, no bits set*/ + case 1: istr = 66; break; /*Page, bit 0 set*/ + case 2: istr = 67; break; /*LAN, bit 1 set*/ + case 3: istr = 68; break; /*PET*/ + case 4: istr = 69; break; /*SNMP OEM*/ + default: istr = 70; /*None*/ + } + break; + case 0x25: /* Entity Presence */ + if (reading & 0x01) istr = 8; /*Present*/ + else if (reading & 0x02) istr = 9; /*Absent*/ + else if (reading & 0x04) istr = 16; /*Disabled*/ + else istr = 42; /* NotAvailable */ + break; + case 0x28: /* BMC FW Health */ + if (reading == 0) istr = 0; /*OK*/ + else istr = 12; /*Faulty*/ + break; + case 0x29: /* Battery */ + switch(reading & 0x7f) { + case 0x00: istr = 0; break; /*OK*/ + case 0x01: istr = 15; break; /*Predict Fail*/ + case 0x04: istr = 9; break; /*Present*/ + case 0x02: + default: istr = 12; break; /*Failed/Faulty*/ + } + break; + case 0x2A: /* Session Audit (IPMI 2.0) */ + if (reading == 0x00) istr = 45; /*Activated*/ + else istr = 46; /*Deactivated*/ + break; + case 0x2B: /* Version Change */ + b = bitnum(reading1); + switch(b) { + case 0: istr = 0; break; /*OK, no bits set*/ + case 1: istr = 72; break; /*HW Changed, bit 0 set*/ + case 2: istr = 73; break; /*SW Changed, bit 1 set*/ + case 3: istr = 74; break; /*HW incompatibility*/ + default: istr = 75; break; /*Change error*/ + } + break; + case 0x60: /* SCSI 1 Term Flt */ + case 0x61: /* SCSI 2 Term Flt */ + break; + /* sensor types 0xC0 - 0xFF are OEM RESERVED */ + case 0xF1: /* ATCA IPMB-0 Sensor */ + if ((reading & 0x7fff) == 0x0008) istr = 0; /*OK*/ + else istr = bitnum(reading1); /* other error, TODO: refine this */ + break; + case 0xC0: /* SMI State, NMI State */ + case 0xD8: /* BIST */ + case 0xF0: /* ATCA FRU HotSwap, TODO: refine this */ + case 0xF2: /* ATCA Module HotSwap, TODO: refine this */ + case 0xF3: /* SMI Timeout, etc. */ + if (reading & 0x01) istr = 13; /* Asserted */ + else istr = 0; /* "OK", Deasserted */ + break; + default: + if (fdebug) + printf("sensor[%x] type %02x not decoded, reading = %04x\n", + num,type,reading); + istr = STR_OTHER; /* other " - " */ + } + return(istr); +} /* end decode_comp_reading */ + +#define STYPSZ 15 +static char *get_stype_str(uchar stype) +{ /*return sensor type string, with fixed length */ + static char stype_str[STYPSZ+1]; + char *tmpstr; + int i, n; + tmpstr = get_sensor_type_desc(stype); + n = strlen_(tmpstr); + if (n > STYPSZ) n = STYPSZ; + strncpy(stype_str,tmpstr,n); + for (i = n; i < STYPSZ; i++) stype_str[i] = ' '; + stype_str[i] = 0; + tmpstr = stype_str; + return(tmpstr); +} + +void +ShowSDR(char *tag, uchar *sdr) +{ + SDR01REC *sdr01; + SDR02REC *sdr02; + SDR08REC *sdr08; + SDR11REC *sdr11; + SDR12REC *sdr12; + SDR14REC *sdr14; + SDRc0REC *sdrc0; + char idstr[32]; + char *typestr = NULL; + int vend; + int len, ilen, i, j; + int ioff; + uchar sens[4]; + uchar sens_cap; + uchar shar_cnt; + int rc; + double val; + char brearm; + uchar sep[4]; + char rdgstr[50]; + + len = sdr[4] + 5; + sens_cap = 0x80; /*ignore*/ + if (fdebug) printf("ShowSDR: len=%d, type=%x\n",len,sdr[3]); + memset(sens,0,4); + if (frawsdr || fdebug) { + printf("raw SDR: "); + for (i = 0; i < len; i++) + printf("%02x ",sdr[i]); + printf("\n"); + } + switch(sdr[3]) + { + case 0x01: /* Full sensor record */ + sdr01 = (SDR01REC *)sdr; + ioff = 48; + if (ioff > len) { + if (fdebug) printf("bad length: type=%x, len=%d, ioff=%d\n", + sdr[3],len,ioff); + printf("Bad SDR Length, please apply the correct FRU/SDR diskette\n"); + return; + } + sens_cap = sdr[11]; /*sdr01->sens_capab*/ + ilen = len - ioff; + if (ilen >= sizeof(idstr)) ilen = sizeof(idstr) - 1; + memcpy(idstr,&sdr[ioff],ilen); + for (i=ilen; i<16; i++) { idstr[i] = ' '; ilen++; } + idstr[ilen] = 0; /* stringify */ + if ((sdr01->sens_capab & 0x40) == 0) brearm = 'm'; /*manual rearm*/ + else brearm = 'a'; /*automatic rearm*/ + if (fdebug) printf("entity %d.%d, idlen=%d sizeof=%d idstr0=%c s0=%x\n", + sdr01->entity_id, sdr01->entity_inst, + ilen,sizeof(SDR01REC),idstr[0],sdr[ioff]); + rc = GetSensorReading(sdr01->sens_num,sdr01,sens); + if (rc != 0) { /* if rc != 0, leave sens values zero */ + i = 41; /* Unknown */ + val = 0; + if (rc == 0xCB) { /*sensor not present*/ + i = 10; /* Absent */ + typestr = "na"; + } else typestr = decode_rv(rc); + } else { + j = (sens[2] & 0x3f); /*sensor reading state*/ + i = bitnum((ushort)j); /*sensor_dstatus index*/ + if (fdebug) + printf("bitnum(%02x)=%d raw=%02x init=%x base/units=%x/%x\n", + sens[2],i,sens[0],sens[1],sdr01->sens_base, + sdr01->sens_units); + if ((sens[1] & 0x20) != 0) { i = 7; val = 0; } /* Init state */ + else val = RawToFloat(sens[0],sdr); + typestr = get_unit_type(sdr01->sens_units, sdr01->sens_base, + sdr01->sens_mod, fsimple); +#ifdef WRONG + if (is_romley(vend_id,prod_id) && + (sdr01->sens_type == 0x0C) && (sdr01->sens_units & 0x01)) + { /* Intel Memory Thermal Throttling %, raw 0x01 == 0.5 % */ + val = (val / 2); /* handle MTT SDR errata */ + } /*correct solution is to fix the SDR m-value instead */ +#endif + } + rc = decode_oem_sensor(sdr,sens,oem_string,sizeof(oem_string)); + if (rc == 0) { + strncpy(rdgstr,oem_string,sizeof(rdgstr)); + } else { + if (fsimple) + snprintf(rdgstr,sizeof(rdgstr),"%s %c %.2f %s", + sensor_dstatus[i],bdelim,val,typestr); + else + snprintf(rdgstr,sizeof(rdgstr),"%02x %s %.2f %s", + sens[0], sensor_dstatus[i],val,typestr); + } + sep[0] = 0; /*null string*/ + printf("%s", tag); + if (fsimple) { + sprintf(sep,"%c ",bdelim); + printf("%04x %c Full %c %s %c %02x %c %s %c %s%c", + sdr01->recid, bdelim, bdelim, + get_stype_str(sdr01->sens_type), + bdelim, sdr01->sens_num,bdelim, idstr, + bdelim,rdgstr,chEol); + } else + printf("%04x SDR Full %02x %02x %02x %c %02x snum %02x %s = %s%c", + sdr01->recid, sdr01->rectype, sdr01->ev_type, + sdr01->sens_ownid, brearm, sdr01->sens_type, sdr01->sens_num, + idstr, rdgstr, chEol); + if (fdebug && fshowthr) + printf("cap=%02x settable=%02x, readable=%02x\n", + sens_cap,sdr[19],sdr[18]); + if (sens_verbose) /* if -v, also show Entity ID */ + printf("\t%sEntity ID %d.%d (%s), Capab: %s%c", + sep, sdr01->entity_id, sdr01->entity_inst, + decode_entity_id(sdr01->entity_id), // sens_cap, + decode_capab(sens_cap),chEol); + if (fshowthr && (sens_cap & 0x0f) != 0x03) { + uchar thresh[7]; + /* Thresholds, so show them */ + /* Use settable bits to show thresholds, since the + * readable values will be off for Full SDRs. + * If cant set any thresholds, only show SDR thresholds */ + if (sdr[19] == 0) rc = 1; + else { + /* Show volatile thresholds. */ + rc = GetSensorThresholds(sdr01->sens_num,&thresh[0]); + if (rc == 0) ShowThresh(2,thresh[0],&thresh[1],sdr); + } + /* Show SDR non-volatile thresholds. */ + if (sens_verbose || rc !=0) ShowThresh(0,sdr[18],&sdr[36],sdr); + // ShowThresh(0,0x3f,&sdr[36],sdr); /* to show all %%%% */ + } + if (fwrap) { /* (chEol != '\n') include time */ + time_t ltime; + time(<ime); + if (fsimple) + printf("%c %s",bdelim,ctime(<ime)); /*ctime has '\n' */ + else + printf("at %s",ctime(<ime)); /*ctime has '\n' */ + } + break; + case 0x02: /* Compact sensor record */ + sdr02 = (SDR02REC *)sdr; + ioff = 32; + if (ioff > len) { + if (fdebug) printf("bad length: type=%x, len=%d, ioff=%d\n", + sdr[3],len,ioff); + printf("Bad SDR Length, please apply the correct FRU/SDR diskette\n"); + return; + } + sens_cap = sdr[11]; /*sdr02->sens_capab*/ + shar_cnt = sdr02->shar_cnt & 0x0f; /*sdr[23]*/ + ilen = len - ioff; + if ((ilen+1) >= sizeof(idstr)) ilen = sizeof(idstr) - 2; + memcpy(idstr,&sdr[ioff],ilen); + if ((shar_cnt > 1) && (sdr02->shar_off & 0x80) != 0) { /*do shared SDR*/ + j = (sdr02->shar_off & 0x7f); /*sdr[24] = modifier offset*/ + if (fdebug) printf("share count = %d, mod_offset = %d\n",shar_cnt,j); + if ((sdr02->shar_cnt & 0x10) != 0) { /*alpha*/ + idstr[ilen++] = 0x40 + j; /* j=1 -> 'A' */ + idstr[ilen] = 0; /* stringify */ + } else { /*numeric*/ + sprintf(&idstr[ilen],"%d",j); + ilen = strlen_(idstr); + } + } /* else normal idstr */ + for (i=ilen; i<16; i++) { idstr[i] = ' '; ilen++; } + idstr[ilen] = 0; /* stringify */ + if ((sdr02->sens_capab & 0x40) == 0) brearm = 'm'; /*manual rearm*/ + else brearm = 'a'; /*automatic rearm*/ + if (fdebug) printf("ilen=%d, istr0=%c, sizeof=%d, s0=%x\n", + ilen,idstr[0],sizeof(SDR02REC),sdr[ioff]); + memset(sens,0,sizeof(sens)); + rc = GetSensorReading(sdr02->sens_num,sdr02,sens); + if (rc != 0) { /* if rc != 0, leave sens values zero */ + i = 41; /* Unknown */ + val = 0; + if (rc == 0xCB) { /*sensor not present*/ + i = 10; /* Absent */ + typestr = "na"; + } else typestr = decode_rv(rc); + } else { + if ((sens[1] & 0x20) != 0) i = 42; /*init state, NotAvailable*/ + else { + rc = decode_oem_sensor(sdr,sens,oem_string,sizeof(oem_string)); + if (rc == 0) i = STR_OEM; + else i = decode_comp_reading(sdr02->sens_type,sdr02->ev_type, + sdr02->sens_num,sens[2],sens[3]); + } + } + if (fdebug) + printf("snum %x type %x evt %x reading %02x%02x i=%d rc=%d %s\n", + sdr02->sens_num,sdr02->sens_type,sdr02->ev_type, + sens[3],sens[2],i,rc, decode_rv(rc)); + j = sens[2] | ((sens[3] & 0x7f) << 8); /*full reading, less h.o. bit*/ + sep[0] = 0; /*null string*/ + printf("%s", tag); + if (fsimple) { + sprintf(sep,"%c ",bdelim); + printf("%04x %c Compact %c %s %c %02x %c %s %c %s %c%c", + sdr02->recid, bdelim, bdelim, + get_stype_str(sdr02->sens_type), + bdelim, sdr02->sens_num, bdelim, idstr, + bdelim, sensor_dstatus[i],bdelim,chEol); + } else if (i == STR_OEM) { + // idstr[ilen] = 0; /*cut out padding in idstr*/ + printf("%04x SDR Comp %02x %02x %02x %c %02x snum %02x %s = %04x %s%c", + sdr02->recid, sdr02->rectype, sdr02->ev_type, + sdr02->sens_ownid, brearm, sdr02->sens_type, sdr02->sens_num, + idstr, j, sensor_dstatus[i],chEol); + // sensor_dstatus[i] == oem_string + } else { + printf("%04x SDR Comp %02x %02x %02x %c %02x snum %02x %s = %04x %s%c", + sdr02->recid, sdr02->rectype, sdr02->ev_type, + sdr02->sens_ownid, brearm, sdr02->sens_type, sdr02->sens_num, + idstr, j, sensor_dstatus[i],chEol); + /* idstr, sens[0], sens[1], sens[2], sens[3], */ + } + if (fdebug && fshowthr) + printf("cap=%02x settable=%02x, readable=%02x\n", + sens_cap,sdr[19],sdr[18]); + if (fshowthr) /*also show Entity ID */ + printf("\t%sEntity ID %d.%d (%s), Capab: %s%c", + sep, sdr02->entity_id, sdr02->entity_inst, + decode_entity_id(sdr02->entity_id), // sens_cap, + decode_capab(sens_cap),chEol); + if (fshowthr && + ((sens_cap & 0x80) == 0) && (sens_cap & 0x0C) != 0) { + uchar thresh[7]; + /* Thresholds, show them */ + /* Use readable bits to get & show thresholds */ + if (sdr[20] != 0) { + rc = GetSensorThresholds(sdr02->sens_num,&thresh[0]); + if (rc == 0) ShowThresh(1,thresh[0],&thresh[1],sdr); + } + } + if (fwrap) { /*include time and \n */ + time_t ltime; + time(<ime); + if (fsimple) + printf("%c %s",bdelim,ctime(<ime)); /*ctime has '\n' */ + else + printf("at %s",ctime(<ime)); /*ctime has '\n' */ + } + break; + case 0x03: /* Event-only sensor record, treat like Compact SDR */ + sdr02 = (SDR02REC *)sdr; + ioff = 17; + if (ioff > len) { + printf("Bad SDR %x Length %d. Please apply the correct FRU/SDR diskette\n", + sdr02->recid, len); + return; + } + if (!fsimple) + { + ilen = len - ioff; + if (ilen >= sizeof(idstr)) ilen = sizeof(idstr) - 1; + memcpy(idstr,&sdr[ioff],ilen); + for (i=ilen; i<16; i++) { idstr[i] = ' '; ilen++; } + idstr[ilen] = 0; /* stringify */ + sens_cap = sdr[11]; + memset(sens,0,sizeof(sens)); + if ((sdr02->sens_capab & 0x40) == 0) brearm = 'm'; /*manual rearm*/ + else brearm = 'a'; /*automatic rearm*/ + // rc = GetSensorReading(sdr02->sens_num,sdr02,sens); + /* EvtOnly SDRs do not support readings. + * GetSensorReading would return ccode=0xCB (not present), + * but this skips error msg */ + rc = 0xCB; + i = bitnum((ushort)sens[2]); + j = sens[2] | ((sens[3] & 0x7f) << 8); + printf("%s",tag); + printf("%04x SDR EvtO %02x %02x %02x %c %02x snum %02x %s = %04x %s\n", + sdr02->recid, sdr02->rectype, sdr02->reclen, + sdr02->sens_ownid, 'a', sdr[10], sdr02->sens_num, + idstr, j, sensor_dstatus[i]); + // sens[0], sens[1], sens[2], sens[3], sensor_dstatus[i] + } + break; + case 0x08: /* Entity Association record */ + sdr08 = (SDR08REC *)sdr; + if (!fsimple) + { + printf("%s",tag); + printf("%04x SDR EntA %02x %02x %02x %02x %02x: ", + sdr08->recid, sdr08->rectype, sdr08->reclen, + sdr08->contid, sdr08->continst, sdr08->flags); + for (i = 0; i < 8; i++) printf("%02x ",sdr08->edata[i]); + printf("\n"); + } + break; + case 0x09: /* Device-relative Entity Association record */ + sdr08 = (SDR08REC *)sdr; /*but SDR09 is 26 bytes*/ + if (!fsimple) + { + printf("%s",tag); + printf("%04x SDR DEnt %02x %02x %02x %02x %02x %02x %02x: ", + sdr08->recid, sdr08->rectype, sdr08->reclen, + sdr08->contid, sdr08->continst, sdr08->flags, + sdr08->edata[0], sdr08->edata[1]); + /*display 2 of 4 contained entity devices edata[2-10] */ + for (i = 2; i < 8; i++) printf("%02x ",sdr08->edata[i]); + printf("\n"); + } + break; + case 0x10: /* Generic Device Locator record */ + sdr11 = (SDR11REC *)sdr; + ioff = 16; + if (ioff > len) { + if (fdebug) printf("SDR %x bad length: type=%x, len=%d, ioff=%d\n", + sdr11->recid, sdr[3],len,ioff); + return; + } + if (!fsimple) + { + ilen = len - ioff; + if (ilen >= sizeof(idstr)) ilen = sizeof(idstr) - 1; + memcpy(idstr,&sdr[ioff],ilen); + idstr[ilen] = 0; /* stringify */ + printf("%s", tag); + if (fsimple) + printf("DevLocator record[%x]%c device %02x %c %s\n", + sdr11->recid, bdelim,sdr11->dev_slave_adr,bdelim,idstr); + else + printf("%04x SDR DLoc %02x %02x dev: %02x %02x %02x %02x %02x %02x %s\n", + sdr11->recid, sdr11->rectype, sdr11->reclen, + sdr11->dev_access_adr, sdr11->dev_slave_adr, + sdr11->access_lun, sdr[8], sdr[10], sdr[11], + idstr); + } + break; + case 0x11: /* FRU record */ + sdr11 = (SDR11REC *)sdr; + ioff = 16; + if (ioff > len) { + if (fdebug) printf("SDR %x bad length: type=%x len=%d ioff=%d\n", + sdr11->recid, sdr[3],len,ioff); + printf("Please apply the correct FRU/SDR diskette\n"); + return; + } + if (!fsimple) + { + ilen = len - ioff; + if (ilen >= sizeof(idstr)) ilen = sizeof(idstr) - 1; + memcpy(idstr,&sdr[ioff],ilen); + idstr[ilen] = 0; /* stringify */ + if (fdebug) printf("ilen=%d, istr0=%c, sizeof=%d, s0=%x\n", + ilen,idstr[0],sizeof(SDR11REC),sdr[ioff]); + printf("%s", tag); + if (fsimple) + printf("FRU record[%x]: device %02x : %s\n", + sdr11->recid, sdr11->dev_slave_adr,idstr); + else + printf("%04x SDR FRU %02x %02x dev: %02x %02x %02x %02x %02x %02x %s\n", + sdr11->recid, sdr11->rectype, sdr11->reclen, + sdr11->dev_access_adr, sdr11->dev_slave_adr /*fru_id*/, + sdr11->access_lun, sdr11->chan_num, + sdr11->entity_id, sdr11->entity_inst, + idstr); + } + break; + case 0x12: /* IPMB record */ + sdr12 = (SDR12REC *)sdr; + ioff = 16; + if (ioff > len) { + if (fdebug) printf("bad length: type=%x, len=%d, ioff=%d\n", + sdr[3],len,ioff); + printf("Please apply the correct FRU/SDR diskette\n"); + return; + } + if (!fsimple) + { + ilen = len - ioff; + if (ilen >= sizeof(idstr)) ilen = sizeof(idstr) - 1; + memcpy(idstr,&sdr[ioff],ilen); + idstr[ilen] = 0; /* stringify */ + if (fdebug) printf("ilen=%d, istr0=%c, sizeof=%d, s0=%x\n", + ilen,idstr[0],sizeof(SDR12REC),sdr[ioff]); + printf("%s", tag); + if (fsimple) + printf("IPMB record[%x]%c addr %02x %02x %c %s\n", + sdr12->recid, bdelim,sdr12->dev_slave_adr, + sdr12->chan_num,bdelim,idstr); + else + printf("%04x SDR IPMB %02x %02x dev: %02x %02x %02x %02x %02x %s\n", + sdr12->recid, sdr12->rectype, sdr12->reclen, + sdr12->dev_slave_adr, sdr12->chan_num, sdr12->dev_capab, + sdr12->entity_id, sdr12->entity_inst, + idstr); + } + break; + case 0x14: /* BMC Message Channel Info record */ + sdr14 = (SDR14REC *)sdr; + if(!fsimple){ + printf("%s", tag); + printf("%04x SDR BMsg %02x %02x: ", + sdr14->recid, sdr14->rectype, sdr14->reclen ); + for (i = 0; i < 8; i++) printf("%02x ",sdr14->mdata[i]); + printf("%s %s %02x\n",decode_itype(sdr14->mint), + decode_itype(sdr14->eint), sdr14->rsvd); + } + break; + case 0xc0: /* OEM SDR record (manuf_id 343. = Intel) */ + sdrc0 = (SDRc0REC *)sdr; + if(!fsimple) + { + vend = sdrc0->manuf_id[0] + (sdrc0->manuf_id[1] << 8) + + (sdrc0->manuf_id[2] << 16); + printf("%s",tag); + printf("%04x SDR OEM %02x %02x ", + sdrc0->recid, sdrc0->rectype, sdrc0->reclen); + show_oemsdr(vend,sdr); + } + break; + default: + sdrc0 = (SDRc0REC *)sdr; + /* also saw type = 0x08 & 0x14 on STL2s */ + if (!fsimple){ + printf("%s", tag); + printf("%04x SDR type=%02x ", sdrc0->recid, sdr[3]); + for (i = 0; i < len; i++) printf("%02x ",sdr[i]); + printf("\n"); + } + } + return; +} + +static int +ShowPowerOnHours(void) +{ + uchar resp[MAX_BUFFER_SIZE]; + int sresp = MAX_BUFFER_SIZE; + uchar cc; + int rc = -1; + int i; + unsigned int hrs; + + if (fmBMC) return(0); + if (fsimple) return(0); + 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] == 0) /*avoid div-by-zero*/ i = 1; + else if (resp[0] == 60) /*normal*/ i = 1; + else { + i = 60 / resp[0]; + hrs = hrs / i; + } + printf(" SDR IPMI sensor: Power On Hours \t = %d hours\n", + hrs); + } + if (fdebug) { + printf("PowerOnHours (rc=%d cc=%x len=%d): ",rc,cc,sresp); + if (rc == 0) + for (i = 0; i < sresp; i++) printf("%02x ",resp[i]); + printf("\n"); + } + return(rc); +} + +int SaveThreshold(int id, int sensor_num, int sensor_lo, int sensor_hi, + uchar *thr_set) +{ + int rv = 0; + char lostr[20]; + char histr[20]; + FILE *fd; + + /* persist the thresholds by re-applying with ipmiutil sensor commands.*/ + if (thr_set != NULL) { + sprintf(lostr,"-u 0x%02x%02x%02x%02x%02x%02x", + sensor_thr[0], sensor_thr[1], sensor_thr[2], + sensor_thr[3], sensor_thr[4], sensor_thr[5]); + histr[0] = 0; /*empty string*/ + } else { + if (sensor_lo != 0xff) { + sprintf(lostr,"-l 0x%02x",sensor_lo); + } else lostr[0] = 0; + if (sensor_hi != 0xff) { + sprintf(histr,"-h 0x%02x",sensor_hi); + } else histr[0] = 0; + } + fd = fopen(savefile,"a+"); + if (fd == NULL) return(-1); + fprintf(fd, "ipmiutil sensor -i 0x%04x -n 0x%02x %s %s\n", id, sensor_num, + lostr,histr); + fclose(fd); + return(rv); +} + +#ifdef NOT_USED +#define PICMG_GET_ADDR_INFO 0x01 +static int get_picmg_addrinfo(uchar a1, uchar a2, uchar *addrdata) +{ + uchar idata[5]; + uchar rdata[16]; + int rlen; + ushort icmd; + uchar ilen, cc; + int rv; + + idata[0] = 0x00; + idata[1] = 0x00; + idata[2] = 0x03; + idata[3] = a1; /* 01 thru 0f */ + idata[4] = a2; /* 00, 01 thru 09 */ + ilen = 5; + rlen = sizeof(rdata); + icmd = PICMG_GET_ADDR_INFO | (NETFN_PICMG << 8); + rv = ipmi_cmd_mc(icmd, idata, ilen, rdata, &rlen, &cc, fdebug); + if (rv == 0 && cc != 0) rv = cc; + if (rv == 0) { + if (fdebug) { + printf("picmg_addr(%02x,%02x)",a1,a2); + dump_buf("picmg_addr",rdata,rlen,0); + } + memcpy(addrdata,rdata,rlen); + } + return(rv); +} +#endif + +#ifdef WIN32 +static int get_filesize(char *fileName, ulong *psize) +{ + int rv; + WIN32_FILE_ATTRIBUTE_DATA fileInfo; + + if (fileName == NULL) return -1; + if (psize == NULL) return -1; + rv = GetFileAttributesEx(fileName, GetFileExInfoStandard, (void*)&fileInfo); + if (!rv) return -1; + *psize = (long)fileInfo.nFileSizeLow; + return 0; +} +#endif + +int read_sdr_binfile(char *binfile, uchar **pbufret, int *buflen) +{ + uchar *pbuf = NULL; + FILE *fp; + int len; + int ret; +#ifdef WIN32 + { + ulong flen; + ret = get_filesize(binfile, &flen); + if (ret == 0) len = flen; + else { + ret = get_LastError(); + printf("Cannot get file size for %s, error %d\n",binfile,ret); + return(ret); + } + } +#endif + fp = fopen(binfile,"r"); + if (fp == NULL) { + ret = get_LastError(); + printf("Cannot open file %s, error %d\n",binfile,ret); + return(ret); + } +#ifndef WIN32 + { + struct stat st; + /* use fstat to get file size and allocate buffer */ + ret = fstat(fileno(fp), &st); + len = st.st_size; /*file size in bytes*/ + if (ret != 0) { + ret = get_LastError(); + printf("Cannot stat file %s, error %d\n",binfile,ret); + return(ret); + } + } +#endif + // len = nsdrs * SDR_SZ; /*estimate max size for n sdrs*/ + sz_sdrs = len; + pbuf = malloc(len); + if (fdebug) printf("restore: malloc(%d) pbuf=%p\n",len,pbuf); + if (pbuf == NULL) { + ret = -1; + fclose(fp); + return(ret); + } + /*ok, so proceed with restore*/ + ret = 0; + len = (int)fread(pbuf, 1, sz_sdrs, fp); + if (len <= 0) { + ret = get_LastError(); + printf("Error %d reading file %s\n",ret,binfile); + sz_sdrs = 0; /*for safety*/ + } + fclose(fp); + if (fdebug) { + printf("SDR buffer from file (len=%d,sz=%d)\n",len,sz_sdrs); + dump_buf("SDR buffer",pbuf,len,1); + } + *pbufret = pbuf; + *buflen = len; + return(ret); +} + +#ifdef ALONE +#ifdef WIN32 +int __cdecl +#else +int +#endif +main(int argc, char **argv) +#else +/* METACOMMAND or libipmiutil */ +int i_sensor(int argc, char **argv) +#endif +{ + int ret, rv; + int c; + int recid, recnext; + uchar sdrdata[MAX_BUFFER_SIZE]; + uchar devrec[16]; + int sz, i, j; + int fsetfound = 0; + int iloop; + int ipass, npass; + uchar *pset; + char *p; + char *s1; + + printf("%s: version %s\n",progname,progver); + + while ( (c = getopt( argc, argv,"a:bcd:ef:g:h:i:j:l:m:n:opqrstu:vwxT:V:J:L:EYF:P:N:R:U:Z:?")) != EOF ) + switch(c) { + case 'a': /* reArm sensor number N */ + if (strncmp(optarg,"0x",2) == 0) frearm = htoi(&optarg[2]); + else frearm = htoi(optarg); /*was atoi()*/ + break; + case 'c': fsimple = 1; break; /* Canonical/simple output*/ + case 'd': fdump = 1; /* Dump SDRs to a file*/ + binfile = optarg; break; + case 'b': fchild = 1; break; /* Bladed, so get child SDRs */ + case 'e': fchild = 1; break; /* Extra bladed child SDRs */ + case 'f': frestore = 1; /* Restore SDRs from a file*/ + binfile = optarg; break; + case 's': fsimple = 1; break; /* Simple/canonical output */ + /*fcanonical==fsimple*/ + case 'g': + rv = get_group_id(optarg); + if (rv < 0) { + printf("Unrecognized sensor type group (%s)\n",optarg); + ret = ERR_BAD_PARAM; + goto do_exit; + } else fshowgrp = rv; + if (fdebug) printf("num sensor type groups = %d\n",fshowgrp); + break; + case 'i': + fshowidx = 1; + get_idx_range(optarg); + break; + case 'j': fjumpstart = 1; /* Load SDR cache from a file*/ + binfile = optarg; break; + case 't': fshowthr = 1; break; + case 'v': fshowthr = 1; sens_verbose = 1; break; + case 'p': fsavethresh = 1; break; + case 'q': fshowthr = 2; fwrap = 1; break; + case 'r': frawsdr = 1; break; + case 'm': /* specific 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*/ + if (optarg[6] == 's') { + g_addrtype = ADDR_SMI; s1 = "SMI"; + } else { g_addrtype = ADDR_IPMB; s1 = "IPMB"; } + fset_mc = 1; + printf("set MC at %s bus=%x sa=%x lun=%x\n", + s1,g_bus,g_sa,g_lun); + break; + case 'o': + fgetmem = 1; + break; + case 'n': + if (strncmp(optarg,"0x",2) == 0) i = htoi(&optarg[2]); + else i = htoi(optarg); /*was atoi()*/ + sensor_num = (uchar)i; + printf("sensor_num = 0x%x\n",sensor_num); + break; + case 'h': /* highest threshold */ + if (strncmp(optarg,"0x",2) == 0) { + i = htoi(&optarg[2]); + sensor_hi = (uchar)i; + fsetthresh = 1; + } else { + sensor_hi_f = atof(optarg); + fsetthresh = 2; /*indicates float conversion*/ + } + break; + case 'l': /* lowest threshold */ + if (strncmp(optarg,"0x",2) == 0) { + i = htoi(&optarg[2]); + sensor_lo = (uchar)i; + fsetthresh = 1; + } else { + sensor_lo_f = atof(optarg); + fsetthresh = 2; /*indicates float conversion*/ + } + break; + case 'u': /* specify unique thresholds in hex or float */ + /* raw hex format: 0xLNLCLUHNHCHU, all 6 required */ + if (strncmp(optarg,"0x",2) == 0) { /*raw hex thresholds*/ + sensor_thr[0] = htoi(&optarg[2]); /*lo noncrit*/ + sensor_thr[1] = htoi(&optarg[4]); /*lo crit*/ + sensor_thr[2] = htoi(&optarg[6]); /*lo unrec*/ + sensor_thr[3] = htoi(&optarg[8]); /*hi noncrit*/ + sensor_thr[4] = htoi(&optarg[10]); /*hi crit*/ + sensor_thr[5] = htoi(&optarg[12]); /*hi unrec*/ + /* validate sensor threshold ordering */ + rv = validate_thresholds(&sensor_thr[0],0,NULL); + if (rv == 0) { + sensor_lo = sensor_thr[0]; + sensor_hi = sensor_thr[3]; + fsetthresh = 3; /*indicates unique raw thresholds */ + } else { + ret = ERR_BAD_PARAM; + goto do_exit; + } + } else { + /* assume float input thresholds, with ':' separator*/ + /* format LN:LC:LU:HN:HC:HU */ + sz = strlen_(optarg); + p = &optarg[0]; + for (i = 0; i < 6; i++) sensor_thrf[i] = THR_EMPTY; + j = 0; + for (i = 0; i <= sz; i++) { + if (j >= 6) break; + switch(optarg[i]) { + case ':': + case '\n': + case '\0': + optarg[i] = 0; + if (p[0] == 0) sensor_thrf[j] = THR_EMPTY; + else sensor_thrf[j] = atof(p); + if (i+1 < sz) p = &optarg[i+1]; + j++; + break; + default: + break; + } + } + /* validate sensor threshold ordering later */ + // rv = validate_thresholds(&sensor_thrf[0],1,NULL); + // if (rv == 0) { + sensor_lo_f = sensor_thrf[0]; + sensor_hi_f = sensor_thrf[3]; + fsetthresh = 4; /*indicates unique float thresholds */ + // } else { + // ret = ERR_BAD_PARAM; + // goto do_exit; + // } + } /*end-else -u float thresholds*/ + break; + case 'w': fwrap = 1; break; + case 'x': fdebug = 1; break; + case 'L': /* Loop */ + nloops = atoi(optarg); + fdoloop = 1; + break; + case 'V': /* priv level */ + fprivset = 1; + 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 'Y': /* prompt for remote password */ + case 'Z': /* set local MC address */ + parse_lan_options(c,optarg,fdebug); + break; + default: /*usage*/ + printf("Usage: %s [-abcdefghijlmnprstuvwxL -NUPREFTVY]\n",progname); + printf("where -x shows eXtra debug messages\n"); + printf(" -a snum reArms the sensor (snum) for events\n"); + printf(" -b show Bladed child MCs for PICMG (same as -e)\n"); + printf(" -c displays a simpler, Canonical output fmt\n"); + printf(" -d file Dump SDRs to a binary file\n"); + printf(" -e show Every bladed child MC for PICMG\n"); + // printf(" -f file Restore SDRs from a binary dump file\n"); + printf(" -g fan show only this sensor type group\n"); + printf(" -h tval specifies the Highest threshold to set\n"); + printf(" -i id only show these sensor ids\n"); + printf(" -j file Jump-start SDR cache from a binary file\n"); + printf(" -l tval specifies the Lowest threshold to set\n"); + printf(" -m002000 specific MC (bus 00,sa 20,lun 00)\n"); + printf(" -n snum specifies the sensor Number to set hi/lo\n"); + printf(" -o output memory DIMM information\n"); + printf(" -p persist the threshold being set\n"); + printf(" -q shows threshold values in d:d:d format\n"); + printf(" -r show Raw SDR bytes\n"); + printf(" -s displays a Simpler output format\n"); + printf(" -t shows Threshold values in text format\n"); + printf(" -u thr set Unique threshold values (e.g. 3:2:1:48:49:50)\n"); + printf(" -v Verbose: thresholds, max/min, hysteresis\n"); + printf(" -w Wrap thresholds on sensor line\n"); + printf(" -L n Loop n times\n"); + print_lan_opt_usage(); + ret = ERR_USAGE; + goto do_exit; + } + if (fjumpstart && fchild) { + printf("Cannot use -j jumpstart cache with -c child SDRs\n"); + ret = ERR_BAD_PARAM; + goto do_exit; + } + fremote = is_remote(); +#ifndef WIN32 + if (fremote == 0) { + /* only run this as superuser for accessing IPMI devices. */ + i = geteuid(); + if (i > 1) { + printf("Not superuser (%d)\n", i); + ret = ERR_NOT_ALLOWED; + goto do_exit; + } + } +#endif + if (fremote) { + if (!fprivset) { + /* on many systems, getting the SDR Reservation ID requires admin */ + /* if ((fsetthresh != 0) || (frearm != 0)) also require admin */ + parse_lan_options('V',"4",0); + } + } + + ret = ipmi_getdeviceid(devrec,sizeof(devrec),fdebug); + if (ret == 0) { + uchar ipmi_maj; + uchar ipmi_min; + char *pstr; + ipmi_maj = devrec[4] & 0x0f; + ipmi_min = devrec[4] >> 4; + if ((devrec[1] & 0x80) == 0x80) fdevsdrs = 1; + vend_id = devrec[6] + (devrec[7] << 8) + (devrec[8] << 16); + prod_id = devrec[9] + (devrec[10] << 8); + if (vend_id == VENDOR_NSC) { /*NSC mBMC*/ + pstr = "mBMC"; + fmBMC = 1; + fdevsdrs = 0; + } else if (vend_id == VENDOR_INTEL) { /*Intel BMC*/ + /*Intel Sahalee BMC */ + pstr = "BMC"; + fmBMC = 0; + if (is_romley(vend_id,prod_id)) fRomley = 1; + if (prod_id == 0x003E || fRomley) /*Urbanna NSN2U,CG2100*/ + set_max_kcs_loops(URNLOOPS); /*longer KCS timeout*/ + } else { /* Other products */ + pstr = "BMC"; + fmBMC = 0; + if (vend_id == VENDOR_NEC) fdevsdrs = 0; + } + show_devid( devrec[2], devrec[3], ipmi_maj, ipmi_min); + // "-- %s version %x.%x, IPMI version %d.%d \n", pstr, + } else { + goto do_exit; + } + + ret = ipmi_getpicmg( devrec, sizeof(devrec),fdebug); + if (ret == 0) fpicmg = 1; + /*if not PICMG, some vendors override to SDR Rep*/ + fdevsdrs = use_devsdrs(fpicmg); + if (fdevsdrs) printf("supports device sdrs\n"); + npass = 1; + if (g_sa != 0) { + /* target a specific MC via IPMB (usu a picmg blade) */ + ipmi_set_mc(g_bus,g_sa,g_lun,g_addrtype); + fchild = 0; /* no children, only the specified address */ + } else { +#ifdef PICMG_CHILD + /* fchild set above if -b is specified to get Blade child SDRs */ + /* npass = 2 will get both SdrRep & DevSdr passes on CMM */ + if (fpicmg && fdevsdrs) { + npass = 2; + g_addrtype = ADDR_IPMB; + } +#endif + g_sa = BMC_SA; + } + + if (fgetmem) { + if (fremote) printf("Cannot get memory DIMM information remotely.\n"); + else { + int msz; + char desc[80]; + char szstr[25]; + ret = -1; + for (j = 0; j < 1; j++) { + for (i = 0; i < 16; i++) { + rv = get_MemDesc(j, i, desc,&msz); + if (rv == 0) { + if (msz == 0) strcpy(szstr,"not present"); + else if (msz & 0x8000) + sprintf(szstr,"size=%dKB",(msz & 0x7FFF)); + else sprintf(szstr,"size=%dMB",msz); + printf("Memory Device (%d,%d): %s : %s\n", + j,i,desc,szstr); + ret = 0; + } + } + } + } /*end-else*/ + goto do_exit; + } + + if (fdump) { + uchar *pbuf = NULL; + FILE *fp; + int len; + ret = get_sdr_cache(&pbuf); + if (ret == 0) { + fp = fopen(binfile,"w"); + if (fp == NULL) { + ret = get_LastError(); + printf("Cannot open file %s, error %d\n",binfile,ret); + } else { + printf("Writing SDR size %d to %s ...\n",sz_sdrs,binfile); + len = (int)fwrite(pbuf, 1, sz_sdrs, fp); + fclose(fp); + if (len <= 0) { + ret = get_LastError(); + printf("Error %d writing file %s\n",ret,binfile); + } else ret = 0; + } + free_sdr_cache(pbuf); + } + goto do_exit; + } /*endif fdump*/ + + if (frestore) { + uchar sdr[MAX_BUFFER_SIZE]; + ushort id; + int slen; + uchar *pbuf = NULL; + + ret = read_sdr_binfile(binfile,&pbuf,&slen); + if (ret == 0) { /*successful, so write SDRs */ + nsdrs = find_nsdrs(pbuf); + printf("Ready to restore %d SDRs\n",nsdrs); + set_reserve(1); + ret = sdr_clear_repo(fdevsdrs); + if (ret != 0) { + printf("SDR Clear Repository error %d\n",ret); + goto do_exit; + } + id = 0; + while(find_sdr_next(sdr,pbuf,id) == 0) { + id = sdr[0] + (sdr[1] << 8); + if (fdebug) printf("adding SDR[%x]\n",id); + set_reserve(1); + ret = sdr_add_record(sdr,fdevsdrs); + if (ret != 0) { + printf("SDR[%x] add error %d\n",id,ret); + break; + } + } /*end while sdr*/ + } + if (ret == 0) printf("Restored %d SDRs successfully.\n",nsdrs); + free_sdr_cache(pbuf); /* does nothing if (pbuf == NULL) */ + goto do_exit; + } /*endif frestore*/ + + if (fjumpstart) { + uchar *pbuf = NULL; + int slen; + ret = read_sdr_binfile(binfile,&pbuf,&slen); + if (ret != 0) fjumpstart = 0; /* use normal method if error*/ + else { /* set this as the SDR cache */ + psdrcache = pbuf; + sz_sdrs = slen; + nsdrs = find_nsdrs(pbuf); + if (fdebug) printf("jumpstart cache: nsdrs=%d size=%d\n",nsdrs,slen); + } + } /*endif fjumpstart*/ + + for (ipass = 0; ipass < npass; ipass++) + { + if (fjumpstart) ; /*already got this above*/ + else { + ret = GetSDRRepositoryInfo(&j,&fdevsdrs); + if (fdebug) printf("GetSDRRepositoryInfo: ret=%x nSDRs=%d\n",ret,j); + if (ret == 0 && j == 0) { + printf("SDR Repository is empty\n"); + goto do_exit; + } + nsdrs = j; + } + + /* show header for SDR records */ + if (fsimple) + printf(" ID | SDRType | Type |SNum| Name |Status| Reading\n"); + else + printf("_ID_ SDR_Type_xx ET Own Typ S_Num Sens_Description Hex & Interp Reading\n"); + + if (fwrap) chEol = ' '; + if (!fdoloop) nloops = 1; + for (iloop = 0; iloop < nloops; iloop++) + { + if (fshowidx) recid = sensor_idx1; + else recid = 0; + while (recid != 0xffff) + { + if (fjumpstart) { + ret = find_sdr_next(sdrdata,psdrcache,recid); + if (ret != 0) { ret = 0; break; } /*end of sdrs*/ + recnext = sdrdata[0] + (sdrdata[1] << 8); /*same as recid*/ + sz = sdrdata[4] + 5; + } else { + ret = GetSDR(recid,&recnext,sdrdata,sizeof(sdrdata),&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 */ + printf("%04x GetSDR error 0x%02x %s, rlen=%d\n",recid,ret, + decode_cc((ushort)0,(uchar)ret),sz); + if (ret == 0xC5) { /* lost Reservation ID, retry */ + /* This means that some other IPMI software has + * requested a Reservation before we finished, so + * we need to refresh the Reservation ID * retry. */ + fDoReserve = 1; /* get a new SDR Reservation ID */ + ret = GetSDR(recid,&recnext,sdrdata,sizeof(sdrdata),&sz); + if (fdebug) + printf("GetSDR[%04x]: ret = %x, next=%x\n",recid,ret, + recnext); + } + } 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 */ + } + } /*end-else*/ + if (ret == 0) { /* (ret == 0) OK, got full SDR */ + if (fdebug) { + dump_buf("got SDR",sdrdata,sz,0); + } + if (sz < MIN_SDR_SZ) goto NextSdr; + /* if recid == 0, get real record id */ + if (recid == 0) recid = sdrdata[0] + (sdrdata[1] << 8); + if (fshowgrp > 0) { + for (i = 0; i < fshowgrp; i++) { + uchar styp; + if (sdrdata[3] == 0x03) styp = sdrdata[10]; /*EvtOnly*/ + else styp = sdrdata[12]; + if (fdebug) printf("sdrt=%02x styp=%02x sgrp[%d]=%02x\n", + sdrdata[3],styp,i,sensor_grps[i]); + if (sdrdata[3] == 0xc0) continue; /*skip OEM SDRs*/ + if (styp == sensor_grps[i]) break; + } + if (i >= fshowgrp) goto NextSdr; + } + + if ((sensor_num == INIT_SNUM) || (sdrdata[7] == sensor_num) + || fsetthresh) { + /* if -n not set or if -n matches, parse and show the SDR */ + ShowSDR("",sdrdata); + } /* else filter SDRs if not matching -n sensor_num */ + +#ifdef PICMG_CHILD + /* + * Special logic for blade child MCs in PICMG ATCA systems + * if fchild, try all child MCs within the chassis. + * SDR type 12 capabilities bits (sdrdata[8]): + * 80 = Chassis Device + * 40 = Bridge + * 20 = IPMB Event Generator + * 10 = IPMB Event Receiver + * 08 = FRU Device + * 04 = SEL Device + * 02 = SDR Repository Device + * 01 = Sensor Device + * But all child MCs use Device SDRs anyway. + */ + if (fpicmg && fchild && (sdrdata[3] == 0x12)) { /* PICMG MC DLR */ + int _recid, _recnext, _sz; + uchar _sdrdata[MAX_SDR_SIZE]; + int devsdrs_save; + uchar cc; + + /* save the BMC globals, use IPMB MC */ + devsdrs_save = fdevsdrs; + fdevsdrs = 1; /* use Device SDRs for the children*/ + if (fdebug) + printf(" --- IPMB MC (sa=%02x cap=%02x id=%02x devsdrs=%d):\n", + sdrdata[5],sdrdata[8],sdrdata[12],fdevsdrs); + fDoReserve = 1; /* get a new SDR Reservation ID */ + ipmi_set_mc(PICMG_SLAVE_BUS,sdrdata[5],sdrdata[6],g_addrtype); + + _sz = 16; + ret = ipmi_cmd_mc(GET_DEVICE_ID,NULL,0,_sdrdata,&_sz,&cc,fdebug); + if (ret == 0 && cc == 0) { + /* Get the SDRs from the IPMB MC */ + _recid = 0; + while (_recid != 0xffff) + { + ret = GetSDR(_recid,&_recnext,_sdrdata,sizeof(_sdrdata),&_sz); + if (ret != 0) { + printf("%04x GetSDR error %d, rlen = %d\n",_recid,ret,_sz); + break; + } + else if (_sz >= MIN_SDR_SZ) + ShowSDR(" ",_sdrdata); + + if (_recnext == _recid) _recid = 0xffff; + else _recid = _recnext; + } /*end while*/ + } /*endif ret==0*/ + + /* restore BMC globals */ + fdevsdrs = devsdrs_save; + ipmi_restore_mc(); + fDoReserve = 1; /* get a new SDR Reservation ID */ + } /*endif fpicmg && fchild*/ +#endif + + if (fdebug) printf("fsetthresh=%d snum=%02x(%02x) sa=%02x(%02x)\n", + fsetthresh,sdrdata[7],sensor_num,sdrdata[5],g_sa); + if (fsetthresh && (sdrdata[7] == sensor_num) + && (sdrdata[5] == g_sa)) /*g_sa usu is BMC_SA*/ + { + /* setting threshold, compute threshold raw values */ + if (fsetthresh == 2) { /*set from float*/ + if (fdebug) + printf("lof=%.2f hif=%.2f\n", sensor_lo_f,sensor_hi_f); + if (sensor_lo_f != 0) + sensor_lo = FloatToRaw(sensor_lo_f,sdrdata,0); + if (sensor_hi_f != 0) + sensor_hi = FloatToRaw(sensor_hi_f,sdrdata,0); + } else if (fsetthresh == 1) { /*raw thresholds*/ + if (sensor_hi != 0xff) + sensor_hi_f = RawToFloat(sensor_hi,sdrdata); + if (sensor_lo != 0xff) + sensor_lo_f = RawToFloat(sensor_lo,sdrdata); + } else if (fsetthresh == 3) { /*unique raw thresholds*/ + if (sensor_hi != 0xff) + sensor_hi_f = RawToFloat(sensor_hi,sdrdata); + if (sensor_lo != 0xff) + sensor_lo_f = RawToFloat(sensor_lo,sdrdata); + } else if (fsetthresh == 4) { /*set unique from float*/ + i = fill_thresholds(&sensor_thrf[0], sdrdata); + /* if (i > 0) ; * filled in some thresholds */ + { /* always set lo/hi if any are non-zero */ + for (j = 0; j < 3; j++) { + if (sensor_thrf[j] != 0) { + sensor_lo_f = sensor_thrf[j]; break; } + } + for (j = 3; j < 6; j++) { + if (sensor_thrf[j] != 0) { + sensor_hi_f = sensor_thrf[j]; break; } + } + } + if (fdebug) + printf("lof=%.2f hif=%.2f\n", sensor_lo_f,sensor_hi_f); + /* convert thrf (float) to thr (raw) */ + if (sensor_lo_f != 0) { + sensor_lo = FloatToRaw(sensor_lo_f,sdrdata,0); + sensor_thr[0] = FloatToRaw(sensor_thrf[0],sdrdata,0); + sensor_thr[1] = FloatToRaw(sensor_thrf[1],sdrdata,0); + sensor_thr[2] = FloatToRaw(sensor_thrf[2],sdrdata,0); + } + if (sensor_hi_f != 0) { + sensor_hi = FloatToRaw(sensor_hi_f,sdrdata,0); + sensor_thr[3] = FloatToRaw(sensor_thrf[3],sdrdata,0); + sensor_thr[4] = FloatToRaw(sensor_thrf[4],sdrdata,0); + sensor_thr[5] = FloatToRaw(sensor_thrf[5],sdrdata,0); + } + /* validate threshold ordering */ + if (validate_thresholds(sensor_thrf,1,sdrdata) != 0) { + ret = ERR_BAD_PARAM; + goto do_exit; + } + } + { + printf("\tSetting SDR %04x sensor %02x to lo=%02x hi=%02x\n", + recid,sensor_num,sensor_lo,sensor_hi); + if (recid == 0) fsetfound = 1; + else fsetfound = recid; + } + } /*endif fsetthresh */ + } /*endif ok, got full SDR */ + +NextSdr: + if (fshowidx) { + /* if we have already read the last in the range, done. */ + if (recid >= sensor_idxN) break; // recnext = 0xffff; // break; + } + if (fjumpstart) recid = recnext; + else { + if (recnext == recid) recid = 0xffff; /*break;*/ + else recid = recnext; + } + } /*end while recid*/ + if (fdoloop && (nloops > 1)) { + printf("\n"); /* output an empty separator line */ + os_usleep(1,0); /*delay 1 sec between loops*/ + } + } /*end for nloops*/ + + if (npass > 1) { /* npass==2 for PICMG */ + /* Switch fdevsdrs from Device to Repository */ + if (fdevsdrs == 0) fdevsdrs = 1; + else fdevsdrs = 0; + fDoReserve = 1; /* get a new SDR Reservation ID */ + } + } /*end for npass*/ + + if ((fshowidx == 0) && (fshowgrp == 0)) { + /* use local rv, errors are ignored for POH */ + rv = ShowPowerOnHours(); + } + + if (frearm != 0) { + ret = RearmSensor((uchar)frearm); + printf("RearmSensor(0x%02x) ret = %d\n",frearm,ret); + } + + if (fsetthresh != 0) { + uchar tdata[7]; + if (fsetfound == 0) { + printf("Did not find sensor number %02x.\nPlease enter the sensor number parameter in hex, as it is displayed above.\n",sensor_num); + } + ret = GetSensorThresholds(sensor_num,tdata); + if (ret != 0) goto do_exit; +#ifdef TEST + printf("thresh(%02x): %02x %02x %02x %02x %02x %02x %02x %02x\n", + sensor_num, sensor_num, tdata[0], tdata[1], tdata[2], + tdata[3], tdata[4], tdata[5], tdata[6]); + printf(" set(%02x): %02x %02x \n", + sensor_num,sensor_lo,sensor_hi); +#endif + if (fsetthresh == 3 || fsetthresh == 4) { + /* apply unique sensor thresholds */ + pset = &sensor_thr[0]; + } else pset = NULL; /* use just hi/lo */ + ret = SetSensorThresholds(sensor_num,sensor_hi,sensor_lo,tdata,pset); + printf("SetSensorThreshold[%02x] to lo=%02x(%4.3f) hi=%02x(%4.3f), ret = %d\n", + sensor_num,sensor_lo,sensor_lo_f,sensor_hi,sensor_hi_f,ret); + if (fsavethresh && ret == 0) { + recid = fsetfound; + rv = SaveThreshold(recid,sensor_num,sensor_lo,sensor_hi,pset); + if (rv == 0) + printf("Saved thresholds for sensor %02x\n",sensor_num); + } + fsetthresh = 0; /*only set threshold once*/ + } + +do_exit: + if (fjumpstart) free_sdr_cache(psdrcache); /* does nothing if ==NULL*/ + /* show_outcome(progname,ret); *handled in ipmiutil.c*/ + ipmi_close_(); + return(ret); +} + +/* end isensor.c */ |