git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@13956 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
		
			
				
	
	
		
			377 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			377 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
 | 
						|
 | 
						|
package xCAT::FSPflash;
 | 
						|
use strict;
 | 
						|
use lib "/opt/xcat/lib/perl";
 | 
						|
use Getopt::Long;
 | 
						|
use xCAT::PPCcli qw(SUCCESS EXPECT_ERROR RC_ERROR NR_ERROR);
 | 
						|
use xCAT::Usage;
 | 
						|
use xCAT::PPCinv;
 | 
						|
use xCAT::DSHCLI;
 | 
						|
use xCAT::Table;
 | 
						|
use Getopt::Long;
 | 
						|
use File::Spec;
 | 
						|
use xCAT::PPCrflash;
 | 
						|
#use Data::Dumper;
 | 
						|
use xCAT::FSPUtils;
 | 
						|
 | 
						|
my $packages_dir= ();
 | 
						|
my $activate	= ();
 | 
						|
my $verbose	= 0;
 | 
						|
my $release_level;
 | 
						|
my $active_level;
 | 
						|
my @dirlist;
 | 
						|
 | 
						|
#######################################
 | 
						|
# This flag tracks the operation to be performed.  If set, it means we need
 | 
						|
# to commit a previously applied update or else recover from one.
 | 
						|
#######################################
 | 
						|
my $housekeeping = undef;
 | 
						|
 | 
						|
#####################################
 | 
						|
#For -V|--verbose,put the $msg into @value
 | 
						|
###################################
 | 
						|
sub dpush {
 | 
						|
	my $value = shift;
 | 
						|
	my $msg = shift;
 | 
						|
 | 
						|
	if($verbose == 1) {
 | 
						|
		push(@$value,$msg);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
##########################################################################
 | 
						|
# Parse the command line for options and operands 
 | 
						|
##########################################################################
 | 
						|
sub parse_args {
 | 
						|
    my $req = shift; 
 | 
						|
    $req->{mgt} = __PACKAGE__;
 | 
						|
    my $opt = xCAT::PPCrflash::parse_args($req);
 | 
						|
    delete($req->{mgt});
 | 
						|
    return $opt;
 | 
						|
}
 | 
						|
 | 
						|
##########################################################################
 | 
						|
# Invokes the callback with the specified message                    
 | 
						|
##########################################################################
 | 
						|
sub send_msg {
 | 
						|
 | 
						|
    my $request = shift;
 | 
						|
    my $ecode   = shift;
 | 
						|
    my %output;
 | 
						|
 | 
						|
    #################################################
 | 
						|
    # Called from child process - send to parent
 | 
						|
    #################################################
 | 
						|
    if ( exists( $request->{pipe} )) {
 | 
						|
        my $out = $request->{pipe};
 | 
						|
 | 
						|
        $output{errorcode} = $ecode;
 | 
						|
        $output{data} = \@_;
 | 
						|
        print $out freeze( [\%output] );
 | 
						|
        print $out "\nENDOFFREEZE6sK4ci\n";
 | 
						|
    }
 | 
						|
    #################################################
 | 
						|
    # Called from parent - invoke callback directly
 | 
						|
    #################################################
 | 
						|
    elsif ( exists( $request->{callback} )) {
 | 
						|
        my $callback = $request->{callback};
 | 
						|
 | 
						|
        $output{errorcode} = $ecode;
 | 
						|
        $output{data} = \@_;
 | 
						|
        $callback->( \%output );
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------------------------#
 | 
						|
# get_lic_filenames - construct and validate the lup filenames for each   #
 | 
						|
# each node                                                               #
 | 
						|
#-------------------------------------------------------------------------#
 | 
						|
#
 | 
						|
sub get_lic_filenames {
 | 
						|
	my $mtms = shift;
 | 
						|
	my $upgrade_required = 0;	
 | 
						|
	my $msg = undef;
 | 
						|
	my $filename;
 | 
						|
 | 
						|
	if(! -d $packages_dir) {
 | 
						|
              $msg = "The directory $packages_dir doesn't exist!";
 | 
						|
              return ("","","", $msg, -1);
 | 
						|
        }
 | 
						|
        
 | 
						|
	#print "opening directory and reading names\n";
 | 
						|
        opendir DIRHANDLE, $packages_dir;
 | 
						|
        @dirlist= readdir DIRHANDLE;
 | 
						|
        closedir DIRHANDLE;
 | 
						|
 | 
						|
        @dirlist = File::Spec->no_upwards( @dirlist );
 | 
						|
 | 
						|
        # Make sure we have some files to process
 | 
						|
        #
 | 
						|
        if( !scalar( @dirlist ) ) {
 | 
						|
        	$msg = "directory $packages_dir is empty";
 | 
						|
                return ("","","",$msg, -1);
 | 
						|
        }
 | 
						|
 | 
						|
        $release_level =~/(\w{4})(\d{3})/;
 | 
						|
        my $pns = $1;
 | 
						|
	my $fff = $2;
 | 
						|
		
 | 
						|
	#Find the latest version lic file
 | 
						|
        @dirlist = grep /\.rpm$/, @dirlist;
 | 
						|
        @dirlist = grep /$1/, @dirlist;
 | 
						|
        if( !scalar( @dirlist ) ) {
 | 
						|
		$msg = "There isn't a package suitable for $mtms";
 | 
						|
                return ("","","",$msg, -1);
 | 
						|
	}
 | 
						|
        if( scalar(@dirlist) > 1) {
 | 
						|
         # Need to find the latest version package.
 | 
						|
        	@dirlist =reverse sort(@dirlist);
 | 
						|
                my $t = "\n";
 | 
						|
                foreach $t(@dirlist) {
 | 
						|
                       $msg =$msg."$t\t";
 | 
						|
                }
 | 
						|
         }
 | 
						|
 | 
						|
         $filename = File::Spec->catfile( $packages_dir, $dirlist[0] );
 | 
						|
         $dirlist[0] =~ /(\w{4})(\d{3})_(\w{3})_(\d{3}).rpm$/;
 | 
						|
    	##############
 | 
						|
    	#If the release levels are different, it will be upgrade_required.
 | 
						|
    	#############
 | 
						|
    	if($fff ne $2) {
 | 
						|
	    	$upgrade_required = 1;
 | 
						|
    	} else {
 | 
						|
 | 
						|
       	 if(($pns eq $1) && ($4 <= $active_level)) {
 | 
						|
    		$msg = $msg. "Upgrade $mtms $activate!";
 | 
						|
	#	if($activate ne "concurrent") {
 | 
						|
	#		$msg = "Option --actviate's value should be disruptive";
 | 
						|
	#		return ("", "","", $msg, -1);
 | 
						|
	#	}
 | 
						|
	  } else {
 | 
						|
		$msg = $msg . "Upgrade $mtms!";
 | 
						|
           if($activate !~ /^(disruptive|deferred)$/) {
 | 
						|
	    		$msg = "Option --activate's value shouldn't be $activate, and it must be disruptive or deferred";
 | 
						|
			return ("", "","", $msg, -1);
 | 
						|
		}
 | 
						|
       	 } 
 | 
						|
	}
 | 
						|
        #print "filename is $filename\n";
 | 
						|
	my $xml_file_name = $filename;
 | 
						|
	$xml_file_name =~ s/(.+\.)rpm/\1xml/;
 | 
						|
	#print "check_licdd_update: source xml file is $xml_file_name\n";
 | 
						|
 | 
						|
	if( ( -z $filename)|| ( -z $xml_file_name) ) {
 | 
						|
		$msg = "The package $filename or xml $xml_file_name is empty" ;
 | 
						|
		return ("", "", "", $msg, -1);
 | 
						|
	}
 | 
						|
		
 | 
						|
	return ($filename, $xml_file_name ,$upgrade_required, $msg, 0);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
##########################
 | 
						|
#Performs Licensed Internal Code (LIC) update support for HMC-attached POWER5 and POWER6 Systems
 | 
						|
###########################
 | 
						|
sub rflash {
 | 
						|
 | 
						|
    my $request = shift;
 | 
						|
    my $hash    = shift;
 | 
						|
    my $exp     = shift;
 | 
						|
    my $subreq  = $request->{subreq};
 | 
						|
    my $hwtype  = @$exp[2];
 | 
						|
    my @result;
 | 
						|
    my $timeout    = $request->{ppctimeout};
 | 
						|
    my $housekeeping = $request->{housekeeping};
 | 
						|
    $packages_dir = $request->{opt}->{p};
 | 
						|
    $activate = $request->{opt}->{activate};	
 | 
						|
    print "housekeeping:$housekeeping\n";
 | 
						|
    my $mtms;
 | 
						|
    my $h;
 | 
						|
    my $user;
 | 
						|
    my $action;
 | 
						|
 | 
						|
    my $tmp_file; #the file handle of the stanza
 | 
						|
    my $rpm_file;
 | 
						|
    my $xml_file;
 | 
						|
    my @rpm_files;
 | 
						|
    my @xml_files;
 | 
						|
    my $upgrade_required;
 | 
						|
    my $stanza = undef;
 | 
						|
    my $mtms_t;	
 | 
						|
    my @value;
 | 
						|
    my %infor;
 | 
						|
    my $role ; #0x01: BPC A, BPC B; 0x01: Primary or only FSP, 0x02: Backup FSP
 | 
						|
 
 | 
						|
    #print "in Directflash \n";
 | 
						|
    #print Dumper($request);
 | 
						|
    #print Dumper($hash);
 | 
						|
 | 
						|
    ####################################
 | 
						|
    # Power commands are grouped by hardware control point
 | 
						|
    # In Direct attach support, the hcp is the related fsp.  
 | 
						|
    ####################################
 | 
						|
    
 | 
						|
    # Example of $hash.    
 | 
						|
    #VAR1 = {
 | 
						|
    #	          '9110-51A*1075ECF' => {
 | 
						|
    #                                   'Server-9110-51A-SN1075ECF' => [
 | 
						|
    #    	                                                          0,
 | 
						|
    #		                                                          0,
 | 
						|
    #									  '9110-51A*1075ECF',
 | 
						|
    #									  'Server-9110-51A-SN1075ECF',
 | 
						|
    #									  'fsp',
 | 
						|
    #									  0
 | 
						|
    #									  ]
 | 
						|
    #					 }
 | 
						|
    # 	   };
 | 
						|
    my $flag = 0;
 | 
						|
    my $flag2 = 0;
 | 
						|
    while (my ($mtms,$h) = each(%$hash) ) {
 | 
						|
	#
 | 
						|
	#For one mtms, it just needs to do the operation one time.
 | 
						|
	#
 | 
						|
        $flag += 1;
 | 
						|
	if($flag > 1) {
 | 
						|
	    last;	
 | 
						|
	}	
 | 
						|
	
 | 
						|
	$mtms =~ /(\w+)-(\w+)\*(\w+)/;
 | 
						|
	my $mtm    = "$1-$2";
 | 
						|
	my $serial = $3;
 | 
						|
		
 | 
						|
	
 | 
						|
        while (my ($name,$d) = each(%$h) ) {
 | 
						|
       	    $flag2 += 1;
 | 
						|
	    if($flag2 > 1) {
 | 
						|
	        last;	
 | 
						|
 	    }
 | 
						|
 | 
						|
            if( !defined($housekeeping) && ($$d[4] =~ /^fsp$/ || $$d[4] =~ /^lpar$/ || $$d[4] =~ /^cec$/)) {
 | 
						|
                $action  =  "get_compatible_version_from_rpm";
 | 
						|
	        my $values = xCAT::FSPUtils::fsp_api_action($request, $name, $d, $action, 0, $request->{opt}->{d} );
 | 
						|
		my $Rc =  @$values[2];
 | 
						|
		my $v = @$values[1];
 | 
						|
		if ($Rc != 0) {
 | 
						|
                    push @value, [$name, $v, -1];
 | 
						|
		    return (\@value);
 | 
						|
		}
 | 
						|
                            
 | 
						|
                #if( $v !~ "nocheckversion") {
 | 
						|
		my @levels = split(/,/, $v);
 | 
						|
	       	
 | 
						|
	        my $frame = $$d[5];
 | 
						|
                my $type = xCAT::DBobjUtils->getnodetype($frame);
 | 
						|
                if ( ( $frame ne $name ) && ( $type eq "frame" ) && $activate !~ /^deferred$/){
 | 
						|
                    
 | 
						|
                    my @frame_d = (0, 0, 0, $frame, "frame", 0);
 | 
						|
	            $action = "list_firmware_level";
 | 
						|
	            $values = xCAT::FSPUtils::fsp_api_action($request, $frame, \@frame_d, $action );	
 | 
						|
	            $Rc =  @$values[2];
 | 
						|
	            my $frame_firmware_level = @$values[1];
 | 
						|
		    if ($Rc != 0) {
 | 
						|
                        push @value, [$frame, $frame_firmware_level, -1];
 | 
						|
		        return (\@value);
 | 
						|
		    }
 | 
						|
                
 | 
						|
	            my $level_a;
 | 
						|
		    my $level_b;
 | 
						|
		    if( $frame_firmware_level =~ /curr_level_a=(\d{3}),curr_ecnumber_a=02(\w{5})/) {
 | 
						|
		        $level_a = "$2_$1";
 | 
						|
		    }
 | 
						|
	
 | 
						|
                   if( $frame_firmware_level =~ /curr_level_b=(\d{3}),curr_ecnumber_b=02(\w{5})/) {
 | 
						|
   		       $level_b = "$2_$1";
 | 
						|
		   }
 | 
						|
		   
 | 
						|
                   #print "frame_firmware_level=$frame_firmware_level,level_a=$level_a,level_b=$level_b\n";
 | 
						|
	           foreach my $l (@levels) {
 | 
						|
	                #print "rpm requires: $l\n"	;
 | 
						|
	                if( (defined($level_a) && (  $l gt $level_a )) ||  (defined($level_b) && (  $l gt $level_b )) ) {
 | 
						|
		            my $res = "New Managed System level for $name is not compatible with current Power Subsystem level 02$level_a on $frame.\nPower Subsystem level 02$l or later is required.";
 | 
						|
		       	
 | 
						|
                            push @value, [$name, $res, -1];
 | 
						|
		            return (\@value);
 | 
						|
		        }	
 | 
						|
		
 | 
						|
		   }
 | 
						|
                 }
 | 
						|
               #} 
 | 
						|
	    
 | 
						|
            }
 | 
						|
 | 
						|
	   if(!defined($housekeeping)) {	   
 | 
						|
               my $values  = xCAT::FSPUtils::fsp_api_action($request, $name, $d, "list_firmware_level"); 
 | 
						|
               my $Rc = @$values[2];
 | 
						|
	       my $level = @$values[1];
 | 
						|
	       #####################################
 | 
						|
	       # Return error
 | 
						|
      	       #####################################
 | 
						|
               if ( $Rc != SUCCESS ) {
 | 
						|
                   push @value, [$name,$level,$Rc];
 | 
						|
                   next;
 | 
						|
               }
 | 
						|
            
 | 
						|
	       if ( $level =~ /ecnumber=(\w+)/ ) {
 | 
						|
                   $release_level = $1;
 | 
						|
                   &dpush( \@value, [$name,"$mtms :release level:$1"]);
 | 
						|
	       }
 | 
						|
				
 | 
						|
               if ( $level =~ /activated_level=(\w+)/ ) {
 | 
						|
                   $active_level = $1;
 | 
						|
                   &dpush( \@value, [$name,"$mtms :activated level:$1"]);
 | 
						|
	        }	
 | 
						|
 | 
						|
	   } 
 | 
						|
	    
 | 
						|
	    
 | 
						|
    	  
 | 
						|
           if($housekeeping =~ /^commit$/) { $action = "code_commit"}
 | 
						|
           if($housekeeping =~ /^recover$/) { $action = "code_reject"}
 | 
						|
           if($housekeeping =~ /^bpa_acdl$/) { $action = "acdl"}
 | 
						|
           if($activate eq "disruptive") { 
 | 
						|
               $action = "code_update";
 | 
						|
           } elsif ($activate eq "deferred") {
 | 
						|
               $action = "code_updateD";
 | 
						|
           } elsif (defined($activate)){
 | 
						|
               #if($activate =~ /^concurrent$/) {
 | 
						|
               my $res = "\'$activate\' option not supported in FSPflash. Please use disruptive or deferred mode";
 | 
						|
               push @value, [$name, $res, -1];
 | 
						|
	       next;
 | 
						|
          }
 | 
						|
	   
 | 
						|
	   my $msg;	
 | 
						|
	   if(!defined($housekeeping)) {	   
 | 
						|
	       my $flag = 0;	
 | 
						|
	       ($rpm_file, $xml_file, $upgrade_required,$msg, $flag) = &get_lic_filenames($mtms);
 | 
						|
	        if( $flag == -1) {
 | 
						|
		    push (@value, [$name,"$mtms: $msg"]);
 | 
						|
	            push (@value, [$name,"Failed to upgrade the firmware of $name"]);
 | 
						|
		    return (\@value);
 | 
						|
	        }
 | 
						|
	       dpush ( \@value, [$name, $msg]);
 | 
						|
	   }
 | 
						|
 | 
						|
           my $res = xCAT::FSPUtils::fsp_api_action($request, $name, $d, $action, 0, $request->{opt}->{d} );
 | 
						|
           if ($action eq "acdl" && @$res[2] eq '0') {
 | 
						|
               push(@value, [$name, "Success", '0']);
 | 
						|
           } else {
 | 
						|
               push(@value,[$name, @$res[1], @$res[2]]);
 | 
						|
           }
 | 
						|
           return (\@value);
 | 
						|
	         
 | 
						|
        }
 | 
						|
    }
 | 
						|
    push(@value, @result);
 | 
						|
    return (\@value);	
 | 
						|
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
1;
 | 
						|
 | 
						|
 |