2007-10-26 22:44:33 +00:00
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
#egan@us.ibm.com
#modified by jbjohnso@us.ibm.com
#(C)IBM Corp
package xCAT_plugin::ipmi ;
2008-09-25 03:04:56 +00:00
BEGIN
{
$ ::XCATROOT = $ ENV { 'XCATROOT' } ? $ ENV { 'XCATROOT' } : '/opt/xcat' ;
}
use lib "$::XCATROOT/lib/perl" ;
2008-07-18 19:59:20 +00:00
use strict ;
use warnings "all" ;
2008-09-25 03:04:56 +00:00
use xCAT::GlobalDef ;
use xCAT_monitoring::monitorctrl ;
2009-03-08 03:30:24 +00:00
use xCAT::SPD qw/decode_spd/ ;
2007-10-26 22:44:33 +00:00
2008-09-19 14:41:14 +00:00
use POSIX qw( ceil floor ) ;
2007-10-26 22:44:33 +00:00
use Storable qw( store_fd retrieve_fd thaw freeze ) ;
2008-01-21 19:49:59 +00:00
use xCAT::Utils ;
2009-03-20 21:36:49 +00:00
use xCAT::SvrUtils ;
2008-04-10 21:06:26 +00:00
use xCAT::Usage ;
2008-03-10 15:36:44 +00:00
use Thread qw( yield ) ;
2009-03-02 18:33:59 +00:00
use LWP 5.64 ;
use HTTP::Request::Common ;
2008-04-07 14:52:17 +00:00
my $ tfactor = 0 ;
2008-09-19 21:15:01 +00:00
my $ vpdhash ;
2008-04-21 15:41:36 +00:00
my % bmc_comm_pids ;
2007-10-26 22:44:33 +00:00
require Exporter ;
2008-07-18 19:59:20 +00:00
our @ ISA = qw( Exporter ) ;
our @ EXPORT = qw(
2007-10-26 22:44:33 +00:00
ipmiinit
ipmicmd
) ;
sub handled_commands {
return {
rpower = > 'nodehm:power,mgt' ,
2008-08-16 13:41:14 +00:00
getipmicons = > 'ipmi' ,
2008-03-12 19:27:41 +00:00
rspconfig = > 'nodehm:mgt' ,
2008-04-12 14:53:11 +00:00
rvitals = > 'nodehm:mgt' ,
rinv = > 'nodehm:mgt' ,
2007-10-26 22:44:33 +00:00
rsetboot = > 'nodehm:mgt' ,
2008-04-12 14:53:11 +00:00
rbeacon = > 'nodehm:mgt' ,
reventlog = > 'nodehm:mgt' ,
2008-09-22 22:57:53 +00:00
rfrurewrite = > 'nodehm:mgt' ,
2009-03-02 18:33:59 +00:00
getrvidparms = > 'nodehm:mgt'
2007-10-26 22:44:33 +00:00
}
}
2009-09-18 19:53:48 +00:00
#use Data::Dumper;
2007-10-26 22:44:33 +00:00
use POSIX "WNOHANG" ;
use IO::Handle ;
use IO::Socket ;
use IO::Select ;
use Class::Struct ;
use Digest::MD5 qw( md5 ) ;
use POSIX qw( WNOHANG mkfifo strftime ) ;
use Fcntl qw( :flock ) ;
2008-04-10 21:06:26 +00:00
2007-10-26 22:44:33 +00:00
#local to module
my @ rmcp = ( 0x06 , 0x00 , 0xff , 0x07 ) ;
my $ auth ;
my $ rssa = 0x20 ;
my $ rqsa = 0x81 ;
my $ seqlun = 0x00 ;
my @ session_id = ( 0 , 0 , 0 , 0 ) ;
my @ challenge = ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) ;
my @ seqnum = ( 0 , 0 , 0 , 0 ) ;
2008-09-06 16:17:01 +00:00
my $ outfd ; #File descriptor for children to send messages to parent
my $ currnode ; #string to describe current node, presumably nodename
my $ globrc = 0 ;
2007-10-26 22:44:33 +00:00
my $ userid ;
my $ passwd ;
2009-03-02 18:33:59 +00:00
my $ ipmi_bmcipaddr ;
2007-10-26 22:44:33 +00:00
my $ timeout ;
my $ port ;
my $ debug ;
2008-03-03 20:51:36 +00:00
my $ ndebug = 0 ;
2009-03-02 18:33:59 +00:00
my @ cmdargv ;
2007-10-26 22:44:33 +00:00
my $ sock ;
my @ user ;
my @ pass ;
my $ channel_number ;
my % sdr_hash ;
my % fru_hash ;
2007-10-30 15:24:43 +00:00
my $ ipmiv2 = 0 ;
2007-10-26 22:44:33 +00:00
my $ authoffset = 0 ;
my $ enable_cache = "yes" ;
my $ cache_dir = "/var/cache/xcat" ;
#my $ibmledtab = $ENV{XCATROOT}."/lib/GUMI/ibmleds.tab";
use xCAT::data::ibmleds ;
use xCAT::data::ipmigenericevents ;
use xCAT::data::ipmisensorevents ;
2008-09-19 14:41:14 +00:00
my $ cache_version = 2 ;
2009-03-07 18:04:32 +00:00
my $ frudex ; #iterator for initfru to use
2007-10-26 22:44:33 +00:00
2008-10-03 17:46:31 +00:00
my $ status_noop = "XXXno-opXXX" ;
2008-11-20 16:58:36 +00:00
my % idpxthermprofiles = (
'0z' = > [ 0x37 , 0x41 , 0 , 0 , 0 , 0 , 5 , 0xa , 0x3c , 0xa , 0xa , 0x1e ] ,
'1a' = > [ 0x30 , 0x3c , 0 , 0 , 0 , 0 , 5 , 0xa , 0x3c , 0xa , 0xa , 0x1e ] ,
'2b' = > [ 0x30 , 0x3c , 0 , 0 , 0 , 0 , 5 , 0xa , 0x3c , 0xa , 0xa , 0x1e ] ,
'3c' = > [ 0x30 , 0x3c , 0 , 0 , 0 , 0 , 5 , 0xa , 0x3c , 0xa , 0xa , 0x1e ] ,
'4d' = > [ 0x37 , 0x44 , 0 , 0 , 0 , 0 , 5 , 0xa , 0x3c , 0xa , 0xa , 0x1e ] ,
'5e' = > [ 0x37 , 0x44 , 0 , 0 , 0 , 0 , 5 , 0xa , 0x3c , 0xa , 0xa , 0x1e ] ,
'6f' = > [ 0x35 , 0x44 , 0 , 0 , 0 , 0 , 5 , 0xa , 0x3c , 0xa , 0xa , 0x1e ] ,
2008-06-10 15:32:14 +00:00
) ;
2007-10-26 22:44:33 +00:00
my % codes = (
0x00 = > "Command Completed Normal" ,
0xC0 = > "Node busy, command could not be processed" ,
2008-07-11 15:22:55 +00:00
0xC1 = > "Invalid or unsupported command" ,
2007-10-26 22:44:33 +00:00
0xC2 = > "Command invalid for given LUN" ,
0xC3 = > "Timeout while processing command, response unavailable" ,
0xC4 = > "Out of space, could not execute command" ,
0xC5 = > "Reservation canceled or invalid reservation ID" ,
0xC6 = > "Request data truncated" ,
0xC7 = > "Request data length invalid" ,
0xC8 = > "Request data field length limit exceeded" ,
0xC9 = > "Parameter out of range" ,
0xCA = > "Cannot return number of requested data bytes" ,
0xCB = > "Requested Sensor, data, or record not present" ,
0xCB = > "Not present" ,
0xCC = > "Invalid data field in Request" ,
0xCD = > "Command illegal for specified sensor or record type" ,
0xCE = > "Command response could not be provided" ,
0xCF = > "Cannot execute duplicated request" ,
0xD0 = > "Command reqponse could not be provided. SDR Repository in update mode" ,
0xD1 = > "Command response could not be provided. Device in firmware update mode" ,
0xD2 = > "Command response could not be provided. BMC initialization or initialization agent in progress" ,
0xD3 = > "Destination unavailable" ,
0xD4 = > "Insufficient privilege level" ,
0xD5 = > "Command or request parameter(s) not supported in present state" ,
0xFF = > "Unspecified error" ,
) ;
my % units = (
2008-03-03 20:51:36 +00:00
0 = > "" , #"unspecified",
2007-10-26 22:44:33 +00:00
1 = > "C" ,
2 = > "F" ,
3 = > "K" ,
4 = > "Volts" ,
5 = > "Amps" ,
6 = > "Watts" ,
7 = > "Joules" ,
8 = > "Coulombs" ,
9 = > "VA" ,
10 = > "Nits" ,
11 = > "lumen" ,
12 = > "lux" ,
13 = > "Candela" ,
14 = > "kPa" ,
15 = > "PSI" ,
16 = > "Newton" ,
17 = > "CFM" ,
18 = > "RPM" ,
19 = > "Hz" ,
20 = > "microsecond" ,
21 = > "millisecond" ,
22 = > "second" ,
23 = > "minute" ,
24 = > "hour" ,
25 = > "day" ,
26 = > "week" ,
27 = > "mil" ,
28 = > "inches" ,
29 = > "feet" ,
30 = > "cu in" ,
31 = > "cu feet" ,
32 = > "mm" ,
33 = > "cm" ,
34 = > "m" ,
35 = > "cu cm" ,
36 = > "cu m" ,
37 = > "liters" ,
38 = > "fluid ounce" ,
39 = > "radians" ,
40 = > "steradians" ,
41 = > "revolutions" ,
42 = > "cycles" ,
43 = > "gravities" ,
44 = > "ounce" ,
45 = > "pound" ,
46 = > "ft-lb" ,
47 = > "oz-in" ,
48 = > "gauss" ,
49 = > "gilberts" ,
50 = > "henry" ,
51 = > "millihenry" ,
52 = > "farad" ,
53 = > "microfarad" ,
54 = > "ohms" ,
55 = > "siemens" ,
56 = > "mole" ,
57 = > "becquerel" ,
58 = > "PPM" ,
59 = > "reserved" ,
60 = > "Decibels" ,
61 = > "DbA" ,
62 = > "DbC" ,
63 = > "gray" ,
64 = > "sievert" ,
65 = > "color temp deg K" ,
66 = > "bit" ,
67 = > "kilobit" ,
68 = > "megabit" ,
69 = > "gigabit" ,
70 = > "byte" ,
71 = > "kilobyte" ,
72 = > "megabyte" ,
73 = > "gigabyte" ,
74 = > "word" ,
75 = > "dword" ,
76 = > "qword" ,
77 = > "line" ,
78 = > "hit" ,
79 = > "miss" ,
80 = > "retry" ,
81 = > "reset" ,
82 = > "overflow" ,
83 = > "underrun" ,
84 = > "collision" ,
85 = > "packets" ,
86 = > "messages" ,
87 = > "characters" ,
88 = > "error" ,
89 = > "correctable error" ,
90 = > "uncorrectable error" ,
) ;
my % chassis_types = (
0 = > "Unspecified" ,
1 = > "Other" ,
2 = > "Unknown" ,
3 = > "Desktop" ,
4 = > "Low Profile Desktop" ,
5 = > "Pizza Box" ,
6 = > "Mini Tower" ,
7 = > "Tower" ,
8 = > "Portable" ,
9 = > "LapTop" ,
10 = > "Notebook" ,
11 = > "Hand Held" ,
12 = > "Docking Station" ,
13 = > "All in One" ,
14 = > "Sub Notebook" ,
15 = > "Space-saving" ,
16 = > "Lunch Box" ,
17 = > "Main Server Chassis" ,
18 = > "Expansion Chassis" ,
19 = > "SubChassis" ,
20 = > "Bus Expansion Chassis" ,
21 = > "Peripheral Chassis" ,
22 = > "RAID Chassis" ,
23 = > "Rack Mount Chassis" ,
) ;
my % MFG_ID = (
2 = > "IBM" ,
343 = > "Intel" ,
) ;
my % PROD_ID = (
"2:34869" = > "e325" ,
"2:3" = > "x346" ,
"2:4" = > "x336" ,
"343:258" = > "Tiger 2" ,
"343:256" = > "Tiger 4" ,
) ;
my $ localtrys = 3 ;
my $ localdebug = 0 ;
struct SDR_rep_info = > {
version = > '$' ,
rec_count = > '$' ,
resv_sdr = > '$' ,
} ;
struct SDR = > {
rec_type = > '$' ,
sensor_owner_id = > '$' ,
sensor_owner_lun = > '$' ,
sensor_number = > '$' ,
entity_id = > '$' ,
entity_instance = > '$' ,
sensor_init = > '$' ,
sensor_cap = > '$' ,
sensor_type = > '$' ,
event_type_code = > '$' ,
ass_event_mask = > '@' ,
deass_event_mask = > '@' ,
dis_read_mask = > '@' ,
sensor_units_1 = > '$' ,
sensor_units_2 = > '$' ,
sensor_units_3 = > '$' ,
linearization = > '$' ,
M = > '$' ,
tolerance = > '$' ,
B = > '$' ,
accuracy = > '$' ,
accuracy_exp = > '$' ,
R_exp = > '$' ,
B_exp = > '$' ,
analog_char_flag = > '$' ,
nominal_reading = > '$' ,
normal_max = > '$' ,
normal_min = > '$' ,
sensor_max_read = > '$' ,
sensor_min_read = > '$' ,
upper_nr_threshold = > '$' ,
upper_crit_thres = > '$' ,
upper_ncrit_thres = > '$' ,
lower_nr_threshold = > '$' ,
lower_crit_thres = > '$' ,
lower_ncrit_thres = > '$' ,
pos_threshold = > '$' ,
neg_threshold = > '$' ,
id_string_type = > '$' ,
id_string = > '$' ,
#LED id
led_id = > '$' ,
2009-03-07 02:04:21 +00:00
fru_type = > '$' ,
fru_subtype = > '$' ,
2007-10-26 22:44:33 +00:00
} ;
struct FRU = > {
rec_type = > '$' ,
desc = > '$' ,
value = > '$' ,
} ;
2009-03-07 02:04:21 +00:00
sub decode_fru_locator { #Handle fru locator records
my @ locator = @ _ ;
my $ sdr = SDR - > new ( ) ;
$ sdr - > rec_type ( 0x11 ) ;
2009-03-07 18:04:32 +00:00
$ sdr - > sensor_owner_id ( "FRU" ) ;
$ sdr - > sensor_owner_lun ( "FRU" ) ;
$ sdr - > sensor_number ( $ locator [ 7 ] ) ;
2009-03-07 02:04:21 +00:00
unless ( $ locator [ 8 ] & 0x80 and ( $ locator [ 8 ] & 0x1f ) == 0 and $ locator [ 9 ] == 0 ) {
#only logical devices at lun 0 supported for now
return undef ;
}
unless ( ( $ locator [ 16 ] & 0xc0 ) == 0xc0 ) { #Only unpacked ASCII for now, no unicode or BCD plus yet
return undef ;
}
my $ idlen = $ locator [ 16 ] & 0x3f ;
unless ( $ idlen > 1 ) { return undef ; }
2009-03-07 18:04:32 +00:00
$ sdr - > id_string ( pack ( "C*" , @ locator [ 17 .. 17 + $ idlen - 1 ] ) ) ;
2009-03-07 02:04:21 +00:00
$ sdr - > fru_type ( $ locator [ 11 ] ) ;
$ sdr - > fru_subtype ( $ locator [ 12 ] ) ;
return $ sdr ;
}
2008-05-12 23:36:47 +00:00
sub waitforack {
my $ sock = shift ;
my $ select = new IO:: Select ;
$ select - > add ( $ sock ) ;
my $ str ;
2009-04-03 14:40:21 +00:00
if ( $ select - > can_read ( 60 ) ) { # Continue after 60 seconds, even if not acked...
2008-05-12 23:36:47 +00:00
if ( $ str = <$sock> ) {
} else {
$ select - > remove ( $ sock ) ; #Block until parent acks data
}
}
}
2008-02-12 21:34:57 +00:00
sub translate_sensor {
my $ reading = shift ;
my $ sdr = shift ;
my $ unitdesc ;
my $ value ;
my $ lformat ;
my $ per ;
$ unitdesc = $ units { $ sdr - > sensor_units_2 } ;
2008-09-18 18:31:01 +00:00
if ( $ sdr - > rec_type == 1 ) {
$ value = ( ( $ sdr - > M * $ reading ) + ( $ sdr - > B * ( 10 ** $ sdr - > B_exp ) ) ) * ( 10 ** $ sdr - > R_exp ) ;
} else {
$ value = $ reading ;
}
if ( $ sdr - > rec_type != 1 or $ sdr - > linearization == 0 ) {
2008-02-12 21:34:57 +00:00
$ reading = $ value ;
if ( $ value == int ( $ value ) ) {
$ lformat = "%-30s%8d%-20s" ;
} else {
$ lformat = "%-30s%8.3f%-20s" ;
}
} elsif ( $ sdr - > linearization == 7 ) {
if ( $ value > 0 ) {
$ reading = 1 / $ value ;
} else {
$ reading = 0 ;
}
$ lformat = "%-30s%8d %-20s" ;
} else {
$ reading = "RAW($sdr->linearization) $reading" ;
}
if ( $ sdr - > sensor_units_1 & 1 ) {
$ per = "% " ;
2008-03-18 16:52:15 +00:00
} else {
$ per = " " ;
}
my $ numformat = ( $ sdr - > sensor_units_1 & 0b11000000 ) >> 6 ;
if ( $ numformat ) {
if ( $ numformat eq 0b11 ) {
#Not sure what to do.. leave it alone for now
} else {
if ( $ reading & 0b10000000 ) {
if ( $ numformat eq 0b01 ) {
$ reading = 0 - ( ( ~ ( $ reading & 0b01111111 ) ) & 0b1111111 ) ;
} elsif ( $ numformat eq 0b10 ) {
$ reading = 0 - ( ( ( ~ ( $ reading & 0b01111111 ) ) & 0b1111111 ) + 1 ) ;
}
}
}
2008-02-12 21:34:57 +00:00
}
if ( $ unitdesc eq "Watts" ) {
my $ f = ( $ reading * 3.413 ) ;
$ unitdesc = "Watts (" . int ( $ f + .5 ) . " BTUs/hr)" ;
#$f = ($reading * 0.00134);
#$unitdesc .= " $f horsepower)";
}
if ( $ unitdesc eq "C" ) {
my $ f = ( $ reading * 9 / 5 ) + 32 ;
$ unitdesc = "C (" . int ( $ f + .5 ) . " F)" ;
}
if ( $ unitdesc eq "F" ) {
my $ c = ( $ reading - 32 ) * 5 / 9 ;
$ unitdesc = "F (" . int ( $ c + .5 ) . " C)" ;
}
2008-03-18 16:52:15 +00:00
return "$reading $unitdesc" ;
2008-02-12 21:34:57 +00:00
}
2007-10-26 22:44:33 +00:00
sub ipmiinit {
my $ ipmimaxp = 80 ;
my $ ipmitimeout = 3 ;
my $ ipmitrys = 3 ;
my $ ipmiuser = 'USERID' ;
my $ ipmipass = 'PASSW0RD' ;
my $ tmp ;
my $ table = xCAT::Table - > new ( 'site' ) ;
if ( $ table ) {
2007-10-31 03:39:56 +00:00
( $ tmp ) = $ table - > getAttribs ( { 'key' = > 'ipmimaxp' } , 'value' ) ;
2007-10-26 22:44:33 +00:00
if ( defined ( $ tmp ) ) { $ ipmimaxp = $ tmp - > { value } ; }
2007-10-31 03:39:56 +00:00
( $ tmp ) = $ table - > getAttribs ( { 'key' = > 'ipmitimeout' } , 'value' ) ;
2007-10-26 22:44:33 +00:00
if ( defined ( $ tmp ) ) { $ ipmitimeout = $ tmp - > { value } ; }
2007-10-31 03:39:56 +00:00
( $ tmp ) = $ table - > getAttribs ( { 'key' = > 'ipmiretries' } , 'value' ) ;
2007-10-26 22:44:33 +00:00
if ( defined ( $ tmp ) ) { $ ipmitrys = $ tmp - > { value } ; }
2007-10-31 03:39:56 +00:00
( $ tmp ) = $ table - > getAttribs ( { 'key' = > 'ipmisdrcache' } , 'value' ) ;
2007-10-26 22:44:33 +00:00
}
$ table = xCAT::Table - > new ( 'passwd' ) ;
if ( $ table ) {
2007-10-31 03:39:56 +00:00
( $ tmp ) = $ table - > getAttribs ( { 'key' = > 'ipmi' } , 'username' , 'password' ) ;
2007-10-26 22:44:33 +00:00
if ( defined ( $ tmp ) ) {
$ ipmiuser = $ tmp - > { username } ;
$ ipmipass = $ tmp - > { password } ;
}
}
return ( $ ipmiuser , $ ipmipass , $ ipmimaxp , $ ipmitimeout , $ ipmitrys ) ;
}
sub ipmicmd {
my $ node = shift ;
$ port = shift ;
$ userid = shift ;
$ passwd = shift ;
$ timeout = shift ;
$ localtrys = shift ;
$ debug = shift ;
$ localdebug = $ debug ;
if ( $ userid eq "(null)" ) {
$ userid = "" ;
}
if ( $ passwd eq "(null)" ) {
$ passwd = "" ;
}
@ user = dopad16 ( $ userid ) ;
@ pass = dopad16 ( $ passwd ) ;
$ seqlun = 0x00 ;
@ session_id = ( 0 , 0 , 0 , 0 ) ;
@ challenge = ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) ;
@ seqnum = ( 0 , 0 , 0 , 0 ) ;
$ authoffset = 0 ;
my $ command = shift ;
2009-03-02 18:33:59 +00:00
@ cmdargv = @ _ ;
2007-10-26 22:44:33 +00:00
my $ subcommand = shift ;
2009-03-02 18:33:59 +00:00
2007-10-26 22:44:33 +00:00
my $ rc = 0 ;
my $ text = "" ;
my $ error = "" ;
my @ output ;
my $ noclose = 0 ;
my $ packed_ip = gethostbyname ( $ node ) ;
if ( ! defined ( $ packed_ip ) ) {
$ text = "failed to get IP for $node" ;
return ( 2 , $ text ) ;
}
2009-03-02 18:33:59 +00:00
$ ipmi_bmcipaddr = inet_ntoa ( $ packed_ip ) ;
2007-10-26 22:44:33 +00:00
$ sock = IO::Socket::INET - > new (
Proto = > 'udp' ,
2009-03-02 18:33:59 +00:00
PeerHost = > $ ipmi_bmcipaddr ,
2007-10-26 22:44:33 +00:00
PeerPort = > $ port ,
) ;
if ( ! defined ( $ sock ) ) {
$ text = "failed to get socket: $@\n" ;
return ( 2 , $ text ) ;
}
$ error = getchanauthcap ( ) ;
if ( $ error ) {
return ( 1 , $ error ) ;
}
if ( $ debug ) {
print "$node: gotchanauthcap\n" ;
}
if ( $ command eq "ping" ) {
return ( 0 , "ping" ) ;
}
$ error = getsessionchallenge ( ) ;
if ( $ error ) {
return ( 1 , $ error ) ;
}
if ( $ debug ) {
print "$node: gotsessionchallenge\n" ;
}
$ error = activatesession ( ) ;
if ( $ error ) {
return ( 1 , $ error ) ;
}
if ( $ debug ) {
print "$node: active session\n" ;
}
$ error = setprivlevel ( ) ;
if ( $ error ) {
return ( 1 , $ error ) ;
}
if ( $ debug ) {
print "$node: priv level set\n" ;
}
if ( $ command eq "rpower" ) {
if ( $ subcommand eq "stat" || $ subcommand eq "state" || $ subcommand eq "status" ) {
( $ rc , $ text ) = power ( "stat" ) ;
}
elsif ( $ subcommand eq "on" ) {
2008-10-03 17:46:31 +00:00
my ( $ oldrc , $ oldtext ) = power ( "stat" ) ;
( $ rc , $ text ) = power ( "on" ) ;
if ( ( $ rc == 0 ) && ( $ text eq "on" ) && ( $ oldtext eq "on" ) ) { $ text . = " $status_noop" ; }
2007-10-26 22:44:33 +00:00
}
elsif ( $ subcommand eq "nmi" ) {
( $ rc , $ text ) = power ( "nmi" ) ;
}
2008-10-13 15:16:41 +00:00
elsif ( $ subcommand eq "off" or $ subcommand eq "softoff" ) {
2008-10-03 17:46:31 +00:00
my ( $ oldrc , $ oldtext ) = power ( "stat" ) ;
2008-10-13 15:16:41 +00:00
( $ rc , $ text ) = power ( $ subcommand ) ;
2008-10-03 17:46:31 +00:00
if ( ( $ rc == 0 ) && ( $ text eq "off" ) && ( $ oldtext eq "off" ) ) { $ text . = " $status_noop" ; }
2007-10-26 22:44:33 +00:00
# if($text0 ne "") {
# $text = $text0 . " " . $text;
# }
}
elsif ( $ subcommand eq "reset" ) {
2008-10-03 17:46:31 +00:00
my ( $ oldrc , $ oldtext ) = power ( "stat" ) ;
2007-10-26 22:44:33 +00:00
( $ rc , $ text ) = power ( "reset" ) ;
2008-06-27 14:11:52 +00:00
$ noclose = 0 ;
2008-10-03 17:46:31 +00:00
if ( ( $ rc == 0 ) && ( $ text eq "off" ) && ( $ oldtext eq "off" ) ) { $ text . = " $status_noop" ; }
2007-10-26 22:44:33 +00:00
}
elsif ( $ subcommand eq "cycle" ) {
my $ text2 ;
( $ rc , $ text ) = power ( "stat" ) ;
if ( $ rc == 0 && $ text eq "on" ) {
( $ rc , $ text ) = power ( "off" ) ;
if ( $ rc == 0 ) {
sleep ( 5 ) ;
}
}
if ( $ rc == 0 && $ text eq "off" ) {
( $ rc , $ text2 ) = power ( "on" ) ;
}
if ( $ rc == 0 ) {
$ text = $ text . " " . $ text2
}
}
elsif ( $ subcommand eq "boot" ) {
my $ text2 ;
( $ rc , $ text ) = power ( "stat" ) ;
if ( $ rc == 0 ) {
if ( $ text eq "on" ) {
( $ rc , $ text2 ) = power ( "reset" ) ;
2008-06-27 14:11:52 +00:00
$ noclose = 0 ;
2007-10-26 22:44:33 +00:00
}
elsif ( $ text eq "off" ) {
( $ rc , $ text2 ) = power ( "on" ) ;
}
else {
$ rc = 1 ;
}
$ text = $ text . " " . $ text2
}
}
else {
$ rc = 1 ;
$ text = "unsupported command $command $subcommand" ;
}
}
elsif ( $ command eq "rbeacon" ) {
( $ rc , $ text ) = beacon ( $ subcommand ) ;
}
2009-03-02 18:33:59 +00:00
elsif ( $ command eq "getrvidparms" ) {
( $ rc , @ output ) = getrvidparms ( $ subcommand ) ;
}
2007-10-26 22:44:33 +00:00
# elsif($command eq "info") {
# if($subcommand eq "sensorname") {
# ($rc,$text) = initsdr();
# if($rc == 0) {
# my $key;
# $text="";
# foreach $key (keys %sdr_hash) {
# my $sdr = $sdr_hash{$key};
# if($sdr->sensor_number == @_) {
# $text = $sdr_hash{$key}->id_string;
# last;
# }
# }
## if(defined $sdr_hash{@_}) {
## $text = $sdr_hash{@_}->id_string;
## }
# }
# }
# }
elsif ( $ command eq "rvitals" ) {
( $ rc , @ output ) = vitals ( $ subcommand ) ;
}
elsif ( $ command eq "rspreset" ) {
( $ rc , @ output ) = resetbmc ( ) ;
$ noclose = 1 ;
}
elsif ( $ command eq "reventlog" ) {
if ( $ subcommand eq "decodealert" ) {
( $ rc , $ text ) = decodealert ( @ _ ) ;
}
else {
( $ rc , @ output ) = eventlog ( $ subcommand ) ;
}
}
elsif ( $ command eq "rinv" ) {
( $ rc , @ output ) = inv ( $ subcommand ) ;
}
elsif ( $ command eq "fru" ) {
( $ rc , @ output ) = fru ( $ subcommand ) ;
}
elsif ( $ command eq "sol.command" ) {
my $ dc = 0 ;
$@ = "" ;
eval {
my $ cc = 0 ;
my $ kid ;
my $ pid = $$ ;
$ SIG { USR1 } = sub { $ cc = 0 ; } ;
$ SIG { USR2 } = sub { $ dc + + ; } ;
$ SIG { CHLD } = sub { while ( waitpid ( - 1 , WNOHANG ) > 0 ) { sleep ( 1 ) ; } } ;
mkfifo ( "/tmp/.sol.$pid" , 0666 ) ;
2008-01-21 19:49:59 +00:00
my $ child = xCAT::Utils - > xfork ( ) ;
2007-10-26 22:44:33 +00:00
if ( ! defined $ child ) {
die ;
}
if ( $ child > 0 ) {
$ cc = 1 ;
}
else {
system ( "$subcommand /tmp/.sol.$pid" ) ;
if ( $? / 256 == 1 ) {
kill ( 12 , $ pid ) ;
}
if ( $? / 256 == 2 ) {
kill ( 12 , $ pid ) ;
sleep ( 1 ) ;
kill ( 12 , $ pid ) ;
}
kill ( 10 , $ pid ) ;
exit ( 0 ) ;
}
open ( FH , "< /tmp/.sol.$pid" ) ;
my $ kpid = <FH> ;
close ( FH ) ;
unlink ( "/tmp/.sol.$pid" ) ;
while ( $ cc == 1 ) {
sleep ( 5 ) ;
( $ rc , $ text ) = power ( "stat" ) ;
$ text = "" ;
if ( $ rc != 0 ) {
kill ( 15 , $ kpid ) ;
$ cc = 0 ;
}
}
do {
$ kid = waitpid ( - 1 , WNOHANG ) ;
sleep ( 1 ) ;
} until ( $ kid == - 1 ) ;
} ;
if ( $@ ) {
@ output = $@ ;
}
$ rc = $ dc ;
if ( $ rc == 1 ) {
$ noclose = 1 ;
}
}
elsif ( $ command eq "rgetnetinfo" ) {
2008-03-27 20:17:49 +00:00
my @ subcommands = ( $ subcommand ) ;
2007-10-26 22:44:33 +00:00
if ( $ subcommand eq "all" ) {
2008-03-27 20:17:49 +00:00
@ subcommands = (
2007-10-26 22:44:33 +00:00
"ip" ,
"netmask" ,
"gateway" ,
"backupgateway" ,
"snmpdest1" ,
"snmpdest2" ,
"snmpdest3" ,
"snmpdest4" ,
"community" ,
) ;
2008-03-27 20:17:49 +00:00
2007-10-26 22:44:33 +00:00
my @ coutput ;
foreach ( @ subcommands ) {
$ subcommand = $ _ ;
( $ rc , @ output ) = getnetinfo ( $ subcommand ) ;
push ( @ coutput , @ output ) ;
}
@ output = @ coutput ;
}
else {
( $ rc , @ output ) = getnetinfo ( $ subcommand ) ;
}
}
2008-03-12 19:27:41 +00:00
elsif ( $ command eq "rspconfig" ) {
2008-03-27 20:17:49 +00:00
foreach ( $ subcommand , @ _ ) {
my @ coutput ;
( $ rc , @ coutput ) = setnetinfo ( $ _ ) ;
if ( $ rc == 0 ) {
( $ rc , @ coutput ) = getnetinfo ( $ _ ) ;
}
push ( @ output , @ coutput ) ;
}
2007-10-26 22:44:33 +00:00
}
elsif ( $ command eq "sete325cli" ) {
( $ rc , @ output ) = sete325cli ( $ subcommand ) ;
}
elsif ( $ command eq "sete326cli" ) {
( $ rc , @ output ) = sete325cli ( $ subcommand ) ;
}
elsif ( $ command eq "generic" ) {
( $ rc , @ output ) = generic ( $ subcommand ) ;
}
2008-09-22 22:57:53 +00:00
elsif ( $ command eq "rfrurewrite" ) {
2007-10-26 22:44:33 +00:00
( $ rc , @ output ) = writefru ( $ subcommand , shift ) ;
}
elsif ( $ command eq "fru" ) {
( $ rc , @ output ) = fru ( $ subcommand ) ;
}
elsif ( $ command eq "rsetboot" ) {
( $ rc , @ output ) = setboot ( $ subcommand ) ;
}
else {
$ rc = 1 ;
$ text = "unsupported command $command $subcommand" ;
}
if ( $ debug ) {
print "$node: command completed\n" ;
}
if ( $ noclose == 0 ) {
$ error = closesession ( ) ;
2009-10-05 15:05:29 +00:00
#In most cases where closesession fails to receive a response,
#the BMC is ignoring us because it managed to get the first one
#and the network dropped it on the way back
#if($error) {
# return(1,"$text, session close: $error");
#}
2007-10-26 22:44:33 +00:00
if ( $ debug ) {
print "$node: session closed.\n" ;
}
}
if ( $ text ) {
push ( @ output , $ text ) ;
}
$ sock - > close ( ) ;
return ( $ rc , @ output ) ;
}
sub resetbmc {
my $ netfun = 0x18 ;
my @ cmd = ( 0x02 ) ;
my @ returnd = ( ) ;
my $ rc = 0 ;
my $ text ;
my $ error ;
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
} else {
if ( 0 == $ returnd [ 36 ] ) {
$ text = "BMC reset" ;
} else {
2008-07-11 15:22:55 +00:00
if ( $ codes { $ returnd [ 36 ] } ) {
$ text = $ codes { $ returnd [ 36 ] } ;
} else {
$ text = sprintf ( "BMC Responded with code %d" , $ returnd [ 36 ] ) ;
}
2007-10-26 22:44:33 +00:00
}
}
return ( $ rc , $ text ) ;
}
sub setnetinfo {
my $ subcommand = shift ;
2008-03-12 19:27:41 +00:00
my $ argument ;
( $ subcommand , $ argument ) = split ( /=/ , $ subcommand ) ;
2008-03-12 02:57:01 +00:00
my @ input = @ _ ;
2007-10-26 22:44:33 +00:00
my $ netfun = 0x30 ;
my @ cmd ;
my @ returnd = ( ) ;
my $ error ;
my $ rc = 0 ;
my $ text ;
my $ code ;
my $ match ;
if ( $ subcommand eq "snmpdest" ) {
$ subcommand = "snmpdest1" ;
}
2008-06-10 15:32:14 +00:00
2007-10-26 22:44:33 +00:00
2008-03-12 19:27:41 +00:00
unless ( defined ( $ argument ) ) {
return 0 ;
}
2008-06-10 15:32:14 +00:00
if ( $ subcommand eq "thermprofile" ) {
return idpxthermprofile ( $ argument ) ;
}
2008-03-28 18:23:19 +00:00
if ( $ subcommand eq "alert" and $ argument eq "on" or $ argument =~ /^en/ or $ argument =~ /^enable/ ) {
2008-03-12 19:27:41 +00:00
$ netfun = 0x10 ;
@ cmd = ( 0x12 , 0x9 , 0x1 , 0x18 , 0x11 , 0x00 ) ;
2008-03-28 18:23:19 +00:00
} elsif ( $ subcommand eq "alert" and $ argument eq "off" or $ argument =~ /^dis/ or $ argument =~ /^disable/ ) {
2008-03-12 19:27:41 +00:00
$ netfun = 0x10 ;
@ cmd = ( 0x12 , 0x9 , 0x1 , 0x10 , 0x11 , 0x00 ) ;
}
elsif ( $ subcommand eq "garp" ) {
my $ halfsec = $ argument * 2 ; #pop(@input) * 2;
2007-10-26 22:44:33 +00:00
if ( $ halfsec > 255 ) {
$ halfsec = 255 ;
}
if ( $ halfsec < 4 ) {
$ halfsec = 4 ;
}
@ cmd = ( 0x01 , $ channel_number , 0x0b , $ halfsec ) ;
}
2008-03-12 20:46:17 +00:00
elsif ( $ subcommand =~ m/community/ ) {
my $ cindex = 0 ;
my @ clist ;
foreach ( 0 .. 17 ) {
push @ clist , 0 ;
}
foreach ( split // , $ argument ) {
$ clist [ $ cindex + + ] = ord ( $ _ ) ;
}
@ cmd = ( 1 , $ channel_number , 0x10 , @ clist ) ;
}
2007-10-26 22:44:33 +00:00
elsif ( $ subcommand =~ m/snmpdest(\d+)/ ) {
2008-03-12 19:27:41 +00:00
my $ dstip = $ argument ; #pop(@input);
2007-10-26 22:44:33 +00:00
my @ dip = split /\./ , $ dstip ;
@ cmd = ( 0x01 , $ channel_number , 0x13 , $ 1 , 0x00 , 0x00 , $ dip [ 0 ] , $ dip [ 1 ] , $ dip [ 2 ] , $ dip [ 3 ] , 0 , 0 , 0 , 0 , 0 , 0 ) ;
}
2008-03-12 02:57:01 +00:00
#elsif($subcommand eq "alert" ) {
# my $action=pop(@input);
#print "action=$action\n";
# $netfun=0x28; #TODO: not right
# mapping alert action to number
# my $act_number=8;
# if ($action eq "on") {$act_number=8;}
# elsif ($action eq "off") { $act_number=0;}
# else { return(1,"unsupported alert action $action");}
# @cmd = (0x12, $channel_number,0x09, 0x01, $act_number+16, 0x11,0x00);
#}
2007-10-26 22:44:33 +00:00
else {
2008-03-12 19:27:41 +00:00
return ( 1 , "configuration of $subcommand is not implemented currently" ) ;
2007-10-26 22:44:33 +00:00
}
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
}
else {
2008-03-12 20:46:17 +00:00
if ( $ subcommand eq "garp" or $ subcommand =~ m/snmpdest\d+/ or $ subcommand eq "alert" or $ subcommand =~ /community/ ) {
2007-10-26 22:44:33 +00:00
$ code = $ returnd [ 36 ] ;
if ( $ code == 0x00 ) {
$ text = "ok" ;
}
2008-03-12 19:27:41 +00:00
}
2007-10-26 22:44:33 +00:00
if ( ! $ text ) {
$ rc = 1 ;
$ text = sprintf ( "unknown response %02x" , $ code ) ;
}
}
return ( $ rc , $ text ) ;
}
sub getnetinfo {
my $ subcommand = shift ;
2008-03-12 19:27:41 +00:00
$ subcommand =~ s/=.*// ;
2008-06-10 15:32:14 +00:00
if ( $ subcommand eq "thermprofile" ) {
my $ code ;
my @ returnd ;
my $ thermdata ;
2008-11-20 16:58:36 +00:00
my $ netfun = 0x2e << 2 ; #currently combined netfun & lun, to be simplified later
my @ cmd = ( 0x41 , 0x4d , 0x4f , 0x00 , 0x6f , 0xff , 0x61 , 0x00 ) ;
my @ bytes ;
my $ error = docmd ( $ netfun , \ @ cmd , \ @ bytes ) ;
@ bytes = splice @ bytes , 36 - $ authoffset ;
@ bytes = splice @ bytes , 16 ;
2008-06-10 15:32:14 +00:00
my $ validprofiles = "" ;
2008-11-20 16:58:36 +00:00
foreach ( keys % idpxthermprofiles ) {
if ( sprintf ( "%02x %02x %02x %02x %02x %02x %02x" , @ bytes ) eq sprintf ( "%02x %02x %02x %02x %02x %02x %02x" , @ { $ idpxthermprofiles { $ _ } } ) ) {
2008-06-10 15:32:14 +00:00
$ validprofiles . = "$_," ;
}
}
if ( $ validprofiles ) {
chop ( $ validprofiles ) ;
return ( 0 , "The following thermal profiles are in effect: " . $ validprofiles ) ;
}
2008-11-20 16:58:36 +00:00
return ( 1 , sprintf ( "Unable to identify current thermal profile: \"%02x %02x %02x %02x %02x %02x %02x\"" , @ bytes ) ) ;
2008-06-10 15:32:14 +00:00
}
2007-10-26 22:44:33 +00:00
my $ netfun = 0x30 ;
my @ cmd ;
my @ returnd = ( ) ;
my $ error ;
my $ rc = 0 ;
my $ text ;
my $ code ;
my $ format = "%-25s" ;
if ( $ subcommand eq "snmpdest" ) {
$ subcommand = "snmpdest1" ;
}
2008-03-12 19:27:41 +00:00
if ( $ subcommand eq "alert" ) {
$ netfun = 0x10 ;
@ cmd = ( 0x13 , 9 , 1 , 0 ) ;
}
elsif ( $ subcommand eq "garp" ) {
2007-10-26 22:44:33 +00:00
@ cmd = ( 0x02 , $ channel_number , 0x0b , 0x00 , 0x00 ) ;
}
elsif ( $ subcommand =~ m/^snmpdest(\d+)/ ) {
@ cmd = ( 0x02 , $ channel_number , 0x13 , $ 1 , 0x00 ) ;
}
elsif ( $ subcommand eq "ip" ) {
@ cmd = ( 0x02 , $ channel_number , 0x03 , 0x00 , 0x00 ) ;
}
elsif ( $ subcommand eq "netmask" ) {
@ cmd = ( 0x02 , $ channel_number , 0x06 , 0x00 , 0x00 ) ;
}
elsif ( $ subcommand eq "gateway" ) {
@ cmd = ( 0x02 , $ channel_number , 0x0C , 0x00 , 0x00 ) ;
}
elsif ( $ subcommand eq "backupgateway" ) {
@ cmd = ( 0x02 , $ channel_number , 0x0E , 0x00 , 0x00 ) ;
}
elsif ( $ subcommand eq "community" ) {
@ cmd = ( 0x02 , $ channel_number , 0x10 , 0x00 , 0x00 ) ;
}
else {
return ( 1 , "unsupported command getnetinfo $subcommand" ) ;
}
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
2008-04-08 02:08:01 +00:00
2007-10-26 22:44:33 +00:00
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
}
else {
2008-04-08 02:08:01 +00:00
# response format:
# 4 bytes (RMCP header)
# 1 byte (auth type)
# 4 bytes (session sequence)
# 4 bytes (session id)
# 16 bytes (message auth code, not present if auth type is 0, $authoffset=16)
# 1 byte (ipmi message length)
# 1 byte (requester's address
# 1 byte (netfun, req lun)
# 1 byte (checksum)
# 1 byte (Responder's slave address)
# 1 byte (Sequence number, generated by the requester)
# 1 byte (command)
# 1 byte (return code)
# 1 byte (param revision)
# N bytes (data)
# 1 byte (checksum)
2007-10-26 22:44:33 +00:00
if ( $ subcommand eq "garp" ) {
2008-04-08 02:08:01 +00:00
$ code = $ returnd [ 36 - $ authoffset ] ;
2007-10-26 22:44:33 +00:00
if ( $ code == 0x00 ) {
2008-04-08 02:08:01 +00:00
$ code = $ returnd [ 38 - $ authoffset ] / 2 ;
2007-10-26 22:44:33 +00:00
$ text = sprintf ( "$format %d" , "Gratuitous ARP seconds:" , $ code ) ;
}
else {
$ rc = 1 ;
$ text = $ codes { $ code } ;
}
}
2008-03-12 19:27:41 +00:00
elsif ( $ subcommand eq "alert" ) {
2008-04-08 02:08:01 +00:00
if ( $ returnd [ 39 - $ authoffset ] & 0x8 ) {
2008-03-27 20:17:49 +00:00
$ text = "SP Alerting: enabled" ;
2008-03-12 19:27:41 +00:00
} else {
2008-03-27 20:17:49 +00:00
$ text = "SP Alerting: disabled" ;
2008-03-12 19:27:41 +00:00
}
}
2007-10-26 22:44:33 +00:00
elsif ( $ subcommand =~ m/^snmpdest(\d+)/ ) {
$ text = sprintf ( "$format %d.%d.%d.%d" ,
2008-03-27 20:17:49 +00:00
"SP SNMP Destination $1:" ,
2008-04-08 02:08:01 +00:00
$ returnd [ 41 - $ authoffset ] ,
$ returnd [ 42 - $ authoffset ] ,
$ returnd [ 43 - $ authoffset ] ,
$ returnd [ 44 - $ authoffset ] ) ;
2007-10-26 22:44:33 +00:00
}
elsif ( $ subcommand eq "ip" ) {
$ text = sprintf ( "$format %d.%d.%d.%d" ,
"BMC IP:" ,
2008-04-08 02:08:01 +00:00
$ returnd [ 38 - $ authoffset ] ,
$ returnd [ 39 - $ authoffset ] ,
$ returnd [ 40 - $ authoffset ] ,
$ returnd [ 41 - $ authoffset ] ) ;
2007-10-26 22:44:33 +00:00
}
elsif ( $ subcommand eq "netmask" ) {
$ text = sprintf ( "$format %d.%d.%d.%d" ,
"BMC Netmask:" ,
2008-04-08 02:08:01 +00:00
$ returnd [ 38 - $ authoffset ] ,
$ returnd [ 39 - $ authoffset ] ,
$ returnd [ 40 - $ authoffset ] ,
$ returnd [ 41 - $ authoffset ] ) ;
2007-10-26 22:44:33 +00:00
}
elsif ( $ subcommand eq "gateway" ) {
$ text = sprintf ( "$format %d.%d.%d.%d" ,
"BMC Gateway:" ,
2008-04-08 02:08:01 +00:00
$ returnd [ 38 - $ authoffset ] ,
$ returnd [ 39 - $ authoffset ] ,
$ returnd [ 40 - $ authoffset ] ,
$ returnd [ 41 - $ authoffset ] ) ;
2007-10-26 22:44:33 +00:00
}
elsif ( $ subcommand eq "backupgateway" ) {
$ text = sprintf ( "$format %d.%d.%d.%d" ,
"BMC Backup Gateway:" ,
2008-04-08 02:08:01 +00:00
$ returnd [ 38 - $ authoffset ] ,
$ returnd [ 39 - $ authoffset ] ,
$ returnd [ 40 - $ authoffset ] ,
$ returnd [ 41 - $ authoffset ] ) ;
2007-10-26 22:44:33 +00:00
}
elsif ( $ subcommand eq "community" ) {
2008-03-27 20:17:49 +00:00
$ text = sprintf ( "$format " , "SP SNMP Community:" ) ;
2008-04-08 02:08:01 +00:00
my $ l = 38 - $ authoffset ;
2007-10-26 22:44:33 +00:00
while ( $ returnd [ $ l ] ne 0 ) {
$ l = $ l + 1 ;
}
2008-04-08 02:08:01 +00:00
my $ i = 38 - $ authoffset ;
2007-10-26 22:44:33 +00:00
while ( $ i < $ l ) {
$ text = $ text . sprintf ( "%c" , $ returnd [ $ i ] ) ;
$ i = $ i + 1 ;
}
}
if ( ! $ text ) {
$ rc = 1 ;
$ text = sprintf ( "unknown response %02x" , $ code ) ;
}
}
return ( $ rc , $ text ) ;
}
sub sete325cli {
my $ subcommand = shift ;
my $ netfun = 0xc8 ;
my @ cmd ;
my @ returnd = ( ) ;
my $ error ;
my $ rc = 0 ;
my $ text ;
my $ code ;
if ( $ subcommand eq "disable" ) {
@ cmd = ( 0x00 ) ;
}
elsif ( $ subcommand eq "cli" ) {
@ cmd = ( 0x02 ) ;
}
else {
return ( 1 , "unsupported command sete325cli $subcommand" ) ;
}
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
}
else {
if ( $ code == 0x00 ) {
$ rc = 0 ;
$ text = "$subcommand" ;
}
else {
$ rc = 1 ;
$ text = $ codes { $ code } ;
}
if ( ! $ text ) {
$ rc = 1 ;
$ text = sprintf ( "unknown response %02x" , $ code ) ;
}
}
return ( $ rc , $ text ) ;
}
sub setboot {
my $ subcommand = shift ;
my $ netfun = 0x00 ;
my @ cmd = ( 0x08 , 0x3 , 0x8 ) ;
my @ returnd = ( ) ;
my $ error ;
my $ rc = 0 ;
my $ text = "" ;
my $ code ;
my $ skipset = 0 ;
my % bootchoices = (
0 = > 'BIOS default' ,
1 = > 'Network' ,
2 = > 'Hard Drive' ,
5 = > 'CD/DVD' ,
6 = > 'BIOS Setup' ,
2008-07-14 15:33:06 +00:00
15 = > 'Floppy'
2007-10-26 22:44:33 +00:00
) ;
#This disables the 60 second timer
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ subcommand eq "net" ) {
@ cmd = ( 0x08 , 0x5 , 0x80 , 0x4 , 0x0 , 0x0 , 0x0 ) ;
}
elsif ( $ subcommand eq "hd" ) {
@ cmd = ( 0x08 , 0x5 , 0x80 , 0x8 , 0x0 , 0x0 , 0x0 ) ;
}
elsif ( $ subcommand eq "cd" ) {
@ cmd = ( 0x08 , 0x5 , 0x80 , 0x14 , 0x0 , 0x0 , 0x0 ) ;
}
2008-07-14 15:33:06 +00:00
elsif ( $ subcommand eq "floppy" ) {
@ cmd = ( 0x08 , 0x5 , 0x80 , 0x3c , 0x0 , 0x0 , 0x0 ) ;
}
2007-10-26 22:44:33 +00:00
elsif ( $ subcommand =~ m/^def/ ) {
@ cmd = ( 0x08 , 0x5 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 ) ;
}
elsif ( $ subcommand eq "setup" ) { #Not supported by BMCs I've checked so far..
@ cmd = ( 0x08 , 0x5 , 0x18 , 0x0 , 0x0 , 0x0 , 0x0 ) ;
}
elsif ( $ subcommand =~ m/^stat/ ) {
$ skipset = 1 ;
}
else {
return ( 1 , "unsupported command setboot $subcommand" ) ;
}
unless ( $ skipset ) {
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
return ( 1 , $ error ) ;
}
$ code = $ returnd [ 36 - $ authoffset ] ;
unless ( $ code == 0x00 ) {
return ( 1 , $ codes { $ code } ) ;
}
}
@ cmd = ( 0x09 , 0x5 , 0x0 , 0x0 ) ;
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
return ( 1 , $ error ) ;
}
$ code = $ returnd [ 36 - $ authoffset ] ;
unless ( $ code == 0x00 ) {
return ( 1 , $ codes { $ code } ) ;
}
unless ( $ returnd [ 39 - $ authoffset ] & 0x80 ) {
$ text = "boot override inactive" ;
return ( $ rc , $ text ) ;
}
my $ boot = ( $ returnd [ 40 - $ authoffset ] & 0x3C ) >> 2 ;
$ text = $ bootchoices { $ boot } ;
return ( $ rc , $ text ) ;
}
2008-06-10 15:32:14 +00:00
sub idpxthermprofile {
#iDataplex thermal profiles as of 6/10/2008
my $ subcommand = lc ( shift ) ;
my @ returnd ;
my $ netfun = 0xb8 ;
2008-11-20 16:58:36 +00:00
my @ cmd = ( 0x41 , 0x4d , 0x4f , 0x00 , 0x6f , 0xfe , 0x60 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xff ) ;
if ( $ idpxthermprofiles { $ subcommand } ) {
push @ cmd , @ { $ idpxthermprofiles { $ subcommand } } ;
2008-06-10 15:32:14 +00:00
} else {
return ( 1 , "Not an understood thermal profile, expected a 2 hex digit value corresponding to chassis label on iDataplex server" ) ;
}
docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
return ( 0 , "OK" ) ;
}
2009-03-02 18:33:59 +00:00
sub getrvidparms {
my $ netfun = 0x3a ;
my @ mcinfo = getdevid ( ) ;
unless ( $ mcinfo [ 2 ] == 2 ) { #Only implemented for IBM servers
return ( 1 , "Remote video is not supported on this system" ) ;
}
#TODO: use get bmc capabilities to see if rvid is actually supported before bothering the client java app
my @ build_id ;
my $ localerror = docmd (
0xe8 ,
[ 0x50 ] ,
\ @ build_id
) ;
if ( $ localerror ) {
return ( 1 , $ localerror ) ;
}
@ build_id = splice @ build_id , 36 - $ authoffset ;
unless ( $ build_id [ 1 ] == 0x59 and $ build_id [ 2 ] == 0x55 and $ build_id [ 3 ] == 0x4f and $ build_id [ 4 ] == 0x4f ) { #Only know how to cope with yuoo builds
return ( 1 , "Remote video is not supported on this system" ) ;
}
#wvid should be a possiblity, time to do the http...
my $ browser = LWP::UserAgent - > new ( ) ;
my $ message = "$userid,$passwd" ;
$ browser - > cookie_jar ( { } ) ;
my $ baseurl = "http://" . $ ipmi_bmcipaddr . "/" ;
my $ response = $ browser - > request ( POST $ baseurl . "/session/create" , 'Content-Type' = > "text/xml" , Content = > $ message ) ;
unless ( $ response - > content eq "ok" ) {
return ( 1 , "Server returned unexpected data" ) ;
}
$ response = $ browser - > request ( GET $ baseurl . "/kvm/kvm/jnlp" ) ;
my $ jnlp = $ response - > content ;
if ( $ jnlp =~ /This advanced option requires the purchase and installation/ ) {
return ( 1 , "Node does not have feature key for remote video" ) ;
}
2009-03-16 17:31:15 +00:00
$ jnlp =~ s!argument>title=.*Video Viewer</argument>!argument>title=$currnode wvid</argument>! ;
2009-03-02 18:33:59 +00:00
my @ return = ( "method:imm" , "jnlp:$jnlp" ) ;
if ( grep /-m/ , @ cmdargv ) {
$ response = $ browser - > request ( GET $ baseurl . "/kvm/vm/jnlp" ) ;
push @ return , "mediajnlp:" . $ response - > content ;
}
return ( 0 , @ return ) ;
}
2007-10-26 22:44:33 +00:00
sub power {
my $ subcommand = shift ;
my $ netfun = 0x00 ;
my @ cmd ;
my @ returnd = ( ) ;
my $ error ;
my $ rc = 0 ;
my $ text ;
my $ code ;
if ( $ subcommand eq "stat" ) {
@ cmd = ( 0x01 ) ;
}
elsif ( $ subcommand eq "on" ) {
@ cmd = ( 0x02 , 0x01 ) ;
}
2008-10-13 15:16:41 +00:00
elsif ( $ subcommand eq "softoff" ) {
@ cmd = ( 0x02 , 0x05 ) ;
}
2007-10-26 22:44:33 +00:00
elsif ( $ subcommand eq "off" ) {
@ cmd = ( 0x02 , 0x00 ) ;
}
elsif ( $ subcommand eq "reset" ) {
@ cmd = ( 0x02 , 0x03 ) ;
}
elsif ( $ subcommand eq "nmi" ) {
@ cmd = ( 0x02 , 0x04 ) ;
}
else {
return ( 1 , "unsupported command power $subcommand" ) ;
}
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
}
else {
if ( $ subcommand eq "stat" ) {
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code == 0x00 ) {
$ code = $ returnd [ 37 - $ authoffset ] ;
if ( $ code & 0b00000001 ) {
$ text = "on" ;
}
else {
$ text = "off" ;
}
}
else {
$ rc = 1 ;
$ text = $ codes { $ code } ;
}
}
if ( $ subcommand eq "nmi" ) {
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code == 0x00 ) {
$ text = "nmi" ;
}
else {
$ rc = 1 ;
$ text = $ codes { $ code } ;
}
}
if ( $ subcommand eq "on" ) {
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code == 0x00 ) {
$ text = "on" ;
}
else {
$ rc = 1 ;
$ text = $ codes { $ code } ;
}
}
2008-10-13 15:16:41 +00:00
if ( $ subcommand eq "softoff" ) {
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code == 0x00 ) {
$ text = "softoff" ;
}
else {
$ rc = 1 ;
$ text = $ codes { $ code } ;
}
}
2007-10-26 22:44:33 +00:00
if ( $ subcommand eq "off" ) {
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code == 0x00 ) {
$ text = "off" ;
}
elsif ( $ code == 0xd5 ) {
$ text = "off" ;
}
else {
$ rc = 1 ;
$ text = $ codes { $ code } ;
}
}
if ( $ subcommand eq "reset" ) {
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code == 0x00 ) {
$ text = "reset" ;
}
elsif ( $ code == 0xd5 ) {
$ text = "off" ;
}
else {
$ rc = 1 ;
$ text = $ codes { $ code } ;
}
}
if ( ! $ text ) {
$ rc = 1 ;
$ text = sprintf ( "unknown response %02x" , $ code ) ;
}
}
return ( $ rc , $ text ) ;
}
sub generic {
my $ subcommand = shift ;
my $ netfun ;
my @ args ;
my @ cmd ;
my @ returnd = ( ) ;
my $ error ;
my $ rc = 0 ;
my $ text ;
my $ code ;
( $ netfun , @ args ) = split ( /-/ , $ subcommand ) ;
$ netfun = oct ( $ netfun ) ;
printf ( "netfun: 0x%02x\n" , $ netfun ) ;
print "command: " ;
foreach ( @ args ) {
push ( @ cmd , oct ( $ _ ) ) ;
printf ( "0x%02x " , oct ( $ _ ) ) ;
}
print "\n\n" ;
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
}
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code == 0x00 ) {
}
else {
$ rc = 1 ;
$ text = $ codes { $ code } ;
}
printf ( "return code: 0x%02x\n\n" , $ code ) ;
print "return data:\n" ;
my @ rdata = @ returnd [ 37 - $ authoffset .. @ returnd - 2 ] ;
hexadump ( \ @ rdata ) ;
print "\n" ;
print "full output:\n" ;
hexadump ( \ @ returnd ) ;
print "\n" ;
# if(!$text) {
# $rc = 1;
# $text = sprintf("unknown response %02x",$code);
# }
return ( $ rc , $ text ) ;
}
sub beacon {
my $ subcommand = shift ;
my $ netfun = 0x00 ;
my @ cmd ;
my @ returnd = ( ) ;
my $ error ;
my $ rc = 0 ;
my $ text ;
my $ code ;
2009-06-24 23:31:03 +00:00
if ( $ subcommand eq "" ) {
return ( 1 , "please specify on or off for ipmi nodes" ) ;
}
2007-10-26 22:44:33 +00:00
if ( $ subcommand eq "on" ) {
2007-10-30 15:24:43 +00:00
if ( $ ipmiv2 ) {
@ cmd = ( 0x04 , 0x0 , 0x01 ) ;
} else {
@ cmd = ( 0x04 , 0xFF ) ;
}
2007-10-26 22:44:33 +00:00
}
elsif ( $ subcommand eq "off" ) {
2007-10-30 15:24:43 +00:00
if ( $ ipmiv2 ) {
@ cmd = ( 0x04 , 0x0 , 0x00 ) ;
} else {
@ cmd = ( 0x04 , 0x00 ) ;
}
2007-10-26 22:44:33 +00:00
}
else {
return ( 1 , "unsupported command beacon $subcommand" ) ;
}
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
}
else {
if ( $ subcommand eq "on" ) {
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code == 0x00 ) {
$ text = "on" ;
}
else {
$ rc = 1 ;
$ text = $ codes { $ code } ;
}
}
if ( $ subcommand eq "off" ) {
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code == 0x00 ) {
$ text = "off" ;
}
else {
$ rc = 1 ;
$ text = $ codes { $ code } ;
}
}
if ( ! $ text ) {
$ rc = 1 ;
$ text = sprintf ( "unknown response %02x" , $ code ) ;
}
}
return ( $ rc , $ text ) ;
}
sub inv {
my $ subcommand = shift ;
my $ rc = 0 ;
my $ text ;
my @ output ;
my @ types ;
my $ format = "%-20s %s" ;
2009-03-07 02:04:21 +00:00
( $ rc , $ text ) = initsdr ( ) ; #Look for those precious locator reconds
if ( $ rc != 0 ) {
return ( $ rc , $ text ) ;
}
2007-10-26 22:44:33 +00:00
( $ rc , $ text ) = initfru ( ) ;
if ( $ rc != 0 ) {
return ( $ rc , $ text ) ;
}
2008-05-15 15:06:00 +00:00
unless ( $ subcommand ) {
$ subcommand = "all" ;
}
2007-10-26 22:44:33 +00:00
if ( $ subcommand eq "all" ) {
2009-03-07 18:04:32 +00:00
@ types = qw( model serial deviceid mprom guid misc hw asset ) ;
2008-09-19 00:38:58 +00:00
}
elsif ( $ subcommand eq "asset" ) {
@ types = qw( asset ) ;
2007-10-26 22:44:33 +00:00
}
elsif ( $ subcommand eq "model" ) {
@ types = qw( model ) ;
}
elsif ( $ subcommand eq "serial" ) {
@ types = qw( serial ) ;
}
elsif ( $ subcommand eq "vpd" ) {
@ types = qw( model serial deviceid mprom ) ;
}
elsif ( $ subcommand eq "mprom" ) {
@ types = qw( mprom ) ;
}
2008-09-19 00:38:58 +00:00
elsif ( $ subcommand eq "misc" ) {
@ types = qw( misc ) ;
}
2007-10-26 22:44:33 +00:00
elsif ( $ subcommand eq "deviceid" ) {
@ types = qw( deviceid ) ;
}
elsif ( $ subcommand eq "guid" ) {
@ types = qw( guid ) ;
}
elsif ( $ subcommand eq "uuid" ) {
@ types = qw( guid ) ;
}
else {
2009-03-07 18:04:32 +00:00
@ types = ( $ subcommand ) ;
#return(1,"unsupported BMC inv argument $subcommand");
2007-10-26 22:44:33 +00:00
}
2008-09-19 00:38:58 +00:00
my $ otext ;
my $ key ;
2007-10-26 22:44:33 +00:00
2008-09-19 00:38:58 +00:00
foreach $ key ( sort keys % fru_hash ) {
my $ fru = $ fru_hash { $ key } ;
2009-03-07 18:04:32 +00:00
my $ type ;
foreach $ type ( split /,/ , $ fru - > rec_type ) {
if ( grep { $ _ eq $ type } @ types ) {
$ otext = sprintf ( $ format , $ fru_hash { $ key } - > desc . ":" , $ fru_hash { $ key } - > value ) ;
#print $otext;
push ( @ output , $ otext ) ;
last ;
}
}
2007-10-26 22:44:33 +00:00
}
return ( $ rc , @ output ) ;
}
sub initoemfru {
my $ mfg_id = shift ;
my $ prod_id = shift ;
my $ device_id = shift ;
my $ netfun ;
my @ cmd ;
my @ returnd = ( ) ;
my $ error ;
my $ rc = 0 ;
my $ text ;
my @ output ;
my $ code ;
if ( $ mfg_id == 2 && ( $ prod_id == 34869 or $ prod_id == 31081 or $ prod_id == 34888 ) ) {
$ netfun = 0xc8 ;
@ cmd = ( 0x05 ) ;
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
return ( $ rc , $ text ) ;
}
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code == 0x00 ) {
}
else {
$ rc = 1 ;
$ text = $ codes { $ code } ;
}
if ( $ rc != 0 ) {
if ( ! $ text ) {
$ text = sprintf ( "unknown response %02x" , $ code ) ;
}
return ( $ rc , $ text ) ;
}
my @ oem_fru_data = @ returnd [ 37 - $ authoffset .. @ returnd - 2 ] ;
my $ model_type = getascii ( @ oem_fru_data [ 0 .. 3 ] ) ;
my $ model_number = getascii ( @ oem_fru_data [ 4 .. 6 ] ) ;
my $ serial = getascii ( @ oem_fru_data [ 7 .. 13 ] ) ;
my $ model = "$model_type-$model_number" ;
my $ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "serial" ) ;
$ fru - > desc ( "Serial Number" ) ;
$ fru - > value ( $ serial ) ;
$ fru_hash { 1 } = $ fru ;
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "model" ) ;
$ fru - > desc ( "Model Number" ) ;
$ fru - > value ( $ model ) ;
$ fru_hash { 2 } = $ fru ;
return ( 2 , "" ) ;
}
if ( $ mfg_id == 2 && $ prod_id == 4 && 0 ) {
$ netfun = 0x3a ;
@ cmd = ( 0x0b , 0x0 , 0x0 , 0x0 , 0x1 , 0x8 ) ;
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
return ( $ rc , $ text ) ;
}
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code == 0x00 ) {
}
else {
$ rc = 1 ;
$ text = $ codes { $ code } ;
}
if ( $ rc != 0 ) {
if ( ! $ text ) {
$ text = sprintf ( "unknown response %02x" , $ code ) ;
}
return ( $ rc , $ text ) ;
}
hexadump ( \ @ returnd ) ;
return ( 2 , "" ) ;
my @ oem_fru_data = @ returnd [ 37 - $ authoffset .. @ returnd - 2 ] ;
my $ model_type = getascii ( @ oem_fru_data [ 0 .. 3 ] ) ;
my $ model_number = getascii ( @ oem_fru_data [ 4 .. 6 ] ) ;
my $ serial = getascii ( @ oem_fru_data [ 7 .. 13 ] ) ;
my $ model = "$model_type-$model_number" ;
my $ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "serial" ) ;
$ fru - > desc ( "Serial Number" ) ;
$ fru - > value ( $ serial ) ;
$ fru_hash { 1 } = $ fru ;
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "model" ) ;
$ fru - > desc ( "Model Number" ) ;
$ fru - > value ( $ model ) ;
$ fru_hash { 2 } = $ fru ;
return ( 2 , "" ) ;
}
if ( $ mfg_id == 2 && $ prod_id == 20 ) {
my $ serial = "unknown" ;
my $ model = "x3655" ;
my $ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "serial" ) ;
$ fru - > desc ( "Serial Number" ) ;
$ fru - > value ( $ serial ) ;
$ fru_hash { 1 } = $ fru ;
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "model" ) ;
$ fru - > desc ( "Model Number" ) ;
$ fru - > value ( $ model ) ;
$ fru_hash { 2 } = $ fru ;
return ( 2 , "" ) ;
}
if ( $ mfg_id == 2 && $ prod_id == 3 ) {
my $ serial = "unknown" ;
my $ model = "x346" ;
my $ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "serial" ) ;
$ fru - > desc ( "Serial Number" ) ;
$ fru - > value ( $ serial ) ;
$ fru_hash { 1 } = $ fru ;
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "model" ) ;
$ fru - > desc ( "Model Number" ) ;
$ fru - > value ( $ model ) ;
$ fru_hash { 2 } = $ fru ;
return ( 2 , "" ) ;
}
if ( $ mfg_id == 2 && $ prod_id == 4 ) {
my $ serial = "unknown" ;
my $ model = "x336" ;
my $ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "serial" ) ;
$ fru - > desc ( "Serial Number" ) ;
$ fru - > value ( $ serial ) ;
$ fru_hash { 1 } = $ fru ;
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "model" ) ;
$ fru - > desc ( "Model Number" ) ;
$ fru - > value ( $ model ) ;
$ fru_hash { 2 } = $ fru ;
return ( 2 , "" ) ;
}
2008-03-07 21:43:45 +00:00
my $ serial = "unkown" ;
my $ model = "unkown" ;
my $ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "serial" ) ;
$ fru - > desc ( "Serial Number" ) ;
$ fru - > value ( $ serial ) ;
$ fru_hash { 1 } = $ fru ;
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "model" ) ;
$ fru - > desc ( "Model Number" ) ;
$ fru - > value ( $ model ) ;
$ fru_hash { 2 } = $ fru ;
return ( 2 , "" ) ;
2007-10-26 22:44:33 +00:00
return ( 1 , "No OEM FRU Support" ) ;
}
2009-03-07 18:04:32 +00:00
sub add_textual_fru {
my $ parsedfru = shift ;
my $ description = shift ;
my $ category = shift ;
my $ subcategory = shift ;
my $ types = shift ;
if ( $ parsedfru - > { $ category } and $ parsedfru - > { $ category } - > { $ subcategory } ) {
my $ fru ;
my @ subfrus ;
if ( ref $ parsedfru - > { $ category } - > { $ subcategory } eq 'ARRAY' ) {
@ subfrus = @ { $ parsedfru - > { $ category } - > { $ subcategory } } ;
} else {
@ subfrus = ( $ parsedfru - > { $ category } - > { $ subcategory } )
}
foreach ( @ subfrus ) {
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( $ types ) ;
$ fru - > desc ( $ description ) ;
2009-03-08 03:30:24 +00:00
if ( not ref $ _ ) {
2009-03-07 18:04:32 +00:00
$ fru - > value ( $ _ ) ;
} else {
if ( $ _ - > { encoding } == 3 ) {
$ fru - > value ( $ _ - > { value } ) ;
} else {
$ fru - > value ( phex ( $ _ - > { value } ) ) ;
}
}
$ fru_hash { $ frudex + + } = $ fru ;
}
}
}
sub add_textual_frus {
my $ parsedfru = shift ;
my $ desc = shift ;
my $ categorydesc = shift ;
my $ category = shift ;
2009-03-08 16:30:56 +00:00
my $ type = shift ;
unless ( $ type ) { $ type = 'hw' ; }
2009-03-07 18:04:32 +00:00
add_textual_fru ( $ parsedfru , $ desc . " " . $ categorydesc . "Part Number" , $ category , "partnumber" , "hw" ) ;
add_textual_fru ( $ parsedfru , $ desc . " " . $ categorydesc . "Manufacturer" , $ category , "manufacturer" , "hw" ) ;
add_textual_fru ( $ parsedfru , $ desc . " " . $ categorydesc . "Serial Number" , $ category , "serialnumber" , "hw" ) ;
2009-03-08 03:30:24 +00:00
add_textual_fru ( $ parsedfru , $ desc . " " . $ categorydesc . "" , $ category , "name" , "hw" ) ;
if ( $ parsedfru - > { $ category } - > { builddate } ) {
2009-03-07 18:04:32 +00:00
add_textual_fru ( $ parsedfru , $ desc . " " . $ categorydesc . "Manufacture Date" , $ category , "builddate" , "hw" ) ;
}
2009-03-08 03:30:24 +00:00
if ( $ parsedfru - > { $ category } - > { buildlocation } ) {
add_textual_fru ( $ parsedfru , $ desc . " " . $ categorydesc . "Manufacture Location" , $ category , "buildlocation" , "hw" ) ;
}
if ( $ parsedfru - > { $ category } - > { model } ) {
add_textual_fru ( $ parsedfru , $ desc . " " . $ categorydesc . "Model" , $ category , "model" , "hw" ) ;
}
2009-03-07 18:04:32 +00:00
add_textual_fru ( $ parsedfru , $ desc . " " . $ categorydesc . "Additional Info" , $ category , "extra" , "hw" ) ;
}
2007-10-26 22:44:33 +00:00
sub initfru {
my $ netfun = 0x28 ;
my @ cmd ;
my @ returnd = ( ) ;
my $ error ;
my $ rc = 0 ;
my $ text ;
my @ output ;
my $ code ;
my $ mfg_id ;
my $ prod_id ;
my $ device_id ;
my $ dev_rev ;
my $ fw_rev1 ;
my $ fw_rev2 ;
my $ mprom ;
my $ fru ;
my $ guid ;
my @ guidcmd ;
( $ rc , $ text , $ mfg_id , $ prod_id , $ device_id , $ dev_rev , $ fw_rev1 , $ fw_rev2 ) = getdevid ( ) ;
if ( $ rc != 0 ) {
return ( $ rc , $ text ) ;
}
@ guidcmd = ( 0x18 , 0x37 ) ;
if ( $ mfg_id == 2 && $ prod_id == 34869 ) {
@ guidcmd = ( 0x18 , 0x08 ) ;
}
if ( $ mfg_id == 2 && $ prod_id == 4 ) {
@ guidcmd = ( 0x18 , 0x08 ) ;
}
if ( $ mfg_id == 2 && $ prod_id == 3 ) {
@ guidcmd = ( 0x18 , 0x08 ) ;
}
( $ rc , $ text , $ guid ) = getguid ( \ @ guidcmd ) ;
if ( $ rc != 0 ) {
return ( $ rc , $ text ) ;
}
if ( $ mfg_id == 2 && $ prod_id == 34869 ) {
$ mprom = sprintf ( "%x.%x" , $ fw_rev1 , $ fw_rev2 ) ;
}
2008-09-19 00:38:58 +00:00
elsif ( $ mfg_id == 2 ) {
2007-10-26 22:44:33 +00:00
my @ lcmd = ( 0x50 ) ;
my @ lreturnd = ( ) ;
my $ lerror = docmd (
0xe8 ,
\ @ lcmd ,
\ @ lreturnd
) ;
2008-09-16 20:12:44 +00:00
if ( $ lerror eq "" && $ lreturnd [ 36 - $ authoffset ] == 0 ) {
2007-10-26 22:44:33 +00:00
my @ a = ( $ fw_rev2 ) ;
my @ b = @ lreturnd [ 37 - $ authoffset .. $# lreturnd - 1 ] ;
$ mprom = sprintf ( "%d.%s (%s)" , $ fw_rev1 , decodebcd ( \ @ a ) , getascii ( @ b ) ) ;
} else {
my @ a = ( $ fw_rev2 ) ;
$ mprom = sprintf ( "%d.%s" , $ fw_rev1 , decodebcd ( \ @ a ) ) ;
}
2008-09-19 00:38:58 +00:00
} else {
my @ a = ( $ fw_rev2 ) ;
$ mprom = sprintf ( "%d.%s" , $ fw_rev1 , decodebcd ( \ @ a ) ) ;
}
2007-10-26 22:44:33 +00:00
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "mprom" ) ;
$ fru - > desc ( "BMC Firmware" ) ;
$ fru - > value ( $ mprom ) ;
$ fru_hash { mprom } = $ fru ;
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "guid" ) ;
$ fru - > desc ( "GUID" ) ;
$ fru - > value ( $ guid ) ;
$ fru_hash { guid } = $ fru ;
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "deviceid" ) ;
$ fru - > desc ( "Manufacturer ID" ) ;
my $ value = $ mfg_id ;
if ( $ MFG_ID { $ mfg_id } ) {
$ value = "$MFG_ID{$mfg_id} ($mfg_id)" ;
}
$ fru - > value ( $ value ) ;
$ fru_hash { mfg_id } = $ fru ;
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "deviceid" ) ;
$ fru - > desc ( "Product ID" ) ;
$ value = $ prod_id ;
my $ tmp = "$mfg_id:$prod_id" ;
if ( $ PROD_ID { $ tmp } ) {
$ value = "$PROD_ID{$tmp} ($prod_id)" ;
}
$ fru - > value ( $ value ) ;
$ fru_hash { prod_id } = $ fru ;
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "deviceid" ) ;
$ fru - > desc ( "Device ID" ) ;
$ fru - > value ( $ device_id ) ;
$ fru_hash { device_id } = $ fru ;
# ($rc,$text)=initoemfru($mfg_id,$prod_id,$device_id);
# if($rc == 1) {
# return($rc,$text);
# }
# if($rc == 2) {
# return(0,"");
# }
2008-09-19 00:38:58 +00:00
$ netfun = 0x28 ; # Storage (0x0A << 2)
my @ bytes ;
2007-10-26 22:44:33 +00:00
@ cmd = ( 0x10 , 0x00 ) ;
2008-09-19 00:38:58 +00:00
$ error = docmd ( $ netfun , \ @ cmd , \ @ bytes ) ;
if ( $ error ) { return ( 1 , $ error ) ; }
@ bytes = splice @ bytes , 36 - $ authoffset ;
pop @ bytes ;
unless ( defined $ bytes [ 0 ] and $ bytes [ 0 ] == 0 ) {
if ( $ codes { $ bytes [ 0 ] } ) {
return ( 1 , "FRU device 0 inaccessible" . $ codes { $ bytes [ 0 ] } ) ;
} else {
return ( 1 , "FRU device 0 inaccessible" ) ;
}
}
my $ frusize = ( $ bytes [ 2 ] << 8 ) + $ bytes [ 1 ] ;
2007-10-26 22:44:33 +00:00
2008-09-19 00:38:58 +00:00
( $ rc , @ bytes ) = frudump ( 0 , $ frusize , 16 ) ;
2007-10-26 22:44:33 +00:00
if ( $ rc != 0 ) {
2008-09-19 00:38:58 +00:00
return ( $ rc , @ bytes ) ;
2007-10-26 22:44:33 +00:00
}
2008-09-19 00:38:58 +00:00
my $ fruhash ;
( $ error , $ fruhash ) = parsefru ( \ @ bytes ) ;
if ( $ error ) {
2007-10-26 22:44:33 +00:00
( $ rc , $ text ) = initoemfru ( $ mfg_id , $ prod_id , $ device_id ) ;
if ( $ rc == 1 ) {
$ text = "FRU format unknown" ;
return ( $ rc , $ text ) ;
}
if ( $ rc == 2 ) {
return ( 0 , "" ) ;
}
}
2009-03-07 18:04:32 +00:00
$ frudex = 0 ;
2008-09-19 00:38:58 +00:00
if ( defined $ fruhash - > { product } - > { manufacturer } - > { value } ) {
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "misc" ) ;
$ fru - > desc ( "System Manufacturer" ) ;
if ( $ fruhash - > { product } - > { product } - > { encoding } == 3 ) {
$ fru - > value ( $ fruhash - > { product } - > { manufacturer } - > { value } ) ;
} else {
$ fru - > value ( phex ( $ fruhash - > { product } - > { manufacturer } - > { value } ) ) ;
}
$ fru_hash { $ frudex + + } = $ fru ;
}
if ( defined $ fruhash - > { product } - > { product } - > { value } ) {
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "model" ) ;
$ fru - > desc ( "System Description" ) ;
if ( $ fruhash - > { product } - > { product } - > { encoding } == 3 ) {
$ fru - > value ( $ fruhash - > { product } - > { product } - > { value } ) ;
} else {
$ fru - > value ( phex ( $ fruhash - > { product } - > { product } - > { value } ) ) ;
}
$ fru_hash { $ frudex + + } = $ fru ;
}
if ( defined $ fruhash - > { product } - > { model } - > { value } ) {
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "model" ) ;
$ fru - > desc ( "System Model/MTM" ) ;
if ( $ fruhash - > { product } - > { model } - > { encoding } == 3 ) {
$ fru - > value ( $ fruhash - > { product } - > { model } - > { value } ) ;
} else {
$ fru - > value ( phex ( $ fruhash - > { product } - > { model } - > { value } ) ) ;
}
$ fru_hash { $ frudex + + } = $ fru ;
}
if ( defined $ fruhash - > { product } - > { version } - > { value } ) {
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "misc" ) ;
$ fru - > desc ( "System Revision" ) ;
if ( $ fruhash - > { product } - > { version } - > { encoding } == 3 ) {
$ fru - > value ( $ fruhash - > { product } - > { version } - > { value } ) ;
} else {
$ fru - > value ( phex ( $ fruhash - > { product } - > { version } - > { value } ) ) ;
}
$ fru_hash { $ frudex + + } = $ fru ;
}
if ( defined $ fruhash - > { product } - > { serialnumber } - > { value } ) {
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "serial" ) ;
$ fru - > desc ( "System Serial Number" ) ;
if ( $ fruhash - > { product } - > { serialnumber } - > { encoding } == 3 ) {
$ fru - > value ( $ fruhash - > { product } - > { serialnumber } - > { value } ) ;
} else {
$ fru - > value ( phex ( $ fruhash - > { product } - > { serialnumber } - > { value } ) ) ;
}
$ fru_hash { $ frudex + + } = $ fru ;
}
if ( defined $ fruhash - > { product } - > { asset } - > { value } ) {
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "asset" ) ;
$ fru - > desc ( "System Asset Number" ) ;
if ( $ fruhash - > { product } - > { asset } - > { encoding } == 3 ) {
$ fru - > value ( $ fruhash - > { product } - > { asset } - > { value } ) ;
} else {
$ fru - > value ( phex ( $ fruhash - > { product } - > { asset } - > { value } ) ) ;
}
$ fru_hash { $ frudex + + } = $ fru ;
}
foreach ( @ { $ fruhash - > { product } - > { extra } } ) {
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "misc" ) ;
$ fru - > desc ( "Product Extra data" ) ;
if ( $ _ - > { encoding } == 3 ) {
$ fru - > value ( $ _ - > { value } ) ;
} else {
2009-03-07 02:04:21 +00:00
#print Dumper($_);
#print $_->{encoding};
next ;
2008-09-19 00:38:58 +00:00
$ fru - > value ( phex ( $ _ - > { value } ) ) ;
}
$ fru_hash { $ frudex + + } = $ fru ;
}
2008-09-16 20:12:44 +00:00
2008-09-19 00:38:58 +00:00
if ( $ fruhash - > { chassis } - > { serialnumber } - > { value } ) {
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "serial" ) ;
$ fru - > desc ( "Chassis Serial Number" ) ;
if ( $ fruhash - > { chassis } - > { serialnumber } - > { encoding } == 3 ) {
$ fru - > value ( $ fruhash - > { chassis } - > { serialnumber } - > { value } ) ;
} else {
$ fru - > value ( phex ( $ fruhash - > { chassis } - > { serialnumber } - > { value } ) ) ;
}
$ fru_hash { $ frudex + + } = $ fru ;
2008-09-16 20:12:44 +00:00
}
2007-10-26 22:44:33 +00:00
2008-09-19 00:38:58 +00:00
if ( $ fruhash - > { chassis } - > { partnumber } - > { value } ) {
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "model" ) ;
$ fru - > desc ( "Chassis Part Number" ) ;
if ( $ fruhash - > { chassis } - > { partnumber } - > { encoding } == 3 ) {
$ fru - > value ( $ fruhash - > { chassis } - > { partnumber } - > { value } ) ;
} else {
$ fru - > value ( phex ( $ fruhash - > { chassis } - > { partnumber } - > { value } ) ) ;
}
$ fru_hash { $ frudex + + } = $ fru ;
}
2007-10-26 22:44:33 +00:00
2008-09-19 00:38:58 +00:00
foreach ( @ { $ fruhash - > { chassis } - > { extra } } ) {
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "misc" ) ;
$ fru - > desc ( "Chassis Extra data" ) ;
if ( $ _ - > { encoding } == 3 ) {
$ fru - > value ( $ _ - > { value } ) ;
} else {
2009-03-07 02:04:21 +00:00
next ;
#print Dumper($_);
#print $_->{encoding};
2008-09-19 00:38:58 +00:00
$ fru - > value ( phex ( $ _ - > { value } ) ) ;
}
$ fru_hash { $ frudex + + } = $ fru ;
}
if ( $ fruhash - > { board } - > { builddate } ) {
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "misc" ) ;
$ fru - > desc ( "Board manufacture date" ) ;
$ fru - > value ( $ fruhash - > { board } - > { builddate } ) ;
$ fru_hash { $ frudex + + } = $ fru ;
}
if ( $ fruhash - > { board } - > { manufacturer } - > { value } ) {
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "misc" ) ;
$ fru - > desc ( "Board manufacturer" ) ;
if ( $ fruhash - > { board } - > { manufacturer } - > { encoding } == 3 ) {
$ fru - > value ( $ fruhash - > { board } - > { manufacturer } - > { value } ) ;
} else {
$ fru - > value ( phex ( $ fruhash - > { board } - > { manufacturer } - > { value } ) ) ;
}
$ fru_hash { $ frudex + + } = $ fru ;
}
if ( $ fruhash - > { board } - > { name } - > { value } ) {
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "misc" ) ;
$ fru - > desc ( "Board Description" ) ;
if ( $ fruhash - > { board } - > { name } - > { encoding } == 3 ) {
$ fru - > value ( $ fruhash - > { board } - > { name } - > { value } ) ;
} else {
$ fru - > value ( phex ( $ fruhash - > { board } - > { name } - > { value } ) ) ;
}
$ fru_hash { $ frudex + + } = $ fru ;
}
if ( $ fruhash - > { board } - > { serialnumber } - > { value } ) {
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "misc" ) ;
$ fru - > desc ( "Board Serial Number" ) ;
if ( $ fruhash - > { board } - > { serialnumber } - > { encoding } == 3 ) {
$ fru - > value ( $ fruhash - > { board } - > { serialnumber } - > { value } ) ;
} else {
$ fru - > value ( phex ( $ fruhash - > { board } - > { serialnumber } - > { value } ) ) ;
}
$ fru_hash { $ frudex + + } = $ fru ;
}
if ( $ fruhash - > { board } - > { partnumber } - > { value } ) {
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "misc" ) ;
$ fru - > desc ( "Board Model Number" ) ;
if ( $ fruhash - > { board } - > { partnumber } - > { encoding } == 3 ) {
$ fru - > value ( $ fruhash - > { board } - > { partnumber } - > { value } ) ;
} else {
$ fru - > value ( phex ( $ fruhash - > { board } - > { partnumber } - > { value } ) ) ;
}
$ fru_hash { $ frudex + + } = $ fru ;
}
foreach ( @ { $ fruhash - > { board } - > { extra } } ) {
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "misc" ) ;
$ fru - > desc ( "Board Extra data" ) ;
if ( $ _ - > { encoding } == 3 ) {
$ fru - > value ( $ _ - > { value } ) ;
} else {
2009-03-07 02:04:21 +00:00
next ;
#print Dumper($_);
#print $_->{encoding};
2008-09-19 00:38:58 +00:00
$ fru - > value ( phex ( $ _ - > { value } ) ) ;
}
$ fru_hash { $ frudex + + } = $ fru ;
}
2009-03-07 02:04:21 +00:00
#Ok, done with fru 0, on to the other fru devices from SDR
my $ key ;
2009-03-07 18:04:32 +00:00
my $ subrc ;
2009-03-07 02:04:21 +00:00
foreach $ key ( sort { $ sdr_hash { $ a } - > id_string cmp $ sdr_hash { $ b } - > id_string } keys % sdr_hash ) {
my $ sdr = $ sdr_hash { $ key } ;
unless ( $ sdr - > rec_type == 0x11 and $ sdr - > fru_type == 0x10 ) { #skip non fru sdr stuff and frus I don't understand
next ;
}
2009-03-07 18:04:32 +00:00
if ( $ sdr - > fru_type == 0x10 ) { #supported
if ( $ sdr - > fru_subtype == 0x1 ) { #DIMM
$ fru = FRU - > new ( ) ;
$ fru - > rec_type ( "hw,dimm" ) ;
$ fru - > desc ( $ sdr - > id_string ) ;
( $ subrc , @ bytes ) = frudump ( 0 , get_frusize ( $ sdr - > sensor_number ) , 16 , $ sdr - > sensor_number ) ;
if ( $ subrc ) {
print $ sdr - > id_string . ":" . $ bytes [ 0 ] . "\n" ;
$ fru - > value ( $ bytes [ 0 ] ) ;
$ fru_hash { $ frudex + + } = $ fru ;
next ;
}
2009-03-08 03:30:24 +00:00
my $ parsedfru = decode_spd ( @ bytes ) ;
2009-03-08 16:30:56 +00:00
add_textual_frus ( $ parsedfru , $ sdr - > id_string , "" , 'product' , 'dimm,hw' ) ;
2009-03-07 18:04:32 +00:00
} elsif ( $ sdr - > fru_subtype == 0 or $ sdr - > fru_subtype == 2 ) {
( $ subrc , @ bytes ) = frudump ( 0 , get_frusize ( $ sdr - > sensor_number ) , 16 , $ sdr - > sensor_number ) ;
if ( $ subrc ) {
$ fru = FRU - > new ( ) ;
$ fru - > value ( $ bytes [ 0 ] ) ;
$ fru - > rec_type ( "hw" ) ;
$ fru - > desc ( $ sdr - > id_string ) ;
$ fru_hash { $ frudex + + } = $ fru ;
next ;
}
my $ parsedfru = parsefru ( \ @ bytes ) ;
add_textual_frus ( $ parsedfru , $ sdr - > id_string , "Board " , 'board' ) ;
add_textual_frus ( $ parsedfru , $ sdr - > id_string , "Product " , 'product' ) ;
add_textual_frus ( $ parsedfru , $ sdr - > id_string , "Chassis " , 'chassis' ) ;
}
2009-03-07 02:04:21 +00:00
}
}
2008-09-19 00:38:58 +00:00
2007-10-26 22:44:33 +00:00
return ( $ rc , $ text ) ;
}
2009-03-07 18:04:32 +00:00
sub get_frusize {
my $ fruid = shift ;
my $ netfun = 0x28 ; # Storage (0x0A << 2)
my @ cmd = ( 0x10 , $ fruid ) ;
my @ bytes ;
my $ error = docmd ( $ netfun , \ @ cmd , \ @ bytes ) ;
@ bytes = splice @ bytes , 36 - $ authoffset ;
pop @ bytes ;
unless ( defined $ bytes [ 0 ] and $ bytes [ 0 ] == 0 ) {
if ( $ codes { $ bytes [ 0 ] } ) {
return ( 0 , $ codes { $ bytes [ 0 ] } ) ;
}
return ( 0 , "FRU device $fruid inaccessible" ) ;
}
return ( $ bytes [ 2 ] << 8 ) + $ bytes [ 1 ] ;
}
2008-09-19 00:38:58 +00:00
2008-09-19 03:31:20 +00:00
sub formfru {
my $ fruhash = shift ;
my $ frusize = shift ;
$ frusize -= 8 ; #consume 8 bytes for mandatory header
my $ availindex = 1 ;
my @ bytes = ( 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) ; #
if ( $ fruhash - > { internal } ) { #Allocate the space at header time
$ bytes [ 1 ] = $ availindex ;
2008-09-19 14:41:14 +00:00
$ availindex += ceil ( ( scalar @ { $ fruhash - > { internal } } ) / 8 ) ;
2008-09-19 03:31:20 +00:00
$ frusize -= ( scalar @ { $ fruhash - > { internal } } ) ; #consume internal bytes
push @ bytes , @ { $ fruhash - > { internal } } ;
}
if ( $ fruhash - > { chassis } ) {
$ bytes [ 2 ] = $ availindex ;
push @ bytes , @ { $ fruhash - > { chassis } - > { raw } } ;
2008-09-19 14:41:14 +00:00
$ availindex += ceil ( ( scalar @ { $ fruhash - > { chassis } - > { raw } } ) / 8 ) ;
$ frusize -= ceil ( ( scalar @ { $ fruhash - > { chassis } - > { raw } } ) / 8 ) * 8 ;
2008-09-19 03:31:20 +00:00
}
if ( $ fruhash - > { board } ) {
$ bytes [ 3 ] = $ availindex ;
push @ bytes , @ { $ fruhash - > { board } - > { raw } } ;
2008-09-19 14:41:14 +00:00
$ availindex += ceil ( ( scalar @ { $ fruhash - > { board } - > { raw } } ) / 8 ) ;
$ frusize -= ceil ( ( scalar @ { $ fruhash - > { board } - > { raw } } ) / 8 ) * 8 ;
2008-09-19 03:31:20 +00:00
}
2008-09-19 21:15:01 +00:00
#xCAT will always have a product FRU in this process
$ bytes [ 4 ] = $ availindex ;
2008-09-22 22:56:42 +00:00
unless ( defined $ fruhash - > { product } ) { #Make sure there is a data structure
#to latch onto..
2008-09-19 21:15:01 +00:00
$ fruhash - > { product } = { } ;
2008-09-19 03:31:20 +00:00
}
2008-09-19 21:15:01 +00:00
my @ prodbytes = buildprodfru ( $ fruhash - > { product } ) ;
push @ bytes , @ prodbytes ;
$ availindex += ceil ( ( scalar @ prodbytes ) / 8 ) ;
$ frusize -= ceil ( ( scalar @ prodbytes ) / 8 ) * 8 ; ;
#End of product fru setup
2008-09-19 03:31:20 +00:00
if ( $ fruhash - > { extra } ) {
$ bytes [ 5 ] = $ availindex ;
push @ bytes , @ { $ fruhash - > { extra } } ;
2008-09-19 14:41:14 +00:00
$ frusize -= ceil ( ( scalar @ { $ fruhash - > { extra } } ) / 8 ) * 8 ;
2008-09-19 03:31:20 +00:00
#Don't need to track availindex anymore
}
$ bytes [ 7 ] = dochksum ( [ @ bytes [ 0 .. 6 ] ] ) ;
if ( $ frusize < 0 ) {
return undef ;
} else {
return \ @ bytes ;
}
}
2008-09-19 14:41:14 +00:00
sub transfieldtobytes {
my $ hashref = shift ;
unless ( defined $ hashref ) {
return ( 0xC0 ) ;
}
my @ data ;
my $ size ;
if ( $ hashref - > { encoding } == 3 ) {
@ data = unpack ( "C*" , $ hashref - > { value } ) ;
} else {
@ data = @ { $ hashref - > { value } } ;
}
$ size = scalar ( @ data ) ;
2008-09-19 21:15:01 +00:00
if ( $ size > 64 ) {
die "Field too large for IPMI FRU specification" ;
}
2008-09-19 14:41:14 +00:00
unshift ( @ data , $ size | ( $ hashref - > { encoding } << 6 ) ) ;
return @ data ;
}
2008-09-19 21:15:01 +00:00
sub mergefru {
my $ phash = shift ; #Product hash
if ( $ vpdhash - > { $ currnode } - > [ 0 ] - > { mtm } ) {
$ phash - > { model } - > { encoding } = 3 ;
$ phash - > { model } - > { value } = $ vpdhash - > { $ currnode } - > [ 0 ] - > { mtm } ;
}
if ( $ vpdhash - > { $ currnode } - > [ 0 ] - > { serial } ) {
$ phash - > { serialnumber } - > { encoding } = 3 ;
$ phash - > { serialnumber } - > { value } = $ vpdhash - > { $ currnode } - > [ 0 ] - > { serial } ;
}
if ( $ vpdhash - > { $ currnode } - > [ 0 ] - > { asset } ) {
$ phash - > { asset } - > { encoding } = 3 ;
$ phash - > { asset } - > { value } = $ vpdhash - > { $ currnode } - > [ 0 ] - > { asset } ;
}
}
2008-09-19 03:31:20 +00:00
sub buildprodfru {
my $ prod = shift ;
2008-09-19 21:15:01 +00:00
mergefru ( $ prod ) ;
2008-09-19 14:41:14 +00:00
my @ bytes = ( 1 , 0 , 0 ) ;
my @ data ;
my $ padsize ;
push @ bytes , transfieldtobytes ( $ prod - > { manufacturer } ) ;
push @ bytes , transfieldtobytes ( $ prod - > { product } ) ;
push @ bytes , transfieldtobytes ( $ prod - > { model } ) ;
push @ bytes , transfieldtobytes ( $ prod - > { version } ) ;
push @ bytes , transfieldtobytes ( $ prod - > { serialnumber } ) ;
push @ bytes , transfieldtobytes ( $ prod - > { asset } ) ;
push @ bytes , transfieldtobytes ( $ prod - > { fruid } ) ;
push @ bytes , transfieldtobytes ( $ prod - > { fruid } ) ;
foreach ( @ { $ prod - > { extra } } ) {
2008-09-19 21:15:01 +00:00
my $ sig = getascii ( transfieldtobytes ( $ _ ) ) ;
2008-10-04 14:40:05 +00:00
unless ( $ sig and $ sig =~ /FRU by xCAT/ ) {
push @ bytes , transfieldtobytes ( $ _ ) ;
2008-09-19 21:15:01 +00:00
}
}
2008-10-04 14:40:05 +00:00
push @ bytes , transfieldtobytes ( { encoding = > 3 , value = > "$currnode FRU by xCAT " . xCAT::Utils:: Version ( 'short' ) } ) ;
2008-09-19 14:41:14 +00:00
push @ bytes , ( 0xc1 ) ;
$ bytes [ 1 ] = ceil ( ( scalar ( @ bytes ) + 1 ) / 8 ) ;
$ padsize = ( ceil ( ( scalar ( @ bytes ) + 1 ) / 8 ) * 8 ) - scalar ( @ bytes ) - 1 ;
while ( $ padsize - - ) {
push @ bytes , ( 0x00 ) ;
}
$ padsize = dochksum ( \ @ bytes ) ; #reuse padsize for a second to store checksum
push @ bytes , $ padsize ;
2008-09-19 03:31:20 +00:00
return @ bytes ;
}
2008-09-19 00:38:58 +00:00
2007-10-26 22:44:33 +00:00
sub fru {
my $ subcommand = shift ;
my $ netfun = 0x28 ;
my @ cmd ;
my @ returnd = ( ) ;
my $ error ;
my $ rc = 0 ;
my $ text ;
my @ output ;
my $ code ;
@ cmd = ( 0x10 , 0x00 ) ;
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
return ( $ rc , $ text ) ;
}
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code == 0x00 ) {
}
else {
$ rc = 1 ;
$ text = $ codes { $ code } ;
}
if ( $ rc != 0 ) {
if ( ! $ text ) {
$ text = sprintf ( "unknown response %02x" , $ code ) ;
}
return ( $ rc , $ text ) ;
}
my $ fru_size_ls = $ returnd [ 37 - $ authoffset ] ;
my $ fru_size_ms = $ returnd [ 38 - $ authoffset ] ;
my $ fru_size = $ fru_size_ms * 256 + $ fru_size_ls ;
if ( $ subcommand eq "dump" ) {
print "FRU Size: $fru_size\n" ;
my ( $ rc , @ output ) = frudump ( 0 , $ fru_size , 8 ) ;
if ( $ rc ) {
return ( $ rc , @ output ) ;
}
hexadump ( \ @ output ) ;
return ( 0 , "" ) ;
}
if ( $ subcommand eq "wipe" ) {
my @ bytes = ( ) ;
for ( my $ i = 0 ; $ i < $ fru_size ; $ i + + ) {
push ( @ bytes , 0xff ) ;
}
my ( $ rc , $ text ) = fruwrite ( 0 , \ @ bytes , 8 ) ;
if ( $ rc ) {
return ( $ rc , $ text ) ;
}
return ( 0 , "FRU $fru_size bytes wiped" ) ;
}
return ( 0 , "" ) ;
}
sub frudump {
my $ offset = shift ;
my $ length = shift ;
my $ chunk = shift ;
2009-03-07 02:04:21 +00:00
my $ fruid = shift ;
unless ( defined $ fruid ) { $ fruid = 0 ; }
2009-03-07 18:04:32 +00:00
unless ( $ length ) { return ( 1 , $ chunk ) ; } #chunk happens to get the error text
2007-10-26 22:44:33 +00:00
my $ netfun = 0x28 ;
my @ cmd ;
my @ returnd = ( ) ;
my $ error ;
my $ rc = 0 ;
my $ text ;
my @ output ;
my $ code ;
my @ fru_data = ( ) ;
for ( my $ c = $ offset ; $ c < $ length + $ offset ; $ c += $ chunk ) {
my $ ms = int ( $ c / 0x100 ) ;
my $ ls = $ c - $ ms * 0x100 ;
2009-03-07 18:04:32 +00:00
my $ reqsize = $ chunk ;
if ( $ c + $ chunk > $ length + $ offset ) {
$ reqsize = ( $ length + $ offset - $ c ) ;
}
2007-10-26 22:44:33 +00:00
2009-03-07 18:04:32 +00:00
@ cmd = ( 0x11 , $ fruid , $ ls , $ ms , $ reqsize ) ;
2007-10-26 22:44:33 +00:00
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
return ( $ rc , $ text ) ;
}
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code == 0x00 ) {
}
else {
$ rc = 1 ;
2009-03-08 03:30:24 +00:00
$ text = $ codes { $ code } ;
2007-10-26 22:44:33 +00:00
}
if ( $ rc != 0 ) {
if ( ! $ text ) {
$ text = sprintf ( "unknown response %02x" , $ code ) ;
}
return ( $ rc , $ text ) ;
}
my $ count = $ returnd [ 37 - $ authoffset ] ;
2009-03-07 18:04:32 +00:00
if ( $ count != $ reqsize ) {
2007-10-26 22:44:33 +00:00
$ rc = 1 ;
2009-03-07 18:04:32 +00:00
$ text = "FRU read error (bytes requested: $reqsize, got: $count)" ;
2007-10-26 22:44:33 +00:00
return ( $ rc , $ text ) ;
}
my @ data = @ returnd [ 38 - $ authoffset .. @ returnd - 2 ] ;
@ fru_data = ( @ fru_data , @ data ) ;
}
return ( 0 , @ fru_data ) ;
}
2008-09-18 03:48:13 +00:00
sub parsefru {
my $ bytes = shift ;
2008-09-18 20:54:08 +00:00
my $ fruhash ;
2008-09-18 03:48:13 +00:00
my $ curridx ; #store indexes as needed for convenience
my $ currsize ; #store current size
my $ subidx ;
my @ currarea ;
unless ( $ bytes - > [ 0 ] == 1 ) {
if ( $ bytes - > [ 0 ] == 0 or $ bytes - > [ 0 ] == 0xff ) { #not in spec, but probably unitialized, xCAT probably will rewrite fresh
return "clear" , undef ;
} else { #some meaning suggested, but not parsable, xCAT shouldn't meddle
return "unknown" , undef ;
}
}
if ( $ bytes - > [ 1 ] ) { #The FRU spec, unfortunately, gave no easy way to tell the size of internal area
#consequently, will find the next defined field and preserve the addressing and size of current FRU
#area until then
my $ internal_size ;
if ( $ bytes - > [ 2 ] ) {
$ internal_size = $ bytes - > [ 2 ] * 8 - ( $ bytes - > [ 1 ] * 8 ) ;
} elsif ( $ bytes - > [ 3 ] ) {
$ internal_size = $ bytes - > [ 3 ] * 8 - ( $ bytes - > [ 1 ] * 8 ) ;
} elsif ( $ bytes - > [ 4 ] ) {
$ internal_size = $ bytes - > [ 4 ] * 8 - ( $ bytes - > [ 1 ] * 8 ) ;
} elsif ( $ bytes - > [ 5 ] ) {
$ internal_size = $ bytes - > [ 5 ] * 8 - ( $ bytes - > [ 1 ] * 8 ) ;
} else { #The FRU area is intact enough to signify xCAT can't safely manipulate contents
return "unknown-winternal" , undef ;
}
#capture slice of bytes
2008-09-19 03:31:20 +00:00
$ fruhash - > { internal } = [ @ { $ bytes } [ ( $ bytes - > [ 1 ] * 8 ) .. ( $ bytes - > [ 1 ] * 8 + $ internal_size - 1 ) ] ] ; #,$bytes->[1]*8,$internal_size];
2008-09-18 03:48:13 +00:00
}
if ( $ bytes - > [ 2 ] ) { #Chassis info area, xCAT will preserve fields, not manipulate them
$ curridx = $ bytes - > [ 2 ] * 8 ;
unless ( $ bytes - > [ $ curridx ] == 1 ) { #definitely unparsable, but the section is preservable
return "unknown-COULDGUESS" , undef ; #be lazy for now, TODO revisit this and add guessing if it ever matters
}
$ currsize = ( $ bytes - > [ $ curridx + 1 ] ) * 8 ;
2008-09-19 03:31:20 +00:00
@ currarea = @ { $ bytes } [ $ curridx .. ( $ curridx + $ currsize - 1 ) ] ; #splice @$bytes,$curridx,$currsize;
2008-09-18 20:54:08 +00:00
$ fruhash - > { chassis } = parsechassis ( @ currarea ) ;
}
if ( $ bytes - > [ 3 ] ) { #Board info area, to be preserved
$ curridx = $ bytes - > [ 3 ] * 8 ;
unless ( $ bytes - > [ $ curridx ] == 1 ) {
return "unknown-COULDGUESS" , undef ;
}
$ currsize = ( $ bytes - > [ $ curridx + 1 ] ) * 8 ;
2008-09-19 03:31:20 +00:00
@ currarea = @ { $ bytes } [ $ curridx .. ( $ curridx + $ currsize - 1 ) ] ;
2008-09-18 20:54:08 +00:00
$ fruhash - > { board } = parseboard ( @ currarea ) ;
}
if ( $ bytes - > [ 4 ] ) { #Product info area present, will probably be thoroughly modified
$ curridx = $ bytes - > [ 4 ] * 8 ;
unless ( $ bytes - > [ $ curridx ] == 1 ) {
return "unknown-COULDGUESS" , undef ;
}
$ currsize = ( $ bytes - > [ $ curridx + 1 ] ) * 8 ;
2008-09-19 03:31:20 +00:00
@ currarea = @ { $ bytes } [ $ curridx .. ( $ curridx + $ currsize - 1 ) ] ;
2008-09-18 20:54:08 +00:00
$ fruhash - > { product } = parseprod ( @ currarea ) ;
}
if ( $ bytes - > [ 5 ] ) { #Generic multirecord present..
$ fruhash - > { extra } = [] ;
my $ last = 0 ;
$ curridx = $ bytes - > [ 5 ] * 8 ;
my $ currsize ;
while ( not $ last ) {
if ( $ bytes - > [ $ curridx + 1 ] & 128 ) {
$ last = 1 ;
}
$ currsize = $ bytes - > [ $ curridx + 2 ] ;
2008-09-19 03:31:20 +00:00
push @ { $ fruhash - > { extra } } , $ bytes - > [ $ curridx .. $ curridx + 4 + $ currsize - 1 ] ;
2008-09-18 20:54:08 +00:00
}
2008-09-18 03:48:13 +00:00
}
2008-09-19 00:38:58 +00:00
return 0 , $ fruhash ;
2008-09-18 03:48:13 +00:00
}
2008-09-18 20:54:08 +00:00
sub parseprod {
my @ area = @ _ ;
my % info ;
my $ language = $ area [ 2 ] ;
my $ idx = 3 ;
my $ currsize ;
my $ currdata ;
my $ encode ;
( $ currsize , $ currdata , $ encode ) = extractfield ( \ @ area , $ idx ) ;
unless ( $ currsize ) {
return \ % info ;
}
$ idx += $ currsize ;
if ( $ currsize > 1 ) {
$ info { manufacturer } - > { encoding } = $ encode ;
$ info { manufacturer } - > { value } = $ currdata ;
}
( $ currsize , $ currdata , $ encode ) = extractfield ( \ @ area , $ idx ) ;
unless ( $ currsize ) {
return \ % info ;
}
$ idx += $ currsize ;
if ( $ currsize > 1 ) {
$ info { product } - > { encoding } = $ encode ;
$ info { product } - > { value } = $ currdata ;
}
( $ currsize , $ currdata , $ encode ) = extractfield ( \ @ area , $ idx ) ;
unless ( $ currsize ) {
return \ % info ;
}
$ idx += $ currsize ;
if ( $ currsize > 1 ) {
$ info { model } - > { encoding } = $ encode ;
$ info { model } - > { value } = $ currdata ;
}
( $ currsize , $ currdata , $ encode ) = extractfield ( \ @ area , $ idx ) ;
unless ( $ currsize ) {
return \ % info ;
}
$ idx += $ currsize ;
if ( $ currsize > 1 ) {
$ info { version } - > { encoding } = $ encode ;
$ info { version } - > { value } = $ currdata ;
}
( $ currsize , $ currdata , $ encode ) = extractfield ( \ @ area , $ idx ) ;
unless ( $ currsize ) {
return \ % info ;
}
$ idx += $ currsize ;
if ( $ currsize > 1 ) {
$ info { serialnumber } - > { encoding } = $ encode ;
$ info { serialnumber } - > { value } = $ currdata ;
}
( $ currsize , $ currdata , $ encode ) = extractfield ( \ @ area , $ idx ) ;
unless ( $ currsize ) {
return \ % info ;
}
$ idx += $ currsize ;
if ( $ currsize > 1 ) {
$ info { asset } - > { encoding } = $ encode ;
$ info { asset } - > { value } = $ currdata ;
}
( $ currsize , $ currdata , $ encode ) = extractfield ( \ @ area , $ idx ) ;
unless ( $ currsize ) {
return \ % info ;
}
$ idx += $ currsize ;
if ( $ currsize > 1 ) {
$ info { fruid } - > { encoding } = $ encode ;
$ info { fruid } - > { value } = $ currdata ;
}
( $ currsize , $ currdata , $ encode ) = extractfield ( \ @ area , $ idx ) ;
if ( $ currsize ) {
$ info { extra } = [] ;
}
while ( $ currsize > 0 ) {
if ( $ currsize > 1 ) {
2008-09-19 00:38:58 +00:00
push @ { $ info { extra } } , { value = > $ currdata , encoding = > $ encode } ;
2008-09-18 20:54:08 +00:00
}
$ idx += $ currsize ;
( $ currsize , $ currdata , $ encode ) = extractfield ( \ @ area , $ idx ) ;
}
return \ % info ;
}
sub parseboard {
my @ area = @ _ ;
my % boardinf ;
my $ idx = 6 ;
my $ language = $ area [ 2 ] ;
my $ tstamp = ( $ area [ 3 ] + ( $ area [ 4 ] << 8 ) + ( $ area [ 5 ] << 16 ) ) * 60 + 820472400 ; #820472400 is meant to be 1/1/1996
$ boardinf { raw } = [ @ area ] ; #store for verbatim replacement
2009-03-07 18:04:32 +00:00
unless ( $ tstamp == 820472400 ) {
$ boardinf { builddate } = scalar localtime ( $ tstamp ) ;
}
2008-09-18 20:54:08 +00:00
my $ encode ;
my $ currsize ;
my $ currdata ;
( $ currsize , $ currdata , $ encode ) = extractfield ( \ @ area , $ idx ) ;
unless ( $ currsize ) {
return \ % boardinf ;
}
$ idx += $ currsize ;
if ( $ currsize > 1 ) {
$ boardinf { manufacturer } - > { encoding } = $ encode ;
$ boardinf { manufacturer } - > { value } = $ currdata ;
}
( $ currsize , $ currdata , $ encode ) = extractfield ( \ @ area , $ idx ) ;
unless ( $ currsize ) {
return \ % boardinf ;
}
$ idx += $ currsize ;
if ( $ currsize > 1 ) {
$ boardinf { name } - > { encoding } = $ encode ;
$ boardinf { name } - > { value } = $ currdata ;
}
( $ currsize , $ currdata , $ encode ) = extractfield ( \ @ area , $ idx ) ;
unless ( $ currsize ) {
return \ % boardinf ;
}
$ idx += $ currsize ;
if ( $ currsize > 1 ) {
$ boardinf { serialnumber } - > { encoding } = $ encode ;
$ boardinf { serialnumber } - > { value } = $ currdata ;
}
( $ currsize , $ currdata , $ encode ) = extractfield ( \ @ area , $ idx ) ;
unless ( $ currsize ) {
return \ % boardinf ;
}
$ idx += $ currsize ;
if ( $ currsize > 1 ) {
$ boardinf { partnumber } - > { encoding } = $ encode ;
$ boardinf { partnumber } - > { value } = $ currdata ;
}
( $ currsize , $ currdata , $ encode ) = extractfield ( \ @ area , $ idx ) ;
unless ( $ currsize ) {
return \ % boardinf ;
}
$ idx += $ currsize ;
if ( $ currsize > 1 ) {
$ boardinf { fruid } - > { encoding } = $ encode ;
$ boardinf { fruid } - > { value } = $ currdata ;
}
( $ currsize , $ currdata , $ encode ) = extractfield ( \ @ area , $ idx ) ;
if ( $ currsize ) {
$ boardinf { extra } = [] ;
}
while ( $ currsize > 0 ) {
if ( $ currsize > 1 ) {
2008-09-19 00:38:58 +00:00
push @ { $ boardinf { extra } } , { value = > $ currdata , encoding = > $ encode } ;
2008-09-18 20:54:08 +00:00
}
$ idx += $ currsize ;
( $ currsize , $ currdata , $ encode ) = extractfield ( \ @ area , $ idx ) ;
}
return \ % boardinf ;
}
2008-09-18 03:48:13 +00:00
sub parsechassis {
my @ chassarea = @ _ ;
my % chassisinf ;
my $ currsize ;
2008-09-18 20:54:08 +00:00
my $ currdata ;
2008-09-18 03:48:13 +00:00
my $ idx = 3 ;
2008-09-18 20:54:08 +00:00
my $ encode ;
$ chassisinf { raw } = [ @ chassarea ] ; #store for verbatim replacement
2008-09-18 03:48:13 +00:00
$ chassisinf { type } = "unknown" ;
if ( $ chassis_types { $ chassarea [ 2 ] } ) {
$ chassisinf { type } = $ chassis_types { $ chassarea [ 2 ] } ;
}
if ( $ chassarea [ $ idx ] == 0xc1 ) {
return \ % chassisinf ;
}
2008-09-18 20:54:08 +00:00
( $ currsize , $ currdata , $ encode ) = extractfield ( \ @ chassarea , $ idx ) ;
unless ( $ currsize ) {
return \ % chassisinf ;
}
$ idx += $ currsize ;
if ( $ currsize > 1 ) {
$ chassisinf { partnumber } - > { encoding } = $ encode ;
$ chassisinf { partnumber } - > { value } = $ currdata ;
2008-09-18 03:48:13 +00:00
}
2008-09-18 20:54:08 +00:00
( $ currsize , $ currdata , $ encode ) = extractfield ( \ @ chassarea , $ idx ) ;
unless ( $ currsize ) {
2008-09-18 03:48:13 +00:00
return \ % chassisinf ;
}
2008-09-18 20:54:08 +00:00
$ idx += $ currsize ;
if ( $ currsize > 1 ) {
$ chassisinf { serialnumber } - > { encoding } = $ encode ;
$ chassisinf { serialnumber } - > { value } = $ currdata ;
}
( $ currsize , $ currdata , $ encode ) = extractfield ( \ @ chassarea , $ idx ) ;
if ( $ currsize ) {
$ chassisinf { extra } = [] ;
}
while ( $ currsize > 0 ) {
if ( $ currsize > 1 ) {
2008-09-19 00:38:58 +00:00
push @ { $ chassisinf { extra } } , { value = > $ currdata , encoding = > $ encode } ;
2008-09-18 03:48:13 +00:00
}
2008-09-18 20:54:08 +00:00
$ idx += $ currsize ;
( $ currsize , $ currdata , $ encode ) = extractfield ( \ @ chassarea , $ idx ) ;
2008-09-18 03:48:13 +00:00
}
2008-09-18 20:54:08 +00:00
return \ % chassisinf ;
}
sub extractfield { #idx is location of the type/length byte, returns something appropriate
my $ area = shift ;
my $ idx = shift ;
my $ language = shift ;
my $ data ;
my $ size = $ area - > [ $ idx ] & 0b00111111 ;
my $ encoding = ( $ area - > [ $ idx ] & 0b11000000 ) >> 6 ;
unless ( $ size ) {
return 1 , undef , undef ;
}
if ( $ size == 1 && $ encoding == 3 ) {
return 0 , '' , '' ;
}
if ( $ encoding == 3 ) {
$ data = getascii ( @$ area [ $ idx + 1 .. $ size + $ idx ] ) ;
2008-09-18 03:48:13 +00:00
} else {
2008-09-18 20:54:08 +00:00
$ data = [ @$ area [ $ idx + 1 .. $ size + $ idx ] ] ;
2008-09-18 03:48:13 +00:00
}
2008-09-18 20:54:08 +00:00
return $ size + 1 , $ data , $ encoding ;
2008-09-18 03:48:13 +00:00
}
2008-09-18 20:54:08 +00:00
2007-10-26 22:44:33 +00:00
sub writefru {
2008-09-18 03:48:13 +00:00
my $ netfun = 0x28 ; # Storage (0x0A << 2)
my @ cmd = ( 0x10 , 0 ) ;
2007-10-26 22:44:33 +00:00
my @ bytes ;
2008-09-18 03:48:13 +00:00
my $ error = docmd ( $ netfun , \ @ cmd , \ @ bytes ) ;
@ bytes = splice @ bytes , 36 - $ authoffset ;
pop @ bytes ;
unless ( defined $ bytes [ 0 ] and $ bytes [ 0 ] == 0 ) {
return ( 1 , "FRU device 0 inaccessible" ) ;
}
my $ frusize = ( $ bytes [ 2 ] << 8 ) + $ bytes [ 1 ] ;
( $ error , @ bytes ) = frudump ( 0 , $ frusize , 16 ) ;
2008-10-12 20:33:11 +00:00
if ( $ error ) {
return ( 1 , "Error retrieving FRU: " . $ error ) ;
}
2008-09-19 00:38:58 +00:00
my $ fruhash ;
( $ error , $ fruhash ) = parsefru ( \ @ bytes ) ;
2008-09-19 21:15:01 +00:00
my $ newfru = formfru ( $ fruhash , $ frusize ) ;
unless ( $ newfru ) {
return ( 1 , "FRU data will not fit in BMC FRU space, fields too long" ) ;
}
2008-10-12 20:33:11 +00:00
my $ rc = 1 ;
my $ writeattempts = 0 ;
2008-09-19 21:15:01 +00:00
my $ text ;
2008-10-12 20:33:11 +00:00
while ( $ rc and $ writeattempts < 15 ) {
if ( $ writeattempts ) {
sleep 1 ;
}
( $ rc , $ text ) = fruwrite ( 0 , $ newfru , 8 ) ;
2009-03-07 02:20:03 +00:00
if ( $ text =~ /rotected/ ) {
last ;
}
2008-10-12 20:33:11 +00:00
$ writeattempts + + ;
}
2007-10-26 22:44:33 +00:00
if ( $ rc ) {
return ( $ rc , $ text ) ;
}
return ( 0 , "FRU Updated" ) ;
}
sub fruwrite {
my $ offset = shift ;
my $ bytes = shift ;
my $ chunk = shift ;
my $ length = @$ bytes ;
my $ netfun = 0x28 ;
my @ cmd ;
my @ returnd = ( ) ;
my $ error ;
my $ rc = 0 ;
my $ text ;
my @ output ;
my $ code ;
my @ fru_data = ( ) ;
for ( my $ c = $ offset ; $ c < $ length + $ offset ; $ c += $ chunk ) {
my $ ms = int ( $ c / 0x100 ) ;
my $ ls = $ c - $ ms * 0x100 ;
@ cmd = ( 0x12 , 0x00 , $ ls , $ ms , @$ bytes [ $ c - $ offset .. $ c - $ offset + $ chunk - 1 ] ) ;
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
return ( $ rc , $ text ) ;
}
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code == 0x00 ) {
}
else {
$ rc = 1 ;
$ text = $ codes { $ code } ;
}
if ( $ rc != 0 ) {
2009-03-07 02:20:03 +00:00
if ( $ code == 0x80 ) {
$ text = "Write protected FRU" ;
}
2007-10-26 22:44:33 +00:00
if ( ! $ text ) {
$ text = sprintf ( "unknown response %02x" , $ code ) ;
}
return ( $ rc , $ text ) ;
}
my $ count = $ returnd [ 37 - $ authoffset ] ;
if ( $ count != $ chunk ) {
$ rc = 1 ;
$ text = "FRU write error (bytes requested: $chunk, wrote: $count)" ;
return ( $ rc , $ text ) ;
}
}
return ( 0 ) ;
}
sub decodealert {
2008-03-12 02:57:01 +00:00
my $ trap = shift ;
my $ skip_sdrinit = 0 ;
2008-03-01 22:08:04 +00:00
if ( $ trap =~ /xCAT_plugin::ipmi/ ) {
$ trap = shift ;
2008-03-12 02:57:01 +00:00
$ skip_sdrinit = 1 ;
2008-03-01 22:08:04 +00:00
}
2007-10-26 22:44:33 +00:00
my $ node = shift ;
2008-03-12 02:57:01 +00:00
my @ pet = @ _ ;
2007-10-26 22:44:33 +00:00
my $ rc ;
my $ text ;
2008-03-12 02:57:01 +00:00
if ( ! $ skip_sdrinit ) {
2008-03-03 20:51:36 +00:00
( $ rc , $ text ) = initsdr ( ) ;
2007-10-26 22:44:33 +00:00
if ( $ rc != 0 ) {
2008-03-03 20:51:36 +00:00
return ( $ rc , $ text ) ;
2007-10-26 22:44:33 +00:00
}
2008-03-12 02:57:01 +00:00
}
2007-10-26 22:44:33 +00:00
my $ type ;
my $ desc ;
#my $ipmisensoreventtab = "$ENV{XCATROOT}/lib/GUMI/ipmisensorevent.tab";
#my $ipmigenericeventtab = "$ENV{XCATROOT}/lib/GUMI/ipmigenericevent.tab";
my $ offsetmask = 0b00000000000000000000000000001111 ;
my $ offsetrmask = 0b00000000000000000000000001110000 ;
my $ assertionmask = 0b00000000000000000000000010000000 ;
my $ eventtypemask = 0b00000000000000001111111100000000 ;
my $ sensortypemask = 0b00000000111111110000000000000000 ;
my $ reservedmask = 0b11111111000000000000000000000000 ;
my $ offset = $ trap & $ offsetmask ;
my $ offsetr = $ trap & $ offsetrmask ;
my $ event_dir = $ trap & $ assertionmask ;
my $ event_type = ( $ trap & $ eventtypemask ) >> 8 ;
my $ sensor_type = ( $ trap & $ sensortypemask ) >> 16 ;
my $ reserved = ( $ trap & $ reservedmask ) >> 24 ;
if ( $ debug >= 2 ) {
printf ( "offset: %02xh\n" , $ offset ) ;
printf ( "offsetr: %02xh\n" , $ offsetr ) ;
printf ( "assertion: %02xh\n" , $ event_dir ) ;
printf ( "eventtype: %02xh\n" , $ event_type ) ;
printf ( "sensortype: %02xh\n" , $ sensor_type ) ;
printf ( "reserved: %02xh\n" , $ reserved ) ;
}
2008-03-12 02:57:01 +00:00
my @ hex = ( 0 , @ pet ) ;
2007-10-26 22:44:33 +00:00
my $ pad = $ hex [ 0 ] ;
my @ uuid = @ hex [ 1 .. 16 ] ;
my @ seqnum = @ hex [ 17 , 18 ] ;
my @ timestamp = @ hex [ 19 , 20 , 21 , 22 ] ;
my @ utcoffset = @ hex [ 23 , 24 ] ;
my $ trap_source_type = $ hex [ 25 ] ;
my $ event_source_type = $ hex [ 26 ] ;
my $ sev = $ hex [ 27 ] ;
my $ sensor_device = $ hex [ 28 ] ;
my $ sensor_num = $ hex [ 29 ] ;
my $ entity_id = $ hex [ 30 ] ;
my $ entity_instance = $ hex [ 31 ] ;
my $ event_data_1 = $ hex [ 32 ] ;
my $ event_data_2 = $ hex [ 33 ] ;
my $ event_data_3 = $ hex [ 34 ] ;
my @ event_data = @ hex [ 35 .. 39 ] ;
my $ langcode = $ hex [ 40 ] ;
my $ mfg_id = $ hex [ 41 ] + $ hex [ 42 ] * 0x100 + $ hex [ 43 ] * 0x10000 + $ hex [ 44 ] * 0x1000000 ;
my $ prod_id = $ hex [ 45 ] + $ hex [ 46 ] * 0x100 ;
my @ oem = $ hex [ 47 .. @ hex - 1 ] ;
if ( $ sev == 0x00 ) {
$ sev = "LOG" ;
}
elsif ( $ sev == 0x01 ) {
$ sev = "MONITOR" ;
}
elsif ( $ sev == 0x02 ) {
$ sev = "INFORMATION" ;
}
elsif ( $ sev == 0x04 ) {
$ sev = "OK" ;
}
elsif ( $ sev == 0x08 ) {
$ sev = "WARNING" ;
}
elsif ( $ sev == 0x10 ) {
$ sev = "CRITICAL" ;
}
elsif ( $ sev == 0x20 ) {
$ sev = "NON-RECOVERABLE" ;
}
else {
$ sev = "UNKNOWN-SEVERITY:$sev" ;
}
$ text = "$sev:" ;
( $ rc , $ type , $ desc ) = getsensorevent ( $ sensor_type , $ offset , "ipmisensorevents" ) ;
if ( $ rc == 1 ) {
$ type = "Unknown Type $sensor_type" ;
$ desc = "Unknown Event $offset" ;
$ rc = 0 ;
}
if ( $ event_type <= 0x0c ) {
my $ gtype ;
my $ gdesc ;
( $ rc , $ gtype , $ gdesc ) = getsensorevent ( $ event_type , $ offset , "ipmigenericevents" ) ;
if ( $ rc == 1 ) {
$ gtype = "Unknown Type $gtype" ;
$ gdesc = "Unknown Event $offset" ;
$ rc = 0 ;
}
$ desc = $ gdesc ;
}
if ( $ type eq "" || $ type eq "-" ) {
$ type = "OEM Sensor Type $sensor_type"
}
if ( $ desc eq "" || $ desc eq "-" ) {
$ desc = "OEM Sensor Event $offset"
}
if ( $ type eq $ desc ) {
$ desc = "" ;
}
my $ extra_info = getaddsensorevent ( $ sensor_type , $ offset , $ event_data_1 , $ event_data_2 , $ event_data_3 ) ;
if ( $ extra_info ) {
if ( $ desc ) {
$ desc = "$desc $extra_info" ;
}
else {
$ desc = "$extra_info" ;
}
}
$ text = "$text $type," ;
$ text = "$text $desc" ;
my $ key ;
my $ sensor_desc = sprintf ( "Sensor 0x%02x" , $ sensor_num ) ;
foreach $ key ( keys % sdr_hash ) {
my $ sdr = $ sdr_hash { $ key } ;
if ( $ sdr - > sensor_number == $ sensor_num ) {
$ sensor_desc = $ sdr_hash { $ key } - > id_string ;
if ( $ sdr - > rec_type == 0x01 ) {
last ;
}
}
}
$ text = "$text ($sensor_desc)" ;
if ( $ event_dir ) {
$ text = "$text - Recovered" ;
}
return ( 0 , $ text ) ;
}
2009-03-10 13:58:48 +00:00
sub readauxentry {
my $ netfn = 0x2e << 2 ;
my $ entrynum = shift ;
my $ entryls = ( $ entrynum & 0xff ) ;
my $ entryms = ( $ entrynum >> 8 ) ;
my @ cmd = ( 0x93 , 0x4d , 0x4f , 0x00 , $ entryls , $ entryms , 0 , 0 , 0xff , 0x5 ) ; #Get log size andup to 1275 bytes of data, keeping it under 1500 to accomodate mixed-mtu circumstances
my @ data ;
my $ error = docmd (
$ netfn ,
\ @ cmd ,
\ @ data
) ;
if ( $ error ) { return $ error ; }
@ data = splice @ data , 36 - $ authoffset ;
if ( $ data [ 0 ] ) { return $ data [ 0 ] ; }
my $ text ;
unless ( $ data [ 1 ] == 0x4d and $ data [ 2 ] == 0x4f and $ data [ 3 ] == 0 ) { return "Unrecognized response format" }
$ entrynum = $ data [ 6 ] + ( $ data [ 7 ] << 8 ) ;
if ( ( $ data [ 10 ] & 1 ) == 1 ) {
$ text = "POSSIBLY INCOMPLETE DATA FOLLOWS:\n" ;
}
my $ addtext = "" ;
if ( $ data [ 5 ] > 5 ) {
$ addtext = "\nTODO:SUPPORT MORE DATA THAT WAS SEEN HERE" ;
}
@ data = splice @ data , 11 ;
pop @ data ;
while ( scalar ( @ data ) ) {
2009-03-10 17:14:00 +00:00
my @ subdata = splice @ data , 0 , 30 ;
2009-03-10 13:58:48 +00:00
my $ numbytes = scalar ( @ subdata ) ;
2009-03-10 17:14:00 +00:00
my $ formatstring = "%02x" x $ numbytes ;
$ formatstring =~ s/%02x%02x/%02x%02x /g ;
$ text . = sprintf ( $ formatstring . "\n" , @ subdata ) ;
2009-03-10 13:58:48 +00:00
}
$ text . = $ addtext ;
return ( 0 , $ entrynum , $ text ) ;
}
2007-10-26 22:44:33 +00:00
sub eventlog {
my $ subcommand = shift ;
my $ netfun = 0x28 ;
my @ cmd ;
my @ returnd = ( ) ;
my $ error ;
my $ rc = 0 ;
my $ text ;
my $ code ;
my @ output ;
my $ num ;
my $ entry ;
2008-09-06 16:17:01 +00:00
my $ skiptail = 0 ;
2007-10-26 22:44:33 +00:00
my @ sel ;
#my $ipmisensoreventtab = "$ENV{XCATROOT}/lib/GUMI/ipmisensorevent.tab";
#my $ipmigenericeventtab = "$ENV{XCATROOT}/lib/GUMI/ipmigenericevent.tab";
my $ mfg_id ;
my $ prod_id ;
my $ device_id ;
( $ rc , $ text , $ mfg_id , $ prod_id , $ device_id ) = getdevid ( ) ;
$ rc = 0 ;
2008-05-05 13:47:09 +00:00
unless ( defined ( $ subcommand ) ) {
$ subcommand = 'all' ;
}
2007-10-26 22:44:33 +00:00
if ( $ subcommand eq "all" ) {
2008-09-06 16:17:01 +00:00
$ skiptail = 1 ;
2007-10-26 22:44:33 +00:00
$ num = 0x100 * 0x100 ;
}
elsif ( $ subcommand eq "clear" ) {
}
elsif ( $ subcommand =~ /^\d+$/ ) {
$ num = $ subcommand ;
}
else {
return ( 1 , "unsupported command eventlog $subcommand" ) ;
}
2008-04-07 14:52:17 +00:00
#Here we set tfactor based on the delta between the BMC reported time and our
#time. The IPMI spec says the BMC should return seconds since 1970 in local
#time, but the reality is the firmware pushing to the BMC has no context
#to know, so here we guess and adjust all timestamps based on delta between
#our now and the BMC's now
$ error = docmd (
$ netfun ,
[ 0x48 ] ,
\ @ returnd
) ;
$ tfactor = $ returnd [ 40 ] << 24 | $ returnd [ 39 ] << 16 | $ returnd [ 38 ] << 8 | $ returnd [ 37 ] ;
2008-04-07 15:49:36 +00:00
if ( $ tfactor > 0x20000000 ) {
$ tfactor -= time ( ) ;
} else {
$ tfactor = 0 ;
}
2008-04-07 14:52:17 +00:00
2007-10-26 22:44:33 +00:00
@ cmd = ( 0x40 ) ;
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
return ( $ rc , $ text ) ;
}
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code == 0x00 ) {
}
elsif ( $ code == 0x81 ) {
$ rc = 1 ;
$ text = "cannot execute command, SEL erase in progress" ;
}
else {
$ rc = 1 ;
$ text = $ codes { $ code } ;
}
if ( $ rc != 0 ) {
if ( ! $ text ) {
$ text = sprintf ( "unknown response %02x" , $ code ) ;
}
return ( $ rc , $ text ) ;
}
my $ sel_version = $ returnd [ 37 - $ authoffset ] ;
if ( $ sel_version != 0x51 ) {
$ rc = 1 ;
$ text = sprintf ( "SEL version 51h support only, version reported: %x" , $ sel_version ) ;
return ( $ rc , $ text ) ;
}
my $ num_entries = $ returnd [ 39 - $ authoffset ] * 256 + $ returnd [ 38 - $ authoffset ] ;
if ( $ num_entries <= 0 ) {
$ rc = 1 ;
$ text = "no SEL entries" ;
return ( $ rc , $ text ) ;
}
my $ canres = $ returnd [ 50 - $ authoffset ] & 0b00000010 ;
if ( ! $ canres ) {
$ rc = 1 ;
$ text = "SEL reservation not supported" ;
return ( $ rc , $ text ) ;
}
2008-09-06 16:17:01 +00:00
my $ res_id_ls = 0 ;
my $ res_id_ms = 0 ;
2009-03-10 13:58:48 +00:00
my % auxloginfo ;
2008-09-06 16:17:01 +00:00
if ( $ subcommand =~ /clear/ ) { #Don't bother with a reservation unless a clear is involved
#atomic SEL retrieval need not require it, so an event during retrieval will not kill reventlog effort off
@ cmd = ( 0x42 ) ;
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
return ( $ rc , $ text ) ;
}
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code == 0x00 ) {
}
elsif ( $ code == 0x81 ) {
$ rc = 1 ;
$ text = "cannot execute command, SEL erase in progress" ;
}
else {
$ rc = 1 ;
$ text = $ codes { $ code } ;
}
if ( $ rc != 0 ) {
if ( ! $ text ) {
$ text = sprintf ( "unknown response %02x" , $ code ) ;
}
return ( $ rc , $ text ) ;
}
2007-10-26 22:44:33 +00:00
2008-09-06 16:17:01 +00:00
$ res_id_ls = $ returnd [ 37 - $ authoffset ] ;
$ res_id_ms = $ returnd [ 38 - $ authoffset ] ;
2009-03-10 13:58:48 +00:00
} elsif ( $ mfg_id == 2 ) {
#For requests other than clear, we check for IBM extended auxillary log data
my @ auxdata ;
my $ netfn = 0xa << 2 ;
my @ auxlogcmd = ( 0x5a , 1 ) ;
$ error = docmd (
$ netfn ,
\ @ auxlogcmd ,
\ @ auxdata ) ;
@ auxdata = splice @ auxdata , 36 - $ authoffset ;
2009-09-18 19:53:48 +00:00
#print Dumper(\@auxdata);
2009-03-10 13:58:48 +00:00
unless ( $ error or $ auxdata [ 0 ] or $ auxdata [ 5 ] != 0x4d or $ auxdata [ 6 ] != 0x4f or $ auxdata [ 7 ] != 0x0 ) { #Don't bother if support cannot be confirmed by service processor
$ netfn = 0x2e << 2 ; #switch netfunctions to read
my $ numauxlogs = $ auxdata [ 8 ] + ( $ auxdata [ 9 ] << 8 ) ;
my $ auxidx = 1 ;
my $ rc ;
my $ entry ;
my $ extdata ;
while ( $ auxidx <= $ numauxlogs ) {
( $ rc , $ entry , $ extdata ) = readauxentry ( $ auxidx + + ) ;
unless ( $ rc ) {
if ( $ auxloginfo { $ entry } ) {
2009-03-10 17:14:00 +00:00
$ auxloginfo { $ entry } . = "!" . $ extdata ;
2009-03-10 13:58:48 +00:00
} else {
$ auxloginfo { $ entry } = $ extdata ;
}
}
}
if ( $ auxloginfo { 0 } ) {
if ( $ skiptail ) {
2009-03-10 17:14:00 +00:00
foreach ( split /!/ , $ auxloginfo { 0 } ) {
sendoutput ( 0 , ":Unassociated auxillary data detected:" ) ;
foreach ( split /\n/ , $ _ ) {
sendoutput ( 0 , $ _ ) ;
}
}
2009-03-10 13:58:48 +00:00
}
}
2009-09-18 19:53:48 +00:00
#print Dumper(\%auxloginfo);
2009-03-10 13:58:48 +00:00
}
2008-09-06 16:17:01 +00:00
}
2007-10-26 22:44:33 +00:00
2009-03-10 13:58:48 +00:00
2007-10-26 22:44:33 +00:00
if ( $ subcommand eq "clear" ) {
@ cmd = ( 0x47 , $ res_id_ls , $ res_id_ms , 0x43 , 0x4c , 0x52 , 0xaa ) ;
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
return ( $ rc , $ text ) ;
}
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code == 0x00 ) {
}
else {
$ rc = 1 ;
$ text = $ codes { $ code } ;
}
if ( $ rc != 0 ) {
if ( ! $ text ) {
$ text = sprintf ( "unknown response %02x" , $ code ) ;
}
return ( $ rc , $ text ) ;
}
my $ erase_status = $ returnd [ 37 - $ authoffset ] & 0b00000001 ;
#skip test for now, need to get new res id for some machines
while ( $ erase_status == 0 && 0 ) {
sleep ( 1 ) ;
@ cmd = ( 0x47 , $ res_id_ls , $ res_id_ms , 0x43 , 0x4c , 0x52 , 0x00 ) ;
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
return ( $ rc , $ text ) ;
}
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code == 0x00 ) {
}
else {
$ rc = 1 ;
$ text = $ codes { $ code } ;
}
if ( $ rc != 0 ) {
if ( ! $ text ) {
$ text = sprintf ( "unknown response %02x" , $ code ) ;
}
return ( $ rc , $ text ) ;
}
$ erase_status = $ returnd [ 37 - $ authoffset ] & 0b00000001 ;
}
$ text = "SEL cleared" ;
return ( $ rc , $ text ) ;
}
( $ rc , $ text ) = initsdr ( ) ;
if ( $ rc != 0 ) {
return ( $ rc , $ text ) ;
}
@ cmd = ( 0x43 , $ res_id_ls , $ res_id_ms , 0x00 , 0x00 , 0x00 , 0xFF ) ;
while ( 1 ) {
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
2008-09-06 16:17:01 +00:00
if ( $ skiptail ) {
sendoutput ( $ rc , $ text ) ;
return ;
}
push ( @ output , $ text ) ;
2008-02-12 20:05:12 +00:00
return ( $ rc , @ output ) ;
2007-10-26 22:44:33 +00:00
}
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code == 0x00 ) {
}
elsif ( $ code == 0x81 ) {
$ rc = 1 ;
$ text = "cannot execute command, SEL erase in progress" ;
}
else {
$ rc = 1 ;
$ text = $ codes { $ code } ;
}
if ( $ rc != 0 ) {
if ( ! $ text ) {
$ text = sprintf ( "unknown response %02x" , $ code ) ;
}
2008-09-06 16:17:01 +00:00
if ( $ skiptail ) {
sendoutput ( $ rc , $ text ) ;
return ;
}
push ( @ output , $ text ) ;
2008-02-12 20:05:12 +00:00
return ( $ rc , @ output ) ;
2007-10-26 22:44:33 +00:00
}
my $ next_rec_ls = $ returnd [ 37 - $ authoffset ] ;
my $ next_rec_ms = $ returnd [ 38 - $ authoffset ] ;
my @ sel_data = @ returnd [ 39 - $ authoffset .. 39 - $ authoffset + 16 ] ;
@ cmd = ( 0x43 , $ res_id_ls , $ res_id_ms , $ next_rec_ls , $ next_rec_ms , 0x00 , 0xFF ) ;
$ entry + + ;
2008-09-06 16:17:01 +00:00
if ( $ debug ) {
2007-10-26 22:44:33 +00:00
print "$entry: " ;
hexdump ( \ @ sel_data ) ;
2008-09-06 16:17:01 +00:00
}
2007-10-26 22:44:33 +00:00
my $ record_id = $ sel_data [ 0 ] + $ sel_data [ 1 ] * 256 ;
my $ record_type = $ sel_data [ 2 ] ;
if ( $ record_type == 0x02 ) {
}
else {
$ text = getoemevent ( $ record_type , $ mfg_id , \ @ sel_data ) ;
2009-03-10 13:58:48 +00:00
if ( $ auxloginfo { $ entry } ) {
$ text . = " With additional data:\n" . $ auxloginfo { $ entry } ;
}
2008-09-06 16:17:01 +00:00
if ( $ skiptail ) {
sendoutput ( $ rc , $ text ) ;
} else {
push ( @ output , $ text ) ;
}
2007-10-26 22:44:33 +00:00
if ( $ next_rec_ms == 0xFF && $ next_rec_ls == 0xFF ) {
last ;
}
next ;
}
2008-04-07 15:31:27 +00:00
my $ timestamp = ( $ sel_data [ 3 ] | $ sel_data [ 4 ] << 8 | $ sel_data [ 5 ] << 16 | $ sel_data [ 6 ] << 24 ) ;
2008-09-06 16:17:01 +00:00
unless ( $ timestamp < 0x20000000 ) { #IPMI Spec says below this is effectively BMC uptime, not correctable
$ timestamp -= $ tfactor ; #apply correction factor based on how off the current BMC clock is from management server
2008-04-07 15:31:27 +00:00
}
2007-10-26 22:44:33 +00:00
my ( $ seldate , $ seltime ) = timestamp2datetime ( $ timestamp ) ;
# $text = "$entry: $seldate $seltime";
$ text = ":$seldate $seltime" ;
# my $gen_id_slave_addr = ($sel_data[7] & 0b11111110) >> 1;
# my $gen_id_slave_addr_hs = ($sel_data[7] & 0b00000001);
# my $gen_id_ch_num = ($sel_data[8] & 0b11110000) >> 4;
# my $gen_id_ipmb = ($sel_data[8] & 0b00000011);
my $ sensor_owner_id = $ sel_data [ 7 ] ;
my $ sensor_owner_lun = $ sel_data [ 8 ] ;
my $ sensor_type = $ sel_data [ 10 ] ;
my $ sensor_num = $ sel_data [ 11 ] ;
my $ event_dir = $ sel_data [ 12 ] & 0b10000000 ;
my $ event_type = $ sel_data [ 12 ] & 0b01111111 ;
my $ offset = $ sel_data [ 13 ] & 0b00001111 ;
my $ event_data_1 = $ sel_data [ 13 ] ;
my $ event_data_2 = $ sel_data [ 14 ] ;
my $ event_data_3 = $ sel_data [ 15 ] ;
my $ sev = 0 ;
$ sev = ( $ sel_data [ 14 ] & 0b11110000 ) >> 4 ;
# if($event_type != 1) {
# $sev = ($sel_data[14] & 0b11110000) >> 4;
# }
# $text = "$text $sev:";
my $ type ;
my $ desc ;
( $ rc , $ type , $ desc ) = getsensorevent ( $ sensor_type , $ offset , "ipmisensorevents" ) ;
if ( $ rc == 1 ) {
$ type = "Unknown Type $sensor_type" ;
$ desc = "Unknown Event $offset" ;
$ rc = 0 ;
}
if ( $ event_type <= 0x0c ) {
my $ gtype ;
my $ gdesc ;
( $ rc , $ gtype , $ gdesc ) = getsensorevent ( $ event_type , $ offset , "ipmigenericevents" ) ;
if ( $ rc == 1 ) {
$ gtype = "Unknown Type $gtype" ;
$ gdesc = "Unknown Event $offset" ;
$ rc = 0 ;
}
$ desc = $ gdesc ;
}
if ( $ type eq "" || $ type eq "-" ) {
$ type = "OEM Sensor Type $sensor_type"
}
if ( $ desc eq "" || $ desc eq "-" ) {
$ desc = "OEM Sensor Event $offset"
}
if ( $ type eq $ desc ) {
$ desc = "" ;
}
my $ extra_info = getaddsensorevent ( $ sensor_type , $ offset , $ event_data_1 , $ event_data_2 , $ event_data_3 ) ;
if ( $ extra_info ) {
if ( $ desc ) {
$ desc = "$desc $extra_info" ;
}
else {
$ desc = "$extra_info" ;
}
}
$ text = "$text $type," ;
$ text = "$text $desc" ;
# my $key;
my $ key = $ sensor_owner_id . "." . $ sensor_owner_lun . "." . $ sensor_num ;
my $ sensor_desc = sprintf ( "Sensor 0x%02x" , $ sensor_num ) ;
# foreach $key (keys %sdr_hash) {
# my $sdr = $sdr_hash{$key};
# if($sdr->sensor_number == $sensor_num) {
# $sensor_desc = $sdr_hash{$key}->id_string;
# last;
# }
# }
if ( defined $ sdr_hash { $ key } ) {
$ sensor_desc = $ sdr_hash { $ key } - > id_string ;
2008-02-12 21:34:57 +00:00
if ( $ sdr_hash { $ key } - > event_type_code == 1 ) {
if ( ( $ event_data_1 & 0b11000000 ) == 0b01000000 ) {
$ sensor_desc . = " reading " . translate_sensor ( $ event_data_2 , $ sdr_hash { $ key } ) ;
if ( ( $ event_data_1 & 0b00110000 ) == 0b00010000 ) {
$ sensor_desc . = " with threshold " . translate_sensor ( $ event_data_3 , $ sdr_hash { $ key } ) ;
}
}
}
2007-10-26 22:44:33 +00:00
}
$ text = "$text ($sensor_desc)" ;
if ( $ event_dir ) {
$ text = "$text - Recovered" ;
}
2009-03-10 13:58:48 +00:00
if ( $ auxloginfo { $ entry } ) {
2009-03-10 17:14:00 +00:00
$ text . = " with additional data:" ;
if ( $ skiptail ) {
sendoutput ( $ rc , $ text ) ;
foreach ( split /\n/ , $ auxloginfo { $ entry } ) {
sendoutput ( 0 , $ _ ) ;
}
} else {
push ( @ output , $ text ) ;
push @ output , split /\n/ , $ auxloginfo { $ entry } ;
}
2008-09-06 16:17:01 +00:00
} else {
2009-03-10 17:14:00 +00:00
if ( $ skiptail ) {
sendoutput ( $ rc , $ text ) ;
} else {
push ( @ output , $ text ) ;
}
2008-09-06 16:17:01 +00:00
}
2007-10-26 22:44:33 +00:00
if ( $ next_rec_ms == 0xFF && $ next_rec_ls == 0xFF ) {
last ;
}
}
my @ routput = reverse ( @ output ) ;
my @ noutput ;
my $ c ;
foreach ( @ routput ) {
$ c + + ;
if ( $ c > $ num ) {
last ;
}
push ( @ noutput , $ _ ) ;
}
@ output = reverse ( @ noutput ) ;
return ( $ rc , @ output ) ;
}
sub getoemevent {
my $ record_type = shift ;
my $ mfg_id = shift ;
my $ sel_data = shift ;
2008-04-07 15:11:56 +00:00
my $ text = ":" ;
2007-10-26 22:44:33 +00:00
if ( $ record_type < 0xE0 && $ record_type > 0x2F ) { #Should be timestampped, whatever it is
2008-04-07 15:31:27 +00:00
my $ timestamp = ( @$ sel_data [ 3 ] | @$ sel_data [ 4 ] << 8 | @$ sel_data [ 5 ] << 16 | @$ sel_data [ 6 ] << 24 ) ;
unless ( $ timestamp < 0x20000000 ) {
$ timestamp -= $ tfactor ;
}
2007-10-26 22:44:33 +00:00
my ( $ seldate , $ seltime ) = timestamp2datetime ( $ timestamp ) ;
my @ rest = @$ sel_data [ 7 .. 15 ] ;
if ( $ mfg_id == 2 ) {
2008-04-07 15:11:56 +00:00
$ text . = "$seldate $seltime IBM OEM Event-" ;
2007-10-26 22:44:33 +00:00
if ( $ rest [ 3 ] == 0 && $ rest [ 4 ] == 0 && $ rest [ 7 ] == 0 ) {
$ text = $ text . "PCI Event/Error, details in next event"
} elsif ( $ rest [ 3 ] == 1 && $ rest [ 4 ] == 0 && $ rest [ 7 ] == 0 ) {
$ text = $ text . "Processor Event/Error occurred, details in next event"
} elsif ( $ rest [ 3 ] == 2 && $ rest [ 4 ] == 0 && $ rest [ 7 ] == 0 ) {
$ text = $ text . "Memory Event/Error occurred, details in next event"
} elsif ( $ rest [ 3 ] == 3 && $ rest [ 4 ] == 0 && $ rest [ 7 ] == 0 ) {
$ text = $ text . "Scalability Event/Error occurred, details in next event"
} elsif ( $ rest [ 3 ] == 4 && $ rest [ 4 ] == 0 && $ rest [ 7 ] == 0 ) {
$ text = $ text . "PCI bus Event/Error occurred, details in next event"
} elsif ( $ rest [ 3 ] == 5 && $ rest [ 4 ] == 0 && $ rest [ 7 ] == 0 ) {
$ text = $ text . "Chipset Event/Error occurred, details in next event"
} elsif ( $ rest [ 3 ] == 6 && $ rest [ 4 ] == 1 && $ rest [ 7 ] == 0 ) {
$ text = $ text . "BIOS/BMC Power Executive mismatch (BIOS $rest[5], BMC $rest[6])"
} elsif ( $ rest [ 3 ] == 6 && $ rest [ 4 ] == 2 && $ rest [ 7 ] == 0 ) {
$ text = $ text . "Boot denied due to power limitations"
} else {
$ text = $ text . "Unknown event " . phex ( \ @ rest ) ;
}
} else {
2008-04-07 15:11:56 +00:00
$ text . = "$seldate $seltime " . sprintf ( "Unknown OEM SEL Type %02x:" , $ record_type ) . phex ( \ @ rest ) ;
2007-10-26 22:44:33 +00:00
}
} else { #Non-timestamped
my % memerrors = (
0x00 = > "DIMM enabled" ,
0x01 = > "DIMM disabled, failed ECC test" ,
0x02 = > "POST/BIOS memory test failed, DIMM disabled" ,
0x03 = > "DIMM disabled, non-supported memory device" ,
0x04 = > "DIMM disabled, non-matching or missing DIMM(s)" ,
) ;
my % pcierrors = (
0x00 = > "Device OK" ,
0x01 = > "Required ROM space not available" ,
0x02 = > "Required I/O Space not available" ,
0x03 = > "Required memory not available" ,
0x04 = > "Required memory below 1MB not available" ,
0x05 = > "ROM checksum failed" ,
0x06 = > "BIST failed" ,
0x07 = > "Planar device missing or disabled by user" ,
0x08 = > "PCI device has an invalid PCI configuration space header" ,
0x09 = > "FRU information for added PCI device" ,
0x0a = > "FRU information for removed PCI device" ,
0x0b = > "A PCI device was added, PCI FRU information is stored in next log entry" ,
0x0c = > "A PCI device was removed, PCI FRU information is stored in next log entry" ,
0x0d = > "Requested resources not available" ,
0x0e = > "Required I/O Space Not Available" ,
0x0f = > "Required I/O Space Not Available" ,
0x10 = > "Required I/O Space Not Available" ,
0x11 = > "Required I/O Space Not Available" ,
0x12 = > "Required I/O Space Not Available" ,
0x13 = > "Planar video disabled due to add in video card" ,
0x14 = > "FRU information for PCI device partially disabled " ,
0x15 = > "A PCI device was partially disabled, PCI FRU information is stored in next log entry" ,
0x16 = > "A 33Mhz device is installed on a 66Mhz bus, PCI device information is stored in next log entry" ,
0x17 = > "FRU information, 33Mhz device installed on 66Mhz bus" ,
0x18 = > "Merge cable missing" ,
0x19 = > "Node 1 to Node 2 cable missing" ,
0x1a = > "Node 1 to Node 3 cable missing" ,
0x1b = > "Node 2 to Node 3 cable missing" ,
0x1c = > "Nodes could not merge" ,
0x1d = > "No 8 way SMP cable" ,
0x1e = > "Primary North Bridge to PCI Host Bridge IB Link has failed" ,
0x1f = > "Redundant PCI Host Bridge IB Link has failed" ,
) ;
my % procerrors = (
0x00 = > "Processor has failed BIST" ,
0x01 = > "Unable to apply processor microcode update" ,
0x02 = > "POST does not support current stepping level of processor" ,
0x03 = > "CPU mismatch detected" ,
) ;
my @ rest = @$ sel_data [ 3 .. 15 ] ;
if ( $ record_type == 0xE0 && $ rest [ 0 ] == 2 && $ mfg_id == 2 && $ rest [ 1 ] == 0 && $ rest [ 12 ] == 1 ) { #Rev 1 POST memory event
$ text = "IBM Memory POST Event-" ;
my $ msuffix = sprintf ( ", chassis %d, card %d, dimm %d" , $ rest [ 3 ] , $ rest [ 4 ] , $ rest [ 5 ] ) ;
#the next bit is a basic lookup table, should implement as a table ala ibmleds.tab, or a hash... yeah, a hash...
$ text = $ text . $ memerrors { $ rest [ 2 ] } . $ msuffix ;
} elsif ( $ record_type == 0xE0 && $ rest [ 0 ] == 1 && $ mfg_id == 2 && $ rest [ 12 ] == 0 ) { #A processor error or event, rev 0 only known in the spec I looked at
$ text = $ text . $ procerrors { $ rest [ 1 ] } ;
} elsif ( $ record_type == 0xE0 && $ rest [ 0 ] == 0 && $ mfg_id == 2 ) { #A PCI error or event, rev 1 or 2, the revs differe in endianness
my $ msuffix ;
if ( $ rest [ 12 ] == 0 ) {
$ msuffix = sprintf ( "chassis %d, slot %d, bus %s, device %02x%02x:%02x%02x" , $ rest [ 2 ] , $ rest [ 3 ] , $ rest [ 4 ] , $ rest [ 5 ] , $ rest [ 6 ] , $ rest [ 7 ] , $ rest [ 8 ] ) ;
} elsif ( $ rest [ 12 ] == 1 ) {
$ msuffix = sprintf ( "chassis %d, slot %d, bus %s, device %02x%02x:%02x%02x" , $ rest [ 2 ] , $ rest [ 3 ] , $ rest [ 4 ] , $ rest [ 5 ] , $ rest [ 6 ] , $ rest [ 7 ] , $ rest [ 8 ] ) ;
} else {
return ( "Unknown IBM PCI event/error format" ) ;
}
$ text = $ text . $ pcierrors { $ rest [ 1 ] } . $ msuffix ;
} else {
#Some event we can't define that is OEM or some otherwise unknown event
$ text = sprintf ( "SEL Type %02x:" , $ record_type ) . phex ( \ @ rest ) ;
}
} #End timestampped intepretation
return ( $ text ) ;
}
sub getsensorevent
{
my $ sensortype = sprintf ( "%02Xh" , shift ) ;
my $ sensoroffset = sprintf ( "%02Xh" , shift ) ;
my $ file = shift ;
my @ line ;
my $ type ;
my $ code ;
my $ desc ;
my $ offset ;
my $ rc = 1 ;
if ( $ file eq "ipmigenericevents" ) {
if ( $ xCAT:: data:: ipmigenericevents:: ipmigenericevents { "$sensortype,$sensoroffset" } ) {
( $ type , $ desc ) = split ( /,/ , $ xCAT:: data:: ipmigenericevents:: ipmigenericevents { "$sensortype,$sensoroffset" } , 2 ) ;
return ( 0 , $ type , $ desc ) ;
}
if ( $ xCAT:: data:: ipmigenericevents:: ipmigenericevents { "$sensortype,-" } ) {
( $ type , $ desc ) = split ( /,/ , $ xCAT:: data:: ipmigenericevents:: ipmigenericevents { "$sensortype,-" } , 2 ) ;
return ( 0 , $ type , $ desc ) ;
}
}
if ( $ file eq "ipmisensorevents" ) {
if ( $ xCAT:: data:: ipmisensorevents:: ipmisensorevents { "$sensortype,$sensoroffset" } ) {
( $ type , $ desc ) = split ( /,/ , $ xCAT:: data:: ipmisensorevents:: ipmisensorevents { "$sensortype,$sensoroffset" } , 2 ) ;
return ( 0 , $ type , $ desc ) ;
}
if ( $ xCAT:: data:: ipmisensorevents:: ipmisensorevents { "$sensortype,-" } ) {
( $ type , $ desc ) = split ( /,/ , $ xCAT:: data:: ipmisensorevents:: ipmisensorevents { "$sensortype,-" } , 2 ) ;
return ( 0 , $ type , $ desc ) ;
}
}
2008-09-06 14:48:24 +00:00
return ( 0 , "No Mappings found ($sensortype)" , "No Mappings found ($sensoroffset)" ) ;
2007-10-26 22:44:33 +00:00
}
sub getaddsensorevent {
my $ sensor_type = shift ;
my $ offset = shift ;
my $ event_data_1 = shift ;
my $ event_data_2 = shift ;
my $ event_data_3 = shift ;
my $ text = "" ;
2008-09-06 18:22:55 +00:00
if ( $ sensor_type == 0x08 && $ offset == 6 ) {
my % extra = (
0x0 = > "Vendor mismatch" ,
0x1 = > "Revision mismatch" ,
0x2 = > "Processor missing" ,
) ;
if ( $ extra { $ event_data_3 } ) {
$ text = $ extra { $ event_data_3 } ;
}
}
if ( $ sensor_type == 0x0C ) {
$ text = sprintf ( "Memory module %d" , $ event_data_3 ) ;
}
2007-10-26 22:44:33 +00:00
if ( $ sensor_type == 0x0f ) {
if ( $ offset == 0x00 ) {
my % extra = (
0x00 = > "Unspecified" ,
0x01 = > "No system memory installed" ,
0x02 = > "No usable system memory" ,
0x03 = > "Unrecoverable hard disk failure" ,
0x04 = > "Unrecoverable system board failure" ,
0x05 = > "Unrecoverable diskette failure" ,
0x06 = > "Unrecoverable hard disk controller failure" ,
0x07 = > "Unrecoverable keyboard failure" ,
0x08 = > "Removable boot media not found" ,
0x09 = > "Unrecoverable video controller failure" ,
0x0a = > "No video device detected" ,
0x0b = > "Firmware (BIOS) ROM corruption detected" ,
0x0c = > "CPU voltage mismatch" ,
2008-02-12 21:34:57 +00:00
0x0d = > "CPU speed matching failure" ,
2007-10-26 22:44:33 +00:00
) ;
$ text = $ extra { $ event_data_2 } ;
}
if ( $ offset == 0x02 ) {
my % extra = (
0x00 = > "Unspecified" ,
0x01 = > "Memory initialization" ,
0x02 = > "Hard-disk initialization" ,
0x03 = > "Secondary processor(s) initialization" ,
0x04 = > "User authentication" ,
0x05 = > "User-initiated system setup" ,
0x06 = > "USB resource configuration" ,
0x07 = > "PCI resource configuration" ,
0x08 = > "Option ROM initialization" ,
0x09 = > "Video initialization" ,
0x0a = > "Cache initialization" ,
0x0b = > "SM Bus initialization" ,
0x0c = > "Keyboard controller initialization" ,
0x0d = > "Embedded controller/management controller initialization" ,
0x0e = > "Docking station attachement" ,
0x0f = > "Enabling docking station" ,
0x10 = > "Docking staion ejection" ,
0x11 = > "Disable docking station" ,
0x12 = > "Calling operation system wake-up vector" ,
0x13 = > "Starting operation system boot process, call init 19h" ,
0x14 = > "Baseboard or motherboard initialization" ,
0x16 = > "Floppy initialization" ,
0x17 = > "Keyboard test" ,
0x18 = > "Pointing device test" ,
0x19 = > "Primary processor initialization" ,
) ;
$ text = $ extra { $ event_data_2 } ;
}
}
2008-09-06 18:22:55 +00:00
if ( $ sensor_type == 0x10 ) {
if ( $ offset == 0x0 ) {
$ text = sprintf ( "Memory module %d" , $ event_data_2 ) ;
} elsif ( $ offset == 0x01 ) {
$ text = "Disabled for " ;
unless ( $ event_data_3 & 0x20 ) {
if ( $ event_data_3 & 0x10 ) {
$ text . = "assertions of" ;
} else {
$ text . = "deassertions of" ;
}
}
$ text . = sprintf ( "type %02xh/offset %02xh" , $ event_data_2 , $ event_data_3 & 0x0F ) ;
} elsif ( $ offset == 0x05 ) {
$ text = "$event_data_3% full" ;
}
}
2007-10-26 22:44:33 +00:00
if ( $ sensor_type == 0x12 ) {
if ( $ offset == 0x03 ) {
}
if ( $ offset == 0x04 ) {
if ( $ event_data_2 & 0b00100000 ) {
$ text = "$text, NMI" ;
}
if ( $ event_data_2 & 0b00010000 ) {
$ text = "$text, OEM action" ;
}
if ( $ event_data_2 & 0b00001000 ) {
$ text = "$text, power cycle" ;
}
if ( $ event_data_2 & 0b00000100 ) {
$ text = "$text, reset" ;
}
if ( $ event_data_2 & 0b00000010 ) {
$ text = "$text, power off" ;
}
if ( $ event_data_2 & 0b00000001 ) {
$ text = "$text, Alert" ;
}
$ text =~ s/^, // ;
}
}
2008-09-06 19:09:49 +00:00
if ( $ sensor_type == 0x1d && $ offset == 0x07 ) {
my % causes = (
0 = > "Unknown" ,
1 = > "Chassis reset via User command to BMC" ,
2 = > "Reset button" ,
3 = > "Power button" ,
4 = > "Watchdog action" ,
5 = > "OEM" ,
6 = > "AC Power apply force on" ,
7 = > "Restore previous power state on AC" ,
8 = > "PEF initiated reset" ,
9 = > "PEF initiated power cycle" ,
10 = > "Soft reboot" ,
11 = > "RTC Wake" ,
) ;
if ( $ causes { $ event_data_2 & 0xf } ) {
$ text = $ causes { $ event_data_2 } ;
} else {
$ text = "Unrecognized cause " . $ event_data_2 & 0xf ;
}
$ text . = "via channel $event_data_3" ;
}
2008-09-06 18:22:55 +00:00
if ( $ sensor_type == 0x21 ) {
my % extra = (
0 = > "PCI slot" ,
1 = > "Drive array" ,
2 = > "External connector" ,
3 = > "Docking port" ,
4 = > "Other slot" ,
5 = > "Sensor ID" ,
6 = > "AdvncedTCA" ,
7 = > "Memory slot" ,
8 = > "FAN" ,
9 = > "PCIe" ,
10 = > "SCSI" ,
11 = > "SATA/SAS" ,
) ;
$ text = $ extra { $ event_data_2 & 127 } ;
unless ( $ text ) {
$ text = "Unknown slot/conn type " . $ event_data_2 & 127 ;
}
$ text . = " $event_data_3" ;
}
if ( $ sensor_type == 0x23 ) {
my % extra = (
0x10 = > "SMI" ,
0x20 = > "NMI" ,
0x30 = > "Messaging Interrupt" ,
0xF0 = > "Unspecified" ,
0x01 = > "BIOS FRB2" ,
0x02 = > "BIOS/POST" ,
0x03 = > "OS Load" ,
0x04 = > "SMS/OS" ,
0x05 = > "OEM" ,
0x0F = > "Unspecified"
) ;
if ( $ extra { $ event_data_2 & 0xF0 } ) {
$ text = $ extra { $ event_data_2 & 0xF0 } ;
}
if ( $ extra { $ event_data_2 & 0x0F } ) {
$ text . = ", " . $ extra { $ event_data_2 & 0x0F } ;
}
$ text =~ s/^, // ;
}
2008-09-06 19:09:49 +00:00
if ( $ sensor_type == 0x28 ) {
if ( $ offset == 0x4 ) {
$ text = "Sensor $event_data_2" ;
} elsif ( $ offset == 0x5 ) {
$ text = "" ;
my $ logicalfru = 0 ;
if ( $ event_data_2 & 128 ) {
$ logicalfru = 1 ;
}
my $ intelligent = 1 ;
if ( $ event_data_2 & 24 ) {
$ text . = "LUN " . ( $ event_data_2 & 24 ) >> 3 ;
} else {
$ intelligent = 0 ;
}
if ( $ event_data_2 & 7 ) {
$ text . = "Bus ID " . ( $ event_data_2 & 7 ) ;
}
if ( $ logicalfru ) {
$ text . = "FRU ID " . $ event_data_3 ;
} elsif ( not $ intelligent ) {
$ text . = "I2C addr " . $ event_data_3 >> 1 ;
}
}
}
2008-09-06 18:22:55 +00:00
if ( $ sensor_type == 0x2a ) {
$ text = sprintf ( "Channel %d, User %d" , $ event_data_3 & 0x0f , $ event_data_2 & 0x3f ) ;
if ( $ offset == 1 ) {
if ( ( $ event_data_3 & 207 ) == 1 ) {
$ text . = " at user request" ;
} elsif ( ( $ event_data_3 & 207 ) == 2 ) {
$ text . = " timed out" ;
} elsif ( ( $ event_data_3 & 207 ) == 3 ) {
$ text . = " configuration change" ;
}
}
}
if ( $ sensor_type == 0x2b ) {
my % extra = (
0x0 = > "Unspecified" ,
0x1 = > "BMC device ID" ,
0x2 = > "BMC Firmware" ,
0x3 = > "BMC Hardware" ,
0x4 = > "BMC manufacturer" ,
0x5 = > "IPMI Version" ,
0x6 = > "BMC aux firmware ID" ,
0x7 = > "BMC boot block" ,
0x8 = > "Other BMC Firmware" ,
0x09 = > "BIOS/EFI change" ,
0x0a = > "SMBIOS change" ,
0x0b = > "OS change" ,
0x0c = > "OS Loader change" ,
0x0d = > "Diagnostics change" ,
0x0e = > "Management agent change" ,
0x0f = > "Management software change" ,
0x10 = > "Management middleware change" ,
0x11 = > "FPGA/CPLD/PSoC change" ,
0x12 = > "FRU change" ,
0x13 = > "device addition/removal" ,
0x14 = > "Equivalent replacement" ,
0x15 = > "Newer replacement" ,
0x16 = > "Older replacement" ,
0x17 = > "DIP/Jumper change" ,
) ;
if ( $ extra { $ event_data_2 } ) {
$ text = $ extra { $ event_data_2 } ;
} else {
$ text = "Unknown version change type $event_data_2" ;
}
}
if ( $ sensor_type == 0x2c ) {
my % extra = (
0 = > "" ,
1 = > "Software dictated" ,
2 = > "Latch operated" ,
3 = > "Hotswap buton pressed" ,
4 = > "automatic operation" ,
5 = > "Communication lost" ,
6 = > "Communication lost locally" ,
7 = > "Unexpected removal" ,
8 = > "Operator intervention" ,
9 = > "Unknwon IPMB address" ,
10 = > "Unexpected deactivation" ,
0xf = > "unknown" ,
) ;
if ( $ extra { $ event_data_2 >> 4 } ) {
$ text = $ extra { $ event_data_2 >> 4 } ;
} else {
$ text = "Unrecognized cause " . $ event_data_2 >> 4 ;
}
my $ prev_state = $ event_data_2 & 0xf ;
unless ( $ prev_state == $ offset ) {
my % oldstates = (
0 = > "Not Installed" ,
1 = > "Inactive" ,
2 = > "Activation requested" ,
3 = > "Activating" ,
4 = > "Active" ,
5 = > "Deactivation requested" ,
6 = > "Deactivating" ,
7 = > "Communication lost" ,
) ;
if ( $ oldstates { $ prev_state } ) {
$ text . = "(was " . $ oldstates { $ prev_state } . ")" ;
} else {
$ text . = "(was in unrecognized state $prev_state)" ;
}
}
}
2007-10-26 22:44:33 +00:00
return ( $ text ) ;
}
sub checkleds {
my $ netfun = 0xe8 ; #really 0x3a
my @ cmd ;
my @ returnd = ( ) ;
my $ error ;
my $ led_id_ms ;
my $ led_id_ls ;
my $ rc = 0 ;
my @ output = ( ) ;
my $ text = "" ;
my $ key ;
my $ mfg_id ;
my $ prod_id ;
( $ rc , $ text , $ mfg_id , $ prod_id ) = getdevid ( ) ;
if ( $ mfg_id != 2 ) {
2008-03-26 13:34:39 +00:00
return ( 0 , "LED status not supported on this system" ) ;
2007-10-26 22:44:33 +00:00
}
( $ rc , $ text ) = initsdr ( ) ;
if ( $ rc != 0 ) {
return ( $ rc , $ text ) ;
}
foreach $ key ( sort { $ sdr_hash { $ a } - > id_string cmp $ sdr_hash { $ b } - > id_string } keys % sdr_hash ) {
my $ sdr = $ sdr_hash { $ key } ;
2009-03-07 02:04:21 +00:00
if ( $ sdr - > rec_type == 0xC0 && $ sdr - > sensor_type == 0xED ) {
2007-10-26 22:44:33 +00:00
#this stuff is to help me build the file from spec paste
#my $tehstr=sprintf("grep 0x%04X /opt/xcat/lib/x3755led.tab",$sdr->led_id);
#my $tehstr=`$tehstr`;
#$tehstr =~ s/^0x....//;
#printf("%X.%X.0x%04x",$mfg_id,$prod_id,$sdr->led_id);
#print $tehstr;
#We are inconsistant in our spec, first try a best guess
#at endianness, assume the smaller value is MSB
if ( ( $ sdr - > led_id & 0xff ) > ( $ sdr - > led_id >> 8 ) ) {
$ led_id_ls = $ sdr - > led_id & 0xff ;
$ led_id_ms = $ sdr - > led_id >> 8 ;
} else {
$ led_id_ls = $ sdr - > led_id >> 8 ;
$ led_id_ms = $ sdr - > led_id & 0xff ;
}
@ cmd = ( 0xc0 , $ led_id_ms , $ led_id_ls ) ;
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
return ( $ rc , $ text ) ;
}
if ( $ returnd [ 36 - $ authoffset ] == 0xc9 ) {
my $ tmp ;
#we probably guessed endianness wrong.
$ tmp = $ led_id_ls ;
$ led_id_ls = $ led_id_ms ;
$ led_id_ms = $ tmp ;
@ cmd = ( 0xc0 , $ led_id_ms , $ led_id_ls ) ;
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
return ( $ rc , $ text ) ;
}
}
2009-03-07 02:04:21 +00:00
if ( $ returnd [ 38 - $ authoffset ] ) { # != 0) {
2007-10-26 22:44:33 +00:00
#It's on...
if ( $ returnd [ 42 - $ authoffset ] == 4 ) {
2008-03-03 20:51:36 +00:00
push ( @ output , sprintf ( "BIOS or admininstrator has %s lit" , getsensorname ( $ mfg_id , $ prod_id , $ sdr - > led_id , "ibmleds" ) ) ) ;
2007-10-26 22:44:33 +00:00
}
elsif ( $ returnd [ 42 - $ authoffset ] == 3 ) {
push ( @ output , sprintf ( "A user has manually requested LED 0x%04x (%s) be active" , $ sdr - > led_id , getsensorname ( $ mfg_id , $ prod_id , $ sdr - > led_id , "ibmleds" ) ) ) ;
}
elsif ( $ returnd [ 42 - $ authoffset ] == 1 && $ sdr - > led_id != 0 ) {
push ( @ output , sprintf ( "LED 0x%02x%02x (%s) active to indicate LED 0x%02x%02x (%s) is active" , $ led_id_ms , $ led_id_ls , getsensorname ( $ mfg_id , $ prod_id , $ sdr - > led_id , "ibmleds" ) , $ returnd [ 40 - $ authoffset ] , $ returnd [ 41 - $ authoffset ] , getsensorname ( $ mfg_id , $ prod_id , ( $ returnd [ 40 - $ authoffset ] << 8 ) + $ returnd [ 41 - $ authoffset ] , "ibmleds" ) ) ) ;
}
elsif ( $ sdr - > led_id == 0 ) {
push ( @ output , sprintf ( "LED 0x0000 (%s) active to indicate system error condition." , getsensorname ( $ mfg_id , $ prod_id , $ sdr - > led_id , "ibmleds" ) ) ) ;
}
elsif ( $ returnd [ 42 - $ authoffset ] == 2 ) {
my $ sensor_desc ;
#Ok, LED is tied to a sensor..
my $ sensor_num = $ returnd [ 41 - $ authoffset ] ;
foreach $ key ( keys % sdr_hash ) {
my $ osdr = $ sdr_hash { $ key } ;
if ( $ osdr - > sensor_number == $ sensor_num ) {
$ sensor_desc = $ sdr_hash { $ key } - > id_string ;
if ( $ osdr - > rec_type == 0x01 ) {
last ;
}
}
}
$ rc = 0 ;
#push(@output,sprintf("Sensor 0x%02x (%s) has activated LED 0x%04x",$sensor_num,$sensor_desc,$sdr->led_id));
push ( @ output , sprintf ( "LED 0x%02x%02x active to indicate Sensor 0x%02x (%s) error." , $ led_id_ms , $ led_id_ls , $ sensor_num , $ sensor_desc ) ) ;
}
}
}
}
if ( $# output == - 1 ) {
push ( @ output , "No active error LEDs detected" ) ;
}
return ( $ rc , @ output ) ;
}
sub vitals {
my $ subcommand = shift ;
my $ rc = 0 ;
my $ text ;
my $ key ;
my @ sensor_filters = ( 0x00 ) ;
my @ output ;
my $ reading ;
my $ unitdesc ;
my $ value ;
2009-03-24 20:01:36 +00:00
my $ extext ;
2007-10-26 22:44:33 +00:00
my $ format = "%-30s%8s %-20s" ;
my $ per = " " ;
2008-03-03 20:51:36 +00:00
my $ doall ;
$ doall = 0 ;
2007-10-26 22:44:33 +00:00
$ rc = 0 ;
if ( $ subcommand eq "all" ) {
2008-03-03 20:51:36 +00:00
@ sensor_filters = ( 0x01 ) ; #,0x02,0x03,0x04);
$ doall = 1 ;
2007-10-26 22:44:33 +00:00
}
elsif ( $ subcommand =~ /temp/ ) {
@ sensor_filters = ( 0x01 ) ;
}
elsif ( $ subcommand eq "voltage" ) {
2007-11-19 20:24:58 +00:00
@ sensor_filters = ( 0x02 ) ;
2007-10-26 22:44:33 +00:00
}
2007-11-19 20:24:58 +00:00
elsif ( $ subcommand =~ /watt/ ) {
@ sensor_filters = ( 0x03 ) ;
}
2007-10-26 22:44:33 +00:00
elsif ( $ subcommand eq "fanspeed" ) {
@ sensor_filters = ( 0x04 ) ;
}
elsif ( $ subcommand eq "power" ) {
( $ rc , $ text ) = power ( "stat" ) ;
$ text = sprintf ( $ format , "Power Status:" , $ text ) ;
return ( $ rc , $ text ) ;
}
elsif ( $ subcommand eq "leds" ) {
my @ cleds ;
( $ rc , @ cleds ) = checkleds ( ) ;
foreach $ text ( @ cleds ) {
push ( @ output , $ text ) ;
}
}
else {
return ( 1 , "unsupported command vitals $subcommand" ) ;
}
( $ rc , $ text ) = initsdr ( ) ;
if ( $ rc != 0 ) {
return ( $ rc , $ text ) ;
}
foreach ( @ sensor_filters ) {
my $ filter = $ _ ;
foreach $ key ( sort { $ sdr_hash { $ a } - > id_string cmp $ sdr_hash { $ b } - > id_string } keys % sdr_hash ) {
my $ sdr = $ sdr_hash { $ key } ;
2009-03-07 02:04:21 +00:00
if ( ( $ doall and not $ sdr - > rec_type == 0x11 and not $ sdr - > sensor_type == 0xed ) or ( $ sdr - > rec_type == 0x01 and $ sdr - > sensor_type == $ filter ) ) {
2007-10-26 22:44:33 +00:00
my $ lformat = $ format ;
2009-03-24 20:01:36 +00:00
( $ rc , $ reading , $ extext ) = readsensor ( $ sdr ) ;
2007-10-26 22:44:33 +00:00
$ unitdesc = "" ;
if ( $ rc == 0 ) {
$ unitdesc = $ units { $ sdr - > sensor_units_2 } ;
2008-09-18 18:20:52 +00:00
$ value = $ reading ;
if ( $ sdr - > rec_type == 1 ) {
$ value = ( ( $ sdr - > M * $ reading ) + ( $ sdr - > B * ( 10 ** $ sdr - > B_exp ) ) ) * ( 10 ** $ sdr - > R_exp ) ;
}
if ( $ sdr - > rec_type != 1 or $ sdr - > linearization == 0 ) {
2007-10-26 22:44:33 +00:00
$ reading = $ value ;
if ( $ value == int ( $ value ) ) {
2009-03-24 20:01:36 +00:00
$ lformat = "%-30s%8d%s" ;
2007-10-26 22:44:33 +00:00
}
else {
2009-03-24 20:01:36 +00:00
$ lformat = "%-30s%8.3f%s" ;
2007-10-26 22:44:33 +00:00
}
}
elsif ( $ sdr - > linearization == 7 ) {
if ( $ value > 0 ) {
$ reading = 1 / $ value ;
}
else {
$ reading = 0 ;
}
2009-03-24 20:01:36 +00:00
$ lformat = "%-30s%8d %s" ;
2007-10-26 22:44:33 +00:00
}
else {
2008-09-18 18:20:52 +00:00
$ reading = "RAW(" . $ sdr - > linearization . ") $reading" ;
2007-10-26 22:44:33 +00:00
}
if ( $ sdr - > sensor_units_1 & 1 ) {
$ per = "% " ;
2008-03-18 16:52:15 +00:00
} else {
$ per = " " ;
}
my $ numformat = ( $ sdr - > sensor_units_1 & 0b11000000 ) >> 6 ;
if ( $ numformat ) {
if ( $ numformat eq 0b11 ) {
#Not sure what to do here..
} else {
if ( $ reading & 0b10000000 ) {
if ( $ numformat eq 0b01 ) {
$ reading = 0 - ( ( ~ ( $ reading & 0b01111111 ) ) & 0b1111111 ) ;
} elsif ( $ numformat eq 0b10 ) {
$ reading = 0 - ( ( ( ~ ( $ reading & 0b01111111 ) ) & 0b1111111 ) + 1 ) ;
}
}
}
}
2007-10-26 22:44:33 +00:00
2007-11-19 20:24:58 +00:00
if ( $ unitdesc eq "Watts" ) {
my $ f = ( $ reading * 3.413 ) ;
$ unitdesc = "Watts (" . int ( $ f + .5 ) . " BTUs/hr)" ;
}
2007-10-26 22:44:33 +00:00
if ( $ unitdesc eq "C" ) {
my $ f = ( $ reading * 9 / 5 ) + 32 ;
$ unitdesc = "C (" . int ( $ f + .5 ) . " F)" ;
}
if ( $ unitdesc eq "F" ) {
my $ c = ( $ reading - 32 ) * 5 / 9 ;
$ unitdesc = "F (" . int ( $ c + .5 ) . " C)" ;
}
}
2008-03-03 20:51:36 +00:00
#$unitdesc.= sprintf(" %x",$sdr->sensor_type);
2007-10-26 22:44:33 +00:00
$ text = sprintf ( $ lformat , $ sdr - > id_string . ":" , $ reading , $ per . $ unitdesc ) ;
2009-03-24 20:01:36 +00:00
if ( $ extext ) {
$ text = "$text ($extext)" ;
}
2007-10-26 22:44:33 +00:00
push ( @ output , $ text ) ;
}
# else {
# printf("%x %s %d\n",$sdr->sensor_number,$sdr->id_string,$sdr->sensor_type);
# }
}
}
if ( $ subcommand eq "all" ) {
my @ cleds ;
( $ rc , $ text ) = power ( "stat" ) ;
2008-09-18 18:20:52 +00:00
$ text = sprintf ( $ format , "Power Status:" , $ text , "" ) ;
2007-10-26 22:44:33 +00:00
push ( @ output , $ text ) ;
( $ rc , @ cleds ) = checkleds ( ) ;
foreach $ text ( @ cleds ) {
push ( @ output , $ text ) ;
}
}
return ( $ rc , @ output ) ;
}
sub readsensor {
2009-03-24 20:01:36 +00:00
my $ sdr = shift ;
my $ sensor = $ sdr - > sensor_number ;
2007-10-26 22:44:33 +00:00
my $ netfun = 0x10 ;
my @ cmd ;
my @ returnd = ( ) ;
my $ error ;
my $ rc = 0 ;
my $ text ;
my $ code ;
@ cmd = ( 0x2d , $ sensor ) ;
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
return ( $ rc , $ text ) ;
}
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code != 0x00 ) {
$ rc = 1 ;
$ text = $ codes { $ code } ;
if ( ! $ text ) {
$ text = sprintf ( "unknown response %02x" , $ code ) ;
}
chomp $ text ;
return ( $ rc , $ text ) ;
}
if ( $ returnd [ 38 - $ authoffset ] & 0x20 ) {
$ rc = 1 ;
$ text = "N/A" ;
return ( $ rc , $ text ) ;
}
$ text = $ returnd [ 37 - $ authoffset ] ;
2009-03-24 20:01:36 +00:00
my $ exdata1 = $ returnd [ 39 - $ authoffset ] ;
my $ exdata2 = $ returnd [ 39 - $ authoffset ] ;
my $ extext ;
my @ exparts ;
if ( $ sdr - > event_type_code == 0x1 ) {
if ( $ exdata1 & 1 << 5 ) {
$ extext = "At or above upper non-recoverable threshold" ;
} elsif ( $ exdata1 & 1 << 4 ) {
$ extext = "At or above upper critical threshold" ;
} elsif ( $ exdata1 & 1 << 3 ) {
$ extext = "At or above upper non-critical threshold" ;
}
if ( $ exdata1 & 1 << 2 ) {
$ extext = "At or below lower non-critical threshold" ;
} elsif ( $ exdata1 & 1 << 1 ) {
$ extext = "At or below lower critical threshold" ;
} elsif ( $ exdata1 & 1 ) {
$ extext = "At or below lower non-recoverable threshold" ;
}
} elsif ( $ sdr - > event_type_code == 0x6f ) {
if ( $ sdr - > sensor_type == 0x10 ) {
@ exparts = ( ) ;
if ( $ exdata1 & 1 << 4 ) {
push @ exparts , "SEL full" ;
} elsif ( $ exdata1 & 1 << 5 ) {
push @ exparts , "SEL almost full" ;
}
if ( $ exdata1 & 1 ) {
push @ exparts , "Correctable Memory Error Logging Disabled" ;
}
if ( $ exdata1 & 1 << 3 ) {
push @ exparts , "All logging disabled" ;
} elsif ( $ exdata1 & 1 << 1 ) {
push @ exparts , "Some logging disabled" ;
}
if ( @ exparts ) {
$ extext = join ( "," , @ exparts ) ;
}
} elsif ( $ sdr - > sensor_type == 0x7 ) {
@ exparts = ( ) ;
if ( $ exdata1 & 1 ) {
push @ exparts , "IERR" ;
}
if ( $ exdata1 & 1 << 1 ) {
push @ exparts , "Thermal trip" ;
}
if ( $ exdata1 & 1 << 2 ) {
push @ exparts , "FRB1/BIST failure" ;
}
if ( $ exdata1 & 1 << 3 ) {
push @ exparts , "FRB2/Hang in POST due to processor" ;
}
if ( $ exdata1 & 1 << 4 ) {
push @ exparts , "FRB3/Processor Initialization failure" ;
}
if ( $ exdata1 & 1 << 5 ) {
push @ exparts , "Configuration error" ;
}
if ( $ exdata1 & 1 << 6 ) {
push @ exparts , "Uncorrectable CPU-complex error" ;
}
if ( $ exdata1 & 1 << 7 ) {
push @ exparts , "Present" ;
}
if ( $ exdata1 & 1 << 8 ) {
push @ exparts , "Processor disabled" ;
}
if ( $ exdata1 & 1 << 9 ) {
push @ exparts , "Terminator present" ;
}
if ( $ exdata1 & 1 << 10 ) {
push @ exparts , "Hardware throttled" ;
}
} elsif ( $ sdr - > sensor_type == 0x8 ) {
@ exparts = ( ) ;
if ( $ exdata1 & 1 ) {
push @ exparts , "Present" ;
}
if ( $ exdata1 & 1 << 1 ) {
push @ exparts , "Failed" ;
}
if ( $ exdata1 & 1 << 2 ) {
push @ exparts , "Failure predicted" ;
}
if ( $ exdata1 & 1 << 3 ) {
push @ exparts , "AC Lost" ;
}
if ( $ exdata1 & 1 << 4 ) {
push @ exparts , "AC input lost or out of range" ;
}
if ( $ exdata1 & 1 << 5 ) {
push @ exparts , "AC input out of range" ;
}
if ( $ exdata1 & 1 << 6 ) {
push @ exparts , "Configuration error" ;
}
if ( @ exparts ) {
$ extext = join ( "," , @ exparts ) ;
}
} elsif ( $ sdr - > sensor_type == 0x13 ) {
@ exparts = ( ) ;
if ( $ exdata1 & 1 ) {
push @ exparts , "Front panel NMI/Diagnostic" ;
}
if ( $ exdata1 & 1 << 1 ) {
push @ exparts , "Bus timeout" ;
}
if ( $ exdata1 & 1 << 2 ) {
push @ exparts , "I/O channel check NMI" ;
}
if ( $ exdata1 & 1 << 3 ) {
push @ exparts , "Software NMI" ;
}
if ( $ exdata1 & 1 << 4 ) {
push @ exparts , "PCI PERR" ;
}
if ( $ exdata1 & 1 << 5 ) {
push @ exparts , "PCI SERR" ;
}
if ( $ exdata1 & 1 << 6 ) {
push @ exparts , "EISA failsafe timeout" ;
}
if ( $ exdata1 & 1 << 7 ) {
push @ exparts , "Bus correctable .rror" ;
}
if ( $ exdata1 & 1 << 8 ) {
push @ exparts , "Bus uncorrectable error" ;
}
if ( $ exdata1 & 1 << 9 ) {
push @ exparts , "Fatal NMI" ;
}
if ( $ exdata1 & 1 << 10 ) {
push @ exparts , "Bus fatal error" ;
}
if ( @ exparts ) {
$ extext = join ( "," , @ exparts ) ;
}
} elsif ( $ sdr - > sensor_type == 0xc ) {
@ exparts = ( ) ;
if ( $ exdata1 & 1 ) {
push @ exparts , "Correctable error(s)" ;
}
if ( $ exdata1 & 1 << 1 ) {
push @ exparts , "Uncorrectable error(s)" ;
}
if ( $ exdata1 & 1 << 2 ) {
push @ exparts , "Parity" ;
}
if ( $ exdata1 & 1 << 3 ) {
push @ exparts , "Memory scrub failure" ;
}
if ( $ exdata1 & 1 << 4 ) {
push @ exparts , "DIMM disabled" ;
}
if ( $ exdata1 & 1 << 5 ) {
push @ exparts , "Correctable error limit reached" ;
}
if ( $ exdata1 & 1 << 6 ) {
push @ exparts , "Present" ;
}
if ( $ exdata1 & 1 << 7 ) {
push @ exparts , "Configuration error" ;
}
if ( $ exdata1 & 1 << 8 ) {
push @ exparts , "Spare" ;
}
if ( @ exparts ) {
$ extext = join ( "," , @ exparts ) ;
}
} elsif ( $ sdr - > sensor_type == 0x21 ) {
@ exparts = ( ) ;
if ( $ exdata1 & 1 ) {
push @ exparts , "Fault" ;
}
if ( $ exdata1 & 1 << 1 ) {
push @ exparts , "Identify" ;
}
if ( $ exdata1 & 1 << 2 ) {
push @ exparts , "Installed/attached" ;
}
if ( $ exdata1 & 1 << 3 ) {
push @ exparts , "Ready for install" ;
}
if ( $ exdata1 & 1 << 4 ) {
push @ exparts , "Ready for removal" ;
}
if ( $ exdata1 & 1 << 5 ) {
push @ exparts , "Powered off" ;
}
if ( $ exdata1 & 1 << 6 ) {
push @ exparts , "Removal requested" ;
}
if ( $ exdata1 & 1 << 7 ) {
push @ exparts , "Interlocked" ;
}
if ( $ exdata1 & 1 << 8 ) {
push @ exparts , "Disabled" ;
}
if ( $ exdata1 & 1 << 9 ) {
push @ exparts , "Spare" ;
}
} elsif ( $ sdr - > sensor_type == 0xf ) {
@ exparts = ( ) ;
if ( $ exdata1 & 1 ) {
push @ exparts , "POST error" ;
}
if ( $ exdata1 & 1 << 1 ) {
push @ exparts , "Firmware hang" ;
}
if ( $ exdata1 & 1 << 2 ) {
push @ exparts , "Firmware progress" ;
}
if ( @ exparts ) {
$ extext = join ( "," , @ exparts ) ;
}
} elsif ( $ sdr - > sensor_type == 0x9 ) {
@ exparts = ( ) ;
if ( $ exdata1 & 1 ) {
push @ exparts , "Power off" ;
}
if ( $ exdata1 & 1 << 1 ) {
push @ exparts , "Power off" ;
}
if ( $ exdata1 & 1 << 2 ) {
push @ exparts , "240VA Power Down" ;
}
if ( $ exdata1 & 1 << 3 ) {
push @ exparts , "Interlock Power Down" ;
}
if ( $ exdata1 & 1 << 4 ) {
push @ exparts , "AC lost" ;
}
if ( $ exdata1 & 1 << 5 ) {
push @ exparts , "Soft power control failure" ;
}
if ( $ exdata1 & 1 << 6 ) {
push @ exparts , "Power unit failure" ;
}
if ( $ exdata1 & 1 << 7 ) {
push @ exparts , "Power unit failure predicted" ;
}
if ( @ exparts ) {
$ extext = join ( "," , @ exparts ) ;
}
} else {
$ extext = "xCAT needs to add support for " . $ sdr - > sensor_type ;
}
}
2007-10-26 22:44:33 +00:00
2009-03-24 20:01:36 +00:00
return ( $ rc , $ text , $ extext ) ;
2007-10-26 22:44:33 +00:00
}
sub initsdr {
my $ netfun ;
my @ cmd ;
my @ returnd = ( ) ;
my $ error ;
my $ rc = 0 ;
my $ text ;
my $ code ;
my $ sdr_rep_info = SDR_rep_info - > new ( ) ;
my $ resv_id_ls ;
my $ resv_id_ms ;
my $ nrid_ls = 0 ;
my $ nrid_ms = 0 ;
my $ rid_ls = 0 ;
my $ rid_ms = 0 ;
my $ sdr_ver ;
my $ sdr_type ;
my $ sdr_offset ;
my $ sdr_len ;
my @ sdr_data = ( ) ;
my $ offset ;
my $ len ;
my $ i ;
# my $numbytes = 27;
my $ numbytes = 22 ;
my $ override_string ;
my $ ipmisensortab = "$ENV{XCATROOT}/lib/GUMI/ipmisensor.tab" ;
my $ byte_format ;
my $ cache_file ;
my $ mfg_id ;
my $ prod_id ;
my $ device_id ;
my $ dev_rev ;
my $ fw_rev1 ;
my $ fw_rev2 ;
( $ rc , $ text , $ mfg_id , $ prod_id , $ device_id , $ dev_rev , $ fw_rev1 , $ fw_rev2 ) = getdevid ( ) ;
if ( $ rc != 0 ) {
return ( $ rc , $ text ) ;
}
$ cache_file = "$cache_dir/sdr_$mfg_id.$prod_id.$device_id.$dev_rev.$fw_rev1.$fw_rev2.$cache_version" ;
if ( $ enable_cache eq "yes" ) {
$ rc = loadsdrcache ( $ cache_file ) ;
if ( $ rc == 0 ) {
return ( $ rc ) ;
}
$ rc = 0 ;
}
( $ rc , $ text ) = get_sdr_rep_info ( $ sdr_rep_info ) ;
if ( $ rc != 0 ) {
return ( $ rc , $ text ) ;
}
if ( $ sdr_rep_info - > version != 0x51 ) {
$ rc = 1 ;
$ text = "SDR version 51h support only." ;
return ( $ rc , $ text ) ;
}
if ( $ sdr_rep_info - > resv_sdr != 1 ) {
$ rc = 1 ;
$ text = "SDR reservation unsupported." ;
return ( $ rc , $ text ) ;
}
( $ rc , $ text , $ resv_id_ls , $ resv_id_ms ) = resv_sdr_repo ( ) ;
if ( $ rc != 0 ) {
return ( $ rc , $ text ) ;
}
if ( $ debug ) {
print "mfg,prod,dev: $mfg_id, $prod_id, $device_id\n" ;
printf ( "SDR info: %02x %d %d\n" , $ sdr_rep_info - > version , $ sdr_rep_info - > rec_count , $ sdr_rep_info - > resv_sdr ) ;
print "resv_id: $resv_id_ls $resv_id_ms\n" ;
}
foreach ( 1 .. $ sdr_rep_info - > rec_count ) {
$ netfun = 0x28 ;
@ cmd = ( 0x23 , $ resv_id_ls , $ resv_id_ms , $ nrid_ls , $ nrid_ms , 0 , 5 ) ;
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
return ( $ rc , $ text ) ;
}
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code != 0x00 ) {
$ rc = 1 ;
$ text = $ codes { $ code } ;
if ( ! $ text ) {
$ rc = 1 ;
$ text = sprintf ( "unknown response %02x" , $ code ) ;
}
return ( $ rc , $ text ) ;
}
###x336 hack
$ rid_ls = $ nrid_ls ;
$ rid_ms = $ nrid_ms ;
###
$ nrid_ls = $ returnd [ 37 - $ authoffset ] ;
$ nrid_ms = $ returnd [ 38 - $ authoffset ] ;
### correct IPMI code
# $rid_ls = $returnd[39-$authoffset];
# $rid_ms = $returnd[40-$authoffset];
###
$ sdr_ver = $ returnd [ 41 - $ authoffset ] ;
$ sdr_type = $ returnd [ 42 - $ authoffset ] ;
$ sdr_len = $ returnd [ 43 - $ authoffset ] + 5 ;
if ( $ sdr_type == 0x01 ) {
$ sdr_offset = 0 ;
}
elsif ( $ sdr_type == 0x02 ) {
$ sdr_offset = 16 ;
}
elsif ( $ sdr_type == 0xC0 ) {
#LED descriptor, maybe
}
2009-03-07 02:04:21 +00:00
elsif ( $ sdr_type == 0x11 ) { #FRU locator
}
2007-10-26 22:44:33 +00:00
elsif ( $ sdr_type == 0x12 ) {
next ;
}
else {
next ;
}
@ sdr_data = ( 0 , 0 , 0 , $ sdr_ver , $ sdr_type , $ sdr_len ) ;
$ offset = 5 ;
for ( $ i = 5 ; $ i < $ sdr_len ; $ i += $ numbytes ) {
$ len = $ numbytes ;
if ( $ offset + $ len > $ sdr_len ) {
$ len = $ sdr_len - $ offset ;
}
@ cmd = ( 0x23 , $ resv_id_ls , $ resv_id_ms , $ rid_ls , $ rid_ms , $ offset , $ len ) ;
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
return ( $ rc , $ text ) ;
}
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code != 0x00 ) {
$ rc = 1 ;
$ text = $ codes { $ code } ;
if ( ! $ text ) {
$ rc = 1 ;
$ text = sprintf ( "unknown response %02x" , $ code ) ;
}
return ( $ rc , $ text ) ;
}
@ sdr_data = ( @ sdr_data , @ returnd [ 39 - $ authoffset .. @ returnd - 2 ] ) ;
$ offset += $ len ;
}
2009-03-07 02:04:21 +00:00
if ( $ sdr_type == 0x11 ) { #FRU locator
my $ sdr = decode_fru_locator ( @ sdr_data ) ;
if ( $ sdr ) {
$ sdr_hash { $ sdr - > sensor_owner_id . "." . $ sdr - > sensor_owner_lun . "." . $ sdr - > sensor_number } = $ sdr ;
}
next ;
}
2007-10-26 22:44:33 +00:00
if ( $ debug ) {
hexadump ( \ @ sdr_data ) ;
}
if ( $ sdr_type == 0x12 ) {
hexadump ( \ @ sdr_data ) ;
next ;
}
my $ sdr = SDR - > new ( ) ;
if ( $ mfg_id == 2 && $ sdr_type == 0xC0 && $ sdr_data [ 9 ] == 0xED ) {
#printf("%02x%02x\n",$sdr_data[13],$sdr_data[12]);
$ sdr - > rec_type ( $ sdr_type ) ;
$ sdr - > sensor_type ( $ sdr_data [ 9 ] ) ;
#Using an impossible sensor number to not conflict with decodealert
$ sdr - > sensor_owner_id ( 260 ) ;
$ sdr - > sensor_owner_lun ( 260 ) ;
2008-09-18 18:20:52 +00:00
$ sdr - > id_string ( "LED" ) ;
2007-10-26 22:44:33 +00:00
if ( $ sdr_data [ 12 ] > $ sdr_data [ 13 ] ) {
$ sdr - > led_id ( ( $ sdr_data [ 13 ] << 8 ) + $ sdr_data [ 12 ] ) ;
} else {
$ sdr - > led_id ( ( $ sdr_data [ 12 ] << 8 ) + $ sdr_data [ 13 ] ) ;
}
#$sdr->led_id_ms($sdr_data[13]);
#$sdr->led_id_ls($sdr_data[12]);
$ sdr - > sensor_number ( sprintf ( "%04x" , $ sdr - > led_id ) ) ;
#printf("%02x,%02x,%04x\n",$mfg_id,$prod_id,$sdr->led_id);
#Was going to have a human readable name, but specs
#seem to not to match reality...
#$override_string = getsensorname($mfg_id,$prod_id,$sdr->sensor_number,$ipmiledtab);
#I'm hacking in owner and lun of 260 for LEDs....
$ sdr_hash { "260.260." . $ sdr - > led_id } = $ sdr ;
next ;
}
$ sdr - > rec_type ( $ sdr_type ) ;
$ sdr - > sensor_owner_id ( $ sdr_data [ 6 ] ) ;
$ sdr - > sensor_owner_lun ( $ sdr_data [ 7 ] ) ;
$ sdr - > sensor_number ( $ sdr_data [ 8 ] ) ;
$ sdr - > entity_id ( $ sdr_data [ 9 ] ) ;
$ sdr - > entity_instance ( $ sdr_data [ 10 ] ) ;
$ sdr - > sensor_type ( $ sdr_data [ 13 ] ) ;
2008-02-12 21:34:57 +00:00
$ sdr - > event_type_code ( $ sdr_data [ 14 ] ) ;
2007-10-26 22:44:33 +00:00
$ sdr - > sensor_units_2 ( $ sdr_data [ 22 ] ) ;
$ sdr - > sensor_units_3 ( $ sdr_data [ 23 ] ) ;
if ( $ sdr_type == 0x01 ) {
2008-03-18 16:52:15 +00:00
$ sdr - > sensor_units_1 ( $ sdr_data [ 21 ] ) ;
2007-10-26 22:44:33 +00:00
$ sdr - > linearization ( $ sdr_data [ 24 ] & 0b01111111 ) ;
$ sdr - > M ( comp2int ( 10 , ( ( $ sdr_data [ 26 ] & 0b11000000 ) << 2 ) + $ sdr_data [ 25 ] ) ) ;
$ sdr - > B ( comp2int ( 10 , ( ( $ sdr_data [ 28 ] & 0b11000000 ) << 2 ) + $ sdr_data [ 27 ] ) ) ;
$ sdr - > R_exp ( comp2int ( 4 , ( $ sdr_data [ 30 ] & 0b11110000 ) >> 4 ) ) ;
$ sdr - > B_exp ( comp2int ( 4 , $ sdr_data [ 30 ] & 0b00001111 ) ) ;
2008-03-18 17:01:20 +00:00
} elsif ( $ sdr_type == 0x02 ) {
$ sdr - > sensor_units_1 ( $ sdr_data [ 21 ] ) ;
2009-03-24 20:01:36 +00:00
}
2007-10-26 22:44:33 +00:00
$ sdr - > id_string_type ( $ sdr_data [ 48 - $ sdr_offset ] ) ;
$ override_string = getsensorname ( $ mfg_id , $ prod_id , $ sdr - > sensor_number , $ ipmisensortab ) ;
if ( $ override_string ne "" ) {
$ sdr - > id_string ( $ override_string ) ;
}
else {
2009-03-07 02:04:21 +00:00
unless ( defined $ sdr - > id_string_type ) { next ; }
2007-10-26 22:44:33 +00:00
$ byte_format = ( $ sdr - > id_string_type & 0b11000000 ) >> 6 ;
if ( $ byte_format == 0b11 ) {
my $ len = ( $ sdr - > id_string_type & 0b00011111 ) - 1 ;
if ( $ len > 1 ) {
$ sdr - > id_string ( pack ( "C*" , @ sdr_data [ 49 - $ sdr_offset .. 49 - $ sdr_offset + $ len ] ) ) ;
}
else {
$ sdr - > id_string ( "no description" ) ;
}
}
elsif ( $ byte_format == 0b10 ) {
$ sdr - > id_string ( "ASCII packed unsupported" ) ;
}
elsif ( $ byte_format == 0b01 ) {
$ sdr - > id_string ( "BCD unsupported" ) ;
}
elsif ( $ byte_format == 0b00 ) {
2009-03-07 02:04:21 +00:00
my $ len = ( $ sdr - > id_string_type & 0b00011111 ) - 1 ;
if ( $ len > 1 ) { #It should be something, but need sample to code
$ sdr - > id_string ( "unicode unsupported" ) ;
} else {
next ;
}
2007-10-26 22:44:33 +00:00
}
}
$ sdr_hash { $ sdr - > sensor_owner_id . "." . $ sdr - > sensor_owner_lun . "." . $ sdr - > sensor_number } = $ sdr ;
}
if ( $ debug ) {
my $ key ;
# foreach $key (sort {$sdr_hash{$a}->sensor_number <=> $sdr_hash{$b}->sensor_number} keys %sdr_hash) {
foreach $ key ( sort { $ sdr_hash { $ a } - > id_string cmp $ sdr_hash { $ b } - > id_string } keys % sdr_hash ) {
my $ sdr = $ sdr_hash { $ key } ;
# printf("%d %x %s\n",$sdr->rec_type,$sdr->sensor_number,$sdr->id_string);
# printf("%x %x %x %s\n",$sdr->sensor_owner_id,$sdr->sensor_owner_lun,$sdr->sensor_number,$sdr->id_string);
printf ( "%x %x %x %s %d\n" , $ sdr - > sensor_owner_id , $ sdr - > sensor_owner_lun , $ sdr - > sensor_number , $ sdr - > id_string , $ sdr - > linearization ) ;
}
# printf("\n%x %s\n",$sdr_hash{0x70}->sensor_number,$sdr_hash{0x70}->id_string);
}
if ( $ enable_cache eq "yes" ) {
storsdrcache ( $ cache_file ) ;
}
return ( $ rc , $ text ) ;
}
sub getsensorname
{
my $ mfgid = shift ;
my $ prodid = shift ;
my $ sensor = shift ;
my $ file = shift ;
my $ mfg ;
my $ prod ;
my $ type ;
my $ num ;
my $ desc ;
my $ name = "" ;
if ( $ file eq "ibmleds" ) {
if ( $ xCAT:: data:: ibmleds:: leds { "$mfgid,$prodid" } - > { $ sensor } ) {
2008-03-03 20:51:36 +00:00
return $ xCAT:: data:: ibmleds:: leds { "$mfgid,$prodid" } - > { $ sensor } . " LED" ;
} elsif ( $ ndebug ) {
return "Unknown $sensor/$mfgid/$prodid" ;
2007-10-26 22:44:33 +00:00
} else {
2008-03-03 20:51:36 +00:00
return sprintf ( "LED 0x%x" , $ sensor ) ;
2007-10-26 22:44:33 +00:00
}
} else {
return "" ;
}
}
sub getchassiscap {
my $ netfun = 0x00 ;
my @ cmd ;
my @ returnd = ( ) ;
my $ error ;
my $ rc = 0 ;
my $ text ;
my $ code ;
@ cmd = ( 0x00 ) ;
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
return ( $ rc , $ text ) ;
}
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code == 0x00 ) {
$ text = "" ;
}
else {
$ rc = 1 ;
$ text = $ codes { $ code } ;
if ( ! $ text ) {
$ rc = 1 ;
$ text = sprintf ( "unknown response %02x" , $ code ) ;
}
return ( $ rc , $ text ) ;
}
return ( $ rc , @ returnd [ 37 - $ authoffset .. @ returnd - 2 ] ) ;
}
sub getdevid {
my $ netfun = 0x18 ;
my @ cmd ;
my @ returnd = ( ) ;
my $ error ;
my $ rc = 0 ;
my $ text ;
my $ code ;
@ cmd = ( 0x01 ) ;
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
return ( $ rc , $ text ) ;
}
else {
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code == 0x00 ) {
$ text = "" ;
}
else {
$ rc = 1 ;
$ text = $ codes { $ code } ;
if ( ! $ text ) {
$ rc = 1 ;
$ text = sprintf ( "unknown response %02x" , $ code ) ;
}
return ( $ rc , $ text ) ;
}
}
my $ device_id = $ returnd [ 37 - $ authoffset ] ;
my $ device_rev = $ returnd [ 38 - $ authoffset ] & 0b00001111 ;
my $ firmware_rev1 = $ returnd [ 39 - $ authoffset ] & 0b01111111 ;
my $ firmware_rev2 = $ returnd [ 40 - $ authoffset ] ;
my $ ipmi_ver = $ returnd [ 41 - $ authoffset ] ;
my $ dev_support = $ returnd [ 42 - $ authoffset ] ;
my $ sensor_device = 0 ;
my $ SDR = 0 ;
my $ SEL = 0 ;
my $ FRU = 0 ;
my $ IPMB_ER = 0 ;
my $ IPMB_EG = 0 ;
my $ BD = 0 ;
my $ CD = 0 ;
if ( $ dev_support & 0b00000001 ) {
$ sensor_device = 1 ;
}
if ( $ dev_support & 0b00000010 ) {
$ SDR = 1 ;
}
if ( $ dev_support & 0b00000100 ) {
$ SEL = 1 ;
}
if ( $ dev_support & 0b00001000 ) {
$ FRU = 1 ;
}
if ( $ dev_support & 0b00010000 ) {
$ IPMB_ER = 1 ;
}
if ( $ dev_support & 0b00100000 ) {
$ IPMB_EG = 1 ;
}
if ( $ dev_support & 0b01000000 ) {
$ BD = 1 ;
}
if ( $ dev_support & 0b10000000 ) {
$ CD = 1 ;
}
my $ mfg_id = $ returnd [ 43 - $ authoffset ] + $ returnd [ 44 - $ authoffset ] * 0x100 + $ returnd [ 45 - $ authoffset ] * 0x10000 ;
my $ prod_id = $ returnd [ 46 - $ authoffset ] + $ returnd [ 47 - $ authoffset ] * 0x100 ;
my @ data = @ returnd [ 48 - $ authoffset .. @ returnd - 2 ] ;
return ( $ rc , $ text , $ mfg_id , $ prod_id , $ device_id , $ device_rev , $ firmware_rev1 , $ firmware_rev2 ) ;
}
sub getguid {
my $ guidcmd = shift ;
my $ netfun = @$ guidcmd [ 0 ] || 0x18 ;
my @ cmd = @$ guidcmd [ 1 ] || 0x37 ;
my @ returnd = ( ) ;
my $ error ;
my $ rc = 0 ;
my $ text ;
my $ code ;
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
return ( $ rc , $ text ) ;
}
else {
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code == 0x00 ) {
$ text = "" ;
}
else {
$ rc = 1 ;
$ text = $ codes { $ code } ;
if ( ! $ text ) {
$ rc = 1 ;
$ text = sprintf ( "unknown response %02x" , $ code ) ;
}
return ( $ rc , $ text ) ;
}
}
my @ guid = @ returnd [ 37 - $ authoffset .. 52 - $ authoffset ] ;
my $ guidtext = sprintf ( "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" , @ guid ) ;
$ guidtext =~ tr /[a-z]/ [ A - Z ] / ;
return ( $ rc , $ text , $ guidtext ) ;
}
sub get_sdr_rep_info {
my $ sdr_rep_info = shift ;
my $ netfun = 0x28 ;
my @ cmd ;
my @ returnd = ( ) ;
my $ error ;
my $ rc = 0 ;
my $ text ;
my $ code ;
@ cmd = ( 0x20 ) ;
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
return ( $ rc , $ text ) ;
}
else {
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code == 0x00 ) {
$ text = "" ;
}
else {
$ rc = 1 ;
$ text = $ codes { $ code } ;
if ( ! $ text ) {
$ rc = 1 ;
$ text = sprintf ( "unknown response %02x" , $ code ) ;
}
return ( $ rc , $ text ) ;
}
}
$ sdr_rep_info - > version ( $ returnd [ 37 - $ authoffset ] ) ;
$ sdr_rep_info - > rec_count ( $ returnd [ 38 - $ authoffset ] + $ returnd [ 39 - $ authoffset ] * 0x100 ) ;
$ sdr_rep_info - > resv_sdr ( ( $ returnd [ 50 - $ authoffset ] & 0b00000010 ) ? 1 : 0 ) ;
return ( $ rc , $ text ) ;
}
sub resv_sdr_repo {
my $ netfun = 0x28 ;
my @ cmd ;
my @ returnd = ( ) ;
my $ error ;
my $ rc = 0 ;
my $ text ;
my $ code ;
@ cmd = ( 0x22 ) ;
$ error = docmd (
$ netfun ,
\ @ cmd ,
\ @ returnd
) ;
if ( $ error ) {
$ rc = 1 ;
$ text = $ error ;
return ( $ rc , $ text ) ;
}
else {
$ code = $ returnd [ 36 - $ authoffset ] ;
if ( $ code == 0x00 ) {
$ text = "" ;
}
else {
$ rc = 1 ;
$ text = $ codes { $ code } ;
if ( ! $ text ) {
$ rc = 1 ;
$ text = sprintf ( "unknown response %02x" , $ code ) ;
}
return ( $ rc , $ text ) ;
}
}
my $ resv_id_ls = $ returnd [ 37 - $ authoffset ] ;
my $ resv_id_ms = $ returnd [ 38 - $ authoffset ] ;
return ( $ rc , $ text , $ resv_id_ls , $ resv_id_ms ) ;
}
sub docmd {
my $ netfun = shift ;
my $ cmd = shift ;
my $ response = shift ;
my @ rn ;
my $ length ;
my @ msg ;
my @ message ;
my $ error = "" ;
my @ response ;
my @ data ;
incseqlun ( ) ;
@ data = ( $ rqsa , $ seqlun , @$ cmd ) ;
@ rn = ( $ rssa , $ netfun ) ;
$ length = ( scalar @ data ) + 4 ;
@ message = ( $ rssa , $ netfun , dochksum ( \ @ rn ) , @ data , dochksum ( \ @ data ) ) ;
incseqnum ( ) ;
@ msg = (
@ rmcp ,
$ auth ,
@ seqnum ,
@ session_id ,
authcode ( 2 , \ @ message ) ,
$ length ,
@ message
) ;
( $ error , @$ response ) = domsg ( $ sock , \ @ msg , $ timeout , 1 ) ;
return ( $ error ) ;
}
sub getchanauthcap {
$ auth = 0x00 ;
my $ netfun = 0x18 ;
my @ data ;
my @ rn ;
my $ length ;
my @ msg ;
my $ error = "" ;
my @ response ;
my $ code ;
2008-09-07 03:22:40 +00:00
@ data = ( $ rqsa , $ seqlun , 0x38 , 0x8e , 0x04 ) ;
2007-10-26 22:44:33 +00:00
@ rn = ( $ rssa , $ netfun ) ;
$ length = ( scalar @ data ) + 4 ;
@ msg = (
@ rmcp ,
$ auth ,
@ seqnum ,
@ session_id ,
$ length ,
$ rssa ,
$ netfun ,
dochksum ( \ @ rn ) ,
@ data ,
dochksum ( \ @ data )
) ;
( $ error , @ response ) = domsg ( $ sock , \ @ msg , $ timeout , 0 ) ;
if ( $ error ) {
return ( $ error ) ;
}
$ code = $ response [ 20 ] ;
2008-09-17 16:52:28 +00:00
if ( $ code == 0xcc ) {
#Despite the fact that the IPMI 1.5 spec declared the high bits to be
#reserved, some 1.5 BMCs checked the value anyway (erroneously)
#This retries with the IPMI 2.0 bit cleared
@ data = ( $ rqsa , $ seqlun , 0x38 , 0x0e , 0x04 ) ;
@ rn = ( $ rssa , $ netfun ) ;
$ length = ( scalar @ data ) + 4 ;
@ msg = (
@ rmcp ,
$ auth ,
@ seqnum ,
@ session_id ,
$ length ,
$ rssa ,
$ netfun ,
dochksum ( \ @ rn ) ,
@ data ,
dochksum ( \ @ data )
) ;
( $ error , @ response ) = domsg ( $ sock , \ @ msg , $ timeout , 0 ) ;
if ( $ error ) {
return ( $ error ) ;
}
$ code = $ response [ 20 ] ;
}
2007-10-26 22:44:33 +00:00
if ( $ code != 0x00 ) {
$ error = $ codes { $ code } ;
if ( ! $ error ) {
$ error = "Unknown get channel authentication capabilities error $code"
}
return ( $ error ) ;
}
$ channel_number = $ response [ 21 ] ;
2008-09-07 03:22:40 +00:00
if ( $ response [ 22 ] & 0b10000000 and $ response [ 24 ] & 0b00000010 ) {
2007-10-30 15:24:43 +00:00
$ ipmiv2 = 1 ;
}
2007-10-26 22:44:33 +00:00
if ( $ response [ 22 ] & 0b00000100 ) {
$ auth = 0x02 ;
}
elsif ( $ response [ 22 ] & 0b00010000 ) {
$ auth = 0x04 ;
}
else {
$ error = "unsupported Authentication Type Support" ;
}
return ( $ error ) ;
}
sub getsessionchallenge {
my $ tauth = 0x00 ;
my $ netfun = 0x18 ;
my @ data ;
my @ rn ;
my $ length ;
my @ msg ;
my $ error = "" ;
my @ response ;
my $ code ;
incseqlun ( ) ;
@ data = ( $ rqsa , $ seqlun , 0x39 , $ auth , @ user ) ;
@ rn = ( $ rssa , $ netfun ) ;
$ length = ( scalar @ data ) + 4 ;
@ msg = (
@ rmcp ,
$ tauth ,
@ seqnum ,
@ session_id ,
$ length ,
$ rssa ,
$ netfun ,
dochksum ( \ @ rn ) ,
@ data ,
dochksum ( \ @ data )
) ;
( $ error , @ response ) = domsg ( $ sock , \ @ msg , $ timeout , 0 ) ;
if ( ! $ error ) {
$ code = $ response [ 20 ] ;
if ( $ code != 0x00 ) {
$ error = $ codes { $ code } ;
if ( ! $ error ) {
$ error = "Unknown get session challenge error $code"
}
}
if ( $ code == 0x81 ) {
$ error = "Invalid user name" ;
}
elsif ( $ code == 0x82 ) {
$ error = "null user name not enabled" ;
}
@ session_id = @ response [ 21 , 22 , 23 , 24 ] ;
for ( my $ i = 0 ; $ i < 16 ; $ i + + ) {
$ challenge [ $ i ] = $ response [ 25 + $ i ] ;
}
}
return ( $ error ) ;
}
sub activatesession {
my $ netfun = 0x18 ;
my @ data ;
my @ rn ;
my $ length ;
my @ msg ;
my @ message ;
my $ error = "" ;
my @ response ;
my $ code ;
incseqlun ( ) ;
@ data = ( $ rqsa , $ seqlun , 0x3A , $ auth , 0x04 , @ challenge , 0x01 , 0x00 , 0x00 , 0x00 ) ;
@ rn = ( $ rssa , $ netfun ) ;
$ length = ( scalar @ data ) + 4 ;
@ message = ( $ rssa , $ netfun , dochksum ( \ @ rn ) , @ data , dochksum ( \ @ data ) ) ;
@ msg = (
@ rmcp ,
$ auth ,
@ seqnum ,
@ session_id ,
authcode ( 2 , \ @ message ) ,
$ length ,
@ message
) ;
( $ error , @ response ) = domsg ( $ sock , \ @ msg , $ timeout , 0 ) ;
if ( ! $ error ) {
$ code = $ response [ 36 ] ;
if ( $ code != 0x00 ) {
$ error = $ codes { $ code } ;
if ( ! $ error ) {
$ error = "Unknown activate session error $code"
}
}
if ( $ code == 0x81 ) {
$ error = "No session slot available" ;
}
elsif ( $ code == 0x82 ) {
$ error = "No slot available for given user" ;
}
elsif ( $ code == 0x83 ) {
$ error = "No slot available to support user due to maximum privilege capability" ;
}
elsif ( $ code == 0x84 ) {
$ error = "Session sequence number out-of-range" ;
}
elsif ( $ code == 0x85 ) {
$ error = "Invalid session ID in request" ;
}
elsif ( $ code == 0x86 ) {
$ error = "Requested maximum privilege level exceeds user and/of channel privilege limit" ;
}
2008-06-27 14:01:26 +00:00
unless ( $ error ) {
$ auth = $ response [ 37 ] ;
if ( $ auth == 0x00 ) {
$ authoffset = 16 ;
}
elsif ( $ auth == 0x02 ) {
}
elsif ( $ auth == 0x04 ) {
}
else {
$ error = "activate session requested unsupported Authentication Type Support" ;
}
}
2007-10-26 22:44:33 +00:00
###check
@ session_id = @ response [ 38 , 39 , 40 , 41 ] ;
@ seqnum = @ response [ 42 , 43 , 44 , 45 ] ;
}
return ( $ error ) ;
}
sub setprivlevel ()
{
my $ netfun = 0x18 ;
my @ data ;
my @ rn ;
my $ length ;
my @ msg ;
my @ message ;
my $ error = "" ;
my @ response ;
my $ code ;
incseqlun ( ) ;
@ data = ( $ rqsa , $ seqlun , 0x3B , 0x04 ) ;
@ rn = ( $ rssa , $ netfun ) ;
$ length = ( scalar @ data ) + 4 ;
@ message = ( $ rssa , $ netfun , dochksum ( \ @ rn ) , @ data , dochksum ( \ @ data ) ) ;
@ msg = (
@ rmcp ,
$ auth ,
@ seqnum ,
@ session_id ,
authcode ( 2 , \ @ message ) ,
$ length ,
@ message
) ;
( $ error , @ response ) = domsg ( $ sock , \ @ msg , $ timeout , 1 ) ;
if ( ! $ error ) {
$ code = $ response [ 36 - $ authoffset ] ;
if ( $ code != 0x00 ) {
$ error = $ codes { $ code } ;
if ( ! $ error ) {
$ error = "Unknown set session privilege level error $code"
}
}
if ( $ code == 0x80 ) {
$ error = "Requested level not available for this user" ;
}
elsif ( $ code == 0x81 ) {
$ error = "Requested level exceeds channel and/or user privilege limit" ;
}
elsif ( $ code == 0x82 ) {
$ error = "Cannot disable user level authentication" ;
}
}
return ( $ error ) ;
}
sub closesession ()
{
incseqnum ( ) ;
my $ netfun = 0x18 ;
my @ data ;
my @ rn ;
my $ length ;
my @ msg ;
my @ message ;
my $ error = "" ;
my @ response ;
my $ code ;
incseqlun ( ) ;
@ data = ( $ rqsa , $ seqlun , 0x3C , @ session_id ) ;
@ rn = ( $ rssa , $ netfun ) ;
$ length = ( scalar @ data ) + 4 ;
@ message = ( $ rssa , $ netfun , dochksum ( \ @ rn ) , @ data , dochksum ( \ @ data ) ) ;
@ msg = (
@ rmcp ,
$ auth ,
@ seqnum ,
@ session_id ,
authcode ( 2 , \ @ message ) ,
$ length ,
@ message
) ;
2009-10-05 15:05:29 +00:00
( $ error , @ response ) = domsg ( $ sock , \ @ msg , 1 , 1 ) ; #Have a quicker retry on the close session
2007-10-26 22:44:33 +00:00
if ( ! $ error ) {
$ code = $ response [ 36 - $ authoffset ] ;
if ( $ code != 0x00 ) {
$ error = $ codes { $ code } ;
if ( ! $ error ) {
$ error = "Unknown close session error $code"
}
}
if ( $ code == 0x87 ) {
$ error = "Invalid session ID in request" ;
}
}
return ( $ error ) ;
}
sub domsg {
my $ sock = shift ;
my $ msg = shift ;
my $ timeout = shift ;
my $ seq = shift || 0 ;
my $ debug = $ localdebug ;
my $ trys = $ localtrys ;
my $ send ;
my $ quit = 0 ;
my $ error = "" ;
my $ recv ;
my @ response ;
my $ timedout ;
my @ foo ;
my @ message ;
$ send = pack ( 'C*' , @$ msg ) ;
while ( $ trys > 0 ) {
$ trys - - ;
$ error = "" ;
$ timedout = 0 ;
if ( $ debug ) {
print "try: $trys, timeout: $timeout\n" ;
}
if ( ! $ sock - > send ( $ send ) ) {
$ error = $! ;
sleep ( 1 ) ;
next ;
}
my $ s = IO::Select - > new ( $ sock ) ;
#local $SIG{ALRM} = sub { $timedout = 1 and die };
#alarm($timeout);
my $ received = $ s - > can_read ( $ timeout ) ;
2008-07-23 23:41:15 +00:00
if ( $ received and $ received > 0 ) {
2009-03-10 13:58:48 +00:00
if ( $ sock - > recv ( $ recv , 1300 ) ) {
2007-10-26 22:44:33 +00:00
if ( $ recv ) {
@ response = unpack ( "C*" , $ recv ) ;
last ;
}
} else {
$ error = $! ;
}
}
else {
$ error = "timeout" ;
}
###ugly updated hack to support md5.
if ( $ seq ) {
incseqnum ( ) ;
@$ msg [ 5 .. 8 ] = @ seqnum [ 0 .. 3 ] ;
@ message = @$ msg [ 30 .. @$ msg - 1 ] ;
if ( $ auth != 0x00 ) {
@$ msg [ 13 .. 28 ] = authcode ( 2 , \ @ message ) ;
}
$ send = pack ( 'C*' , @$ msg ) ;
}
}
if ( $ timedout == 1 ) {
if ( $ error ) {
$ error = "timeout $error"
}
else {
$ error = "timeout"
}
}
return ( $ error , @ response ) ;
}
sub dochksum ()
{
my $ data = shift ;
my $ sum = 0 ;
foreach ( @$ data ) {
$ sum += $ _ ;
}
$ sum = ~ $ sum + 1 ;
return ( $ sum & 0xFF ) ;
}
sub dopad16 {
my @ pad16 = unpack ( "C*" , shift ) ;
for ( my $ i = @ pad16 ; $ i < 16 ; $ i + + ) {
$ pad16 [ $ i ] = 0 ;
}
return ( @ pad16 ) ;
}
sub hexdump {
my $ data = shift ;
foreach ( @$ data ) {
printf ( "%02x " , $ _ ) ;
}
print "\n" ;
}
sub getascii {
my @ alpha ;
my $ text = "" ;
my $ c = 0 ;
foreach ( @ _ ) {
2008-09-18 03:48:13 +00:00
if ( defined $ _ and $ _ < 128 and $ _ > 0x20 ) {
$ alpha [ $ c ] = sprintf ( "%c" , $ _ ) ;
} else {
$ alpha [ $ c ] = " " ;
}
2008-09-22 20:01:54 +00:00
if ( $ alpha [ $ c ] !~ /[\/\w\-:\[\.\]]/ ) {
2007-10-26 22:44:33 +00:00
if ( $ alpha [ ( $ c - 1 ) ] !~ /\s/ ) {
$ alpha [ $ c ] = " " ;
} else {
$ c - - ;
}
}
$ c + + ;
}
foreach ( @ alpha ) {
$ text = $ text . $ _ ;
}
$ text =~ s/^\s+|\s+$// ;
return $ text ;
}
sub phex {
my $ data = shift ;
my @ alpha ;
my $ text = "" ;
my $ c = 0 ;
foreach ( @$ data ) {
$ text = $ text . sprintf ( "%02x " , $ _ ) ;
$ alpha [ $ c ] = sprintf ( "%c" , $ _ ) ;
if ( $ alpha [ $ c ] !~ /\w/ ) {
$ alpha [ $ c ] = " " ;
}
$ c + + ;
}
$ text = $ text . "(" ;
foreach ( @ alpha ) {
$ text = $ text . $ _ ;
}
$ text = $ text . ")" ;
return $ text ;
}
sub hexadump {
my $ data = shift ;
my @ alpha ;
my $ c = 0 ;
foreach ( @$ data ) {
printf ( "%02x " , $ _ ) ;
$ alpha [ $ c ] = sprintf ( "%c" , $ _ ) ;
if ( $ alpha [ $ c ] !~ /\w/ ) {
$ alpha [ $ c ] = "." ;
}
$ c + + ;
if ( $ c == 16 ) {
print " " ;
foreach ( @ alpha ) {
print $ _ ;
}
print "\n" ;
@ alpha = ( ) ;
$ c = 0 ;
}
}
foreach ( $ c .. 16 ) {
print " " ;
}
foreach ( @ alpha ) {
print $ _ ;
}
print "\n" ;
}
sub incseqnum {
my $ i ;
for ( $ i = 0 ; $ i < 4 ; $ i + + ) {
if ( $ seqnum [ $ i ] < 0xFF ) {
$ seqnum [ $ i ] + + ;
last ;
}
$ seqnum [ $ i ] = 0 ;
}
if ( $ seqnum [ 3 ] > 0xFF ) {
@ seqnum = ( 0 , 0 , 0 , 0 ) ;
}
}
sub incseqlun {
$ seqlun += 4 ;
if ( $ seqlun > 0xFF ) {
$ seqlun = 0 ;
}
}
sub authcode {
my $ type = shift ;
my $ message = shift ;
my @ authcode ;
if ( $ auth == 0x02 ) {
if ( $ type == 1 ) {
@ authcode = unpack ( "C*" , md5 ( pack ( "C*" , @ pass , @ session_id , @ challenge , @ pass ) ) ) ;
}
elsif ( $ type == 2 ) {
@ authcode = unpack ( "C*" , md5 ( pack ( "C*" , @ pass , @ session_id , @$ message , @ seqnum , @ pass ) ) ) ;
}
}
elsif ( $ auth == 0x04 ) {
@ authcode = @ pass ;
}
elsif ( $ auth == 0x00 ) {
@ authcode = ( ) ;
}
return ( @ authcode ) ;
}
sub comp2int {
my $ length = shift ;
my $ bits = shift ;
my $ neg = 0 ;
if ( $ bits & 2 ** ( $ length - 1 ) ) {
$ neg = 1 ;
}
$ bits & = ( 2 ** ( $ length - 1 ) - 1 ) ;
if ( $ neg ) {
$ bits -= 2 ** ( $ length - 1 ) ;
}
return ( $ bits ) ;
}
sub timestamp2datetime {
my $ ts = shift ;
2008-04-07 15:31:27 +00:00
if ( $ ts < 0x20000000 ) {
return "BMC Uptime" , sprintf ( "%6d s" , $ ts ) ;
}
2007-10-26 22:44:33 +00:00
my @ t = localtime ( $ ts ) ;
my $ time = strftime ( "%H:%M:%S" , @ t ) ;
my $ date = strftime ( "%m/%d/%Y" , @ t ) ;
return ( $ date , $ time ) ;
}
sub decodebcd {
my $ numbers = shift ;
my @ bcd ;
my $ text ;
my $ ms ;
my $ ls ;
foreach ( @$ numbers ) {
$ ms = ( $ _ & 0b11110000 ) >> 4 ;
$ ls = ( $ _ & 0b00001111 ) ;
push ( @ bcd , $ ms ) ;
push ( @ bcd , $ ls ) ;
}
foreach ( @ bcd ) {
if ( $ _ < 0x0a ) {
$ text . = $ _ ;
}
elsif ( $ _ == 0x0a ) {
$ text . = " " ;
}
elsif ( $ _ == 0x0b ) {
$ text . = "-" ;
}
elsif ( $ _ == 0x0c ) {
$ text . = "." ;
}
}
return ( $ text ) ;
}
sub storsdrcache {
my $ file = shift ;
my $ key ;
my $ fh ;
system ( "mkdir -p $cache_dir" ) ;
if ( ! open ( $ fh , ">$file" ) ) {
return ( 1 ) ;
}
flock ( $ fh , LOCK_EX ) || return ( 1 ) ;
foreach $ key ( keys % sdr_hash ) {
my $ r = $ sdr_hash { $ key } ;
store_fd ( $ r , $ fh ) ;
}
close ( $ fh ) ;
return ( 0 ) ;
}
sub loadsdrcache {
my $ file = shift ;
my $ r ;
my $ c = 0 ;
my $ fh ;
if ( ! open ( $ fh , "<$file" ) ) {
return ( 1 ) ;
}
flock ( $ fh , LOCK_SH ) || return ( 1 ) ;
while ( ) {
eval {
$ r = retrieve_fd ( $ fh ) ;
} || last ;
$ sdr_hash { $ r - > sensor_owner_id . "." . $ r - > sensor_owner_lun . "." . $ r - > sensor_number } = $ r ;
}
close ( $ fh ) ;
return ( 0 ) ;
}
2008-01-25 16:17:19 +00:00
sub preprocess_request {
my $ request = shift ;
2009-07-15 14:54:52 +00:00
if ( $ request - > { _xcatpreprocessed } - > [ 0 ] == 1 ) { return [ $ request ] ; }
#exit if preprocessed
2008-04-12 14:53:11 +00:00
my $ callback = shift ;
2008-01-25 16:17:19 +00:00
my @ requests ;
2008-04-12 14:53:11 +00:00
my $ noderange = $ request - > { node } ; #Should be arrayref
my $ command = $ request - > { command } - > [ 0 ] ;
my $ extrargs = $ request - > { arg } ;
my @ exargs = ( $ request - > { arg } ) ;
if ( ref ( $ extrargs ) ) {
@ exargs = @$ extrargs ;
}
my $ usage_string = xCAT::Usage - > parseCommand ( $ command , @ exargs ) ;
if ( $ usage_string ) {
$ callback - > ( { data = > $ usage_string } ) ;
$ request = { } ;
return ;
}
2009-03-25 02:56:58 +00:00
if ( $ command eq "rpower" ) {
my $ subcmd = $ exargs [ 0 ] ;
2009-05-21 21:19:42 +00:00
if ( $ subcmd eq '' ) {
$ callback - > ( { data = > [ "Please enter an action (eg: boot,off,on, etc)" , $ usage_string ] } ) ;
$ request = { } ;
return 0 ;
}
2009-03-25 02:56:58 +00:00
if ( ( $ subcmd ne 'stat' ) && ( $ subcmd ne 'state' ) && ( $ subcmd ne 'status' ) && ( $ subcmd ne 'on' ) && ( $ subcmd ne 'off' ) && ( $ subcmd ne 'softoff' ) && ( $ subcmd ne 'nmi' ) && ( $ subcmd ne 'cycle' ) && ( $ subcmd ne 'reset' ) && ( $ subcmd ne 'boot' ) ) {
$ callback - > ( { data = > [ "Unsupported command: $command $subcmd" , $ usage_string ] } ) ;
$ request = { } ;
return ;
}
}
2008-04-12 14:53:11 +00:00
if ( ! $ noderange ) {
$ usage_string = xCAT::Usage - > getUsage ( $ command ) ;
$ callback - > ( { data = > $ usage_string } ) ;
$ request = { } ;
return ;
}
2008-04-15 14:37:26 +00:00
#print "noderange=@$noderange\n";
# find service nodes for requested nodes
# build an individual request for each service node
my $ service = "xcat" ;
my $ sn = xCAT::Utils - > get_ServiceNode ( $ noderange , $ service , "MN" ) ;
# build each request for each service node
foreach my $ snkey ( keys %$ sn )
{
#print "snkey=$snkey\n";
my $ reqcopy = { %$ request } ;
$ reqcopy - > { node } = $ sn - > { $ snkey } ;
$ reqcopy - > { '_xcatdest' } = $ snkey ;
2009-07-15 14:54:52 +00:00
$ reqcopy - > { _xcatpreprocessed } - > [ 0 ] = 1 ;
2008-04-15 14:37:26 +00:00
push @ requests , $ reqcopy ;
}
return \ @ requests ;
2008-01-25 16:17:19 +00:00
}
2008-08-16 13:41:14 +00:00
sub getipmicons {
my $ argr = shift ;
#$argr is [$node,$nodeip,$nodeuser,$nodepass];
my $ cb = shift ;
my $ ipmicons = { node = > [ { name = > [ $ argr - > [ 0 ] ] } ] } ;
$ ipmicons - > { node } - > [ 0 ] - > { bmcaddr } - > [ 0 ] = $ argr - > [ 1 ] ;
$ ipmicons - > { node } - > [ 0 ] - > { bmcuser } - > [ 0 ] = $ argr - > [ 2 ] ;
$ ipmicons - > { node } - > [ 0 ] - > { bmcpass } - > [ 0 ] = $ argr - > [ 3 ] ;
$ cb - > ( $ ipmicons ) ;
}
2008-01-25 16:17:19 +00:00
2007-10-26 22:44:33 +00:00
sub process_request {
2008-04-12 14:53:11 +00:00
my $ request = shift ;
my $ callback = shift ;
my $ noderange = $ request - > { node } ; #Should be arrayref
my $ command = $ request - > { command } - > [ 0 ] ;
my $ extrargs = $ request - > { arg } ;
my @ exargs = ( $ request - > { arg } ) ;
if ( ref ( $ extrargs ) ) {
@ exargs = @$ extrargs ;
}
2007-10-26 22:44:33 +00:00
my $ ipmiuser = 'USERID' ;
my $ ipmipass = 'PASSW0RD' ;
my $ ipmitrys = 3 ;
my $ ipmitimeout = 2 ;
my $ ipmimaxp = 64 ;
my $ sitetab = xCAT::Table - > new ( 'site' ) ;
my $ ipmitab = xCAT::Table - > new ( 'ipmi' ) ;
my $ tmp ;
if ( $ sitetab ) {
2007-10-31 03:39:56 +00:00
( $ tmp ) = $ sitetab - > getAttribs ( { 'key' = > 'ipmimaxp' } , 'value' ) ;
2007-10-26 22:44:33 +00:00
if ( defined ( $ tmp ) ) { $ ipmimaxp = $ tmp - > { value } ; }
2007-10-31 03:39:56 +00:00
( $ tmp ) = $ sitetab - > getAttribs ( { 'key' = > 'ipmitimeout' } , 'value' ) ;
2007-10-26 22:44:33 +00:00
if ( defined ( $ tmp ) ) { $ ipmitimeout = $ tmp - > { value } ; }
2007-10-31 03:39:56 +00:00
( $ tmp ) = $ sitetab - > getAttribs ( { 'key' = > 'ipmiretries' } , 'value' ) ;
2007-10-26 22:44:33 +00:00
if ( defined ( $ tmp ) ) { $ ipmitrys = $ tmp - > { value } ; }
2007-10-31 03:39:56 +00:00
( $ tmp ) = $ sitetab - > getAttribs ( { 'key' = > 'ipmisdrcache' } , 'value' ) ;
2007-10-26 22:44:33 +00:00
if ( defined ( $ tmp ) ) { $ enable_cache = $ tmp - > { value } ; }
}
my $ passtab = xCAT::Table - > new ( 'passwd' ) ;
if ( $ passtab ) {
2007-10-31 03:39:56 +00:00
( $ tmp ) = $ passtab - > getAttribs ( { 'key' = > 'ipmi' } , 'username' , 'password' ) ;
2007-10-26 22:44:33 +00:00
if ( defined ( $ tmp ) ) {
$ ipmiuser = $ tmp - > { username } ;
$ ipmipass = $ tmp - > { password } ;
}
}
#my @threads;
my @ donargs = ( ) ;
2008-09-19 21:15:01 +00:00
if ( $ request - > { command } - > [ 0 ] =~ /fru/ ) {
my $ vpdtab = xCAT::Table - > new ( 'vpd' ) ;
$ vpdhash = $ vpdtab - > getNodesAttribs ( $ noderange , [ qw( serial mtm asset ) ] ) ;
}
2008-07-22 19:05:49 +00:00
my $ ipmihash = $ ipmitab - > getNodesAttribs ( $ noderange , [ 'bmc' , 'username' , 'password' ] ) ;
2007-10-26 22:44:33 +00:00
foreach ( @$ noderange ) {
my $ node = $ _ ;
my $ nodeuser = $ ipmiuser ;
my $ nodepass = $ ipmipass ;
my $ nodeip = $ node ;
my $ ent ;
if ( defined ( $ ipmitab ) ) {
2008-07-22 12:48:31 +00:00
$ ent = $ ipmihash - > { $ node } - > [ 0 ] ;
2007-10-26 22:44:33 +00:00
if ( ref ( $ ent ) and defined $ ent - > { bmc } ) { $ nodeip = $ ent - > { bmc } ; }
if ( ref ( $ ent ) and defined $ ent - > { username } ) { $ nodeuser = $ ent - > { username } ; }
if ( ref ( $ ent ) and defined $ ent - > { password } ) { $ nodepass = $ ent - > { password } ; }
}
push @ donargs , [ $ node , $ nodeip , $ nodeuser , $ nodepass ] ;
}
2008-08-16 13:41:14 +00:00
if ( $ request - > { command } - > [ 0 ] eq "getipmicons" ) {
foreach ( @ donargs ) {
getipmicons ( $ _ , $ callback ) ;
}
return ;
}
2008-09-25 03:04:56 +00:00
#get new node status
2009-03-25 02:56:58 +00:00
my % oldnodestatus = ( ) ; #saves the old node status
my @ allerrornodes = ( ) ;
2008-09-25 03:04:56 +00:00
my $ check = 0 ;
2009-03-24 03:12:03 +00:00
my $ global_check = 1 ;
if ( $ sitetab ) {
2009-03-24 19:44:23 +00:00
( my $ ref ) = $ sitetab - > getAttribs ( { key = > 'nodestatus' } , 'value' ) ;
2009-03-24 23:56:42 +00:00
if ( $ ref ) {
2009-03-24 19:44:23 +00:00
if ( $ ref - > { value } =~ /0|n|N/ ) { $ global_check = 0 ; }
2009-03-24 03:12:03 +00:00
}
}
2009-03-25 02:56:58 +00:00
2008-09-25 03:04:56 +00:00
if ( $ command eq 'rpower' ) {
2009-03-24 03:12:03 +00:00
if ( ( $ global_check ) && ( $ extrargs - > [ 0 ] ne 'stat' ) && ( $ extrargs - > [ 0 ] ne 'status' ) && ( $ extrargs - > [ 0 ] ne 'state' ) ) {
2008-09-25 03:04:56 +00:00
$ check = 1 ;
2009-03-25 02:56:58 +00:00
my @ allnodes = ( ) ;
2008-09-25 03:04:56 +00:00
foreach ( @ donargs ) { push ( @ allnodes , $ _ - > [ 0 ] ) ; }
2009-03-25 02:56:58 +00:00
#save the old status
my $ nodelisttab = xCAT::Table - > new ( 'nodelist' ) ;
if ( $ nodelisttab ) {
my $ tabdata = $ nodelisttab - > getNodesAttribs ( \ @ allnodes , [ 'node' , 'status' ] ) ;
foreach my $ node ( @ allnodes )
{
my $ tmp1 = $ tabdata - > { $ node } - > [ 0 ] ;
if ( $ tmp1 ) {
if ( $ tmp1 - > { status } ) { $ oldnodestatus { $ node } = $ tmp1 - > { status } ; }
else { $ oldnodestatus { $ node } = "" ; }
}
}
}
#print "oldstatus:" . Dumper(\%oldnodestatus);
#set the new status to the nodelist.status
my % newnodestatus = ( ) ;
my $ newstat ;
if ( ( $ extrargs - > [ 0 ] eq 'off' ) || ( $ extrargs - > [ 0 ] eq 'softoff' ) ) {
my $ newstat = $ ::STATUS_POWERING_OFF ;
$ newnodestatus { $ newstat } = \ @ allnodes ;
} else {
2008-09-25 03:04:56 +00:00
#get the current nodeset stat
if ( @ allnodes > 0 ) {
2008-09-26 23:07:45 +00:00
my $ nsh = { } ;
2009-03-20 21:36:49 +00:00
my ( $ ret , $ msg ) = xCAT::SvrUtils - > getNodesetStates ( \ @ allnodes , $ nsh ) ;
2008-09-26 23:07:45 +00:00
if ( ! $ ret ) {
foreach ( keys %$ nsh ) {
2009-03-25 02:56:58 +00:00
my $ newstat = xCAT_monitoring::monitorctrl - > getNodeStatusFromNodesetState ( $ _ , "rpower" ) ;
$ newnodestatus { $ newstat } = $ nsh - > { $ _ } ;
2008-09-25 03:04:56 +00:00
}
2009-03-25 02:56:58 +00:00
} else {
$ callback - > ( { data = > $ msg } ) ;
2008-09-25 03:04:56 +00:00
}
}
}
2009-03-25 02:56:58 +00:00
#print "newstatus" . Dumper(\%newnodestatus);
xCAT_monitoring::monitorctrl:: setNodeStatusAttributes ( \ % newnodestatus , 1 ) ;
2008-09-25 03:04:56 +00:00
}
}
2009-03-24 03:12:03 +00:00
2007-10-26 22:44:33 +00:00
my $ children = 0 ;
2009-05-08 18:11:59 +00:00
$ SIG { INT } = $ SIG { TERM } = sub { #prepare to process job termination and propogate it down
foreach ( keys % bmc_comm_pids ) {
kill 2 , $ _ ;
}
exit 0 ;
} ;
2009-04-03 14:40:21 +00:00
$ SIG { CHLD } = sub { my $ kpid ; do { $ kpid = waitpid ( - 1 , WNOHANG ) ; if ( $ bmc_comm_pids { $ kpid } ) { delete $ bmc_comm_pids { $ kpid } ; $ children - - ; } } while $ kpid > 0 ; } ;
2007-10-26 22:44:33 +00:00
my $ sub_fds = new IO:: Select ;
foreach ( @ donargs ) {
2008-10-21 03:08:55 +00:00
while ( $ children > $ ipmimaxp ) {
2009-03-25 02:56:58 +00:00
my $ handlednodes = { } ;
forward_data ( $ callback , $ sub_fds , $ handlednodes ) ;
2008-10-21 03:08:55 +00:00
#update the node status to the nodelist.status table
if ( $ check ) {
2009-03-25 02:56:58 +00:00
updateNodeStatus ( $ handlednodes , \ @ allerrornodes ) ;
2008-10-21 03:08:55 +00:00
}
}
2007-10-26 22:44:33 +00:00
$ children + + ;
my $ cfd ;
my $ pfd ;
2008-05-12 23:36:47 +00:00
socketpair ( $ pfd , $ cfd , AF_UNIX , SOCK_STREAM , PF_UNSPEC ) or die "socketpair: $!" ;
$ cfd - > autoflush ( 1 ) ;
$ pfd - > autoflush ( 1 ) ;
my $ child = xCAT::Utils - > xfork ( ) ;
2007-10-26 22:44:33 +00:00
unless ( defined $ child ) { die "Fork failed" } ;
2008-09-25 03:04:56 +00:00
if ( $ child == 0 ) {
2007-10-26 22:44:33 +00:00
close ( $ cfd ) ;
2008-09-25 03:04:56 +00:00
my $ rrc = donode ( $ pfd , $ _ - > [ 0 ] , $ _ - > [ 1 ] , $ _ - > [ 2 ] , $ _ - > [ 3 ] , $ ipmitimeout , $ ipmitrys , $ command , - args = > \ @ exargs ) ;
2007-10-26 22:44:33 +00:00
close ( $ pfd ) ;
2008-09-25 03:04:56 +00:00
exit ( 0 ) ;
}
2008-04-21 15:41:36 +00:00
$ bmc_comm_pids { $ child } = 1 ;
2007-10-26 22:44:33 +00:00
close ( $ pfd ) ;
$ sub_fds - > add ( $ cfd )
}
2008-05-12 23:36:47 +00:00
while ( $ sub_fds - > count > 0 and $ children > 0 ) {
2009-03-25 02:56:58 +00:00
my $ handlednodes = { } ;
forward_data ( $ callback , $ sub_fds , $ handlednodes ) ;
2008-10-21 03:08:55 +00:00
#update the node status to the nodelist.status table
if ( $ check ) {
2009-03-25 02:56:58 +00:00
updateNodeStatus ( $ handlednodes , \ @ allerrornodes ) ;
2008-09-25 03:04:56 +00:00
}
2008-10-21 03:08:55 +00:00
}
#Make sure they get drained, this probably is overkill but shouldn't hurt
my $ rc = 1 ;
while ( $ rc > 0 ) {
2009-03-25 02:56:58 +00:00
my $ handlednodes = { } ;
$ rc = forward_data ( $ callback , $ sub_fds , $ handlednodes ) ;
2008-10-21 03:08:55 +00:00
#update the node status to the nodelist.status table
if ( $ check ) {
2009-03-25 02:56:58 +00:00
updateNodeStatus ( $ handlednodes , \ @ allerrornodes ) ;
2008-09-25 03:04:56 +00:00
}
2009-03-25 02:56:58 +00:00
}
if ( $ check ) {
#print "allerrornodes=@allerrornodes\n";
#revert the status back for there is no-op for the nodes
my % old = ( ) ;
foreach my $ node ( @ allerrornodes ) {
my $ stat = $ oldnodestatus { $ node } ;
if ( exists ( $ old { $ stat } ) ) {
my $ pa = $ old { $ stat } ;
push ( @$ pa , $ node ) ;
}
else {
$ old { $ stat } = [ $ node ] ;
}
}
xCAT_monitoring::monitorctrl:: setNodeStatusAttributes ( \ % old , 1 ) ;
}
2008-10-21 03:08:55 +00:00
}
sub updateNodeStatus {
2009-03-25 02:56:58 +00:00
my $ handlednodes = shift ;
my $ allerrornodes = shift ;
foreach my $ node ( keys ( %$ handlednodes ) ) {
if ( $ handlednodes - > { $ node } == - 1 ) { push ( @$ allerrornodes , $ node ) ; }
2008-09-25 03:04:56 +00:00
}
2007-10-26 22:44:33 +00:00
}
2008-10-21 03:08:55 +00:00
2007-10-26 22:44:33 +00:00
sub forward_data { #unserialize data from pipe, chunk at a time, use magic to determine end of data structure
my $ callback = shift ;
my $ fds = shift ;
2008-09-25 03:04:56 +00:00
my $ errornodes = shift ;
2007-10-26 22:44:33 +00:00
my @ ready_fds = $ fds - > can_read ( 1 ) ;
my $ rfh ;
my $ rc = @ ready_fds ;
foreach $ rfh ( @ ready_fds ) {
my $ data ;
if ( $ data = <$rfh> ) {
while ( $ data !~ /ENDOFFREEZE6sK4ci/ ) {
$ data . = <$rfh> ;
}
2009-04-03 14:40:21 +00:00
eval { print $ rfh "ACK\n" ; } ; # Ignore ack loss to child that has given up and exited
2007-10-26 22:44:33 +00:00
my $ responses = thaw ( $ data ) ;
foreach ( @$ responses ) {
2008-10-03 17:46:31 +00:00
#save the nodes that has errors and the ones that has no-op for use by the node status monitoring
my $ no_op = 0 ;
if ( exists ( $ _ - > { node } - > [ 0 ] - > { errorcode } ) ) { $ no_op = 1 ; }
else {
my $ text = $ _ - > { node } - > [ 0 ] - > { data } - > [ 0 ] - > { contents } - > [ 0 ] ;
#print "data:$text\n";
if ( ( $ text ) && ( $ text =~ /$status_noop/ ) ) {
$ no_op = 1 ;
#remove the symbols that meant for use by node status
$ _ - > { node } - > [ 0 ] - > { data } - > [ 0 ] - > { contents } - > [ 0 ] =~ s/ $status_noop// ;
}
}
#print "data:". $_->{node}->[0]->{data}->[0]->{contents}->[0] . "\n";
if ( $ no_op ) {
2008-10-21 03:08:55 +00:00
if ( $ errornodes ) { $ errornodes - > { $ _ - > { node } - > [ 0 ] - > { name } - > [ 0 ] } = - 1 ; }
} else {
2008-10-03 17:46:31 +00:00
if ( $ errornodes ) { $ errornodes - > { $ _ - > { node } - > [ 0 ] - > { name } - > [ 0 ] } = 1 ; }
2008-09-25 03:04:56 +00:00
}
2007-10-26 22:44:33 +00:00
$ callback - > ( $ _ ) ;
}
} else {
$ fds - > remove ( $ rfh ) ;
close ( $ rfh ) ;
}
}
2008-03-10 15:36:44 +00:00
yield ; #Avoid useless loop iterations by giving children a chance to fill pipes
2007-10-26 22:44:33 +00:00
return $ rc ;
}
sub donode {
2008-09-06 16:17:01 +00:00
$ outfd = shift ;
2007-10-26 22:44:33 +00:00
my $ node = shift ;
2008-09-06 16:17:01 +00:00
$ currnode = $ node ;
2007-10-26 22:44:33 +00:00
my $ bmcip = shift ;
my $ user = shift ;
my $ pass = shift ;
my $ timeout = shift ;
my $ retries = shift ;
my $ command = shift ;
my % namedargs = @ _ ;
my $ transid = $ namedargs { - transid } ;
2008-03-12 02:57:01 +00:00
my $ extra = $ namedargs { - args } ;
my @ exargs = @$ extra ;
2007-10-26 22:44:33 +00:00
my ( $ rc , @ output ) = ipmicmd ( $ bmcip , 623 , $ user , $ pass , $ timeout , $ retries , 0 , $ command , @ exargs ) ;
my @ outhashes ;
2008-09-06 16:17:01 +00:00
sendoutput ( $ rc , @ output ) ;
2008-03-11 13:10:58 +00:00
yield ;
2007-10-26 22:44:33 +00:00
#my $msgtoparent=freeze(\@outhashes);
# print $outfd $msgtoparent;
2008-09-25 03:04:56 +00:00
return $ rc ;
2007-10-26 22:44:33 +00:00
}
2008-09-06 16:17:01 +00:00
sub sendoutput {
my $ rc = shift ;
foreach ( @ _ ) {
my % output ;
( my $ desc , my $ text ) = split ( /:/ , $ _ , 2 ) ;
unless ( $ text ) {
$ text = $ desc ;
} else {
$ desc =~ s/^\s+// ;
$ desc =~ s/\s+$// ;
if ( $ desc ) {
$ output { node } - > [ 0 ] - > { data } - > [ 0 ] - > { desc } - > [ 0 ] = $ desc ;
}
}
$ text =~ s/^\s+// ;
$ text =~ s/\s+$// ;
$ output { node } - > [ 0 ] - > { name } - > [ 0 ] = $ currnode ;
if ( $ rc ) {
$ output { node } - > [ 0 ] - > { errorcode } = [ $ rc ] ;
2009-03-02 18:33:59 +00:00
$ output { node } - > [ 0 ] - > { error } - > [ 0 ] = $ text ;
} else {
$ output { node } - > [ 0 ] - > { data } - > [ 0 ] - > { contents } - > [ 0 ] = $ text ;
2008-09-06 16:17:01 +00:00
}
#push @outhashes,\%output; #Save everything for the end, don't know how to be slicker with Storable and a pipe
print $ outfd freeze ( [ \ % output ] ) ;
print $ outfd "\nENDOFFREEZE6sK4ci\n" ;
yield ;
waitforack ( $ outfd ) ;
}
}
2007-10-26 22:44:33 +00:00
1 ;