From 5fac183b2ff07545888538eb99d77a05641700ff Mon Sep 17 00:00:00 2001 From: wuzhy Date: Fri, 29 Jan 2010 08:25:04 +0000 Subject: [PATCH] remove the additional file git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@5081 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd --- xCAT-server/lib/xcat/plugins/ipmi.pm.2 | 6688 ------------------------ 1 file changed, 6688 deletions(-) delete mode 100644 xCAT-server/lib/xcat/plugins/ipmi.pm.2 diff --git a/xCAT-server/lib/xcat/plugins/ipmi.pm.2 b/xCAT-server/lib/xcat/plugins/ipmi.pm.2 deleted file mode 100644 index 0461f62e6..000000000 --- a/xCAT-server/lib/xcat/plugins/ipmi.pm.2 +++ /dev/null @@ -1,6688 +0,0 @@ -#!/usr/bin/perl -# 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; -BEGIN -{ - $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; -} -use lib "$::XCATROOT/lib/perl"; -use strict; -use warnings "all"; -use xCAT::GlobalDef; -use xCAT_monitoring::monitorctrl; -use xCAT::SPD qw/decode_spd/; - -use POSIX qw(ceil floor); -use Storable qw(store_fd retrieve_fd thaw freeze); -use xCAT::Utils; -use xCAT::SvrUtils; -use xCAT::Usage; -use Thread qw(yield); -use LWP 5.64; -use HTTP::Request::Common; -my $tfactor = 0; -my $vpdhash; -my %bmc_comm_pids; -my $iem_support; -eval { - require IBM::EnergyManager; - $iem_support=1; -}; - -require Exporter; -our @ISA = qw(Exporter); -our @EXPORT = qw( - ipmiinit - ipmicmd -); - -sub handled_commands { - return { - rpower => 'nodehm:power,mgt', - renergy => 'nodehm:power,mgt', - getipmicons => 'ipmi', - rspconfig => 'nodehm:mgt', - rvitals => 'nodehm:mgt', - rinv => 'nodehm:mgt', - rsetboot => 'nodehm:mgt', - rbeacon => 'nodehm:mgt', - reventlog => 'nodehm:mgt', - rfrurewrite => 'nodehm:mgt', - getrvidparms => 'nodehm:mgt' - } -} - - -#use Data::Dumper; -use POSIX "WNOHANG"; -use IO::Handle; -use IO::Socket; -use IO::Select; -use Class::Struct; -use Digest::MD5 qw(md5); -use Digest::SHA1 qw(sha1); -use POSIX qw(WNOHANG mkfifo strftime); -use Fcntl qw(:flock); - - -#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); -my $outfd; #File descriptor for children to send messages to parent -my $currnode; #string to describe current node, presumably nodename -my $globrc=0; -my $userid; -my $passwd; -my $ipmi_bmcipaddr; -my $timeout; -my $port; -my $debug; -my $ndebug = 0; -my @cmdargv; -my $sock; -my @user; -my @pass; -my $channel_number; -my %sdr_hash; -my %fru_hash; -my %sessiondata; #hold per session variables, in preparation for single-process strategy -my %pendingtransactions; #list of peers with callbacks, callback arguments, and timer expiry data -my $ipmiv2=0; -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; -my $cache_version = 2; -my $frudex; #iterator for initfru to use - -my $status_noop="XXXno-opXXX"; - -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], -); -my %codes = ( - 0x00 => "Command Completed Normal", - 0xC0 => "Node busy, command could not be processed", - 0xC1 => "Invalid or unsupported command", - 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", -); - -#Payload types: -# 0 => IPMI (format 1 0) -# 1 => SOL 1 0 -# 0x10 => rmcp+ open req 1 0 -# 0x11 => rmcp+ response 1 0 -# 0x12 => rakp1 (all 1 0) -# 0x13 => rakp2 -# 0x14 => rakp3 -# 0x15 => rakp4 - -my %units = ( - 0 => "", #"unspecified", - 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 => '$', - fru_type => '$', - fru_subtype => '$', -}; - -struct FRU => { - rec_type => '$', - desc => '$', - value => '$', -}; - -sub decode_fru_locator { #Handle fru locator records - my @locator = @_; - my $sdr = SDR->new(); - $sdr->rec_type(0x11); - $sdr->sensor_owner_id("FRU"); - $sdr->sensor_owner_lun("FRU"); - $sdr->sensor_number($locator[7]); - 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; } - $sdr->id_string(pack("C*",@locator[17..17+$idlen-1])); - $sdr->fru_type($locator[11]); - $sdr->fru_subtype($locator[12]); - - return $sdr; -} - -sub waitforack { - my $sock = shift; - my $select = new IO::Select; - $select->add($sock); - my $str; - if ($select->can_read(60)) { # Continue after 60 seconds, even if not acked... - if ($str = <$sock>) { - } else { - $select->remove($sock); #Block until parent acks data - } - } -} -sub translate_sensor { - my $reading = shift; - my $sdr = shift; - my $unitdesc; - my $value; - my $lformat; - my $per; - $unitdesc = $units{$sdr->sensor_units_2}; - 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) { - $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 = "% "; - } 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); - } - } - } - } - 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)"; - } - return "$reading $unitdesc"; -} - - -sub openrmcpplussession { - #we would request ciphersuite 3, but because AES encryption is surprisingly not included in most distro perl - #crypt::cbc may be of interest - #we are going to start with ciphersuite 2 for now. This is roughly equivalent to 1.5 security - #table 13-9 - #table 13-7 has 1 == SHA1, so does 13-18 - #table 13-9 has AES-CBC-128 as 1, none as 0 - my $sessdata = shift; - my @msg = (6,0,0xff,7,6); #RMCP header, ASF 2, FF seq#, 07 for IPMI, authtype of ipmi2 - push @msg, 0x10; #Set payload type to 10h to indicate an open rmcp+ session request - push @msg, (0,0,0,0); #session id of null as it is non-applicable - push @msg, (0,0,0,0); #seqnum should be zero for this -# need to calculate the payload length, store in 16 bits - my @payload; - my $tag = rand(255); #tag to identify this packet to IPMI device and ourlesves - push @payload, $tag; - push @payload, 0; #request max privilege level rather than specific privileged - push @payload, (0,0); #reserved space, making zero - my $sessid = rand(4294967295); #pick a session id, then put the pieces in the message - $sessdata->{client_sessionid} = $sessid; #Store with the session data for future reference - push @payload, $sessid >> 24 & 0xff; - push @payload, $sessid >> 16 & 0xff; - push @payload, $sessid >> 8 & 0xff; - push @payload, $sessid >> 0 & 0xff; - push @payload, (0,0,0,8,1,0,0,0); #SHA1-96 auth - push @payload, (1,0,0,8,1,0,0,0); #sha1-96 integrity - push @payload, (2,0,0,8,0,0,0,0); #no confidentiality (TODO: AES) - my $psize = scalar @payload; - push @msg, $psize >> 0 & 0xff; - push @msg, $psize >> 8 & 0xff; - push @msg, @payload; - my $send = pack('C*',@msg);#TODO: split here and register callback instead of blocking - my $error; - if(!$sock->send($send)) { - $error = $!; - } - if ($error) { - return $error; - } - my $s = IO::Select->new($sock); - #local $SIG{ALRM} = sub { $timedout = 1 and die }; - #alarm($timeout); - my $received = $s->can_read($timeout); - my $recv; - if($received and $received > 0) { - if ($sock->recv($recv,1300)) { - if($recv) { - my @response = unpack("C*",$recv); - use Data::Dumper; - print Dumper(\@response); - die 'happy'; - } - } - } -} - -sub ipmi_event_loop_iter { #one iteration of an event loop - my $s = IO::Select->new($sock); - my $received = $s->can_read(0); - my $data; - my $peerinf; - my $peerport; - my $peeraddr; - my @cookeddata; - while ($s->can_read(0)) { - $peerinf = $sock->recv($data,1500); #No Jumbo frames I suppose - ($peerport,$peeraddr) = sockaddr_in($peerinf); - $peeraddr = inet_ntoa($peeraddr); #Perhaps not IPv6 friendly, but neither is IPMI currently - unless ($pendingtransactions{$peeraddr}) { #if we have no pending transactions for this peer, skip him - next; #In theory, an SOL function would just leave a callback registered - } - #For now, we only support one transaction per peer, as we have no mechanism to distinguish one packet from another - #may extend this segment to deep dive and support one pending transaction per payload type per peer (where we classify IPMI 1.5 as a 'payload of its own) to allow SOL data and a request to live together on single sessions and be properly sorted on the wa out. - @cookeddata = unpack('C*',$data); - if (defined $pendingtransactions{$peeraddr}->{callback}) { - pendingtransactions{$peeraddr}->{callback}->($pendingtransactions{$peeraddr}->{callback_args},{},@cookeddata); - } - } - my $currtime = time; - - foreach $peeraddr (keys %pendingtransactions) { - if ($pendingtransactions{$peeraddr}->{timeout_time} > $currtime) { - if ($pendingtransactions{$peeraddr}->{retries} > 0) { - $pendingtransactions{$peeraddr}->{retries} -= 1; - $pendingtransactions{$peeraddr}->{timeout_time} = time()+$timeout; - } else { - $pendingtransactions{$peeraddr}->{callback}->($pendingtransactions{$peeraddr}->{callback_args},{timedout=>1}); - unless ($pendingtransactions{$peeraddr}->{persist_callback}) { - delete $pendingtransactions{$peeraddr}; - } - } - } - } -} - - - - - - -sub ipmiv2sessionestablish { - my $sessdata = shift; - openrmcpplussession($sessdata); -} -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) { - ($tmp)=$table->getAttribs({'key'=>'ipmimaxp'},'value'); - if (defined($tmp)) { $ipmimaxp=$tmp->{value}; } - ($tmp)=$table->getAttribs({'key'=>'ipmitimeout'},'value'); - if (defined($tmp)) { $ipmitimeout=$tmp->{value}; } - ($tmp)=$table->getAttribs({'key'=>'ipmiretries'},'value'); - if (defined($tmp)) { $ipmitrys=$tmp->{value}; } - ($tmp)=$table->getAttribs({'key'=>'ipmisdrcache'},'value'); - } - $table = xCAT::Table->new('passwd'); - if ($table) { - ($tmp)=$table->getAttribs({'key'=>'ipmi'},'username','password'); - 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; - my $sessdata = 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); - $sessdata->{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; - @cmdargv = @_; - my $subcommand = shift; - - - 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); - } - $ipmi_bmcipaddr=inet_ntoa($packed_ip); - - #TODO: open only one socket for multiple bmcs (http://docstore.mik.ua/orelly/perl/cookbook/ch17_05.htm) - $sock = IO::Socket::INET->new( - Proto => 'udp', - PeerHost => $ipmi_bmcipaddr, #this would change in a multi-client-single-socket scenario, see url above for how - PeerPort => $port, - ); - if(!defined($sock)) { - $text = "failed to get socket: $@\n"; - return(2,$text); - } - - $error = getchanauthcap($sessdata); #TODO: split function into submission and response handling halves here - if($error) { - return(1,$error); - } - if($debug) { - print "$node: gotchanauthcap\n"; - } - - if($command eq "ping") { - return(0,"ping"); - } - - if (defined $sessdata->{ipmi_version} and $sessdata->{ipmi_version} eq '2,0') { #perform RAKP transation to get session going - $error = ipmiv2sessionestablish($sessdata); #TODO: chain to 'setprivlevel' on completion in an asynchronous model - } else { - $error = getsessionchallenge(); #TODO: split here to chain to activatesession - 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"; - } - } - #TODO: split here to setprivlevel - - $error = setprivlevel(); #TODO: split here to generic function call - if($error) { - return(1,$error); - } - if($debug) { - print "$node: priv level set\n"; - } - - if($command eq "rpower") { #TODO: this should have been a function on it's own instead of all here - if($subcommand eq "stat" || $subcommand eq "state" || $subcommand eq "status") { - ($rc,$text) = power("stat"); - } - elsif($subcommand eq "on") { - my ($oldrc,$oldtext) = power("stat"); - ($rc,$text) = power("on"); - if(($rc == 0) && ($text eq "on") && ($oldtext eq "on")) { $text .= " $status_noop"; } - } - elsif($subcommand eq "nmi") { - ($rc,$text) = power("nmi"); - } - elsif($subcommand eq "off" or $subcommand eq "softoff") { - my ($oldrc,$oldtext) = power("stat"); - ($rc,$text) = power($subcommand); - if(($rc == 0) && ($text eq "off") && ($oldtext eq "off")) { $text .= " $status_noop"; } - -# if($text0 ne "") { -# $text = $text0 . " " . $text; -# } - } - elsif($subcommand eq "reset") { - my ($oldrc,$oldtext) = power("stat"); - ($rc,$text) = power("reset"); - $noclose = 0; - if(($rc == 0) && ($text eq "off") && ($oldtext eq "off")) { $text .= " $status_noop"; } - } - 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"); - $noclose = 0; - } - 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); - } - elsif($command eq "getrvidparms") { - ($rc,@output) = getrvidparms($subcommand); #TODO: tricky, this wouldn't fit into the non-fork diagram cleanly - } -# 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 "renergy") { - ($rc,@output) = renergy($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") { #TODO: if this is actually still used, it needs to be moved, else, killed - 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); - - my $child = xCAT::Utils->xfork(); - 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 = ; - 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") { - my @subcommands = ($subcommand); - if($subcommand eq "all") { - @subcommands = ( - "ip", - "netmask", - "gateway", - "backupgateway", - "snmpdest1", - "snmpdest2", - "snmpdest3", - "snmpdest4", - "community", - ); - - my @coutput; - - foreach(@subcommands) { - $subcommand = $_; - ($rc,@output) = getnetinfo($subcommand); - push(@coutput,@output); - } - - @output = @coutput; - } - else { - ($rc,@output) = getnetinfo($subcommand); - } - } - elsif($command eq "rspconfig") { - foreach ($subcommand,@_) { - my @coutput; - ($rc,@coutput) = setnetinfo($_); - if($rc == 0) { - ($rc,@coutput) = getnetinfo($_); - } - push(@output,@coutput); - } - } - elsif($command eq "sete325cli") { - ($rc,@output) = sete325cli($subcommand); - } - elsif($command eq "sete326cli") { - ($rc,@output) = sete325cli($subcommand); - } - elsif($command eq "generic") { - ($rc,@output) = generic($subcommand); - } - elsif($command eq "rfrurewrite") { - ($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(); - if($error) { - return(1,"$text, session close: $error"); - } - 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[0]) { - $text = "BMC reset"; - } else { - if ($codes{$returnd[0]}) { - $text = $codes{$returnd[0]}; - } else { - $text = sprintf("BMC Responded with code %d",$returnd[36]); - } - } - } - return($rc,$text); -} - -sub setnetinfo { - my $subcommand = shift; - my $argument; - ($subcommand,$argument) = split(/=/,$subcommand); - my @input = @_; - - my $netfun = 0x30; - my @cmd; - my @returnd = (); - my $error; - my $rc = 0; - my $text; - my $code; - my $match; - - if($subcommand eq "snmpdest") { - $subcommand = "snmpdest1"; - } - - - unless(defined($argument)) { - return 0; - } - if ($subcommand eq "thermprofile") { - return idpxthermprofile($argument); - } - if ($subcommand eq "alert" and $argument eq "on" or $argument =~ /^en/ or $argument =~ /^enable/) { - $netfun = 0x10; - @cmd = (0x12,0x9,0x1,0x18,0x11,0x00); - } elsif ($subcommand eq "alert" and $argument eq "off" or $argument =~ /^dis/ or $argument =~ /^disable/) { - $netfun = 0x10; - @cmd = (0x12,0x9,0x1,0x10,0x11,0x00); - } - elsif($subcommand eq "garp") { - my $halfsec = $argument * 2; #pop(@input) * 2; - - if($halfsec > 255) { - $halfsec = 255; - } - if($halfsec < 4) { - $halfsec = 4; - } - - @cmd = (0x01,$channel_number,0x0b,$halfsec); - } - 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); - } - elsif($subcommand =~ m/snmpdest(\d+)/ ) { - my $dstip = $argument; #pop(@input); - 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); - } - #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); - #} - else { - return(1,"configuration of $subcommand is not implemented currently"); - } - - $error = docmd( - $netfun, - \@cmd, - \@returnd - ); - - if($error) { - $rc = 1; - $text = $error; - } - else { - if($subcommand eq "garp" or $subcommand =~ m/snmpdest\d+/ or $subcommand eq "alert" or $subcommand =~ /community/) { - $code = $returnd[0]; - - if($code == 0x00) { - $text = "ok"; - } - } - - if(!$text) { - $rc = 1; - $text = sprintf("unknown response %02x",$code); - } - } - - return($rc,$text); -} - -sub getnetinfo { - my $subcommand = shift; - $subcommand =~ s/=.*//; - if ($subcommand eq "thermprofile") { - my $code; - my @returnd; - my $thermdata; - 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,16; - my $validprofiles=""; - foreach (keys %idpxthermprofiles) { - if (sprintf("%02x %02x %02x %02x %02x %02x %02x",@bytes) eq sprintf("%02x %02x %02x %02x %02x %02x %02x",@{$idpxthermprofiles{$_}})) { - $validprofiles.="$_,"; - } - } - if ($validprofiles) { - chop($validprofiles); - return (0,"The following thermal profiles are in effect: ".$validprofiles); - } - return (1,sprintf("Unable to identify current thermal profile: \"%02x %02x %02x %02x %02x %02x %02x\"",@bytes)); - } - - 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"; - } - - if ($subcommand eq "alert") { - $netfun = 0x10; - @cmd = (0x13,9,1,0); - } - elsif($subcommand eq "garp") { - @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 - ); - - - if($error) { - $rc = 1; - $text = $error; - } - else { - # 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) - if($subcommand eq "garp") { - $code = $returnd[0]; - - if($code == 0x00) { - $code = $returnd[2] / 2; - $text = sprintf("$format %d","Gratuitous ARP seconds:",$code); - } - else { - $rc = 1; - $text = $codes{$code}; - } - } - elsif($subcommand eq "alert") { - if ($returnd[3] & 0x8) { - $text = "SP Alerting: enabled"; - } else { - $text = "SP Alerting: disabled"; - } - } - elsif($subcommand =~ m/^snmpdest(\d+)/ ) { - $text = sprintf("$format %d.%d.%d.%d", - "SP SNMP Destination $1:", - $returnd[5], - $returnd[6], - $returnd[7], - $returnd[8]); - } - elsif($subcommand eq "ip") { - $text = sprintf("$format %d.%d.%d.%d", - "BMC IP:", - $returnd[2], - $returnd[3], - $returnd[4], - $returnd[5]); - } - elsif($subcommand eq "netmask") { - $text = sprintf("$format %d.%d.%d.%d", - "BMC Netmask:", - $returnd[2], - $returnd[3], - $returnd[4], - $returnd[5]); - } - elsif($subcommand eq "gateway") { - $text = sprintf("$format %d.%d.%d.%d", - "BMC Gateway:", - $returnd[2], - $returnd[3], - $returnd[4], - $returnd[5]); - } - elsif($subcommand eq "backupgateway") { - $text = sprintf("$format %d.%d.%d.%d", - "BMC Backup Gateway:", - $returnd[2], - $returnd[3], - $returnd[4], - $returnd[5]); - } - elsif ($subcommand eq "community") { - $text = sprintf("$format ","SP SNMP Community:"); - my $l = 2; - while ($returnd[$l] ne 0) { - $l = $l + 1; - } - my $i=2; - 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', - 15 => 'Floppy' - ); - - #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); - } - elsif ($subcommand eq "floppy" ) { - @cmd=(0x08,0x5,0x80,0x3c,0x0,0x0,0x0); - } - 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[0]; - unless ($code == 0x00) { - return(1,$codes{$code}); - } - } - @cmd=(0x09,0x5,0x0,0x0); - $error = docmd( - $netfun, - \@cmd, - \@returnd - ); - if($error) { - return(1,$error); - } - $code = $returnd[0]; - unless ($code == 0x00) { - return(1,$codes{$code}); - } - unless ($returnd[3] & 0x80) { - $text = "boot override inactive"; - return($rc,$text); - } - my $boot=($returnd[4] & 0x3C) >> 2; - $text = $bootchoices{$boot}; - return($rc,$text); -} - -sub idpxthermprofile { - #iDataplex thermal profiles as of 6/10/2008 - my $subcommand = lc(shift); - my @returnd; - my $netfun = 0xb8; - my @cmd = (0x41,0x4d,0x4f,0x00,0x6f,0xfe,0x60,0,0,0,0,0,0,0,0xff); - if ($idpxthermprofiles{$subcommand}) { - push @cmd,@{$idpxthermprofiles{$subcommand}}; - } 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"); -} - - -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); - } - 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"); - } - $jnlp =~ s!argument>title=.*Video Viewer!argument>title=$currnode wvid!; - 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); -} - - -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); - } - elsif($subcommand eq "softoff") { - @cmd = (0x02,0x05); - } - 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[0]; - - if($code == 0x00) { - $code = $returnd[1]; - - if($code & 0b00000001) { - $text = "on"; - } - else { - $text = "off"; - } - } - else { - $rc = 1; - $text = $codes{$code}; - } - } - if($subcommand eq "nmi") { - $code = $returnd[0]; - - if($code == 0x00) { - $text="nmi"; - } - else { - $rc = 1; - $text = $codes{$code}; - } - } - if($subcommand eq "on") { - $code = $returnd[0]; - - if($code == 0x00) { - $text="on"; - } - else { - $rc = 1; - $text = $codes{$code}; - } - } - if($subcommand eq "softoff") { - $code = $returnd[0]; - - if($code == 0x00) { - $text="softoff"; - } - else { - $rc = 1; - $text = $codes{$code}; - } - } - if($subcommand eq "off") { - $code = $returnd[0]; - - if($code == 0x00) { - $text="off"; - } - elsif($code == 0xd5) { - $text="off"; - } - else { - $rc = 1; - $text = $codes{$code}; - } - } - if($subcommand eq "reset") { - $code = $returnd[0]; - - 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[0]; - - if($code == 0x00) { - } - else { - $rc = 1; - $text = $codes{$code}; - } - - printf("return code: 0x%02x\n\n",$code); - - print "return data:\n"; - my @rdata = @returnd[1..@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; - if($subcommand eq ""){ - return(1,"please specify on or off for ipmi nodes"); - } - if($subcommand eq "on") { - if ($ipmiv2) { - @cmd = (0x04,0x0,0x01); - } else { - @cmd = (0x04,0xFF); - } - } - elsif($subcommand eq "off") { - if ($ipmiv2) { - @cmd = (0x04,0x0,0x00); - } else { - @cmd = (0x04,0x00); - } - } - 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[0]; - - if($code == 0x00) { - $text="on"; - } - else { - $rc = 1; - $text = $codes{$code}; - } - } - if($subcommand eq "off") { - $code = $returnd[0]; - - 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"; - - ($rc,$text) = initsdr(); #Look for those precious locator reconds - if($rc != 0) { - return($rc,$text); - } - ($rc,$text) = initfru(); - if($rc != 0) { - return($rc,$text); - } - - unless ($subcommand) { - $subcommand = "all"; - } - if($subcommand eq "all") { - @types = qw(model serial deviceid mprom guid misc hw asset); - } - elsif($subcommand eq "asset") { - @types = qw(asset); - } - 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); - } - elsif($subcommand eq "misc") { - @types = qw(misc); - } - elsif($subcommand eq "deviceid") { - @types = qw(deviceid); - } - elsif($subcommand eq "guid") { - @types = qw(guid); - } - elsif($subcommand eq "uuid") { - @types = qw(guid); - } - else { - @types = ($subcommand); - #return(1,"unsupported BMC inv argument $subcommand"); - } - - my $otext; - my $key; - - foreach $key (sort keys %fru_hash) { - my $fru = $fru_hash{$key}; - 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; - } - } - } - - 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[0]; - - 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[1..@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[0]; - - 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[1..@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,""); - } - 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,""); - - - return(1,"No OEM FRU Support"); -} - -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); - if (not ref $_) { - $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; - my $type = shift; - unless ($type) { $type = 'hw'; } - 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"); - add_textual_fru($parsedfru,$desc." ".$categorydesc."",$category,"name","hw"); - if ($parsedfru->{$category}->{builddate}) { - add_textual_fru($parsedfru,$desc." ".$categorydesc."Manufacture Date",$category,"builddate","hw"); - } - 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"); - } - add_textual_fru($parsedfru,$desc." ".$categorydesc."Additional Info",$category,"extra","hw"); -} - -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); - } - elsif ($mfg_id == 2) { - my @lcmd = (0x50); - my @lreturnd = (); - my $lerror = docmd( - 0xe8, - \@lcmd, - \@lreturnd - ); - if ($lerror eq "" && $lreturnd[0] == 0) { - my @a = ($fw_rev2); - my @b= @lreturnd[1 .. $#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)); - } - } else { - my @a = ($fw_rev2); - $mprom = sprintf("%d.%s",$fw_rev1,decodebcd(\@a)); - } - - $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,""); -# } - $netfun = 0x28; # Storage (0x0A << 2) - my @bytes; - @cmd=(0x10,0x00); - $error = docmd($netfun,\@cmd,\@bytes); - if ($error) { return (1,$error); } - 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]; - - ($rc,@bytes) = frudump(0,$frusize,16); - if($rc != 0) { - return($rc,@bytes); - } - my $fruhash; - ($error,$fruhash) = parsefru(\@bytes); - if ($error) { - ($rc,$text)=initoemfru($mfg_id,$prod_id,$device_id); - if($rc == 1) { - $text = "FRU format unknown"; - return($rc,$text); - } - if($rc == 2) { - return(0,""); - } - } - $frudex=0; - 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 { - #print Dumper($_); - #print $_->{encoding}; - next; - $fru->value(phex($_->{value})); - } - $fru_hash{$frudex++} = $fru; - } - - - 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; - } - - 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; - } - - - foreach (@{$fruhash->{chassis}->{extra}}) { - $fru = FRU->new(); - $fru->rec_type("misc"); - $fru->desc("Chassis Extra data"); - if ($_->{encoding} == 3) { - $fru->value($_->{value}); - } else { - next; - #print Dumper($_); - #print $_->{encoding}; - $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 { - next; - #print Dumper($_); - #print $_->{encoding}; - $fru->value(phex($_->{value})); - } - $fru_hash{$frudex++} = $fru; - } - #Ok, done with fru 0, on to the other fru devices from SDR - my $key; - my $subrc; - 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; - } - - 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; - } - my $parsedfru = decode_spd(@bytes); - add_textual_frus($parsedfru,$sdr->id_string,"",'product','dimm,hw'); - } 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'); - } - } - } - - - - return($rc,$text); -} -sub get_frusize { - my $fruid=shift; - my $netfun = 0x28; # Storage (0x0A << 2) - my @cmd=(0x10,$fruid); - my @bytes; - my $error = docmd($netfun,\@cmd,\@bytes); - 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]; -} - -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; - $availindex+=ceil((scalar @{$fruhash->{internal}})/8); - $frusize-=(scalar @{$fruhash->{internal}}); #consume internal bytes - push @bytes,@{$fruhash->{internal}}; - } - if ($fruhash->{chassis}) { - $bytes[2]=$availindex; - push @bytes,@{$fruhash->{chassis}->{raw}}; - $availindex+=ceil((scalar @{$fruhash->{chassis}->{raw}})/8); - $frusize -= ceil((scalar @{$fruhash->{chassis}->{raw}})/8)*8; - } - if ($fruhash->{board}) { - $bytes[3]=$availindex; - push @bytes,@{$fruhash->{board}->{raw}}; - $availindex+=ceil((scalar @{$fruhash->{board}->{raw}})/8); - $frusize -= ceil((scalar @{$fruhash->{board}->{raw}})/8)*8; - } - #xCAT will always have a product FRU in this process - $bytes[4]=$availindex; - unless (defined $fruhash->{product}) { #Make sure there is a data structure - #to latch onto.. - $fruhash->{product}={}; - } - my @prodbytes = buildprodfru($fruhash->{product}); - push @bytes,@prodbytes; - $availindex+=ceil((scalar @prodbytes)/8); - $frusize -= ceil((scalar @prodbytes)/8)*8;; - #End of product fru setup - if ($fruhash->{extra}) { - $bytes[5]=$availindex; - push @bytes,@{$fruhash->{extra}}; - $frusize -= ceil((scalar @{$fruhash->{extra}})/8)*8; - #Don't need to track availindex anymore - } - $bytes[7] = dochksum([@bytes[0..6]]); - if ($frusize<0) { - return undef; - } else { - return \@bytes; - } -} - -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); - if ($size > 64) { - die "Field too large for IPMI FRU specification"; - } - unshift(@data,$size|($hashref->{encoding}<<6)); - return @data; -} -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}; - } -} - -sub buildprodfru { - my $prod=shift; - mergefru($prod); - 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}}) { - my $sig=getascii(transfieldtobytes($_)); - unless ($sig and $sig =~ /FRU by xCAT/) { - push @bytes,transfieldtobytes($_); - } - } - push @bytes,transfieldtobytes({encoding=>3,value=>"$currnode FRU by xCAT ".xCAT::Utils::Version('short')}); - 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; - - return @bytes; -} - -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[0]; - - 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[1]; - my $fru_size_ms = $returnd[2]; - 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; - my $fruid = shift; - unless (defined $fruid) { $fruid = 0; } - unless ($length) { return (1,$chunk); } #chunk happens to get the error text - - 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; - my $reqsize = $chunk; - if ($c+$chunk > $length+$offset) { - $reqsize = ($length+$offset-$c); - } - - @cmd=(0x11,$fruid,$ls,$ms,$reqsize); - $error = docmd( - $netfun, - \@cmd, - \@returnd - ); - - if($error) { - $rc = 1; - $text = $error; - return($rc,$text); - } - - $code = $returnd[0]; - - if($code == 0x00) { - } - else { - $rc = 1; - $text = $codes{$code}; - } - - if($rc != 0) { - if(!$text) { - $text = sprintf("unknown response %02x",$code); - } - return($rc,$text); - } - - my $count = $returnd[1]; - if($count != $reqsize) { - $rc = 1; - $text = "FRU read error (bytes requested: $reqsize, got: $count)"; - return($rc,$text); - } - - my @data = @returnd[2..@returnd-2]; - @fru_data = (@fru_data,@data); - } - - return(0,@fru_data); -} - -sub parsefru { - my $bytes = shift; - my $fruhash; - 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 - $fruhash->{internal}=[@{$bytes}[($bytes->[1]*8)..($bytes->[1]*8+$internal_size-1)]]; #,$bytes->[1]*8,$internal_size]; - } - 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; - @currarea=@{$bytes}[$curridx..($curridx+$currsize-1)]; #splice @$bytes,$curridx,$currsize; - $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; - @currarea=@{$bytes}[$curridx..($curridx+$currsize-1)]; - $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; - @currarea=@{$bytes}[$curridx..($curridx+$currsize-1)]; - $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]; - push @{$fruhash->{extra}},$bytes->[$curridx..$curridx+4+$currsize-1]; - } - } - return 0,$fruhash; -} - -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) { - push @{$info{extra}},{value=>$currdata,encoding=>$encode}; - } - $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 - unless ($tstamp == 820472400) { - $boardinf{builddate}=scalar localtime($tstamp); - } - 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) { - push @{$boardinf{extra}},{value=>$currdata,encoding=>$encode}; - } - $idx+=$currsize; - ($currsize,$currdata,$encode)=extractfield(\@area,$idx); - } - return \%boardinf; -} -sub parsechassis { - my @chassarea=@_; - my %chassisinf; - my $currsize; - my $currdata; - my $idx=3; - my $encode; - $chassisinf{raw}=[@chassarea]; #store for verbatim replacement - $chassisinf{type}="unknown"; - if ($chassis_types{$chassarea[2]}) { - $chassisinf{type}=$chassis_types{$chassarea[2]}; - } - if ($chassarea[$idx] == 0xc1) { - return \%chassisinf; - } - ($currsize,$currdata,$encode)=extractfield(\@chassarea,$idx); - unless ($currsize) { - return \%chassisinf; - } - $idx+=$currsize; - if ($currsize>1) { - $chassisinf{partnumber}->{encoding}=$encode; - $chassisinf{partnumber}->{value}=$currdata; - } - ($currsize,$currdata,$encode)=extractfield(\@chassarea,$idx); - unless ($currsize) { - return \%chassisinf; - } - $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) { - push @{$chassisinf{extra}},{value=>$currdata,encoding=>$encode}; - } - $idx+=$currsize; - ($currsize,$currdata,$encode)=extractfield(\@chassarea,$idx); - } - 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]); - } else { - $data = [@$area[$idx+1..$size+$idx]]; - } - return $size+1,$data,$encoding; -} - - - - - - -sub writefru { - my $netfun = 0x28; # Storage (0x0A << 2) - my @cmd=(0x10,0); - my @bytes; - my $error = docmd($netfun,\@cmd,\@bytes); - 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); - if ($error) { - return (1,"Error retrieving FRU: ".$error); - } - my $fruhash; - ($error,$fruhash) = parsefru(\@bytes); - my $newfru=formfru($fruhash,$frusize); - unless ($newfru) { - return (1,"FRU data will not fit in BMC FRU space, fields too long"); - } - my $rc=1; - my $writeattempts=0; - my $text; - while ($rc and $writeattempts<15) { - if ($writeattempts) { - sleep 1; - } - ($rc,$text) = fruwrite(0,$newfru,8); - if ($text =~ /rotected/) { - last; - } - $writeattempts++; - } - 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[0]; - - if($code == 0x00) { - } - else { - $rc = 1; - $text = $codes{$code}; - } - - if($rc != 0) { - if ($code == 0x80) { - $text = "Write protected FRU"; - } - if(!$text) { - $text = sprintf("unknown response %02x",$code); - } - return($rc,$text); - } - - my $count = $returnd[1]; - if($count != $chunk) { - $rc = 1; - $text = "FRU write error (bytes requested: $chunk, wrote: $count)"; - return($rc,$text); - } - } - - return(0); -} - -sub decodealert { - my $trap = shift; - my $skip_sdrinit=0; - if ($trap =~ /xCAT_plugin::ipmi/) { - $trap=shift; - $skip_sdrinit=1; - } - my $node = shift; - my @pet = @_; - my $rc; - my $text; - - if (!$skip_sdrinit) { - ($rc,$text) = initsdr(); - if($rc != 0) { - return($rc,$text); - } - } - - 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); - } - - my @hex = (0,@pet); - 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); -} - -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; } - 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)) { - my @subdata = splice @data,0,30; - my $numbytes = scalar(@subdata); - my $formatstring="%02x"x$numbytes; - $formatstring =~ s/%02x%02x/%02x%02x /g; - $text.=sprintf($formatstring."\n",@subdata); - } - $text.=$addtext; - return (0,$entrynum,$text); - - -} - - - -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; - my $skiptail=0; - 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; - unless (defined($subcommand)) { - $subcommand = 'all'; - } - if($subcommand eq "all") { - $skiptail=1; - - $num = 0x100 * 0x100; - } - elsif($subcommand eq "clear") { - } - elsif($subcommand =~ /^\d+$/) { - $num = $subcommand; - } - else { - return(1,"unsupported command eventlog $subcommand"); - } - - #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[4]<<24 | $returnd[3]<<16 | $returnd[2]<<8 | $returnd[1]; - if ($tfactor > 0x20000000) { - $tfactor -= time(); - } else { - $tfactor = 0; - } - - @cmd=(0x40); - $error = docmd( - $netfun, - \@cmd, - \@returnd - ); - - if($error) { - $rc = 1; - $text = $error; - return($rc,$text); - } - - $code = $returnd[0]; - - 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[1]; - 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[3]*256 + $returnd[2]; - if($num_entries <= 0) { - $rc = 1; - $text = "no SEL entries"; - return($rc,$text); - } - - my $canres = $returnd[14] & 0b00000010; - if(!$canres) { - $rc = 1; - $text = "SEL reservation not supported"; - return($rc,$text); - } - - my $res_id_ls=0; - my $res_id_ms=0; - my %auxloginfo; - 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[0]; - - 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); - } - - $res_id_ls = $returnd[1]; - $res_id_ms = $returnd[2]; - } 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); - #print Dumper(\@auxdata); - 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}) { - $auxloginfo{$entry}.="!".$extdata; - } else { - $auxloginfo{$entry}=$extdata; - } - } - } - if ($auxloginfo{0}) { - if ($skiptail) { - foreach (split /!/,$auxloginfo{0}) { - sendoutput(0,":Unassociated auxillary data detected:"); - foreach (split /\n/,$_) { - sendoutput(0,$_); - } - } - } - } - #print Dumper(\%auxloginfo); - } - } - - - 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[0]; - - 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[1] & 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[0]; - - 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[1] & 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; - if ($skiptail) { - sendoutput($rc,$text); - return; - } - push(@output,$text); - return($rc,@output); - } - - $code = $returnd[0]; - - 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); - } - if ($skiptail) { - sendoutput($rc,$text); - return; - } - push(@output,$text); - return($rc,@output); - } - - my $next_rec_ls = $returnd[1]; - my $next_rec_ms = $returnd[2]; - my @sel_data = @returnd[3..19]; - @cmd=(0x43,$res_id_ls,$res_id_ms,$next_rec_ls,$next_rec_ms,0x00,0xFF); - - $entry++; - if ($debug) { - print "$entry: "; - hexdump(\@sel_data); - } - - 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); - if ($auxloginfo{$entry}) { - $text.=" With additional data:\n".$auxloginfo{$entry}; - } - if ($skiptail) { - sendoutput($rc,$text); - } else { - push(@output,$text); - } - if($next_rec_ms == 0xFF && $next_rec_ls == 0xFF) { - last; - } - next; - } - - my $timestamp = ($sel_data[3] | $sel_data[4]<<8 | $sel_data[5]<<16 | $sel_data[6]<<24); - 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 - } - 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; - 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}); - } - } - } - } - - $text = "$text ($sensor_desc)"; - - if($event_dir) { - $text = "$text - Recovered"; - } - - if ($auxloginfo{$entry}) { - $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}; - } - - } else { - if ($skiptail) { - sendoutput($rc,$text); - } else { - push(@output,$text); - } - } - - 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; - my $text=":"; - if ($record_type < 0xE0 && $record_type > 0x2F) { #Should be timestampped, whatever it is - my $timestamp = (@$sel_data[3] | @$sel_data[4]<<8 | @$sel_data[5]<<16 | @$sel_data[6]<<24); - unless ($timestamp < 0x20000000) { - $timestamp -= $tfactor; - } - my ($seldate,$seltime) = timestamp2datetime($timestamp); - my @rest = @$sel_data[7..15]; - if ($mfg_id==2) { - $text.="$seldate $seltime IBM OEM Event-"; - 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 { - $text .= "$seldate $seltime " . sprintf("Unknown OEM SEL Type %02x:",$record_type) . phex(\@rest); - } - } 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); - } - } - return (0,"No Mappings found ($sensortype)","No Mappings found ($sensoroffset)"); -} - -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 = ""; - - 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); - } - - 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", - 0x0d => "CPU speed matching failure", - ); - $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}; - } - } - 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"; - } - } - - 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/^, //; - } - } - 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"; - } - 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/^, //; - } - 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; - } - } - } - - 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)"; - } - } - } - - - - return($text); -} - -sub initiem { - my $iem = IBM::EnergyManager->new(); - my @payload = $iem->get_next_payload(); - my $netfun = shift @payload; - my @returnd; - my $error = docmd( - $netfun<<2, - \@payload, - \@returnd - ); - $iem->handle_next_payload(@returnd); - return $iem; -} - -sub readenergy { - unless ($iem_support) { - return (1,"IBM::EnergyManager package required for this value"); - } - my @entries; - my $iem = initiem(); - my $entry; - $iem->prep_get_ac_energy(); - $entry = process_data_from_iem($iem); - $iem->prep_get_precision(); - execute_iem_commands($iem); #this gets all precision data initialized - $entry .= sprintf(" +/-%.1f%%",$iem->energy_ac_precision()*0.1); #note while \x{B1} would be cool, it's non-trivial to support - push @entries,$entry; - $iem->prep_get_dc_energy(); - $entry = process_data_from_iem($iem); - $entry .= sprintf(" +/-%.1f%%",$iem->energy_dc_precision()*0.1); - push @entries,$entry; - return (0,@entries); - -} - -sub execute_iem_commands { - my $iem = shift; - my @payload = $iem->get_next_payload(); - my @returnd; - while (scalar @payload) { - my $netfun = shift @payload; - my $error = docmd($netfun<<2,\@payload,\@returnd); - if ($error) { return $error; } - $iem->handle_next_payload(@returnd); - @payload = $iem->get_next_payload(); - } - return 0; -} - -sub process_data_from_iem { - my $iem = shift; - my @returnd; - my @iemdata; - if (!execute_iem_commands($iem)) { - @iemdata = $iem->extract_data; - } - my $label = shift @iemdata; - my $units = shift @iemdata; - my $value=0; - my $shift=0; - while (scalar @iemdata) { #stuff the 64-bits of data into an int, would break in 32 bit - $value+=pop(@iemdata)<<$shift; - #$value.=sprintf("%02x ",shift @iemdata); - $shift+=8; - } - if ($units eq "mJ") { - $units = "kWh"; - $value = $value / 3600000000; - return sprintf("$label: %.4f $units",$value); - } elsif ($units eq "mW") { - $units = "W"; - $value = $value / 1000.0; - return sprintf("$label: %.1f $units",$value); - } -} - -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) { - return (0,"LED status not supported on this system"); - } - - ($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}; - if($sdr->rec_type == 0xC0 && $sdr->sensor_type == 0xED) { - #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[0] == 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); - } - } - - if ($returnd[2]) { # != 0) { - #It's on... - if ($returnd[6] == 4) { - push(@output,sprintf("BIOS or admininstrator has %s lit",getsensorname($mfg_id,$prod_id,$sdr->led_id,"ibmleds"))); - } - elsif ($returnd[6] == 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[6] == 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[4],$returnd[5],getsensorname($mfg_id,$prod_id,($returnd[4]<<8)+$returnd[5],"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[6] == 2) { - my $sensor_desc; - #Ok, LED is tied to a sensor.. - my $sensor_num=$returnd[5]; - 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 renergy { - my @subcommands = shift; - my @output; - my @settable_keys = qw/savingstatus cappingstatus cappingwatt/; - unless ($iem_support) { - return (1,"Command unsupported without IBM::EnergyManager installed"); - } - my $iem = initiem(); - my @directives=(); - foreach (@subcommands) { - push @directives,split /,/,$_; - } - my $directive; - my $value; - my $key; - foreach $directive (@directives) { - $value=undef; - $key=undef; - if ($directive =~ /(.*)=(.*)\z/) { #todo: assigment - $key = $1; - $value = $2; - unless (grep /$key/,@settable_keys and $value) { - return (1,"Malformed argument $directive"); - } - if ($key eq "cappingwatt") { - $value = $value*1000; #convert to milliwatts - $iem->prep_set_cap($value); - execute_iem_commands($iem); #this gets all precision data initialized - } - if ($key eq "cappingstatus") { - if (grep /$value/,qw/enable on 1/) { - $value = 1; - } else { - $value = 0; - } - $iem->prep_set_capenable($value); - execute_iem_commands($iem); #this gets all precision data initialized - } - - } - if ($directive =~ /cappingmaxmin/) { - my $entry; - $iem->prep_get_mincap(); - $entry = process_data_from_iem($iem); - push @output,$entry; - $iem->prep_get_maxcap(); - $entry = process_data_from_iem($iem); - push @output,$entry; - } - if ($directive =~ /cappingvalue/) { - my $entry; - $iem->prep_get_cap(); - push @output,process_data_from_iem($iem); - } - if ($directive =~ /cappingstatus/) { - my $entry; - $iem->prep_get_powerstatus(); - execute_iem_commands($iem); - my $capenabled = $iem->capping_enabled(); - push @output,"cappingstatus: ".($capenabled ? "on" : "off"); - } - if ($directive =~ /relhistogram/) { - my $entry; - $iem->prep_retrieve_histogram(); - execute_iem_commands($iem); - my @histdata = $iem->extract_relative_histogram; - foreach (sort { $a <=> $b } keys %{$histdata[0]}) { - push @output,"$_: ".$histdata[0]->{$_}; - } - } - } - return (0,@output); -} -sub vitals { - my $subcommand = shift; - my @textfilters = split /,/,$subcommand; - unless (scalar @textfilters) { @textfilters = ("all"); } - - my $rc = 0; - my $text; - my $key; - my %sensor_filters=(); - my @output; - my $reading; - my $unitdesc; - my $value; - my $extext; - my $format = "%-30s%8s %-20s"; - my $per = " "; - my $doall; - $doall=0; - $rc=0; - #filters: defined in sensor type codes and data table - # 1 == temp, 2 == voltage 3== current (we lump in wattage here for lack of a better spot), 4 == fan - - if(grep { $_ eq "all"} @textfilters) { - $sensor_filters{1}=1; #,0x02,0x03,0x04); rather than filtering, unfiltered results - $sensor_filters{energy}=1; - $doall=1; - } - if(grep /temp/,@textfilters) { - $sensor_filters{0x01}=1; - } - if(grep /volt/,@textfilters) { - $sensor_filters{0x02}=1; - } - if(grep /watt/,@textfilters) { - $sensor_filters{0x03}=1; - } - if(grep /fan/,@textfilters) { - $sensor_filters{0x04}=1; - } - if(grep /power/,@textfilters) { #power does not really include energy, but most people use 'power' to mean both - $sensor_filters{0x03}=1; - $sensor_filters{powerstate}=1; - $sensor_filters{energy}=1; - } - if(grep /energy/,@textfilters) { - $sensor_filters{energy}=1; - } - if(grep /led/,@textfilters) { - $sensor_filters{leds}=1; - } - unless (keys %sensor_filters) { - return(1,"unsupported command vitals $subcommand"); - } - - ($rc,$text) = initsdr(); - if($rc != 0) { - return($rc,$text); - } - - foreach(keys %sensor_filters) { - my $filter = $_; - if ($filter eq "energy" or $filter eq "leds") { next; } - - foreach $key (sort {$sdr_hash{$a}->id_string cmp $sdr_hash{$b}->id_string} keys %sdr_hash) { - my $sdr = $sdr_hash{$key}; - if(($doall and not $sdr->rec_type == 0x11 and not $sdr->sensor_type==0xed) or ($sdr->rec_type == 0x01 and $sdr->sensor_type == $filter)) { - my $lformat = $format; - - ($rc,$reading,$extext) = readsensor($sdr); - $unitdesc = ""; - if($rc == 0) { - $unitdesc = $units{$sdr->sensor_units_2}; - - $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) { - $reading = $value; - if($value == int($value)) { - $lformat = "%-30s%8d%s"; - } - else { - $lformat = "%-30s%8.3f%s"; - } - } - elsif($sdr->linearization == 7) { - if($value > 0) { - $reading = 1/$value; - } - else { - $reading = 0; - } - $lformat = "%-30s%8d %s"; - } - else { - $reading = "RAW(".$sdr->linearization.") $reading"; - } - - if($sdr->sensor_units_1 & 1) { - $per = "% "; - } 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); - } - } - } - } - - if($unitdesc eq "Watts") { - my $f = ($reading * 3.413); - $unitdesc = "Watts (".int($f+.5)." BTUs/hr)"; - } - 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)"; - } - } - #$unitdesc.= sprintf(" %x",$sdr->sensor_type); - $text = sprintf($lformat,$sdr->id_string . ":",$reading,$per.$unitdesc); - if ($extext) { - $text="$text ($extext)"; - } - push(@output,$text); - } -# else { -# printf("%x %s %d\n",$sdr->sensor_number,$sdr->id_string,$sdr->sensor_type); -# } - } - } - - if($sensor_filters{leds}) { - my @cleds; - ($rc,@cleds) = checkleds(); - push @output,@cleds; - } - if ($sensor_filters{powerstate}) { - ($rc,$text) = power("stat"); - $text = sprintf($format,"Power Status:",$text,""); - push(@output,$text); - } - if ($sensor_filters{energy}) { - my @energies; - ($rc,@energies)=readenergy(); - push @output,@energies; - } - - return($rc,@output); -} - -sub readsensor { - my $sdr = shift; - my $sensor = $sdr->sensor_number; - 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[0]; - if($code != 0x00) { - $rc = 1; - $text = $codes{$code}; - - if(!$text) { - $text = sprintf("unknown response %02x",$code); - } - chomp $text; - - return($rc,$text); - } - - if ($returnd[2] & 0x20) { - $rc = 1; - $text = "N/A"; - return($rc,$text); - } - $text = $returnd[1]; - my $exdata1 = $returnd[3]; - my $exdata2 = $returnd[3]; - 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; - } - } - - return($rc,$text,$extext); -} - -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[0]; - 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[1]; - $nrid_ms = $returnd[2]; -### correct IPMI code -# $rid_ls = $returnd[3]; -# $rid_ms = $returnd[4]; -### - $sdr_ver = $returnd[5]; - $sdr_type = $returnd[6]; - $sdr_len = $returnd[7] + 5; - - if($sdr_type == 0x01) { - $sdr_offset = 0; - } - elsif($sdr_type == 0x02) { - $sdr_offset = 16; - } - elsif($sdr_type == 0xC0) { - #LED descriptor, maybe - } - elsif($sdr_type == 0x11) { #FRU locator - } - 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[0]; - 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[3..@returnd-2]); - - $offset += $len; - } - 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; - } - - 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); - $sdr->id_string("LED"); - 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]); - $sdr->event_type_code($sdr_data[14]); - $sdr->sensor_units_2($sdr_data[22]); - $sdr->sensor_units_3($sdr_data[23]); - - if($sdr_type == 0x01) { - $sdr->sensor_units_1($sdr_data[21]); - $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)); - } elsif ($sdr_type == 0x02) { - $sdr->sensor_units_1($sdr_data[21]); - } - - $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 { - unless (defined $sdr->id_string_type) { next; } - $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) { - 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; - } - } - } - - $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}) { - return $xCAT::data::ibmleds::leds{"$mfgid,$prodid"}->{$sensor}. " LED"; - } elsif ($ndebug) { - return "Unknown $sensor/$mfgid/$prodid"; - } else { - return sprintf ("LED 0x%x",$sensor); - } - } 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[0]; - 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[1..@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[0]; - - 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[1]; - my $device_rev = $returnd[2] & 0b00001111; - my $firmware_rev1 = $returnd[3] & 0b01111111; - my $firmware_rev2 = $returnd[4]; - my $ipmi_ver = $returnd[5]; - my $dev_support = $returnd[6]; - 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[7] + $returnd[8]*0x100 + $returnd[9]*0x10000; - my $prod_id = $returnd[10] + $returnd[11]*0x100; - my @data = @returnd[12..@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[0]; - - 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[1..16]; - 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[0]; - - 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[1]); - $sdr_rep_info->rec_count($returnd[2] + $returnd[3]*0x100); - $sdr_rep_info->resv_sdr(($returnd[14] & 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[0]; - - 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[1]; - my $resv_id_ms = $returnd[2]; - - 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); - splice @$response,0,36-$authoffset; - - return($error); -} - -sub getchanauthcap { - my $sessdata = shift; - $auth = 0x00; - my $netfun = 0x18; - my @data; - my @rn; - my $length; - - my @msg; - my $error = ""; - my @response; - my $code; - - @data = ($rqsa,$seqlun,0x38,0x8e,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]; - 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]; - } - if($code != 0x00) { - $error = $codes{$code}; - if(!$error) { - $error = "Unknown get channel authentication capabilities error $code" - } - return($error); - } - - $channel_number=$response[21]; - - if($response[22] & 0b10000000 and $response[24] & 0b00000010) { - $ipmiv2=1; - $sessdata->{ipmi_version} = '2.0'; #currently could be a number, but it could devolve - } - 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"; - } - - 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"; - } - } - -###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 - ); - - ($error,@response) = domsg($sock,\@msg,$timeout,1); - - 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); - if($received and $received > 0) { - if ($sock->recv($recv,1300)) { - 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(@_) { - if (defined $_ and $_ < 128 and $_ > 0x20) { - $alpha[$c] = sprintf("%c",$_); - } else { - $alpha[$c]=" "; - } - if($alpha[$c] !~ /[\/\w\-:\[\.\]]/) { - 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; - if ($ts < 0x20000000) { - return "BMC Uptime",sprintf("%6d s",$ts); - } - 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); -} - - -sub preprocess_request { - my $request = shift; - if ($request->{_xcatpreprocessed}->[0] == 1) { return [$request]; } - #exit if preprocessed - my $callback=shift; - my @requests; - - 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; - } - - if ($command eq "rpower") { - my $subcmd=$exargs[0]; - if($subcmd eq ''){ - $callback->({data=>["Please enter an action (eg: boot,off,on, etc)", $usage_string]}); - $request = {}; - return 0; - - } - 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; - } - } - - - if (!$noderange) { - $usage_string=xCAT::Usage->getUsage($command); - $callback->({data=>$usage_string}); - $request = {}; - return; - } - - #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; - $reqcopy->{_xcatpreprocessed}->[0] = 1; - push @requests, $reqcopy; - } - return \@requests; -} - - -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); -} - - - - -sub process_request { - 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; - } - 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) { - ($tmp)=$sitetab->getAttribs({'key'=>'ipmimaxp'},'value'); - if (defined($tmp)) { $ipmimaxp=$tmp->{value}; } - ($tmp)=$sitetab->getAttribs({'key'=>'ipmitimeout'},'value'); - if (defined($tmp)) { $ipmitimeout=$tmp->{value}; } - ($tmp)=$sitetab->getAttribs({'key'=>'ipmiretries'},'value'); - if (defined($tmp)) { $ipmitrys=$tmp->{value}; } - ($tmp)=$sitetab->getAttribs({'key'=>'ipmisdrcache'},'value'); - if (defined($tmp)) { $enable_cache=$tmp->{value}; } - } - my $passtab = xCAT::Table->new('passwd'); - if ($passtab) { - ($tmp)=$passtab->getAttribs({'key'=>'ipmi'},'username','password'); - if (defined($tmp)) { - $ipmiuser = $tmp->{username}; - $ipmipass = $tmp->{password}; - } - } - - #my @threads; - my @donargs=(); - if ($request->{command}->[0] =~ /fru/) { - my $vpdtab = xCAT::Table->new('vpd'); - $vpdhash = $vpdtab->getNodesAttribs($noderange,[qw(serial mtm asset)]); - } - my $ipmihash = $ipmitab->getNodesAttribs($noderange,['bmc','username','password']) ; - foreach(@$noderange) { - my $node=$_; - my $nodeuser=$ipmiuser; - my $nodepass=$ipmipass; - my $nodeip = $node; - my $ent; - if (defined($ipmitab)) { - $ent=$ipmihash->{$node}->[0]; - 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]; - } - if ($request->{command}->[0] eq "getipmicons") { - foreach (@donargs) { - getipmicons($_,$callback); - } - return; - } - - #get new node status - my %oldnodestatus=(); #saves the old node status - my @allerrornodes=(); - my $check=0; - my $global_check=1; - if ($sitetab) { - (my $ref) = $sitetab->getAttribs({key => 'nodestatus'}, 'value'); - if ($ref) { - if ($ref->{value} =~ /0|n|N/) { $global_check=0; } - } - } - - - if ($command eq 'rpower') { - if (($global_check) && ($extrargs->[0] ne 'stat') && ($extrargs->[0] ne 'status') && ($extrargs->[0] ne 'state')) { - $check=1; - my @allnodes=(); - foreach (@donargs) { push(@allnodes, $_->[0]); } - - #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 { - #get the current nodeset stat - if (@allnodes>0) { - my $nsh={}; - my ($ret, $msg)=xCAT::SvrUtils->getNodesetStates(\@allnodes, $nsh); - if (!$ret) { - foreach (keys %$nsh) { - my $newstat=xCAT_monitoring::monitorctrl->getNodeStatusFromNodesetState($_, "rpower"); - $newnodestatus{$newstat}=$nsh->{$_}; - } - } else { - $callback->({data=>$msg}); - } - } - } - #print "newstatus" . Dumper(\%newnodestatus); - xCAT_monitoring::monitorctrl::setNodeStatusAttributes(\%newnodestatus, 1); - } - } - - my $children = 0; - $SIG{INT} = $SIG{TERM} = sub { #prepare to process job termination and propogate it down - foreach (keys %bmc_comm_pids) { - kill 2, $_; - } - exit 0; - }; - $SIG{CHLD} = sub {my $kpid; do { $kpid = waitpid(-1, WNOHANG); if ($bmc_comm_pids{$kpid}) { delete $bmc_comm_pids{$kpid}; $children--; } } while $kpid > 0; }; - my $sub_fds = new IO::Select; - foreach (@donargs) { - while ($children > $ipmimaxp) { - my $handlednodes={}; - forward_data($callback,$sub_fds,$handlednodes); - #update the node status to the nodelist.status table - if ($check) { - updateNodeStatus($handlednodes, \@allerrornodes); - } - } - $children++; - my $cfd; - my $pfd; - socketpair($pfd, $cfd,AF_UNIX,SOCK_STREAM,PF_UNSPEC) or die "socketpair: $!"; - $cfd->autoflush(1); - $pfd->autoflush(1); - binmode($cfd,':utf8'); - binmode($pfd,':utf8'); - my $child = xCAT::Utils->xfork(); - unless (defined $child) { die "Fork failed" }; - if ($child == 0) { - close($cfd); - my $rrc=donode($pfd,$_->[0],$_->[1],$_->[2],$_->[3],$ipmitimeout,$ipmitrys,$command,-args=>\@exargs); - close($pfd); - exit(0); - } - $bmc_comm_pids{$child}=1; - close ($pfd); - $sub_fds->add($cfd) - } - while ($sub_fds->count > 0 and $children > 0) { - my $handlednodes={}; - forward_data($callback,$sub_fds,$handlednodes); - #update the node status to the nodelist.status table - if ($check) { - updateNodeStatus($handlednodes, \@allerrornodes); - } - } - - #Make sure they get drained, this probably is overkill but shouldn't hurt - my $rc=1; - while ( $rc>0 ) { - my $handlednodes={}; - $rc=forward_data($callback,$sub_fds,$handlednodes); - #update the node status to the nodelist.status table - if ($check) { - updateNodeStatus($handlednodes, \@allerrornodes); - } - } - - 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); - } -} - -sub updateNodeStatus { - my $handlednodes=shift; - my $allerrornodes=shift; - foreach my $node (keys(%$handlednodes)) { - if ($handlednodes->{$node} == -1) { push(@$allerrornodes, $node); } - } -} - - - -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; - my $errornodes=shift; - - 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>; - } - eval { print $rfh "ACK\n"; }; # Ignore ack loss to child that has given up and exited - my $responses=thaw($data); - foreach (@$responses) { - #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) { - if ($errornodes) { $errornodes->{$_->{node}->[0]->{name}->[0]}=-1; } - } else { - if ($errornodes) { $errornodes->{$_->{node}->[0]->{name}->[0]}=1; } - } - $callback->($_); - } - } else { - $fds->remove($rfh); - close($rfh); - } - } - yield; #Avoid useless loop iterations by giving children a chance to fill pipes - return $rc; -} - -sub donode { - $outfd = shift; - my $node = shift; - $currnode=$node; - my $bmcip = shift; - my $user = shift; - my $pass = shift; - my $timeout = shift; - my $retries = shift; - my $command = shift; - $sessiondata{$node} = { - node => $node, #this seems redundant, but some code will not be privy to what the key was - bmc => $bmcip, - user => $user, - pass => $pass, - }; - my %namedargs=@_; - my $transid = $namedargs{-transid}; - my $extra=$namedargs{-args}; - my @exargs=@$extra; - my ($rc,@output) = ipmicmd($bmcip,623,$user,$pass,$timeout,$retries,0,$sessiondata{$node},$command,@exargs); - my @outhashes; - sendoutput($rc,@output); - yield; - #my $msgtoparent=freeze(\@outhashes); - # print $outfd $msgtoparent; - return $rc; -} - -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]; - $output{node}->[0]->{error}->[0]=$text; - } else { - $output{node}->[0]->{data}->[0]->{contents}->[0]=$text; - } - #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); - } -} - -1;