3339 lines
		
	
	
		
			109 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			3339 lines
		
	
	
		
			109 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/env perl
 | |
| # IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
 | |
| #
 | |
| 
 | |
| package xCAT::LparNetbootExp;
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
| 
 | |
| =head1   LparNetbootExp
 | |
| Usage: Install partition
 | |
|         lpar_netboot [-v] [-x] [-f] [-w set_boot_order] [-A -D | [-D] | [-D] -m macaddress] -t ent -s speed -d duplex
 | |
|                 -S server -G gateway -C client hostname profile managed_system lparid remote_host
 | |
| 
 | |
| Usage: Return macaddress
 | |
|         lpar_netboot -M -n [-v] -t ent [-f] [-x] [-D -s speed -d duplex -S server -G gateway -C client] hostname profile managed_system lparid remote_host
 | |
| 
 | |
|         -n      Do not boot partition
 | |
|         -t      Specifies network type ent
 | |
|         -D      Perform ping test, use adapter that successfully ping the server
 | |
|         -s      Network adapter speed
 | |
|         -d      Network adapter duplex
 | |
|         -S      Server IP address
 | |
|         -G      Gateway IP address
 | |
|         -C      Client IP address
 | |
|         -m      MAC Address
 | |
|         -v      Verbose output
 | |
|         -x      Debug output
 | |
|         -f      Force close virtual terminal session
 | |
|         -w      Set boot device order
 | |
|                         0: Don't set boot device order
 | |
|                         1: Set network as boot device
 | |
|                         2: Set network as 1st boot device, disk as 2nd boot device
 | |
|                         3: Set disk as 1st boot device, network as 2nd boot device
 | |
|                         4: set disk as boot device
 | |
|         -M      Discovery ethernet adapter mac address and location code
 | |
|         --help  Prints this help
 | |
| 
 | |
| 
 | |
| =cut
 | |
| 
 | |
| BEGIN
 | |
| {
 | |
|     $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
 | |
|     $::XCATDIR  = $ENV{'XCATDIR'}  ? $ENV{'XCATDIR'}  : '/etc/xcat';
 | |
| }
 | |
| 
 | |
| 
 | |
| use lib "$::XCATROOT/lib/perl";
 | |
| use xCAT::Utils;
 | |
| use Getopt::Long;
 | |
| use xCAT::MsgUtils;
 | |
| use Expect;
 | |
| use strict;
 | |
| use Data::Dumper;
 | |
| my $adapter_found = 0;
 | |
| my @adap_type;
 | |
| my @full_path_name_array;
 | |
| my @phandle_array;
 | |
| my $macaddress;
 | |
| my $phys_loc;
 | |
| my $client_ip;
 | |
| my $gateway_ip;
 | |
| my $device_type;
 | |
| my $server_ip;
 | |
| 
 | |
| # List supported network adapters here.  dev_pat is an array of regexp patterns
 | |
| # the script searches for in the device tree listing.  dev_type is the type
 | |
| # of device displayed in the output.
 | |
| my @dev_pat = (
 | |
|         "ethernet",
 | |
|         "token-ring",
 | |
|         "fddi"
 | |
|         );
 | |
| my @dev_type = (
 | |
|         "ent",
 | |
|         "tok",
 | |
|         "fddi"
 | |
|         );
 | |
| my $dev_count = scalar(@dev_type); #number of supported device type
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------------------------------
 | |
| 
 | |
| =head3    nc_msg
 | |
| 
 | |
|     PROCEDURE
 | |
| 
 | |
|     Declare procedure to write status/error messages
 | |
|     We do it this way so that if /var is full (or some other error occurs)
 | |
|     we can trap it in a common section of code.
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
| 
 | |
| sub nc_msg
 | |
| {
 | |
|     my $verbose = shift;
 | |
|     my $msg = shift;
 | |
|     my $rsp;
 | |
| 
 | |
|     if ( $verbose eq 1 ) {
 | |
|         $rsp->{data}->[0] = $msg;
 | |
|         xCAT::MsgUtils->message("I", $rsp ,$::CALLBACK);
 | |
|     }
 | |
| 
 | |
|     if ( $verbose eq 2 ) {
 | |
|         $rsp->{data}->[0] = $msg;
 | |
|         xCAT::MsgUtils->message("E", $rsp ,$::CALLBACK);
 | |
|     }
 | |
| }
 | |
| #-------------------------------------------------------------------------------
 | |
| 
 | |
| =head3    run_lssyscfg
 | |
| 
 | |
|       Procedure to run the rpower command
 | |
|       test its return code and capture its output
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
| 
 | |
| sub run_lssyscfg
 | |
| {
 | |
|     my $req = shift;
 | |
|     if (($req) && ($req =~ /xCAT::/))
 | |
|     {
 | |
|         $req = shift;
 | |
|     }
 | |
|     my $verbose = shift;
 | |
|     my $node = shift;
 | |
|     my $cmd;
 | |
|     my $out;
 | |
| 
 | |
|     $out = xCAT::Utils->runxcmd(
 | |
|         {
 | |
|             command => ['rpower'],
 | |
|             node    => [$node],
 | |
|             arg     => ['state']
 | |
|         },
 | |
|     $req, 0, 1);
 | |
|     if ($::RUNCMD_RC != 0)   {
 | |
|         nc_msg($verbose, "Unable to run rpower $node state.\n");
 | |
|         return undef;
 | |
|     }
 | |
|     my $output = join ',', @$out;
 | |
|     nc_msg($verbose, "Status: run_lssyscg : partition status : $output\n");
 | |
| 
 | |
|     nc_msg($verbose, "####msg:$output#########\n" );
 | |
| 
 | |
| 
 | |
|     ###################################################################
 | |
|     # Slow down the requests speed to hcp, so that hcp will not busy on
 | |
|     # query.  Instead, hcp should put more time on other activities.
 | |
|     # Another reason to set this sleep is giving some time to the lpars
 | |
|     # to be more stable.
 | |
|     ###################################################################
 | |
|     sleep 4;
 | |
| 
 | |
|     return $output;
 | |
| }
 | |
| 
 | |
| #-------------------------------------------------------------------------------
 | |
| 
 | |
| =head3    usage
 | |
| 
 | |
| 
 | |
|     PROCEDURE
 | |
| 
 | |
|     Declare procedure to write usage message and exit
 | |
| 
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
| 
 | |
| sub usage {
 | |
| 
 | |
|     my $msg = "Usage: Install partition \
 | |
|             \n\t \[-v\] \[-x\] \[-f\] \[-w set_boot_order\] \[-A -D | \[-D\] | \[-D\] -m macaddress\] -t ent -s speed -d duplex \
 | |
|             \n\t\t-S server -G gateway -C client hostname profile managed_system lparid remote_host\
 | |
|             \n \
 | |
|             \nUsage: Return macaddress \
 | |
|             \n\t -M -n \[-v\] -t ent \[-f] \[-x] \[-D -s speed -d duplex -S server -G gateway -C client\] hostname profile managed_system lparid remote_host\
 | |
|             \n \
 | |
|             \n\t-n\tDo not boot partition \
 | |
|             \n\t-t\tSpecifies network type ent \
 | |
|             \n\t-D\tPerform ping test, use adapter that successfully ping the server \
 | |
|             \n\t-s\tNetwork adapter speed \
 | |
|             \n\t-d\tNetwork adapter duplex \
 | |
|             \n\t-S\tServer IP address \
 | |
|             \n\t-G\tGateway IP address \
 | |
|             \n\t-C\tClient IP address \
 | |
|             \n\t-m\tMAC Address \
 | |
|             \n\t-v\tVerbose output \
 | |
|             \n\t-x\tDebug output \
 | |
|             \n\t-f\tForce close virtual terminal session \
 | |
|             \n\t-w\tSet boot device order \
 | |
|             \n\t\t\t0: Don't set boot device order \
 | |
|             \n\t\t\t1: Set network as boot device \
 | |
|             \n\t\t\t2: Set network as 1st boot device, disk as 2nd boot device \
 | |
|             \n\t\t\t3: Set disk as 1st boot device, network as 2nd boot device \
 | |
|             \n\t\t\t4: set disk as boot device \
 | |
|             \n\t-M\tDiscovery ethernet adapter mac address and location code \
 | |
|             \n\t--help\tPrints this help\n";
 | |
|     nc_msg(1, $msg);
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| #-------------------------------------------------------------------------------
 | |
| 
 | |
| =head3    ck_args
 | |
| 
 | |
|  PROCEDURE
 | |
| 
 | |
|  Check command line arguments
 | |
| 
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
| sub ck_args {
 | |
| 
 | |
|     my $opt = shift;
 | |
|     if (($opt) && ($opt =~ /xCAT::/))
 | |
|     {
 | |
|         $opt = shift;
 | |
|     }
 | |
|     my $verbose = shift;
 | |
|     my $node = $opt->{node};
 | |
|     my $mtms = $opt->{fsp};
 | |
|     my $hcp = $opt->{hcp};
 | |
|     my $lparid = $opt->{id};
 | |
|     my $profile = $opt->{pprofile};
 | |
| 
 | |
|     if (exists( $opt->{D}) and (!exists ($opt->{s}) or !exists ($opt->{d} ))) {
 | |
|         nc_msg($verbose, "Speed and duplex required\n");
 | |
|         usage;
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     if (exists ($opt->{D}) and !exists ($opt->{C}))  {
 | |
|         nc_msg($verbose, "Client IP is required\n");
 | |
|         usage;
 | |
|         return 1;
 | |
|     }
 | |
|     if (exists( $opt->{D}) and !exists($opt->{S})) {
 | |
|         nc_msg($verbose, "Server IP is required\n");
 | |
|         usage;
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     if (exists( $opt->{D}) and !exists($opt->{G})) {
 | |
|         nc_msg($verbose, "Gateway IP is required\n");
 | |
|         usage;
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     unless($node) {
 | |
|         nc_msg($verbose, "Node is required\n");
 | |
|         usage;
 | |
|         return 1;
 | |
|     } else {
 | |
|         nc_msg($verbose, "Node is $node\n");
 | |
|     }
 | |
| 
 | |
|     unless($mtms) {
 | |
|         nc_msg($verbose, "Managed system is required\n");
 | |
|         usage;
 | |
|         return 1;
 | |
|     } else {
 | |
|         nc_msg($verbose, "Managed system is $mtms.\n");
 | |
|     }
 | |
| 
 | |
|     unless ($hcp) {
 | |
|         nc_msg($verbose, "Hardware control point address is required\n");
 | |
|         usage;
 | |
|         return 1;
 | |
|     } else {
 | |
|         nc_msg($verbose, "Hardware control point address is $hcp.\n");
 | |
|     }
 | |
| 
 | |
|     unless ($lparid) {
 | |
|         nc_msg($verbose, "Lpar Id is required.\n");
 | |
|         usage;
 | |
|         return 1;
 | |
|     } else {
 | |
|         nc_msg($verbose, "LPAR Id is $lparid.\n");
 | |
|     }
 | |
| 
 | |
|     unless ($profile) {
 | |
|         nc_msg($verbose, "Profile is required.\n");
 | |
|         usage;
 | |
|         return 1;
 | |
|     } else {
 | |
|         nc_msg($verbose, "profile $profile.\n");
 | |
|     }
 | |
| 
 | |
|     if ($opt->{M} and $opt->{g}) {
 | |
|         nc_msg($verbose, "Can not specify -M and -g flags together.\n");
 | |
|         usage;
 | |
|         return 1;
 | |
|     }
 | |
|     if ($opt->{M} and ($opt->{m} or $opt->{l})) {
 | |
|         nc_msg($verbose, "Can not specify -M and -l or -m flags together.\n");
 | |
|         usage;
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     if ($opt->{m} and $opt->{l}) {
 | |
|         nc_msg($verbose, "Can not specify -l and -m flags together.\n");
 | |
|         usage;
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     if ($opt->{A} and ($opt->{m} or $opt->{l})) {
 | |
|         nc_msg($verbose, "Can not specify -A and -m or -l flags together.\n");
 | |
|         usage;
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     if ($opt->{A} and !exists($opt->{D}) and !exists($opt->{n})) {
 | |
|         nc_msg($verbose, "Flag -A must be specify with flag -D for booting.\n");
 | |
|         usage;
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     if ($opt->{M} and $opt->{D} and (!exists($opt->{S}) or !exists($opt->{G}) or !exists($opt->{C}) or !exists( $opt->{s}) or !exists($opt->{d}))) {
 | |
|         nc_msg($verbose, "Flag -M with -D require arguments for -C, -S, -G, -s and -d.\n");
 | |
|         usage;
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     if ($opt->{M} and !exists($opt->{D}) and (!exists($opt->{S}) or !exists($opt->{G}) or !exists($opt->{C}) or !exists($opt->{s}) or !exists($opt->{d}))){
 | |
|         nc_msg($verbose, "Flag -M with arguments for -C, -S, -G, -s and -d require -D flag.\n");
 | |
|         usage;
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     if ($opt->{M} and !exists($opt->{n})) {
 | |
|         nc_msg($verbose, "-M flag requires -n.\n");
 | |
|         usage;
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     if ($node =~ /(\[ ]+)-/) {
 | |
|         nc_msg($verbose, "Error : $node, node is required\n");
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     if ($mtms =~ /(\[ ]+)-/) {
 | |
|         nc_msg($verbose, "Error : $mtms, Managed system is required\n");
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     #if ($profile =~ /(\[ ]+)-/) {
 | |
|     #    nc_msg($verbose, "Error : $profile, profile is required\n");
 | |
|     #    return 1;
 | |
|     #}
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------------------------------
 | |
| 
 | |
| =head3    send_command
 | |
| 
 | |
| 
 | |
|         PROCEDURE
 | |
| 
 | |
|         Declare procedure to send commands slowly. This is needed because
 | |
|         some bytes are missed by the service processor when sent at top speed.
 | |
|         The sleep was needed because a command was sent sometimes before the
 | |
|         results of the previous command had been received.
 | |
| 
 | |
|         The Open Firmware is constrained on how quickly it can process input streams.
 | |
|         The following code causes expect to send 10 characters and then wait 1 second
 | |
|         before sending another 10 bytes.
 | |
| 
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
| 
 | |
| sub send_command  {
 | |
|     my $verbose = shift;
 | |
|     my $rconsole = shift;
 | |
|     my $cmd = shift;
 | |
|     nc_msg($verbose, "sending commands $cmd to expect \n");
 | |
|     my $msg;
 | |
| 
 | |
|     $msg = $rconsole->send($cmd);
 | |
|     sleep 1;
 | |
|     return $msg;
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------------------------------
 | |
| 
 | |
| =head3    get_phandle
 | |
| 
 | |
|  PROCEDURE
 | |
| 
 | |
|  Declare procedure to parse the full device tree that is displayed as a result
 | |
|  of an ls command. The information needed is the phandle and full device name
 | |
|  of a supported network card found in the device tree. The phandle is used in
 | |
|  other procedures to get and change properties of the network card. The full
 | |
|  device name is used to network boot from the network adapter.
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
| 
 | |
| sub get_phandle {
 | |
|     my $rconsole = shift;
 | |
|     my $node = shift;
 | |
|     my $verbose = shift;
 | |
|     my $timeout = 30;
 | |
|     my $done = 0;
 | |
|     my @result;
 | |
|     my $expect_out;
 | |
|     my $retry_count;
 | |
|     my %path;
 | |
|     my $rc = 0;
 | |
| 
 | |
| 
 | |
|     # This is the first procedure entered after getting to the ok prompt. On entry
 | |
|     # the current device is not root. The command 'dev /' is sent to get to the
 | |
|     # root of the device tree. There is no output from the dev command. The expected
 | |
|     # output is the ok prompt ('>').
 | |
|     #
 | |
|     # The pwd command can be used to determine what the current device is.
 | |
|     #
 | |
| 
 | |
|     send_command($verbose, $rconsole,  "dev /\r");
 | |
| 
 | |
|     @result = $rconsole->expect(
 | |
|         $timeout,
 | |
|         [qr/ok/=>
 | |
|         sub {
 | |
|             nc_msg($verbose, "Status: at root\n");
 | |
|             $rconsole->clear_accum();
 | |
|             }
 | |
|         ],
 | |
|         [qr/]/=>
 | |
|         sub {
 | |
|             nc_msg($verbose, "Unexpected prompt\n");
 | |
|             $rconsole->clear_accum();
 | |
|             $rc = 1;
 | |
|             }
 | |
|         ],
 | |
|         [timeout =>
 | |
|         sub {
 | |
|             $rconsole->send("\r");
 | |
|             $rconsole->clear_accum();
 | |
|             $rc = 1;
 | |
|             }
 | |
|         ],
 | |
|         [eof =>
 | |
|         sub {
 | |
|             nc_msg($verbose, "Cannot connect to $node");
 | |
|             $rconsole->clear_accum();
 | |
|             $rc = 1;
 | |
|             }
 | |
|         ],
 | |
|     );
 | |
|     return 1 if ($rc eq 1);
 | |
|     # Next, the 'ls' command is sent. The result is a display of the entire
 | |
|     # device tree. The code then looks at the
 | |
|     # output from the ls command one line at a time, trying to match it with the
 | |
|     # regexp pattern in dev_pat, an array that contains all the supported network
 | |
|     # adapters. When found, the adapter type, the phandle and path name are saved
 | |
|     # in array variables.
 | |
|     #
 | |
|     # The complicated part is that the full path name may be spread over more than
 | |
|     # one line. Each line contains information about a node. If the supported
 | |
|     # network adapter is found on an nth level node, the full path name is the
 | |
|     # concatenation of the node information from the 0th level to the nth level.
 | |
|     # Hence, the path name from each level of the device tree needs to be saved.
 | |
|     #
 | |
|     # The pattern "\n(\[^\r]*)\r" is worth a second look. It took
 | |
|     # many hours of debug and reading the expect book to get it right. When more
 | |
|     # than one line of data is returned to expect at once, it is tricky getting
 | |
|     # exactly one line of data to look at. This pattern works because it looks
 | |
|     # for a newline(\n), any character other than a carriage return(\[^\r]*), and
 | |
|     # then for a carriage return. This causes expect to match a single line.
 | |
|     # If (.*) is used instead of (\[^\r]*), multiple lines are matched. (that was
 | |
|     # attempt number 1)
 | |
|     #
 | |
|     # Once a single line is found, it tries to determine what level in the device
 | |
|     # tree this line is.
 | |
|     # searching through subsequent lines and subsequent levels until an
 | |
|     # adapter is found.
 | |
|     # The level of the current line, which
 | |
|     # is calculated based on the assumption of "Level = (Leading Spaces - 1)/2".
 | |
|     # Leading Spaces is the number of spaces between the first colon ':' and the
 | |
|     # first non-space character of each line.
 | |
|     #
 | |
|     # Using the -d flag helped a lot in finding the correct pattern.
 | |
|     #
 | |
| 
 | |
|     send_command($verbose, $rconsole,  "ls \r");
 | |
| 
 | |
|     $timeout = 60;
 | |
|     $done = 0;
 | |
|     while (!$done) {
 | |
|         # this expect call isolates single lines
 | |
|         # This code uses the tcl regexp to parse the single line
 | |
|         # isolated by expect.
 | |
|         #
 | |
|         # When the ok prompt ('>') is matched, this indicates the end of
 | |
|         # the ls output, at which point the done variable is set, to break
 | |
|         # out of the loop.
 | |
|         #
 | |
|         # All other lines are ignored.
 | |
|         #
 | |
|         @result = ();
 | |
|         @result = $rconsole->expect(
 | |
|             $timeout,
 | |
|             [qr/(\n)([^\r]*)(\r)/=>
 | |
|             sub {
 | |
|                 nc_msg($verbose, "Parsing network adapters... \n");
 | |
|                 #$rconsole->clear_accum();
 | |
|                 }
 | |
|             ],
 | |
|             [qr/>/=>
 | |
|             sub {
 | |
|                 nc_msg($verbose, "finished \n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $done = 1;
 | |
|                 }
 | |
|             ],
 | |
|             [timeout=>
 | |
|             sub {
 | |
|                 nc_msg($verbose, "Timeout isolating single line of ls output\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|             [eof =>
 | |
|             sub {
 | |
|                 nc_msg($verbose, "Cannot connect to $node");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|         );
 | |
|         return 1 if ($rc eq 1);
 | |
|         if ($result[2] =~ /(\w*)\:(\s*)\/(\S*)/) {
 | |
| 
 | |
|             my $x1 = $1;
 | |
|             my $x2 = $2; #number of space
 | |
|             my $x3 = $3; #device
 | |
|             # Each level is inspected for a match
 | |
|             my $level = (length($x2)-1)/2;
 | |
|             $path{$level} = $x3;
 | |
|             my $j = 0;
 | |
| 
 | |
|             for ($j = 0; $j < $dev_count; $j++) {
 | |
|                 if ($x3 =~ /$dev_pat[$j]/) {
 | |
|                     if ( $x3 =~ /hfi-ethernet/ and $dev_pat[$j] eq "ethernet" ){
 | |
|                         next;
 | |
|                     }
 | |
|                     my $i = 0;
 | |
|                     for ($i = 0; $i <= $level; $i++)
 | |
|                     {
 | |
|                         $full_path_name_array[$adapter_found] .= "/" . $path{$i};
 | |
|                     }
 | |
|                     $phandle_array[$adapter_found] = $x1;
 | |
|                     $adap_type[$adapter_found] = $dev_type[$j];
 | |
|                     $adapter_found ++;
 | |
|                     last;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     # Did we find one or more adapters?
 | |
|     if ( $adapter_found > 0 ) {
 | |
|         return 0;
 | |
|     } else {
 | |
|         nc_msg($verbose, "No network adapters found\n" );
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
| }
 | |
| #-------------------------------------------------------------------------------
 | |
| 
 | |
| =head3    get_adap_prop
 | |
| 
 | |
|  PROCEDURE
 | |
| 
 | |
|  Declare procedure to obtain the list of valid adapter connector properties
 | |
|  from the adapter card.  Connector types can be rj45, sc, 9pin, aui,
 | |
|  bnc, or mic.  Speeds can be 10, 100, or 1000.  Duplex can be half or
 | |
|  full.  This procedure will use the "supported-network-types"
 | |
|  argument to the get-package-property command to get the list of
 | |
|  properties for the given adapter.
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
| sub  get_adap_prop    {
 | |
|     my $phandle = shift;
 | |
|     my $rconsole = shift;
 | |
|     my $node = shift;
 | |
|     my $verbose = shift;
 | |
|     my $timeout = 120;
 | |
|     my $rc = 0;
 | |
|     my $state = 0;
 | |
|     my @cmd;
 | |
|     my @done;
 | |
|     my @msg;
 | |
|     my @pattern;
 | |
|     my @newstate;
 | |
|     my @result;
 | |
|     my @adap_prop_array;
 | |
|     my $nw_type;
 | |
|     my $nw_speed;
 | |
|     my $nw_conn;
 | |
|     my $nw_duplex;
 | |
| 
 | |
|     nc_msg($verbose, " Status: get_adap_prop start\n");
 | |
| 
 | |
|     # state 0, stack count 0
 | |
|     $done[0] = 0;
 | |
|     $cmd[0] = "\" supported-network-types\" " . $phandle . " get-package-property\r";
 | |
|     $msg[0] = "Status: rc and all supported network types now on stack\n";
 | |
|     #$pattern[0] = "(.*)3 >(.*)";
 | |
|     #$pattern[0] = "3 >";
 | |
|     $pattern[0] = "ok";
 | |
|     $newstate[0] = 1;
 | |
| 
 | |
|     # state 1, return code and string on stack
 | |
|     $done[1] = 0;
 | |
|     $cmd[1] = ".\r";
 | |
|     $msg[1] = "Status: All supported network types now on stack\n";
 | |
|     #$pattern[1] = "(.*)2 >(.*)";
 | |
|     #$pattern[1] = "2 >";
 | |
|     $pattern[1] = "ok";
 | |
|     $newstate[1] = 2;
 | |
| 
 | |
|     # state 2, data ready to decode
 | |
|     $done[2] = 0;
 | |
|     $cmd[2] = "decode-string\r";
 | |
|     $msg[2] = "Status: supported network type isolated on stack\n";
 | |
|     #$pattern[2] = "(.*)ok(.*)4 >(.*)";
 | |
|     $pattern[2] = "4 >";
 | |
|     $newstate[2] = 3;
 | |
| 
 | |
|     # state 3, decoded string on stack
 | |
|     $done[3]= 0;
 | |
|     $cmd[3] = "dump\r";
 | |
|     $msg[3] = "Status: supported network type off stack\n";
 | |
|     #$pattern[3] = ".*:.*:(.*):.*:.*:(.*):.*(2 >)(.*)";
 | |
|     $pattern[3] = "ok";
 | |
|     $newstate[3] = 4;
 | |
| 
 | |
|     # state 4, need to check for more data to decode
 | |
|     $done[4] = 0;
 | |
|     $cmd[4] = ".s\r";
 | |
|     $msg[4] = "Status: checking for more supported network types\n";
 | |
|     #$pattern[4] = ".s (\[0-9a-f]* )(.*)>";
 | |
|     $pattern[4] = "ok";
 | |
|     $newstate[4]= 5;
 | |
| 
 | |
|     # state 5, done decoding string, clear stack
 | |
|     $done[5] = 0;
 | |
|     $cmd[5]  = ".\r";
 | |
|     $msg[5]  = "Status: one entry on stack cleared\n";
 | |
|     #$pattern[5] = "(.*)ok(.*)1 >(.*)";
 | |
|     $pattern[5] = "ok";
 | |
|     $newstate[5] = 6;
 | |
| 
 | |
|     # state 6, finish clearing stack, choose correct adapter type
 | |
|     $done[6]= 0;
 | |
|     $cmd[6] = ".\r";
 | |
|     $msg[6] = "Status: finished clearing stack\n";
 | |
|     #$pattern[6] = "(.*)ok(.*)0 >(.*)";
 | |
|     $pattern[6] = "ok";
 | |
|     $newstate[6]= 7;
 | |
| 
 | |
|     # state 7, done
 | |
|     $done[7] = 1;
 | |
| 
 | |
|     while($done[$state] eq 0) {
 | |
|         nc_msg($verbose, "Status: command is $cmd[$state]\n");
 | |
|         send_command($verbose, $rconsole, $cmd[$state]);
 | |
|         @result = ();
 | |
|         @result = $rconsole->expect(
 | |
|         $timeout,
 | |
|         [ qr/$pattern[$state]/i,
 | |
|             sub {
 | |
|                if ($state eq 1) {
 | |
|                     if ($rconsole->before() =~ /-\d+/) {
 | |
|                         nc_msg($verbose, "Status: Error getting adapter property for phandle=$phandle.\n");
 | |
|                         $state = 7;
 | |
|                         $rconsole->clear_accum();
 | |
|                         $rc = 1;
 | |
|                         return 1;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 nc_msg($verbose, $msg[$state]);
 | |
|                 $state = $newstate[$state];
 | |
|                 $rconsole->clear_accum();
 | |
|             }
 | |
|         ],
 | |
|         [ qr/]/,
 | |
|             sub {
 | |
|                 nc_msg($verbose, "Unexpected prompt\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|             }
 | |
|         ],
 | |
|         [ qr/(.*)DEFAULT(.*)/,
 | |
|             sub {
 | |
|                 nc_msg($verbose, " Default catch error\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|             }
 | |
|         ],
 | |
|         [ timeout=>
 | |
|             sub {
 | |
|                 nc_msg($verbose, "Timeout in getting adapter properpties\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|             }
 | |
|         ],
 | |
|         [ eof =>
 | |
|             sub {
 | |
|                 nc_msg($verbose, "Cannot connect to $node\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|             }
 | |
|         ]
 | |
|         );
 | |
|         return 1 if ($rc eq 1);
 | |
|         # After state 3, the network type is parsed and the connector
 | |
|         # type extracted.  If the type hasn't been found, add it to
 | |
|         # the list of supported connector types.
 | |
|         if ( $state eq 4 ) {
 | |
|             #  Build the adapter properties from the string
 | |
|             #regexp .*,(.*),(.*),(.*) $nw_type dummy nw_speed nw_conn nw_duplex
 | |
|             #set adap_prop "$nw_speed,$nw_conn,$nw_duplex"
 | |
|             #nc_msg "Status: Adapter properties are $adap_prop\n"
 | |
| 
 | |
|             # if it's not in the list, add it, otherwise continue
 | |
|             if ( $result[3] =~ /(\w*):(.*):(\w*)\,(\w*)\,(\w*):/) {
 | |
|                 $nw_type = $3;
 | |
|                 $nw_speed = $4;
 | |
|                 $nw_conn = $5;
 | |
|                 nc_msg($verbose, "nwtype is $3, nwspeed is $4, nwconn is $5\n");
 | |
|             }
 | |
|             if ( $result[3] =~ /(\w*):(.*):(\w*)\,(\w*):/) {
 | |
|                 $nw_duplex = $4;
 | |
|                 nc_msg($verbose, "nwduplex is $4\n");
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #push @adap_prop_array, $nw_type.",".$nw_speed.",".$nw_conn.",".$nw_duplex;
 | |
|         push @adap_prop_array, $nw_speed.",".$nw_conn.",".$nw_duplex;
 | |
|         nc_msg($verbose, "Status: Adding adapter properties to list\n");
 | |
| 
 | |
|         # After state 4, a test is done to see if all of the supported
 | |
|         # network types have been decoded. If they have been, the
 | |
|         # state variable is left alone. if not, the state variable is
 | |
|         # set to 2, causing a loop back to the step where the
 | |
|         # decode-string command is sent.
 | |
|         if ( $state eq 5 ) {
 | |
|             if ($result[3] =~/2 > \.s \w+ (\w*)/) {
 | |
|                 $state = 2 if ($1 != 0);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     if (scalar(@adap_prop_array) != 0) {
 | |
|         return \@adap_prop_array;
 | |
|     } else {
 | |
|         return 0;
 | |
|     }
 | |
| }
 | |
| 
 | |
| #-------------------------------------------------------------------------------
 | |
| 
 | |
| =head3    get_mac_addr
 | |
| 
 | |
| 
 | |
|   PROCEDURE
 | |
| 
 | |
|   Declare procedure to obtain the ethernet or mac address property from the
 | |
|   ethernet card.
 | |
| 
 | |
|   3 commands lines containing a total of 6 commands are used.
 | |
| 
 | |
|   The get-package-property command is an example of a command
 | |
|   that takes it's arguments off the stack and puts the results back onto the
 | |
|   stack. Because of this, the arguments for the get-package-property command
 | |
|   are in front of the command verb.
 | |
| 
 | |
| 
 | |
|   The only reason this procedure is implemented in a loop is to avoid coding
 | |
|   3 expect commands.
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
| sub get_mac_addr {
 | |
|     my $phandle = shift;
 | |
|     my $rconsole = shift;
 | |
|     my $node = shift;
 | |
|     my $verbose = shift;
 | |
|     my $timeout = 60;
 | |
|     my $state = 0;
 | |
|     my @result;
 | |
|     my $mac_rc;
 | |
|     my @cmd;
 | |
|     my @done;
 | |
|     my @msg;
 | |
|     my @pattern;
 | |
|     my @newstate;
 | |
|     my $mac_address;
 | |
|     my $rc = 0;
 | |
| 
 | |
| 
 | |
|     nc_msg($verbose, "Status: get_mac_addr start\n");
 | |
| 
 | |
|     # cmd(0) could have been sent as 3 commands. " mac-address" (tcl forces
 | |
|     # the use of \") is the first command on this line. The result of entering
 | |
|     # " mac-address" is that 2 stack entries are created, and address and a length.
 | |
|     #
 | |
|     # The next command in cmd(0) is the phandle with no quotes. This results in
 | |
|     # one stack entry because the phandle is an address.
 | |
|     #
 | |
|     # the third command in cmd(0) is get-package-property. After this command, there
 | |
|     # are 3 stack entries (return code, address and length of mac-address).
 | |
|     # state 0, stack count 0, send command
 | |
|     $done[0] = 0;
 | |
|     $cmd[0] = "\" local-mac-address\" ". $phandle . " get-package-property\r";
 | |
|     $msg[0] = "Status: return code and mac-address now on stack\n";
 | |
|     $pattern[0] = "local-mac-address.*ok";#"\s*3 >";
 | |
|     $newstate[0] = 1;
 | |
| 
 | |
|     # cmd(1) is a dot (.). This is a stack manipulation command that removes one
 | |
|     # thing from the stack. pattern(1) is looking for a prompt with the 2 indicating
 | |
|     # that there are 2 things left on the stack.
 | |
|     # state 1, return code and mac-address on stack
 | |
|     $done[1]= 0;
 | |
|     $cmd[1] = ".\r";
 | |
|     $msg[1] = "Status: mac-address now on stack\n";
 | |
|     #$pattern[1] = "(.*)2 >(.*)";
 | |
|     $pattern[1] = "ok"; #"2 >";
 | |
|     $newstate[1]= 2;
 | |
| 
 | |
|     # cmd(2) is the dump command. This takes an address and a length off the stack
 | |
|     # and displays the contents of that storage in ascii and hex. The long pattern
 | |
|     # puts the hex into the variable expect_out(3,string). The tcl verb 'join' is
 | |
|     # used to eliminate the spaces put in by the dump command.
 | |
|     # state 2, mac-address on stack
 | |
|     $done[2] = 0;
 | |
|     $cmd[2] = ": dump-mac ( prop-addr prop-len -- ) \
 | |
|                 cr  \
 | |
|                 dup decode-bytes  2swap 2drop   ( data-addr data-len ) \
 | |
|                 ( data-len ) 0 ?do \
 | |
|                     dup c@ 2 u.r                  ( data-addr ) \
 | |
|                     char+                        ( data-addr' ) \
 | |
|                 loop \
 | |
|                 drop \
 | |
|                 cr \
 | |
|                 ; \r";
 | |
|     $msg[2] = "Status: set command\n";
 | |
|     $pattern[2] = "ok";
 | |
|     $newstate[2]= 3;
 | |
| 
 | |
|     $done[3]= 0;
 | |
|     $cmd[3] = "dump-mac\r";
 | |
|     $msg[3] = "Status: mac-address displayed, stack empty\n";
 | |
|     $pattern[3] = "dump-mac(\\s*)(\\w*)(\\s*)ok";
 | |
|     $newstate[3] = 4 ;
 | |
| 
 | |
| 
 | |
|     # state 4, all done
 | |
|     $done[4] = 1;
 | |
| 
 | |
|     while($done[$state] eq 0) {
 | |
|         @result = ();
 | |
|         send_command($verbose, $rconsole, $cmd[$state]);
 | |
|         @result = $rconsole->expect(
 | |
|             $timeout,
 | |
|             [qr/$pattern[$state]/=>
 | |
|             sub {
 | |
|                 if ($state eq 1) {
 | |
|                     if ($rconsole->before() =~ /-\d+/) {
 | |
|                         nc_msg($verbose, "Status: Error getting MAC address for phandle=$phandle.\n");
 | |
|                         $rconsole->clear_accum();
 | |
|                         $state = 4;
 | |
|                         $rc = 1;
 | |
|                         return undef;
 | |
|                     }
 | |
|                 }
 | |
|                 nc_msg($verbose, $msg[$state]);
 | |
|                 $state = $newstate[$state];
 | |
|                 $rconsole->clear_accum();
 | |
|                 }
 | |
|             ],
 | |
|             [qr/1 > /=>
 | |
|             sub {
 | |
|                 $rconsole->clear_accum();
 | |
|                 if( $state eq 0 ) {
 | |
|                     # An error occurred while obtaining the mac address.  Log the error,
 | |
|                     # but don't quit nodecond.  instead, return NA for the address
 | |
|                     #
 | |
|                     send_command($verbose, $rconsole, ".\r");
 | |
|                     $rconsole->expect(
 | |
|                         $timeout,
 | |
|                         #[ qr/(-*\[0-9\]*)  ok(.*)0 >(.*)/i,
 | |
|                         [ qr/0 >/i,
 | |
|                             sub {
 | |
|                                 #$mac_rc = $expect_out;
 | |
|                                 nc_msg($verbose, "Status: Error getting MAC address for phandle=$phandle. RC=$mac_rc.\n");
 | |
|                                 nc_msg($verbose, "Could not obtain MAC address; setting MAX to NA\n" );
 | |
|                                 $rconsole->clear_accum();
 | |
|                                 $rc = 1;
 | |
|                             }
 | |
|                         ],
 | |
|                         [ timeout=>
 | |
|                             sub {
 | |
|                                 nc_msg($verbose, "Timeout when getting mac address\n");
 | |
|                                 $rconsole->clear_accum();
 | |
|                                 $rc = 1;
 | |
|                             }
 | |
|                         ],
 | |
|                         [ eof =>
 | |
|                             sub {
 | |
|                                 nc_msg($verbose, " Cannot connect to $node\n");
 | |
|                                 $rconsole->clear_accum();
 | |
|                                 $rc = 1;
 | |
|                             }
 | |
|                         ]
 | |
|                     );
 | |
|                 }
 | |
|             }
 | |
|             ],
 | |
|             [qr/]/=>
 | |
|             sub {
 | |
|                 nc_msg($verbose, "Unexpected prompt\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|             [qr/(.*)DEFAULT(.*)/=>
 | |
|             sub {
 | |
|                 nc_msg($verbose, "Default catch error\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|             [timeout=>
 | |
|             sub {
 | |
|                 nc_msg($verbose, "Timeout in getting mac address\n");
 | |
|                 nc_msg($verbose, "timeout state is $state\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|             [eof =>
 | |
|             sub {
 | |
|                 nc_msg($verbose, "Cannot connect to $node");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|         );
 | |
|         return undef if ($rc eq 1);
 | |
|     }
 | |
|     # if the state is 0, 1, or 2, an error occurred and the join will fail
 | |
|     if ($state eq 4) {
 | |
|         if ($result[2] =~ /dump-mac\s*(\w*)\s*ok/) {
 | |
|             $mac_address = $1;
 | |
|         }
 | |
|         return $mac_address;
 | |
|     } else {
 | |
|         return undef;
 | |
|     }
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------------------------------
 | |
| 
 | |
| =head3    get_adaptr_loc
 | |
| 
 | |
| 
 | |
|   PROCEDURE
 | |
| 
 | |
|   Declare procedure to obtain the list of ethernet adapters, their physical
 | |
|   location codes and MAC addresses.
 | |
| 
 | |
|   The get-package-property command is an example of a command
 | |
|   that takes it's arguments off the stack and puts the results back onto the
 | |
|   stack. Because of this, the arguments for the get-package-property command
 | |
|   are in front of the command verb.
 | |
| 
 | |
|   The only reason this procedure is implemented in a loop is to avoid coding
 | |
|   3 expect commands.
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
|  sub get_adaptr_loc {
 | |
|     my $phandle = shift;
 | |
|     my $rconsole = shift;
 | |
|     my $node = shift;
 | |
|     my $verbose = shift;
 | |
|     my @cmd;
 | |
|     my @done;
 | |
|     my @msg;
 | |
|     my @pattern;
 | |
|     my @newstate;
 | |
|     my $state = 0;
 | |
|     my $timeout = 60; # shouldn't take long
 | |
|     my @result;
 | |
|     my @path;
 | |
|     my $loc_code;
 | |
|     my $rc = 0;
 | |
| 
 | |
|     nc_msg($verbose, "Status: get_adaptr_loc start\n");
 | |
|     # cmd(0) could have been sent as 3 commands. " ibm,loc-code" (tcl forces
 | |
|     # the use of \") is the first command on this line. The result of entering
 | |
|     # " ibm,loc-code" is that 2 stack entries are created, and address and a length.
 | |
|     #
 | |
|     # The next command in cmd(0) is the phandle with no quotes. This results in
 | |
|     # one stack entry because the phandle is an address.
 | |
|     #
 | |
|     # the third command in cmd(0) is get-package-property. After this command, there
 | |
|     # are 3 stack entries (return code, address and length of mac-address).
 | |
|     # state 0, stack count 0, send command
 | |
|     $done[0] = 0;
 | |
|     $cmd[0] = "\" ibm,loc-code\" $phandle get-package-property\r";
 | |
|     $msg[0] = "Status:  return code and loc-code now on stack\n";
 | |
|     #$pattern[0] = "(.*)3 >(.*)";
 | |
|     #$pattern[0] = "3 >";
 | |
|     $pattern[0] = "ok";
 | |
|     $newstate[0] = 1;
 | |
| 
 | |
|     # cmd(1) is a dot (.). This is a stack manipulation command that removes one
 | |
|     # thing from the stack. pattern(1) is looking for a prompt with the 2 indicating
 | |
|     # that there are 2 things left on the stack.
 | |
|     # state 1, return code and loc-code on stack
 | |
|     $done[1]= 0;
 | |
|     $cmd[1] = ".\r";
 | |
|     $msg[1] = "Status: loc-code now on stack\n";
 | |
|     #$pattern[1] = "(.*)2 >(.*)";
 | |
|     $pattern[1] = "ok"; #"2 >";
 | |
|     $newstate[1]= 2;
 | |
| 
 | |
|     # state 2, loc-code on stack
 | |
|     $done[2]= 0;
 | |
|     $cmd[2] = "dump\r";
 | |
|     $msg[2] = "Status: loc-code displayed, stack empty\n";
 | |
|     #$pattern[2] = "(.*)(: )(.*)( :)(.*)(\.: ok)";
 | |
|      $pattern[2] = "ok";
 | |
|     $newstate[2]= 3;
 | |
| 
 | |
|     # state 3, all done
 | |
|     $done[3] = 1;
 | |
| 
 | |
|     while($done[$state] eq 0) {
 | |
|         @result = ();
 | |
|         nc_msg($verbose, "PROGRAM Status: command is $cmd[$state]\n");
 | |
|         send_command($verbose, $rconsole, $cmd[$state]);
 | |
|         @result = $rconsole->expect(
 | |
|             $timeout,
 | |
|             [qr/$pattern[$state]/=>
 | |
|             sub {
 | |
|                 if ($state eq 1) {
 | |
|                     if ($rconsole->before() =~ /-\d+/) {
 | |
|                         nc_msg($verbose, "Status: Error getting adapter location for phandle=$phandle.");
 | |
|                         $rconsole->clear_accum();
 | |
|                         $state = 3;
 | |
|                         $rc = 1;
 | |
|                         return undef;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 nc_msg($verbose, $msg[$state]);
 | |
|                 $rconsole->clear_accum();
 | |
|                 $state = $newstate[$state];
 | |
|             }
 | |
|             ],
 | |
|             [qr/1 >/=>
 | |
|             sub {
 | |
|                 $rconsole->clear_accum();
 | |
|                 my $exp = shift;
 | |
|                 if($state eq 0) {
 | |
|                     send_command($verbose, $rconsole, ".\r");
 | |
|                     $exp->expect(
 | |
|                         #[qr/(-*\[0-9\]*)  ok(.*)0 >(.*)/=>
 | |
|                         [qr/0 >/=>
 | |
|                         sub {
 | |
|                             $rconsole->clear_accum();
 | |
|                             my $loc_rc = shift;
 | |
|                             nc_msg($verbose, "Error getting adapter physical location.\n");
 | |
|                             nc_msg($verbose, "Status: Error getting physical location for phandle=$phandle. RC=$loc_rc.\n");
 | |
|                             $rc = 1;
 | |
|                             }
 | |
|                         ],
 | |
|                         [timeout=>
 | |
|                         sub {
 | |
|                             $rconsole->clear_accum();
 | |
|                             nc_msg($verbose, "Timeout when openning console\n");
 | |
|                             $rc = 1;
 | |
|                             }
 | |
|                         ],
 | |
|                         [eof=>
 | |
|                         sub {
 | |
|                             $rconsole->clear_accum();
 | |
|                             nc_msg($verbose, "Cannot connect to the $node\n");
 | |
|                             $rc = 1;
 | |
|                             }
 | |
|                         ],
 | |
|                     );
 | |
| 
 | |
|                 }
 | |
|             }
 | |
|             ],
 | |
|             [qr/]/=>
 | |
|             sub {
 | |
|                 $rconsole->clear_accum();
 | |
|                 nc_msg($verbose, "Unexpected prompt\n");
 | |
|                 $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|             [qr/(.*)DEFAULT(.*)/=>
 | |
|             sub {
 | |
|                 $rconsole->clear_accum();
 | |
|                 nc_msg($verbose, "Default catch error\n");
 | |
|                 $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|             [timeout=>
 | |
|             sub {
 | |
|                 $rconsole->clear_accum();
 | |
|                 nc_msg($verbose, "Timeout when openning console\n");
 | |
|                 $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|             [eof =>
 | |
|             sub {
 | |
|                 $rconsole->clear_accum();
 | |
|                 nc_msg($verbose, "Cannot connect to the $node\n");
 | |
|                 $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|         );
 | |
|         return undef if ($rc eq 1);
 | |
|     }
 | |
|     # Did we find one or more adapters?
 | |
|     my @loc_array = split /\n/,$result[3];
 | |
|     my $found = 0;
 | |
|     $loc_code = '';
 | |
|     foreach my $line ( @loc_array ) {
 | |
|         if ($line =~ /(\w*):(.*):([\w|\.|-]*):/) {
 | |
|             $loc_code .= $3; 
 | |
|             $found = 1;
 | |
|         }
 | |
|     }
 | |
|     if ($found) {
 | |
|         $loc_code =~ s/\.$//;
 | |
|         return $loc_code;
 | |
|     } else {
 | |
|         return undef;
 | |
|     }
 | |
| }
 | |
| 
 | |
| #-------------------------------------------------------------------------------
 | |
| 
 | |
| =head3    ping_server
 | |
| 
 | |
| 
 | |
| 
 | |
|  PROCEDURE
 | |
| 
 | |
|  Declare procedure to obtain the list of valid adapter connector properties
 | |
|  from the adapter card.  Connector types can be rj45, sc, 9pin, aui,
 | |
|  bnc, or mic.  Speeds can be 10, 100, or 1000.  Duplex can be half or
 | |
|  full.  This procedure will use the "supported-network-types"
 | |
|  argument to the get-package-property command to get the list of
 | |
|  properties for the given adapter.
 | |
| 
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
| sub  ping_server{
 | |
|     my $phandle = shift;
 | |
|     my $full_path_name = shift;
 | |
|     my $rconsole = shift;
 | |
|     my $node = shift;
 | |
|     my $mac_address = shift;
 | |
|     my $verbose = shift;
 | |
|     my $adap_speed = shift;
 | |
|     my $adap_duplex = shift;
 | |
|     my $list_type = shift;
 | |
|     my $server_ip = shift;
 | |
|     my $client_ip = shift;
 | |
|     my $gateway_ip = shift;
 | |
|     my $adap_prop_list_array;
 | |
|     #my %env = shift;
 | |
|     my $command;
 | |
|     my $linklocal_ip;
 | |
|     my @result;
 | |
|     my @done;
 | |
|     my @cmd;
 | |
|     my @msg;
 | |
|     my @pattern;
 | |
|     my @newstate;
 | |
|     my $state = 0;
 | |
|     my $timeout;
 | |
| 
 | |
|     nc_msg($verbose, "Status: ping_server start\n");
 | |
| 
 | |
|     #if (exists($env{'FIRMWARE_DUMP'})) {
 | |
|     #    $full_path_name = Firmware_Dump($phandle);
 | |
|     #}
 | |
|     my $j = 0;
 | |
|     my $tty_do_ping = 0;
 | |
|     my $stack_level = 0;
 | |
|     my $properties_matched = 0;
 | |
|     my $adap_conn;
 | |
|     my $speed_list;
 | |
|     my $duplex_list;
 | |
|     my @adap_conn_list;
 | |
|     my $i;
 | |
|     my $ping_debug;
 | |
|     my $ping_rc;
 | |
|     my $rc = 0;
 | |
| 
 | |
|     # If the adapter type chosen is ethernet, need to set the speed and duplex
 | |
|     # of the adapter before we perform the ping.  If token ring or fddi,
 | |
|     # this is not required, so begin with state 2.
 | |
|     #
 | |
|     # cmd(0) sets the given adapter as active, to allow setting of speed
 | |
|     # and duplex
 | |
|     #
 | |
|     # cmd(1) writes the settings to the current adapter
 | |
|     #
 | |
|     # cmd(2) selects the /packages/net node as the active package to access the
 | |
|     # ping command.
 | |
|     #
 | |
|     # The next command in cmd(3) is the ping command. This places the return code
 | |
|     # on the stack. A return code of 0 indicates success.
 | |
|     #
 | |
|     # state 0, set the current adapter
 | |
|     $done[0] = 0;
 | |
|     $cmd[0] = "dev $full_path_name\r";
 | |
|     $msg[0] = "Status: selected $full_path_name as the active adapter\n";
 | |
|     #$pattern[0] = ".*dev(.*)0 >(.*)";
 | |
|     $pattern[0] = "0 >";
 | |
|     $newstate[0] = 1;
 | |
| 
 | |
|     # state 1, send property command to $selected type;
 | |
|     $done[1] = 0;
 | |
|     $cmd[1] = "\" ethernet,$adap_speed,$adap_conn,$adap_duplex\" encode-string \" chosen-network-type\" property\r";
 | |
|     $msg[1] = "Status: chosen network type set\n";
 | |
|     #$pattern[1] =".*ethernet(.*)0 >(.*)";
 | |
|     $pattern[1] ="0 >";
 | |
|     $newstate[1]= 2;
 | |
| 
 | |
|     # state 2, activate /packages/net
 | |
|     $done[2] = 0;
 | |
|     $cmd[2] = "dev /packages/net\r";
 | |
|     $msg[2] = "Status: selected the /packages/net node as the active package\n";
 | |
|     $pattern[2] = ".*dev.*packages.*net(.*)ok(.*)0 >(.*)";
 | |
|     #$pattern[2] = "ok";
 | |
|     $newstate[2]= 3;
 | |
| 
 | |
|     # state 3, ping the server
 | |
|     $done[3] = 0;
 | |
|     $msg[3] = "Status: ping return code now on stack\n";
 | |
|     $newstate[3] = 4;
 | |
| 
 | |
|     # get the timeout for ping test
 | |
|     my $to4pt;
 | |
|     if ( $ENV{TIMEOUT4PINGTEST} =~ /^\d+$/ ) {
 | |
|         $to4pt = ",$ENV{TIMEOUT4PINGTEST}";
 | |
|     } 
 | |
| 
 | |
|     #IPv6
 | |
|     if ( $server_ip =~ /:/ ) {
 | |
|         #::1, calculate link local address
 | |
|         if ($client_ip eq "::1") {
 | |
|             my $command = "/opt/xcat/share/xcat/tools/mac2linklocal -m $mac_address";
 | |
|             $linklocal_ip = $rconsole->send($command);
 | |
|         } else {
 | |
|             $linklocal_ip = $client_ip;
 | |
|         }
 | |
|         $cmd[3] = "ping $full_path_name:ipv6,$server_ip,$linklocal_ip,$gateway_ip$to4pt\r";
 | |
|     } else {
 | |
|         $cmd[3] = "ping $full_path_name:$server_ip,$client_ip,$gateway_ip$to4pt\r";
 | |
|     }
 | |
|     $pattern[3] = ".*ping(.*)ok(.*)0 >(.*)";
 | |
| 
 | |
|     # state 4, all done
 | |
|     $done[4] = 0;
 | |
|     $cmd[4] = "0 to my-self\r";
 | |
|     $msg[4] = "Status: resetting pointer\n";
 | |
|     #$pattern[4] = "(.*)ok(.*)0 >(.*)";
 | |
|     $pattern[4] = "ok";
 | |
|     $newstate[4] = 5;
 | |
| 
 | |
|     # state 5, all done
 | |
|     $done[5] = 1;
 | |
| 
 | |
| 
 | |
|     # for ping, only need to set speed and duplex for ethernet adapters
 | |
|     #
 | |
|     if ( $list_type eq "ent" ) {
 | |
|         $state = 0;
 | |
| 
 | |
|         # Get the list of properties for this adapter
 | |
|         #
 | |
|         $adap_prop_list_array = get_adap_prop($phandle, $rconsole, $node, $verbose);
 | |
|         if ( $adap_prop_list_array eq 1 ) {
 | |
|             nc_msg($verbose, "ERROR return from get_adap_prop\n");
 | |
|             return 1;
 | |
|         }
 | |
| 
 | |
|         if ( $adap_prop_list_array eq 0 ) {
 | |
|             nc_msg($verbose, "No properties found for adapter '$full_path_name'\n");
 | |
|             return 1;
 | |
|         }
 | |
| 
 | |
|         # Now need to verify that the network params we were passed are valid for
 | |
|         # the given adapter
 | |
|         #
 | |
|         my $a_speed;
 | |
|         my $a_conn;
 | |
|         my $a_duplex;
 | |
|         for my $prop (@$adap_prop_list_array) {
 | |
|             if( $prop =~ /(.*),(.*),(.*)/) {
 | |
|                 $a_speed = $1;
 | |
|                 $a_conn = $2;
 | |
|                 $a_duplex = $3;
 | |
|                 if ( ( $a_speed eq $adap_speed ) && ( $a_duplex eq $adap_duplex ) ) {
 | |
|                     $properties_matched = 1;
 | |
|                     if ( grep {$_ eq $a_conn } @adap_conn_list) {
 | |
|                         push @adap_conn_list, $a_conn;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if ( $properties_matched eq 0 ) {
 | |
|             $adap_speed = $a_speed;
 | |
|             $adap_duplex = $a_duplex;
 | |
|             $properties_matched = 1;
 | |
|             push @adap_conn_list, $a_conn;
 | |
|         }
 | |
| 
 | |
|         $i = scalar(@adap_conn_list);
 | |
| 
 | |
|         if ( $properties_matched eq 0 ) {
 | |
|             nc_msg($verbose, "'$adap_speed/$adap_duplex' settings are not supported on this adapter\n");
 | |
|             return 1;
 | |
|         }
 | |
|     } else {
 | |
|         $state = 2;
 | |
|     }
 | |
| 
 | |
|     $timeout = 300;
 | |
|     while ( $done[$state] eq 0 ) {
 | |
| 
 | |
|         send_command($verbose, $rconsole, $cmd[$state]);
 | |
|         @result = $rconsole->expect(
 | |
| 
 | |
|             $timeout,
 | |
|             [qr/$pattern[$state]/s=>
 | |
|             sub {
 | |
|                 nc_msg($verbose, $msg[$state]);
 | |
|                 $rconsole->clear_accum();
 | |
|                 $state = $newstate[$state];
 | |
|                 }
 | |
|             ],
 | |
|             [qr/]/=>
 | |
|             sub {
 | |
|                 nc_msg($verbose, "Unexpected prompt\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|             [qr/(.*)DEFAULT(.*)/=>
 | |
|             sub {
 | |
|                 nc_msg($verbose, "Default catch error\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|             [timeout=>
 | |
|             sub {
 | |
|                 nc_msg($verbose, "Timeout when openning console\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|             [eof=>
 | |
|             sub {
 | |
|                 nc_msg($verbose, "Cannot connect to the $node\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|         );
 | |
| 
 | |
|        return 1 if ($rc eq 1);
 | |
| 
 | |
|         if ( $state eq 1 ) {
 | |
|             $adap_conn = $adap_conn_list[$j];
 | |
|             $cmd[1] = "\" ethernet,$adap_speed,$adap_conn,$adap_duplex\" encode-string \" chosen-network-type\" property\r";
 | |
|             nc_msg($verbose, "Status: Trying connector type $adap_conn\n");
 | |
|             $j++;
 | |
|         }
 | |
|         if ((($tty_do_ping eq 1) && ($state eq 4)) || ($tty_do_ping != 1) && ($state eq 3) ) {
 | |
|             $ping_debug = $result[2];
 | |
|         }
 | |
|         if ( ( ($tty_do_ping eq 1) && ($state eq 5) ) || ($tty_do_ping != 1) && ($state eq 4) ) {
 | |
|             if ( ($tty_do_ping eq 1) && ($state eq 5) ) {
 | |
|                 #$ping_rc = $result[2];
 | |
|                 $stack_level = length($result[4]);
 | |
|             } elsif ( ($state eq 4) && ($tty_do_ping != 1) && ($result[2] =~ /PING SUCCESS/)) {
 | |
|                 $ping_rc = 0;
 | |
|             #} elsif ( $result[2] =~ /unknown word/ ) {
 | |
|             #    nc_msg($verbose, "Status: try tty-do-ping.\n");
 | |
|             #    $ping_rc = 1;
 | |
|             #    $tty_do_ping = 1;
 | |
|             #    $state = 3 ;
 | |
|             #    $cmd[3] = "\"" . $full_path_name . ":" . $client_ip . "," . $server_ip . "," . $gateway_ip . "\" tty-do-ping\r";
 | |
|             #    $pattern[3] = "(.*)ok(.*)(\[1-2\]) >(.*)";
 | |
|             #
 | |
|             #    # state 4, get the return code off the stack
 | |
|             #    $done[4] = 0;
 | |
|             #    $cmd[4] = ".\r";
 | |
|             #    $msg[4] = "Status: return code displayed, stack empty\n";
 | |
|             #    $pattern[4] = "(\[0-9\]*)  ok(.*)(\[0-1\]) >(.*)";
 | |
|             #    $newstate[4] = 5;
 | |
|             #
 | |
|             #    # this command is used to work around a default catch problem in open
 | |
|             #    # firmware.  Without it, a default catch occurs if we try to set
 | |
|             #    # adapter properties again after a ping
 | |
|             #    #
 | |
|             #    # state 5, re$pointer
 | |
|             #    $done[5] = 0;
 | |
|             #    $cmd[5] = "0 to my-self\r";
 | |
|             #    $msg[5] = "Status: resetting pointer\n" ;
 | |
|             #    $pattern[5] = "(.*)ok(.*)0 >(.*)";
 | |
|             #    $newstate[5] = 6 ;
 | |
|             #
 | |
|             #    # state 6, all done
 | |
|             #    $done[6] = 1;
 | |
|             } else {
 | |
|                 $ping_rc = 1;
 | |
|             }
 | |
| 
 | |
|             if ( $ping_rc eq 0 ) {
 | |
|                 nc_msg($verbose, "# $full_path_name ping successful.\n");
 | |
|             } elsif ( $ping_rc eq  1 ) {
 | |
|                 nc_msg($verbose, "# $full_path_name ping unsuccessful.\n");
 | |
|                 nc_msg($verbose, "# $full_path_name ping unsuccessful.\n");
 | |
|                 nc_msg($verbose, "$ping_debug\n");
 | |
| 
 | |
|                 # An unsuccessful return may leave another item on the stack to
 | |
|                 # be removed.  Check for it, and remove if necessary
 | |
|                 my $matchexp = 0;
 | |
|                 my @exp_out;
 | |
|                 while ( $stack_level != 0 ) {
 | |
|                     @exp_out = ();
 | |
|                     send_command($verbose, $rconsole, ".\r");
 | |
|                     @exp_out = $rconsole->expect(
 | |
|                         [qr/(\[0-9\]*)  ok(.*)(\[0-1\]) >(.*)/s=>
 | |
|                         sub {
 | |
|                             $rconsole->clear_accum();
 | |
|                             $matchexp = 1;
 | |
|                             }
 | |
|                         ],
 | |
|                         [qr/]/=>
 | |
|                         sub {
 | |
|                             nc_msg($verbose, "Unexpected prompt\n");
 | |
|                             $rconsole->clear_accum();
 | |
|                             $rc = 1;
 | |
|                             }
 | |
|                         ],
 | |
|                         [qr/(.*)DEFAULT(.*)/=>
 | |
|                         sub {
 | |
|                             nc_msg($verbose, "Default catch error\n");
 | |
|                             $rconsole->clear_accum();
 | |
|                             $rc = 1;
 | |
|                             }
 | |
|                         ],
 | |
|                         [timeout=>
 | |
|                         sub {
 | |
|                             nc_msg($verbose, "Timeout in ping server\n");
 | |
|                             $rconsole->clear_accum();
 | |
|                             $rc = 1;
 | |
|                             }
 | |
|                         ],
 | |
|                         [eof =>
 | |
|                         sub {
 | |
|                             nc_msg($verbose, "Cannot connect to $node\n");
 | |
|                             $rconsole->clear_accum();
 | |
|                             $rc = 1;
 | |
|                             }
 | |
|                         ],
 | |
|                     );
 | |
|                     if ($matchexp) {
 | |
|                         $matchexp = 0;
 | |
|                         $stack_level = length($exp_out[4]);
 | |
|                         nc_msg($verbose, "Status: stack_level is <$stack_level>\n");
 | |
|                     }
 | |
|                 }
 | |
|                 # Check if there are any more adapter connector types
 | |
|                 # to try
 | |
|                 #
 | |
|                 if ( ( $list_type eq "ent" ) && ( $j < $i ) ) {
 | |
|                     $adap_conn = $adap_conn_list[$j];
 | |
|                     nc_msg($verbose, "Status: Trying connector type $adap_conn\n");
 | |
|                     $j++;
 | |
| 
 | |
|                     # Need to work around a default catch problem in open
 | |
|                     # firmware by sending a "0 to my-self" instruction
 | |
|                     # following the ping.  To make sure this happens in
 | |
|                     # this rare case where we have an adapter with multiple connectors,
 | |
|                     # we have to force the instruction into the 0th slot in
 | |
|                     # the array.  This is OK, since we only set the current
 | |
|                     # adapter once, upon entering this procedure.
 | |
|                     #
 | |
|                     $done[0] = 0;
 | |
|                     $cmd[0] = "0 to my-self\r";
 | |
|                     $msg[0] = "Status: resetting pointer\n";
 | |
|                     $pattern[0] = "(.*)ok(.*)0 >(.*)";
 | |
|                     $newstate[0] = 1;
 | |
| 
 | |
|                     $state = 0;
 | |
|                 }
 | |
|             } else {
 | |
|                 nc_msg($verbose, "Unexpected ping return code\n");
 | |
|                 return 1;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     return $ping_rc;
 | |
| }
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------------------------------
 | |
| 
 | |
| =head3    set_disk_boot
 | |
| 
 | |
| 
 | |
| 
 | |
|  PROCEDURE
 | |
| 
 | |
|  Declare procedure to obtain the list of valid adapter connector properties
 | |
|  from the adapter card.  Connector types can be rj45, sc, 9pin, aui,
 | |
|  bnc, or mic.  Speeds can be 10, 100, or 1000.  Duplex can be half or
 | |
|  full.  This procedure will use the "supported-network-types"
 | |
|  argument to the get-package-property command to get the list of
 | |
|  properties for the given adapter.
 | |
| 
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
| sub set_disk_boot {
 | |
|     my @expect_out = shift;
 | |
|     my $rconsole = shift;
 | |
|     my $node = shift;
 | |
|     my $verbose = shift;
 | |
|     my $x0;
 | |
|     my $x1;
 | |
|     my $x2;
 | |
|     my $command;
 | |
|     my @done;
 | |
|     my @cmd;
 | |
|     my @msg;
 | |
|     my @pattern;
 | |
|     my @newstate;
 | |
|     my $timeout;
 | |
|     my $state;
 | |
|     my $rc = 0;
 | |
| 
 | |
|     # state 0, get SMS screen
 | |
|     $done[0] = 0;
 | |
|     if($expect_out[0] =~ /(\n)(\[ ])(\[0-9])(\[.])(\[ ]+)Select Boot Options(\r)/){
 | |
|         $x0 = $1;
 | |
|         $x1 = $2;
 | |
|         $x2 = $3;
 | |
|         $command = $4;
 | |
|     }
 | |
|     $cmd[0] = "$command\r";
 | |
|     $msg[0] = "Status: sending return to repaint SMS screen\n";
 | |
|     $pattern[0] = "(\n)(\[ ])(\[0-9])(\[.])(\[ ]+)Configure Boot Device Order(\r)";
 | |
|     $newstate[0] = 1;
 | |
| 
 | |
|     # state 1, Multiboot
 | |
|     $done[1] = 0;
 | |
|     $msg[1] = "Status: Multiboot\n";
 | |
|     $pattern[1] = "(\n)(\[ ])(\[0-9])(\[.])(\[ ]+)Select 1st Boot Device(\r)";
 | |
|     $newstate[1] = 2;
 | |
| 
 | |
|     # state 2, Configure Boot Device Order
 | |
|     $done[2] = 0;
 | |
|     $msg[2] = "Status: Configure Boot Device Order";
 | |
|     $pattern[2] = "(\n)(\[ ])(\[0-9])(\[.])(\[ ]+)Hard Drive(.*)";
 | |
|     $newstate[2] = 3;
 | |
| 
 | |
|     # state 3, Select Device Type
 | |
|     $done[3] = 0;
 | |
|     $msg[3] = "Status: Select Device Type";
 | |
|     $pattern[3] = "(\n)(\[ ])(\[0-9])(\[.])(\[ ]+)SCSI(.*)";
 | |
|     $newstate[3] = 4;
 | |
| 
 | |
|     # state 4, Select Media Type
 | |
|     $done[4] = 0;
 | |
|     $msg[4] = "Status: Select Media Type";
 | |
|     $pattern[4] = "(\n)(\[ ])(\[1])(\[.])(\[ ]+)(\\S+)(.*)";
 | |
|     $newstate[4] = 5 ;
 | |
| 
 | |
|     # state 5, Select Media Adapter
 | |
|     $done[5] = 0;
 | |
|     $msg[5] = "Status: Select Media Adapter";
 | |
|     $pattern[5] = "(\n)(\[ ])(\[0-9])(\[.])(\[ ]+)(\\S)(\[ ]+)SCSI (\[0-9]+) MB Harddisk(.*)loc=(.*)\[)]";
 | |
|     $newstate[5] = 6;
 | |
| 
 | |
|     # state 6, Select Device
 | |
|     $done[6] = 0;
 | |
|     $msg[6] = "Status: Select Device";
 | |
|     $pattern[6] = "(\n)(\[ ])(\[0-9])(\[.])(\[ ]+)Set Boot Sequence(.*)";
 | |
|     $newstate[6] = 7;
 | |
| 
 | |
|     # state 7, Select Task
 | |
|     $done[7] = 0;
 | |
|     $msg[7] = "Status: Select Task";
 | |
|     $pattern[7] = "(.*)Current Boot Sequence(.*)";
 | |
|     $newstate[7] = 8 ;
 | |
| 
 | |
|     # state 8, Return to Main Menu
 | |
|     $done[8] = 0;
 | |
|     $cmd[8] = "M";
 | |
|     $msg[8] = "Status: Restored Default Setting.\n" ;
 | |
|     $pattern[8] = "(.*)Navigation key(.*)";
 | |
|     $newstate[8] = 9;
 | |
| 
 | |
|     # state 9, Getting to SMS Main Menu
 | |
|     $done[9] = 0;
 | |
|     $cmd[9] = "0\r";
 | |
|     $msg[9] = "Status: Getting to SMS Main Menu.\n";
 | |
|     $pattern[9] = "(.*)Exit SMS(.*)Prompt?(.*)";
 | |
|     $newstate[9] = 10;
 | |
| 
 | |
|     # state 10, Exiting SMS
 | |
|     $done[10] = 0;
 | |
|     $cmd[10] = "Y";
 | |
|     $msg[10] = "Status: Exiting SMS.\n";
 | |
|     $pattern[10] = "(.*)ok(.*)0 >(.*)";
 | |
|     $newstate[10] = 11;
 | |
| 
 | |
|     # state 11, all done
 | |
|     $done[11] = 1;
 | |
| 
 | |
|     $timeout = 30;
 | |
|     $state = 0;
 | |
| 
 | |
|     while ( $done[$state] eq 0 ) {
 | |
|         send_command($verbose, $rconsole, $cmd[$state]);
 | |
|         $rconsole->expect(
 | |
|             [qr/$pattern[$state]/=>
 | |
|                 sub {
 | |
|                     $rconsole->clear_accum();
 | |
|                     if ( $state eq 4 ) {
 | |
|                         if ( $expect_out[6] eq "None" ) {
 | |
|                             $state = 8;
 | |
|                         }
 | |
|                     }
 | |
|                     $state = $newstate[$state];
 | |
|                     if ( ($state != 8) && ($state != 9) && ($state != 10) ) {
 | |
|                         $cmd[$state] = "$expect_out[3]\r";
 | |
|                     }
 | |
|                 }
 | |
|             ],
 | |
|             [qr/THE SELECTED DEVICES WERE NOT DETECTED IN THE SYSTEM/=>
 | |
|                 sub {
 | |
|                     $rconsole->clear_accum();
 | |
|                     nc_msg($verbose, " Status: THE hard disk WERE NOT DETECTED IN THE SYSTEM!\n");
 | |
|                     $rc = 1;
 | |
|                  }
 | |
|             ],
 | |
|             [timeout =>
 | |
|                 sub {
 | |
|                     $rconsole->clear_accum();
 | |
|                     nc_msg($verbose, "Timeout in settin boot order\n");
 | |
|                     $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|             [eof =>
 | |
|                 sub {
 | |
|                     $rconsole->clear_accum();
 | |
|                     nc_msg($verbose, "Cannot connect to $node\n");
 | |
|                     $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|         );
 | |
|         if ($rc eq 1) {
 | |
|             return 1;
 | |
|         } else {
 | |
|             return 0;
 | |
|         }
 | |
|     }
 | |
|     return 0;
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| ###################################################################
 | |
| #
 | |
| # PROCEDURE
 | |
| #
 | |
| # Declare procedure to boot the system from the selected ethernet card.
 | |
| #
 | |
| # This routine does the following:
 | |
| # 1. Initiates the boot across the network. (state 0 or 1)
 | |
| #
 | |
| # state 99 is normal exit and state -1 is error exit.
 | |
| ###################################################################
 | |
| sub boot_network {
 | |
|     my $rconsole = shift;
 | |
|     if (($rconsole) && ($rconsole =~ /xCAT::/))
 | |
|     {
 | |
|         $rconsole = shift;
 | |
|     }
 | |
|     my $full_path_name = shift;
 | |
|     my $speed = shift;
 | |
|     my $duplex = shift;
 | |
|     my $chosen_adap_type = shift;
 | |
|     my $server_ip = shift;
 | |
|     my $client_ip = shift;
 | |
|     my $gateway_ip = shift;
 | |
|     my $netmask = shift;
 | |
|     my $dump_target = shift;
 | |
|     my $dump_lun = shift;
 | |
|     my $dump_port = shift;
 | |
|     my $verbose = shift;
 | |
|     my $extra_args = shift;
 | |
|     my $node = shift;
 | |
|     my $set_boot_order = shift;
 | |
|     my @net_device;
 | |
|     my @pattern;
 | |
|     my @cmd;
 | |
|     my @msg;
 | |
|     my @newstate;
 | |
|     my @done;
 | |
|     my $state = 0;
 | |
|     my $timeout;
 | |
|     my $boot_device_bk;
 | |
|     my $rc = 0;
 | |
| 
 | |
| 
 | |
|     nc_msg($verbose, "Status: boot_network start\n");
 | |
|     ###################################################################
 | |
|     # Variables associated with each of the commands sent by this routine
 | |
|     # are defined below.
 | |
|     #
 | |
|     # The done variable is flag that is set to 1 to break out of the loop
 | |
|     #
 | |
|     # The cmd variable is the command to be sent to the chrp interface.
 | |
|     #     In one case it set in the special processing code because the
 | |
|     #     ihandle is not available then this code is executes.
 | |
|     #
 | |
|     # The msg variable contains the message sent after a successful pattern match
 | |
|     #
 | |
|     # The pattern variable is the pattern passed to expect
 | |
|     #
 | |
|     # The newstate variable indicates what command is to be issued next
 | |
|     ###################################################################
 | |
| 
 | |
|     # If the install adapter is Ethernet or Token Ring, set the speed and
 | |
|     # duplex during boot.
 | |
|     # state 0, stack count 0
 | |
|     $done[0] = 0;
 | |
|     if ($dump_target ne "") {
 | |
|         $net_device[0] = "$full_path_name:iscsi,ciaddr=$client_ip,subnet-mask=$netmask,itname=dummy,iport=$dump_port,ilun=$dump_lun,iname=$dump_target,siaddr=$server_ip,2";
 | |
|         $pattern[0] = "iSCSI";
 | |
|     } else {
 | |
|         if ($extra_args ne "" ) {
 | |
|             if ( $server_ip =~ /:/ ) { #ipv6
 | |
|                 $net_device[0] = "$full_path_name:ipv6,speed=$speed,duplex=$duplex,siaddr=$server_ip,ciaddr=$client_ip,giaddr=$gateway_ip,filename=$node,$extra_args";
 | |
|             } else {
 | |
|                 $net_device[0] = "$full_path_name:speed=$speed,duplex=$duplex,bootp,$server_ip,,$client_ip,$gateway_ip $extra_args";
 | |
|             }
 | |
|         } else {
 | |
|             if ( $server_ip =~ /:/ ) { #ipv6
 | |
|                 $net_device[0] = "$full_path_name:ipv6,speed=$speed,duplex=$duplex,siaddr=$server_ip,ciaddr=$client_ip,giaddr=$gateway_ip,filename=$node";
 | |
|             } else {
 | |
|                 $net_device[0] = "$full_path_name:speed=$speed,duplex=$duplex,bootp,$server_ip,,$client_ip,$gateway_ip";
 | |
|             }
 | |
|         }
 | |
|         $pattern[0] = "BOOTP";
 | |
|     }
 | |
| 
 | |
|     $cmd[0] = "boot $net_device[0]\r";
 | |
|     $msg[0] = "Status: network boot initiated\n";
 | |
|     $newstate[0] = 99;
 | |
| 
 | |
|     # If the install adapter is FDDI, don't set the speed and duplex
 | |
|     # state 1
 | |
|     $done[1] = 0;
 | |
|     $net_device[1] = "$full_path_name:bootp,$server_ip,,$client_ip,$gateway_ip";
 | |
|     $cmd[1] = "boot $net_device[1]\r";
 | |
|     $msg[1] = "Status: network boot initiated\n";
 | |
|     $pattern[1] = "BOOTP";
 | |
|     $newstate[1] = 99;
 | |
| 
 | |
|     # state 99, all done
 | |
|     $done[99] = 1;
 | |
| 
 | |
|     # state -1, all done
 | |
|     $done[100] = 1; #-1???
 | |
| 
 | |
|     if ($chosen_adap_type eq  "fddi" ) {
 | |
|         $state = 1;
 | |
|     } else {
 | |
|         if ($speed eq "" || $duplex eq "" ) {
 | |
|             nc_msg($verbose, "Cannot set speed or duplex for network boot\n");
 | |
|             return 1;
 | |
|         }
 | |
|         $state = 0;
 | |
|     }
 | |
|     ##################################################################
 | |
|     # Set the boot device order.
 | |
|     ##################################################################
 | |
|     if ( $set_boot_order > 0 ) {
 | |
|         $done[2] =  0;
 | |
|         $msg[2] =  "Status: read original boot-device\n";
 | |
|         $cmd[2] =  "printenv boot-device\r";
 | |
|         $pattern[2] =  ".*boot-device\\s+(\\S+)(.*)ok(.*)";
 | |
|         $newstate[2] =  3;
 | |
| 
 | |
|         $done[3] =  0;
 | |
|         $msg[3] =  "Status: set the environment variable boot-device\n";
 | |
|         $pattern[3] =  "(.*)ok(.*)(\[0-9]) >(.*)";
 | |
|         if (  $state eq 0 ) {
 | |
|             $newstate[3] =  0;
 | |
|         } else {
 | |
|             $newstate[3] =  1;
 | |
|         }
 | |
|         $state = 2;
 | |
|     }
 | |
| 
 | |
|     $timeout = 30;        # shouldn't take long
 | |
|     while ( $done[$state] eq 0 ) {
 | |
|         send_command($verbose, $rconsole, $cmd[$state]);
 | |
|         $rconsole->expect(
 | |
|             [qr/$pattern[$state]/=>
 | |
|                 sub {
 | |
|                     $rconsole->clear_accum();
 | |
|                     my @expect_out = shift;
 | |
|                     if ( $state eq 2 ) {
 | |
|                         if ( $set_boot_order eq 1 ) {
 | |
|                             ########################################
 | |
|                             # Set network as boot device
 | |
|                             ########################################
 | |
|                             $cmd[3] = "setenv boot-device $net_device[$newstate[3]]\r";
 | |
|                         } elsif ( $set_boot_order eq 2 ) {
 | |
|                             ########################################
 | |
|                             # Set network as 1st boot device,disk as 2nd boot device
 | |
|                             ########################################
 | |
|                             $boot_device_bk = $expect_out[1];
 | |
|                             $cmd[3] =  "setenv boot-device $net_device[$newstate[3]] $boot_device_bk\r";
 | |
|                         } elsif ( $set_boot_order eq 3 ) {
 | |
|                             ########################################
 | |
|                             # Set disk as 1st boot device,network as 2nd boot device
 | |
|                             ########################################
 | |
|                             $boot_device_bk = $expect_out[1];
 | |
|                             $cmd[3] =  "setenv boot-device $boot_device_bk $net_device[$newstate[3]]\r";
 | |
|                         } elsif ( $set_boot_order eq 4 ) {
 | |
|                             ########################################
 | |
|                             # set disk as boot device
 | |
|                             ########################################
 | |
|                             $boot_device_bk = $expect_out[1];
 | |
|                             $cmd[3] =  "setenv boot-device $boot_device_bk\r";
 | |
|                         }
 | |
|                     }
 | |
|                     nc_msg($verbose, $msg[$state]);
 | |
|                     $state = $newstate[$state];
 | |
|                 }
 | |
|             ],
 | |
|             [qr/----/=>
 | |
|                 sub {
 | |
|                 nc_msg ($verbose, $msg[$state]);
 | |
|                 $rconsole->clear_accum();
 | |
|                 $state = $newstate[$state];
 | |
|                 }
 | |
|             ],
 | |
|             # For some old firmware, does not output "----"
 | |
|             [qr/BOOTP/=>
 | |
|                 sub {
 | |
|                 nc_msg ($verbose, $msg[$state]);
 | |
|                 $rconsole->clear_accum();
 | |
|                 $state = $newstate[$state];
 | |
|                 }
 | |
|             ],
 | |
|             [qr/]/=>
 | |
|                 sub {
 | |
|                 nc_msg($verbose, "Unexpected prompt\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|             [qr/(.*)DEFAULT(.*)/=>
 | |
|                 sub {
 | |
|                     nc_msg($verbose, "Default catch error\n");
 | |
|                     $rconsole->clear_accum();
 | |
|                     $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|             [timeout=>
 | |
|                 sub {
 | |
|                     nc_msg($verbose, "Timeout when openning console\n");
 | |
|                     $rconsole->clear_accum();
 | |
|                     $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|             [eof=>
 | |
|                 sub {
 | |
|                     nc_msg($verbose, "Cannot connect to the $node\n");
 | |
|                     $rconsole->clear_accum();
 | |
|                     $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|         );
 | |
|         return 1 if ($rc eq 1);
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| #
 | |
| # PROCEDURE
 | |
| #
 | |
| #
 | |
| sub Boot {
 | |
|     my $rconsole = shift;
 | |
|     my $node = shift;
 | |
|     my $verbose = shift;
 | |
|     #my @expect_out = shift;
 | |
|     my $rc = 0;
 | |
|     my $timeout;
 | |
|     my $state;
 | |
| 
 | |
|     nc_msg($verbose, "Status: waiting for the boot image to boot up.\n");
 | |
| 
 | |
|     $timeout = 1200;      # could take a while depending on configuration
 | |
|     $rconsole->expect(
 | |
|         [qr/RESTART-CMD/=>
 | |
|             sub {
 | |
|                 # If we see a "problem doing RESTART-CMD" message, we re-hit the OPEN-DEV
 | |
|                 # issue after firmware rebooted itself and we need to retry the netboot once more
 | |
|                 nc_msg($verbose, "The network boot ended in an error.\nError : RESTART-CMD\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|             }
 | |
|         ],
 | |
|         #[!(qr/[0-9A-F]+/)=>
 | |
|         #    sub {
 | |
|         #        nc_msg($verbose, "The network boot ended in an error.\n");
 | |
|         #        #nc_msg($verbose, $expect_out[buffer]);
 | |
|         #        $rc = 1;
 | |
|         #     }
 | |
|         #],
 | |
|         [qr/BOOTP/=>      #-ex
 | |
|             sub {
 | |
|                 nc_msg($verbose, "# Network boot proceeding - matched BOOTP, exiting.\n");
 | |
|                 $rconsole->clear_accum();
 | |
|             }
 | |
|         ],
 | |
|         # Welcome to AIX - some old firmware does not output BOOTP or ----
 | |
|         [qr/Welcome/=>      #-ex
 | |
|             sub {
 | |
|                 nc_msg($verbose, "# Network boot proceeding - matched Welcome, exiting.\n");
 | |
|                 $rconsole->clear_accum();
 | |
|             }
 | |
|         ],
 | |
|         # tftp file download - some old firmware does not output BOOTP or ----
 | |
|         [qr/FILE/=>      #-ex
 | |
|             sub {
 | |
|                 nc_msg($verbose, "# Network boot proceeding - matched FILE.\n");
 | |
|                 $rconsole->clear_accum();
 | |
|             }
 | |
|         ],
 | |
|         # some old firmware does not output BOOTP or ----
 | |
|         [qr/Elapsed/=>      #-ex
 | |
|             sub {
 | |
|                 nc_msg($verbose, "# Network boot proceeding - matched Elapsed, exiting.\n");
 | |
|                 $rconsole->clear_accum();
 | |
|             }
 | |
|         ],
 | |
|         [qr/------/=>      #-ex
 | |
|             sub {
 | |
|                 nc_msg($verbose, "# Network boot proceeding, exiting.\n");
 | |
|                 $rconsole->clear_accum();
 | |
|             }
 | |
|         ],
 | |
|         [timeout=>
 | |
|         sub {
 | |
|             my $mins = $timeout/60;
 | |
|             nc_msg($verbose, "Timeout waiting for the boot image to boot up. \
 | |
|                   \n waited '$mins' minutes for the boot image to boot. \
 | |
|                   \nEither the boot up has taken longer than expected or \
 | |
|                   \nthere is a problem with system boot.  Check the boot \
 | |
|                   \nof the node to determine if there is a problem.\n");
 | |
|             $rconsole->clear_accum();
 | |
|             #nc_msg($verbose, $expect_out[buffer]);
 | |
|             $rc = 1;
 | |
|             }
 | |
|         ],
 | |
|         [eof=>
 | |
|         sub {
 | |
|             nc_msg($verbose, "Port closed waiting for boot image to boot.\n");
 | |
|             $rconsole->clear_accum();
 | |
|             $rc = 1;
 | |
|             }
 | |
|         ],
 | |
|     );
 | |
|     return $rc;
 | |
| }
 | |
| 
 | |
| 
 | |
| ###################################################################
 | |
| #
 | |
| # PROCEDURE
 | |
| #
 | |
| # Create multiple open-dev function in Open Firmware to try open
 | |
| # a device.  The original problem is a firmware issue which fails
 | |
| # to open a device.  This procedure will create multiple sub
 | |
| # function in firmware to circumvent the problem.
 | |
| #
 | |
| ###################################################################
 | |
| sub multiple_open_dev {
 | |
|     my $rconsole = shift;
 | |
|     if (($rconsole) && ($rconsole =~ /xCAT::/))
 | |
|     {
 | |
|         $rconsole = shift;
 | |
|     }
 | |
|     my $node = shift;
 | |
|     my $verbose = shift;
 | |
|     my $expect_out;
 | |
|     my $command;
 | |
|     my $timeout;
 | |
|     my $rc = 0;
 | |
| 
 | |
|     send_command($verbose, $rconsole, "dev /packages/net \r");
 | |
|     send_command($verbose, $rconsole, "FALSE value OPEN-DEV_DEBUG \r");
 | |
| 
 | |
|     if (exists $ENV{'OPEN_DEV_DEBUG'}) {
 | |
|        send_command($verbose, $rconsole, "TRUE to OPEN-DEV_DEBUG \r");
 | |
|     }
 | |
| 
 | |
|     $command = ": new-open-dev ( str len -- true|false ) \
 | |
|                   open-dev_debug if cr .\" NEW-OPEN-DEV: Entering, Device : \" 2dup type cr then \
 | |
|                   { _str _len ; _n } \
 | |
|                   0 -> _n \
 | |
|                   get-msecs dup d# 60000 + ( start timeout ) \
 | |
|                   begin \
 | |
|                      ( start timeout ) get-msecs over > if \
 | |
|                         open-dev_debug if \
 | |
|                            ( start timeout ) drop get-msecs swap - \
 | |
|                            cr .\" FAILED TO OPEN DEVICE\" \
 | |
|                            cr .\" NUMBER OF TRIES \" _n .d \
 | |
|                            cr .\" TIME ELAPSED \" ( time ) .d .\"  MSECONDS\" cr \
 | |
|                         else \
 | |
|                            ( start timout ) 2drop \
 | |
|                         then \
 | |
|                         false exit \
 | |
|                      else \
 | |
|                         true \
 | |
|                      then \
 | |
|                      while \
 | |
|                         ( start timeout ) \
 | |
|                         _n 1 + -> _n \
 | |
|                         _str _len open-dev ( ihandle|false ) ?dup if \
 | |
|                         -rot ( ihandle start timeout ) \
 | |
|                         open-dev_debug if \
 | |
|                            ( start timeout ) drop get-msecs swap - \
 | |
|                            cr .\" SUCCESSFULLY OPENED DEVICE\" \
 | |
|                            cr .\" NUMBER OF TRIES \" _n .d \
 | |
|                            cr .\" TIME ELAPSED \" ( time ) .d .\" MSECONDS\" cr \
 | |
|                         else \
 | |
|                            ( start timeout ) 2drop \
 | |
|                         then \
 | |
|                         ( ihandle ) exit \
 | |
|                  then \
 | |
|                  ( start timeout ) \
 | |
|                  repeat \
 | |
|                  ; \r";
 | |
|     send_command($verbose, $rconsole, $command);
 | |
| 
 | |
|     $timeout = 30;
 | |
|     $rconsole->expect(
 | |
|         $timeout,
 | |
|         [qr/new-open-dev(.*)ok/=>
 | |
|         #[qr/>/=>
 | |
|             sub {
 | |
|                 nc_msg($verbose, "Status: at End of multiple_open_dev \n");
 | |
|                 $rconsole->clear_accum();
 | |
|              }
 | |
|         ],
 | |
|         [qr/]/=>
 | |
|             sub {
 | |
|                 nc_msg($verbose, "Unexpected prompt\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|              }
 | |
|         ],
 | |
|         [timeout =>
 | |
|             sub {
 | |
|                 send_user(2, "Timeout\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|             }
 | |
|         ],
 | |
|         [eof =>
 | |
|             sub {
 | |
|                 send_user(2, "Cannot connect to $node\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|             }
 | |
|         ],
 | |
|     );
 | |
| 
 | |
|     $command = "patch new-open-dev open-dev net-ping \r";
 | |
|     send_command($verbose, $rconsole, $command);
 | |
| 
 | |
|     $rconsole->expect(
 | |
|         $timeout,
 | |
|         [qr/patch new-open-dev(.*)ok/=>
 | |
|         #[qr/>/=>
 | |
|             sub {
 | |
|                 nc_msg($verbose, "Status: at End of multiple_open_dev \n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 return 0;
 | |
|              }
 | |
|         ],
 | |
|         [qr/]/=>
 | |
|             sub {
 | |
|                 nc_msg($verbose, "Unexpected prompt\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|              }
 | |
|         ],
 | |
|         [timeout =>
 | |
|             sub {
 | |
|                 send_user(2, "Timeout\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|             }
 | |
|         ],
 | |
|         [eof =>
 | |
|             sub {
 | |
|                 send_user(2, "Cannot connect to $node\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|             }
 | |
|         ],
 | |
|     );
 | |
| 
 | |
|     return $rc;
 | |
| }
 | |
| ###################################################################
 | |
| #
 | |
| # PROCEDURE
 | |
| #
 | |
| # Declare procedure to get additional firmware debug statement.
 | |
| #
 | |
| ###################################################################
 | |
| sub  Firmware_Dump {
 | |
|     my $rconsole = shift;
 | |
|     my $node = shift;
 | |
|     my $verbose = shift;
 | |
|     my $device_path = shift;
 | |
|     my $phandle = shift;
 | |
|     my $expect_out;
 | |
|     my @done;
 | |
|     my @cmd;
 | |
|     my @msg;
 | |
|     my @pattern;
 | |
|     my @newstate;
 | |
|     my $timeout;
 | |
|     my $state = 0;
 | |
|     my $rc = 0;
 | |
| 
 | |
|     nc_msg($verbose,"Status: Firmware_Dump start\n");
 | |
| 
 | |
|     # state 0
 | |
|     $done[0] = 0;
 | |
|     $cmd[0] = "dev /packages/obp-tftp\r";
 | |
|     $msg[0] = "Status: selected /packages/obp_tftp\n";
 | |
|     $pattern[0] = "(.*)ok(.*)(\[0-9]) >(.*)";
 | |
|     $newstate[0] = 1;
 | |
| 
 | |
|     # state 1
 | |
|     $done[1] = 0;
 | |
|     $cmd[1] = ": testing1 .\" OBP-TFTP entry\" cr init-nvram-adptr-parms ;\r";
 | |
|     $msg[1] = "Status: running test - OBP-TFTP entry\n";
 | |
|     $pattern[1] = "(.*)ok(.*)(\[0-9]) >(.*)";
 | |
|     $newstate[1] = 2;
 | |
| 
 | |
|     # state 2
 | |
|     $done[2] = 0;
 | |
|     $cmd[2] = ": testing2 .\" OBP-TFTP exit, TRUE\" cr true ;\r";
 | |
|     $msg[2] = "Status: running test - OBP-TFTP exit\n";
 | |
|     $pattern[2] = "(.*)ok(.*)(\[0-9]) >(.*)";
 | |
|     $newstate[2] = 3;
 | |
| 
 | |
|     # state 3
 | |
|     $done[3] = 0;
 | |
|     $cmd[3] = "patch testing1 init-nvram-adptr-parms open\r";
 | |
|     $msg[3] = "Status: running test - patch testing1\n";
 | |
|     $pattern[3] = "(.*)ok(.*)(\[0-9]) >(.*)";
 | |
|     $newstate[3] = 4;
 | |
| 
 | |
|     # state 4
 | |
|     $done[4] = 0;
 | |
|     $cmd[4] = "patch testing2 true open\r";
 | |
|     $msg[4] = "Status: running test - patch testing2\n";
 | |
|     $pattern[4] = "(.*)ok(.*)(\[0-9]) >(.*)";
 | |
|     $newstate[4] = 5;
 | |
| 
 | |
|     # state 5
 | |
|     $done[5] = 0;
 | |
|     $cmd[5] = "dev $device_path\r";
 | |
|     $msg[5] = "Status: running test - dev $device_path\n";
 | |
|     $pattern[5] = "(.*)ok(.*)(\[0-9]) >(.*)";
 | |
|     $newstate[5] = 6;
 | |
| 
 | |
|     # state 6
 | |
|     $done[6] = 0;
 | |
|     $cmd[6] = "true to debug-init\r";
 | |
|     $msg[6] = "Status: running test - true to debug-init\n";
 | |
|     $pattern[6] = "(.*)ok(.*)(\[0-9]) >(.*)";
 | |
|     $newstate[6] = 7;
 | |
| 
 | |
|     # state 7
 | |
|     $done[7] = 0;
 | |
|     $cmd[7] = "true to debug-error\r";
 | |
|     $msg[7] = "Status: running test - true to debug-error\n";
 | |
|     $pattern[7] = "(.*)ok(.*)(\[0-9]) >(.*)";
 | |
|     $newstate[7] = 8;
 | |
| 
 | |
|     # state 8
 | |
|     $done[8] = 0;
 | |
|     $cmd[8] = "$phandle to active-package\r";
 | |
|     $msg[8] = "Status: running $phandle to active-package\n";
 | |
|     $pattern[8] = "(.*)ok(.*)(\[0-9]) >(.*)";
 | |
|     $newstate[8] = 9;
 | |
| 
 | |
|     # state 9
 | |
|     $done[9] = 0;
 | |
|     $cmd[9] = ".properties\r";
 | |
|     $msg[9] = "Status: running .properies\n";
 | |
|     $pattern[9] = "(.*)ok(.*)(\[0-9]) >(.*)";
 | |
|     $newstate[9] = 10;
 | |
| 
 | |
|     # state 10
 | |
|     $done[10] = 0;
 | |
|     $cmd[10] = "clear\r";
 | |
|     $msg[10] = "Status: running clear\n";
 | |
|     $pattern[10] = "(.*)ok(.*)(\[0-9]) >(.*)";
 | |
|     $newstate[10] = 11;
 | |
| 
 | |
|     # state 11, all done
 | |
|     $done[11] = 1;
 | |
| 
 | |
|     $state = 0;
 | |
|     $timeout = 30;       # shouldn't take long
 | |
|     while ($done[$state] == 0) {
 | |
|         send_command($verbose, $rconsole, $cmd[$state]);
 | |
|         $rconsole->expect(
 | |
|             [qr/$pattern[$state]/ =>
 | |
|             sub {
 | |
|                 nc_msg($verbose, $msg[$state]);
 | |
|                 $rconsole->clear_accum();
 | |
|                 $state = $newstate[$state];
 | |
|                 }
 | |
|             ],
 | |
|             [qr/]/=>
 | |
|             sub {
 | |
|                 nc_msg($verbose, "Unexpected prompt\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|             [qr/(.*)DEFAULT(.*)/=>
 | |
|             sub {
 | |
|                 nc_msg($verbose, "Default catch error\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|             [timeout=>
 | |
|                 sub {
 | |
|                 nc_msg($verbose, "Timeout\n");
 | |
|                 nc_msg($verbose, "Status: timeout state is $state\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|             [eof =>
 | |
|                 sub {
 | |
|                 nc_msg($verbose, "Cannot connect to $node\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|         );
 | |
|         return 1 if ($rc eq 1);
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
| 
 | |
| =head3    lparnetbootexp
 | |
| 
 | |
|     Function:
 | |
|       Same function as the lpar_netboot.exp
 | |
| 
 | |
|     Return:
 | |
|         0  - good
 | |
|         1  - abort
 | |
|         2  - usage error
 | |
| 
 | |
| =cut
 | |
| #-----------------------------------------------------------------------------
 | |
| sub lparnetbootexp
 | |
| {
 | |
|     my $opt = shift;
 | |
|     if (($opt) && ($opt =~ /xCAT::/))
 | |
|     {
 | |
|         $opt = shift;
 | |
|     }
 | |
|     my $CONSOLEBIN = "/opt/xcat/bin/rcons";
 | |
|     my $PROGRAM = "lpar_netboot";
 | |
|     my $noboot = 0;   #default is to boot
 | |
|     my $Boot_timeout = 3000;
 | |
|     my @expect_out;
 | |
|     my $req = shift;
 | |
|     my $cmd;
 | |
|     my $timeout;
 | |
|     my $output;
 | |
|     my $done;
 | |
|     my $retry_count;
 | |
|     my $query_count;
 | |
|     my $match_pat;
 | |
|     my $loc_code;
 | |
|     my $ping_rc;
 | |
|     my $ping_result;
 | |
|     my $chosen_adap_type;
 | |
|     my $i;
 | |
|     my $phandle;
 | |
|     my $match;
 | |
|     my $list_type;
 | |
|     my $sysoutput;
 | |
|     my $exp_internal;
 | |
| # Flags and initial variable
 | |
|     my $discovery = 0;
 | |
|     my $discover_all = 0;
 | |
|     my $verbose = 0;
 | |
|     my $discover_macaddr = 0;
 | |
|     my $rc = 0;
 | |
|     my $debug_flag = 0;
 | |
|     my $rmvterm_flag = 0;
 | |
|     my $immed_flag = 0;
 | |
|     my $from_of = 0;
 | |
|     my $dev_type_found = 0;
 | |
|     my $list_physical = 0;
 | |
|     my $set_boot_order = 0;
 | |
|     my $colon = 0;
 | |
|     my $choice = 0;
 | |
|     my $full_path_name;
 | |
|     my $adap_speed;
 | |
|     my $adap_duplex;
 | |
|     my $client_ip;
 | |
|     my $server_ip;
 | |
|     my $gateway_ip;
 | |
|     my $extra_args;
 | |
|     my $macaddress;
 | |
|     my $netmask;
 | |
|     my $dump_target;
 | |
|     my $dump_lun;
 | |
|     my $dump_port;
 | |
|     my $phys_loc;
 | |
|     my $userid;
 | |
|     my $passwd;
 | |
|     my $prompt = "\\\$ \$";
 | |
|     my $ssh_spawn_id = 0;
 | |
|     my $mac_address;
 | |
|     my @outputarray;
 | |
|     my $outputarrayindex = 0;
 | |
| 
 | |
|     $::CALLBACK = $req->{callback};
 | |
| #
 | |
| # Log the process id
 | |
| #
 | |
|     my $proc_id = getppid;
 | |
|     nc_msg($verbose, "$PROGRAM Status: process id is $proc_id\n");
 | |
| 
 | |
| #
 | |
| #
 | |
| # Process command line options and parameters
 | |
| #
 | |
| #
 | |
| #done==
 | |
| 
 | |
|     if ( exists ($opt->{A})) {
 | |
|         $discover_all = 1;
 | |
|     }
 | |
| 
 | |
|     if ( exists ($opt->{C})) {
 | |
|         $client_ip = $opt->{C};
 | |
|     }
 | |
| 
 | |
|     if ( exists ($opt->{D})) {
 | |
|         $discovery = 1;
 | |
|     }
 | |
| 
 | |
|     if ( exists ($opt->{G})) {
 | |
|         $gateway_ip = $opt->{G};
 | |
|     }
 | |
| 
 | |
|     if ( exists ($opt->{P})) {
 | |
|         $list_physical = 1;
 | |
|     }
 | |
| 
 | |
|     if ( exists ($opt->{M})) {
 | |
|         $discover_macaddr = 1;
 | |
|     }
 | |
| 
 | |
|     if ( exists ($opt->{N})) {
 | |
|         $netmask = $opt->{N};
 | |
|     }
 | |
| 
 | |
|     if ( exists ($opt->{S})) {
 | |
|         $server_ip = $opt->{S};
 | |
|     }
 | |
| 
 | |
|     if ( exists ($opt->{c})) {
 | |
|         $colon = 1;
 | |
|     }
 | |
| 
 | |
|     if ( exists ($opt->{d})) {
 | |
|         $adap_duplex = $opt->{d};
 | |
|     }
 | |
| 
 | |
|     if ( exists ($opt->{f})) {
 | |
|         $rmvterm_flag = 1;
 | |
|     }
 | |
| 
 | |
|     if ( exists ($opt->{g})) {
 | |
|         $extra_args = $opt->{g};
 | |
|     }
 | |
| 
 | |
|     if ( exists ($opt->{i})) {
 | |
|         $immed_flag = 1;
 | |
|     }
 | |
| 
 | |
|     if ( exists ($opt->{o})) {
 | |
|         $from_of = 1;
 | |
|     }
 | |
| 
 | |
|     if ( exists ($opt->{w})) {
 | |
|         $set_boot_order = $opt->{w};
 | |
|     }
 | |
|      if ( exists ($opt->{L})) {
 | |
|         $dump_lun = $opt->{L};
 | |
|     }
 | |
| 
 | |
|     if ( exists ($opt->{l})) {
 | |
|         $phys_loc = $opt->{l};
 | |
|     }
 | |
| 
 | |
|     if ( exists ($opt->{m})) {
 | |
|         $macaddress = $opt->{m};
 | |
|     }
 | |
| 
 | |
|     if ( exists ($opt->{n})) {
 | |
|         $noboot = 1;
 | |
|     }
 | |
| 
 | |
|     if ( exists ($opt->{p})) {
 | |
|         $dump_port = $opt->{p};
 | |
|     }
 | |
| 
 | |
|     if ( exists ($opt->{s})) {
 | |
|         $adap_speed = $opt->{s};
 | |
|     }
 | |
| 
 | |
|     if ( exists ($opt->{T})) {
 | |
|         $dump_target = $opt->{T};
 | |
|     }
 | |
| 
 | |
|     if ( exists ($opt->{t})) {
 | |
|         $list_type = $opt->{t};
 | |
|         if ( $list_type eq "hfi-ent" ) {
 | |
|             $dev_pat[0] = "hfi-ethernet";
 | |
|             $dev_type[0] = "hfi-ent";
 | |
|         }
 | |
|         #
 | |
|         # Validate the argument
 | |
|         #
 | |
|         $dev_type_found = 0;
 | |
|         foreach my $dev (@dev_type) {
 | |
|             if ( $dev eq $list_type) {
 | |
|                 $dev_type_found = 1;
 | |
|                 last;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if ( $dev_type_found eq 0 ) {
 | |
|            nc_msg($verbose, "$PROGRAM:$dev_type_found, '$list_type' is not a valid adapter choice\n");
 | |
|            return [1];
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if ( exists ($opt->{v})) {
 | |
|         $verbose = 1;
 | |
|     } else {
 | |
|         $verbose = 0;
 | |
|     }
 | |
|     if ( exists ($opt->{x})) {
 | |
|         $debug_flag = 1;
 | |
|     }
 | |
|     if ( exists ($opt->{help})) {
 | |
|         usage;
 | |
|     }
 | |
|     #set arg0 [lindex $argv 0]
 | |
|     #set arg1 [lindex $argv 1]
 | |
|     #if ( scalar(%$opt) > 10 ) {
 | |
|     #    nc_msg($verbose, "$PROGRAM: Extraneous parameter(s)\n");
 | |
|     #    usage;
 | |
|     #}
 | |
| 
 | |
|     if ( $list_physical eq 0 ) {
 | |
|         $dev_pat[3] = "l-lan";
 | |
|         $dev_type[3] = "ent";
 | |
|         $dev_count = scalar(@dev_pat);
 | |
|     } else {
 | |
|         $dev_pat[3] = "";
 | |
|         $dev_type[3] = "";
 | |
|         $dev_count = scalar(@dev_pat);
 | |
|     }
 | |
| 
 | |
|     if ( $set_boot_order > 1 ) {
 | |
|         $dev_pat[4] = "scsi";
 | |
|         $dev_type[4] = "disk";
 | |
|         $dev_count = scalar(@dev_pat);
 | |
|     }
 | |
|     my $node = $opt->{node};
 | |
|     my $profile = $opt->{pprofile};
 | |
|     my $manage = $opt->{fsp};
 | |
|     my $lparid = $opt->{id};
 | |
|     my $hcp = $opt->{hcp};
 | |
| 
 | |
| 
 | |
| 
 | |
|     if ($dev_type_found)    { nc_msg($verbose, "$PROGRAM Status: List only $list_type adapters\n");               }
 | |
|     if ($noboot)            { nc_msg($verbose, "$PROGRAM Status: -n (no boot) flag detected\n");                  }
 | |
|     if ($discovery)         { nc_msg($verbose, "$PROGRAM Status: -D (discovery) flag detected\n");                }
 | |
|     if ($discover_all)      { nc_msg($verbose, "$PROGRAM Status: -A (discover all) flag detected\n" );            }
 | |
|     if ($verbose)           { nc_msg($verbose, "$PROGRAM Status: -v (verbose debug) flag detected\n");            }
 | |
|     if ($discover_macaddr)  { nc_msg($verbose, "$PROGRAM Status: -M (discover mac address) flag detected\n");     }
 | |
|     if ($immed_flag)        { nc_msg($verbose, "$PROGRAM Status: -i (force immediate shutdown) flag detected\n"); }
 | |
|     if ($list_physical)     { nc_msg($verbose, "$PROGRAM Status: -P (list only phsical network) flag detected\n");}
 | |
|     if ($colon)             { nc_msg($verbose, "$PROGRAM Status: -c (list colon separated ) flag detected\n" );   }
 | |
|     if ($debug_flag)        {
 | |
|         nc_msg($verbose, "$PROGRAM Status: -d (debug) flag detected\n");
 | |
|         #$exp_internal = 1;
 | |
|         #$log_user = 1;
 | |
|     }
 | |
|     if ($discovery and $adap_speed )  { nc_msg($verbose, "$PROGRAM Status: using adapter speed of $adap_speed\n" );       }
 | |
|     if ($discovery and $adap_duplex ) { nc_msg($verbose, "$PROGRAM Status: using adapter duplex of $adap_duplex\n" );     }
 | |
|     if ($discovery and $server_ip )   { nc_msg($verbose, "$PROGRAM Status: using server IP address of $server_ip\n");     }
 | |
|     if ($discovery and $client_ip)    { nc_msg($verbose, "$PROGRAM Status: using client IP address of $client_ip\n" );    }
 | |
|     if ($discovery and $gateway_ip)   { nc_msg($verbose, "$PROGRAM Status: using gateway IP address of $gateway_ip\n");   }
 | |
|     if ($discovery and $macaddress)   { nc_msg($verbose, "$PROGRAM Status: using macaddress of $macaddress\n"  );         }
 | |
|     if ($discovery and $phys_loc )    { nc_msg($verbose, "$PROGRAM Status: using physical location code of $phys_loc\n"); }
 | |
|     nc_msg($verbose, "node:".$node);
 | |
|     ####################################
 | |
|     # process the arguments
 | |
|     ####################################
 | |
|     $rc = xCAT::LparNetbootExp->ck_args($opt, $node, $verbose);
 | |
|     if ($rc != 0) {
 | |
|         nc_msg($verbose, "ck_args failed. \n");
 | |
|         return [1];
 | |
|     }
 | |
| 
 | |
|     ####################################
 | |
|     # decide if need to do the connect
 | |
|     ####################################
 | |
| 
 | |
| 
 | |
|     ####################################
 | |
|     # open the console
 | |
|     ####################################
 | |
|     nc_msg($verbose, "open port\n");
 | |
|     $cmd = $::XCATROOT . '/bin/rcons ' . $node . ' -f';
 | |
|     my $rconsole = Expect->new;
 | |
|     ##################################################
 | |
|     # raw_pty() disables command echoing and CRLF
 | |
|     # translation and gives a more pipe-like behaviour.
 | |
|     # Note that this must be set before spawning
 | |
|     # the process. Unfortunately, this does not work
 | |
|     # with AIX (IVM). stty(qw(-echo)) will at least
 | |
|     # disable command echoing on all platforms but
 | |
|     # will not suppress CRLF translation.
 | |
|     ##################################################
 | |
|     #$rconsole->raw_pty(1);
 | |
|     #$rconsole->slave->stty(qw(sane -echo));        #hidden information return from rcons
 | |
| 
 | |
|     ##################################################
 | |
|     # exp_internal(1) sets exp_internal debugging
 | |
|     # to STDERR.
 | |
|     ##################################################
 | |
|     #$rconsole->exp_internal( $verbose );          #hidden information return from rcons
 | |
| 
 | |
|     ##################################################
 | |
|     # log_stdout(0) disables logging to STDOUT.
 | |
|     # This corresponds to the Tcl log_user variable.
 | |
|     ##################################################
 | |
|     #$rconsole->log_stdout( $verbose );           #hidden information return from rcons
 | |
|     $rconsole->log_stdout(0);           #hidden information return from rcons
 | |
| 
 | |
|     my $consolefork = $rconsole->spawn($cmd);
 | |
|     #$rconsole->log_file("/tmp/consolelog");
 | |
|     my $console_pid = $rconsole->pid;
 | |
|     unless ($console_pid) {
 | |
|         nc_msg($verbose, "Unable to open console.\n");
 | |
|         return [1];
 | |
|     }
 | |
|     nc_msg($verbose, "spawn_id is $console_pid.\n");
 | |
|     ####################################
 | |
|     #kill the process after received the signal
 | |
|     ####################################
 | |
| 
 | |
|     ####################################
 | |
|     # check the result of rcons
 | |
|     ####################################
 | |
|     nc_msg($verbose, "Connecting to the $node.\n");
 | |
|     sleep 3;
 | |
|     $timeout = 10;
 | |
|     $rconsole->expect(
 | |
|         $timeout,
 | |
|         [ qr/Enter.* for help.*/i =>
 | |
|             sub {
 | |
|                 $rc = 0;
 | |
|                 $rconsole->clear_accum();
 | |
|                 nc_msg($verbose, "Connected.\n");
 | |
|             }
 | |
|         ],
 | |
|         [ timeout =>
 | |
|             sub {
 | |
|                 $rc = 1;
 | |
|                 $rconsole->clear_accum();
 | |
|                 nc_msg($verbose, "Timeout waiting for console connection.\n");
 | |
|             }
 | |
|         ],
 | |
|         [ eof =>
 | |
|             sub {
 | |
|                 $rc = 2;
 | |
|                 $rconsole->clear_accum();
 | |
|                 nc_msg(1, "Please make sure rcons $node works.\n");
 | |
|             }
 | |
|         ],
 | |
|     );
 | |
| 
 | |
|     unless ($rc eq 0) {
 | |
|         return [1];
 | |
|     }
 | |
|     ####################################
 | |
|     # check the node state
 | |
|     ####################################
 | |
|     nc_msg($verbose, "Checking for power off.\n");
 | |
|     my $subreq = $req->{subreq};
 | |
|     $output = xCAT::LparNetbootExp->run_lssyscfg($subreq, $verbose, $node);
 | |
|     if ($output =~ /Not Available/) {
 | |
|         nc_msg($verbose, "LPAR is Not Available. Please make sure the CEC's state.\n");
 | |
|         return [1];
 | |
|     } else {
 | |
|         nc_msg($verbose, "The lpar state is $output.\n");
 | |
|     }
 | |
| 
 | |
|     if ($from_of) {
 | |
|         unless($output =~ /open firmware/i){
 | |
|             nc_msg(2, "You are using the -o option. Please make sure the LPAR's initial state is open firmware.\n");
 | |
|             return [1];
 | |
|         }
 | |
| 
 | |
|     }
 | |
| 
 | |
|     ####################################
 | |
|     # if -o is not used, power node of
 | |
|     ####################################
 | |
|     unless ($from_of) {
 | |
|         if (($output =~ /^off$/i) or ($output =~ /Not Activated/i) ) {
 | |
|             nc_msg($verbose, "# Power off complete.\n");
 | |
|         } else {
 | |
|             nc_msg($verbose, "# Begin to Power off the node.\n");
 | |
|             $sysoutput = xCAT::Utils->runxcmd(
 | |
|                 {
 | |
|                     command => ['rpower'],
 | |
|                     node    => [$node],
 | |
|                     arg     => ['off']
 | |
|                 },
 | |
|             $subreq, 0, 1);
 | |
|             $output = join ',', @$sysoutput;
 | |
|             if ($::RUNCMD_RC != 0) {    #$::RUNCMD_RC  will get its value from runxcmd_output
 | |
|                 nc_msg($verbose, "Unable to run rpower $node off.\n");
 | |
|                 return [1];
 | |
|             }
 | |
| 
 | |
|             unless ($output =~ /Success/) {
 | |
|                 nc_msg($verbose, "Power off failed.\n");
 | |
|                 return [1];
 | |
|             } else {
 | |
|                 nc_msg($verbose, "Wait for power off.\n");
 | |
|             }
 | |
| 
 | |
|             $done = 0;
 | |
|             $query_count = 0;
 | |
|             while (!$done) {
 | |
|                 $output = xCAT::LparNetbootExp->run_lssyscfg($subreq, $verbose, $node);
 | |
|                 if (($output =~ /^off$/i) or ($output =~ /Not Activated/)) {
 | |
|                     nc_msg($verbose, "Power off complete.\n");
 | |
|                     $done = 1;
 | |
|                     next;
 | |
|                 }
 | |
|                 $query_count++;
 | |
|                 if ($query_count > 300) {
 | |
|                     nc_msg($verbose, "Power off failed.\n");
 | |
|                     return [1];
 | |
|                 }
 | |
|                 sleep 1;
 | |
|             }
 | |
|         }
 | |
| 
 | |
| 
 | |
| 
 | |
|         #################################################
 | |
|         # if set_boot_order is set, set the boot order
 | |
|         # if not set, power the node to open firmware
 | |
|         #################################################
 | |
|         $done = 0;
 | |
|         $retry_count = 0;
 | |
|         if ($set_boot_order > 1) {
 | |
|             nc_msg($verbose, "Power on $node to SMS.\n");
 | |
|             while (!$done) {
 | |
|                 $sysoutput = xCAT::Utils->runxcmd(
 | |
|                     {
 | |
|                         command => ['rpower'],
 | |
|                         node    => [$node],
 | |
|                         arg     => ['sms']
 | |
|                     },
 | |
|                 $subreq, 0, 1);
 | |
|                 $output = join ',', @$sysoutput;
 | |
|                 nc_msg($verbose, "Waiting for power on...\n");
 | |
| 
 | |
|                 if ($::RUNCMD_RC != 0) {
 | |
|                     nc_msg($verbose, "Unable to run rpower $node sms\n");
 | |
|                     return [1];
 | |
|                 }
 | |
|                 unless ($output =~ /Success/) {
 | |
|                     if ($retry_count eq 3) {
 | |
|                         nc_msg($verbose, "Power off failed, msg is $output.\n");
 | |
|                         return [1];
 | |
|                     }
 | |
|                     sleep 1;
 | |
|                     $retry_count ++;
 | |
|                 } else {
 | |
|                     $done = 1;
 | |
|                 }
 | |
|             }
 | |
|         } else {
 | |
|             nc_msg($verbose, "Power on the $node to the Open Firmware.\n");
 | |
|             while (!$done) {
 | |
|                 $sysoutput = xCAT::Utils->runxcmd(
 | |
|                     {
 | |
|                         command => ['rpower'],
 | |
|                         node    => [$node],
 | |
|                         arg     => ['of']
 | |
|                     },
 | |
|                 $subreq, 0, 1);
 | |
|                 $output = join ',', @$sysoutput;
 | |
|                 nc_msg($verbose, "Waiting for power on...\n");
 | |
| 
 | |
|                 if ($::RUNCMD_RC != 0) {
 | |
|                     nc_msg($verbose, "Unable to run rpower $node open firmware.\n");
 | |
|                     return [1];
 | |
|                 }
 | |
|                 unless ($output =~ /Success/) {
 | |
|                     if ($retry_count eq 3) {
 | |
|                         nc_msg($verbose, "Power off failed, msg is $output.\n");
 | |
|                         return [1];
 | |
|                     }
 | |
|                     sleep 1;
 | |
|                     $retry_count ++;
 | |
|                 } else {
 | |
|                     $done = 1;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
| 
 | |
|         ###########################
 | |
|         # Check the node state
 | |
|         ###########################
 | |
|         $done = 0;
 | |
|         $query_count = 0;
 | |
|         $timeout = 1;
 | |
|         nc_msg($verbose, "Check the node state again;");
 | |
|         while(!$done) {
 | |
|             $output = xCAT::LparNetbootExp->run_lssyscfg($subreq, $verbose, $node);
 | |
|             nc_msg($verbose, "The node state is $output.\n");
 | |
|             if ($output =~ /Open Firmware/i) {
 | |
|                 nc_msg($verbose, "Power on complete.\n");
 | |
|                 $done = 1;
 | |
|                 next;
 | |
|             }
 | |
| 
 | |
|             $query_count++;
 | |
|             # if the node is not in openfirmware state, just wait for it
 | |
|             my @result = $rconsole->expect(
 | |
|                 $timeout,
 | |
|                 [ qr/(.*)elect this consol(.*)/=>
 | |
|                 sub {
 | |
|                     $rconsole->send("0\r");
 | |
|                     $rconsole->clear_accum();
 | |
|                     #$rconsole->exp_continue();
 | |
|                     }
 | |
|                 ],
 | |
|             );
 | |
| 
 | |
|             if ($query_count > 300 ) {
 | |
|                 nc_msg($verbose, "Timed out waiting for power on of $node");
 | |
|                 nc_msg($verbose, "error from rpower command : \"$output\" \n");
 | |
|                 return [1];
 | |
|             }
 | |
|             sleep 1;
 | |
|         }
 | |
|     }
 | |
| 
 | |
| 
 | |
|     ##############################
 | |
|     # Check for active console
 | |
|     ##############################
 | |
|     nc_msg($verbose, "Check for active console.\n");
 | |
|     $done = 0;
 | |
|     $retry_count = 0;
 | |
| 
 | |
|     $timeout = 10;
 | |
| 
 | |
|     while (!$done) {
 | |
|         my @result = $rconsole->expect(
 | |
|             $timeout,
 | |
|             #[qr/ok(.*)0 >/=>
 | |
|             [qr/0(.*)ok/=>
 | |
|             sub {
 | |
|                 nc_msg($verbose, " at ok prompt\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $done = 1;
 | |
|                 }
 | |
|             ],
 | |
|             [qr/(.*)elect this consol(.*)/=>
 | |
|             sub {
 | |
|                 nc_msg($verbose, " selecting active console\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rconsole->send("0\r");
 | |
|                 }
 | |
|             ],
 | |
|             [qr/English|French|German|Italian|Spanish|Portuguese|Chinese|Japanese|Korean/=>
 | |
|             sub {
 | |
|                 nc_msg($verbose, "Languagae Selection Panel received\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $rconsole->send("2\r");
 | |
|                 }
 | |
|             ],
 | |
|             [qr/admin/=>
 | |
|             sub {
 | |
|                 nc_msg($verbose, "No password specified\n");
 | |
|                 $rconsole->soft_close();
 | |
|                 $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|             [qr/Invalid Password/=>
 | |
|             sub {
 | |
|                 nc_msg($verbose, "FSP password is invalid.\n");
 | |
|                 $rconsole->soft_close();
 | |
|                 $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|             [qr/SMS(.*)Navigation Keys/=>
 | |
|             sub {
 | |
|                 nc_msg($verbose, "SMS\n");
 | |
|                 $rconsole->clear_accum();
 | |
|                 $done = 1;
 | |
|                 }
 | |
|             ],
 | |
|             [timeout=>
 | |
|             sub {
 | |
|                 $rconsole->send("\r");
 | |
|                 $retry_count++;
 | |
|                 if ($retry_count eq 9) {
 | |
|                     nc_msg($verbose, "Timeout waiting for ok prompt; exiting.\n");
 | |
|                     $rconsole->soft_close();
 | |
|                     $rc = 1;
 | |
|                     }
 | |
|                 }
 | |
|             ],
 | |
|             [eof =>
 | |
|             sub {
 | |
|                 nc_msg($verbose, "Cannot connect to $node");
 | |
|                 $rconsole->soft_close();
 | |
|                 $rc = 1;
 | |
|                 }
 | |
|             ],
 | |
|         );
 | |
|         return [1] if ($rc eq 1);
 | |
|     }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
|     ##############################
 | |
|     # Set the node boot order
 | |
|     ##############################
 | |
|     if ($set_boot_order) {            #rnetboot node will not go here
 | |
|         nc_msg($verbose, "begin to set disk boot");
 | |
|         my $result = set_disk_boot( $rconsole, $node, $verbose);#@expect_out, $rconsole, $node, $verbose);
 | |
|         unless( $result ) {
 | |
|             nc_msg($verbose, "Unable to set $node boot order");
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     sleep 1;
 | |
| 
 | |
|     ##############################
 | |
|     # Call get_phandle to gather
 | |
|     # information for all the
 | |
|     # supported network adapters
 | |
|     # in the device tree.
 | |
|     ##############################
 | |
|     $done = 0;
 | |
|     $retry_count = 0;
 | |
|     nc_msg($verbose, "begin to run get_phandle");
 | |
|     while (!$done) {
 | |
|         my $result = get_phandle($rconsole, $node, $verbose);
 | |
|         if ( $result eq 1) {
 | |
|             $retry_count++;
 | |
|             $rconsole->send("\r");
 | |
|             if ( $retry_count eq 3) {
 | |
|                 nc_msg($verbose, "Unable to obtain network adapter information.  Quitting.\n");
 | |
|                 return [1];
 | |
|             }
 | |
|         } else {
 | |
|             $done = 1;
 | |
|         }
 | |
|     }
 | |
| 
 | |
| 
 | |
|     ##############################
 | |
|     # Call multiple_open_dev to
 | |
|     # circumvent firmware OPEN-DEV
 | |
|     # failure
 | |
|     ##############################
 | |
|     nc_msg($verbose, "begin to run multiple_open_dev");
 | |
|     my $result = xCAT::LparNetbootExp->multiple_open_dev($rconsole, $node, $verbose);
 | |
|     if ( $result eq 1) {
 | |
|        nc_msg($verbose, "Unable to obtain network adapter information.  Quitting.\n");
 | |
|        return [1];
 | |
|     }
 | |
| 
 | |
|     ##############################
 | |
|     #
 | |
|     ##############################
 | |
|     nc_msg($verbose, "begin to process opt-discovery");
 | |
|     if ($discovery) {              #rnetboot node will not go here
 | |
|         nc_msg($verbose, "# Client IP address is $client_ip\n");
 | |
|         nc_msg($verbose, "# Server IP address is $server_ip\n");
 | |
|         nc_msg($verbose, "# Gateway IP address is $gateway_ip\n");
 | |
|     }
 | |
| 
 | |
| 
 | |
|     ##############################
 | |
|     # Display information for all
 | |
|     # supported adapters
 | |
|     ##############################
 | |
|     if ($noboot) {  #if not do net boot
 | |
|         if ($list_type) {
 | |
|             $match_pat = $list_type;
 | |
|         } else {
 | |
|             $match_pat = ".*";
 | |
|         }
 | |
| 
 | |
| 
 | |
|         if($colon) {
 | |
|             nc_msg($verbose, "#Type:Location_Code:MAC_Address:Full_Path_Name:Ping_Result:Device_Type:Size_MB:OS:OS_Version:\n");
 | |
|             $outputarrayindex++;  # start from 1, 0 is used to set as 0
 | |
|             $outputarray[$outputarrayindex] = "#Type:Location_Code:MAC_Address:Full_Path_Name:Ping_Result:Device_Type:Size_MB:OS:OS_Version:";
 | |
|         } else {
 | |
|             nc_msg($verbose, "# Type \tLocation Code \tMAC Address\t Full Path Name\t Ping Result\n");
 | |
|             $outputarrayindex++;
 | |
|             $outputarray[$outputarrayindex] = "# Type \tLocation Code \tMAC Address\t Full Path Name\t Ping Result";
 | |
|         }
 | |
| 
 | |
|         if ( $discover_all ) {    #getmacs here
 | |
|             for( $i = 0; $i < $adapter_found; $i++) {
 | |
|                 if ($adap_type[$i] =~ /$match_pat/) {
 | |
|                     if (!($adap_type[$i] eq "hfi-ent")) {
 | |
|                         $mac_address = get_mac_addr($phandle_array[$i], $rconsole, $node, $verbose);
 | |
|                         $loc_code = get_adaptr_loc($phandle_array[$i], $rconsole, $node, $verbose);
 | |
|                     }
 | |
|                     $ping_result = "";
 | |
|                     if ($discovery) {
 | |
|                         $ping_rc = ping_server($phandle_array[$i], $full_path_name_array[$i], $rconsole, $node, $mac_address, $verbose, $adap_speed, $adap_duplex, $list_type, $server_ip, $client_ip, $gateway_ip);
 | |
|                         nc_msg($verbose, "ping_server returns $ping_rc\n");
 | |
|                         unless( $ping_rc eq 0) {
 | |
|                             $ping_result = "unsuccessful";
 | |
|                         } else {
 | |
|                             $ping_result = "successful";
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
|                     if ( $adap_type[$i] eq "hfi-ent") {
 | |
|                         $mac_address = get_mac_addr($phandle_array[$i], $rconsole, $node, $verbose);
 | |
|                         $loc_code = get_adaptr_loc($phandle_array[$i], $rconsole, $node, $verbose);
 | |
|                     }
 | |
| 
 | |
|                     if ($full_path_name_array[$i] =~ /vdevice/)  {
 | |
|                         $device_type = "virtual";
 | |
|                     } else {
 | |
|                         $device_type = "physical";
 | |
|                     }
 | |
| 
 | |
|                     if (defined($mac_address)) {
 | |
|                         my @newmacs = ();
 | |
|                         my @allmacs = split /\|/,$mac_address;
 | |
|                         if ( !xCAT::Utils->isAIX() ) {
 | |
|                             foreach my $mac_a ( @allmacs ) {
 | |
|                                 $mac_a = lc($mac_a);
 | |
|                                 $mac_a =~ s/(\w{2})/$1:/g;
 | |
|                                 $mac_a =~ s/:$//;
 | |
|                                 push @newmacs, $mac_a;
 | |
|                             }
 | |
|                             $mac_address = join("|",@newmacs);
 | |
|                         } 
 | |
|                     }
 | |
| 
 | |
| 
 | |
|                     if($colon) {
 | |
|                         nc_msg($verbose, "$adap_type[$i]\:$loc_code\:$mac_address\:$full_path_name_array[$i]\:$ping_result\:$device_type\:\:\:\:\n");
 | |
|                         $outputarrayindex++;
 | |
|                         $outputarray[$outputarrayindex] = "$adap_type[$i]\:$loc_code\:$mac_address\:$full_path_name_array[$i]\:$ping_result\:$device_type\:\:\:\:";
 | |
|                     } else {
 | |
|                         nc_msg($verbose, "$adap_type[$i] $loc_code $mac_address $full_path_name_array[$i] $ping_result $device_type\n");
 | |
|                         $outputarrayindex++;
 | |
|                         $outputarray[$outputarrayindex] = "$adap_type[$i] $loc_code $mac_address $full_path_name_array[$i] $ping_result $device_type";
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         } else {
 | |
|             for( $i = 0; $i < $adapter_found; $i++) {
 | |
|                 if ($adap_type[$i] =~ /$match_pat/) {
 | |
|                     if (!($adap_type[$i] eq "hfi-ent")) {
 | |
|                         $mac_address = get_mac_addr($phandle_array[$i], $rconsole, $node, $verbose);
 | |
|                         $loc_code = get_adaptr_loc($phandle_array[$i], $rconsole, $node, $verbose);
 | |
|                     }
 | |
|                     $ping_result = "";
 | |
|                     if ($discovery) {
 | |
|                         $ping_rc = ping_server($phandle_array[$i], $full_path_name_array[$i], $rconsole, $node, $mac_address, $verbose, $adap_speed, $adap_duplex, $list_type, $server_ip, $client_ip, $gateway_ip);
 | |
|                         nc_msg($verbose, "ping_server returns $ping_rc\n");
 | |
|                         unless( $ping_rc eq 0) {
 | |
|                             $ping_result = "unsuccessful";
 | |
|                         } else {
 | |
|                             $ping_result = "successful";
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
|                     if ( $adap_type[$i] eq "hfi-ent") {
 | |
|                         $mac_address = get_mac_addr($phandle_array[$i], $rconsole, $node, $verbose);
 | |
|                         $loc_code = get_adaptr_loc($phandle_array[$i], $rconsole, $node, $verbose);
 | |
|                     }
 | |
| 
 | |
|                     if ($full_path_name_array[$i] =~ /vdevice/)  {
 | |
|                         $device_type = "virtual";
 | |
|                     } else {
 | |
|                         $device_type = "physical";
 | |
|                     }
 | |
| 
 | |
|                     if($colon) {
 | |
|                         nc_msg($verbose, "$adap_type[$i]\:$loc_code\:$mac_address\:$full_path_name_array[$i]\:$ping_result\:$device_type\:\:\:\:\n");
 | |
|                     } else {
 | |
|                         nc_msg($verbose, "$adap_type[$i] $loc_code $mac_address $full_path_name_array[$i] $ping_result $device_type\n");
 | |
|                     }
 | |
|                     last;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         if ($from_of != 1) {
 | |
|             nc_msg($verbose, "power off the node after noboot eq 1\n");
 | |
|             $sysoutput = xCAT::Utils->runxcmd(
 | |
|                 {
 | |
|                     command => ['rpower'],
 | |
|                     node    => [$node],
 | |
|                     arg     => ['off']
 | |
|                 },
 | |
|             $subreq, 0, 1);
 | |
|             $output = join ',', @$sysoutput;
 | |
|             if ($::RUNCMD_RC != 0) {
 | |
|                 nc_msg($verbose, "Unable to run rpower $node sms.\n");
 | |
|                 nc_msg($verbose, "Status: error from rpower command\n");
 | |
|                 nc_msg($verbose, "Error : $output\n");
 | |
|                 return [1];
 | |
|             }
 | |
|         }
 | |
|     } else { # Do a network boot
 | |
|     # Loop throught the adapters and perform a ping test to discover an
 | |
|     # adapter that pings successfully, then use that adapter to network boot.
 | |
|         if ($discover_all) {  #rnetboot should not use -A
 | |
|             for ($i = 0; $i < $adapter_found; $i++) {
 | |
|                 $ping_rc = ping_server($phandle_array[$i], $full_path_name_array[$i], $rconsole, $node, $mac_address, $verbose, $adap_speed, $adap_duplex, $list_type, $server_ip, $client_ip, $gateway_ip);
 | |
| 
 | |
| 
 | |
|                 if ( $ping_rc eq 0) {
 | |
|                     $phandle = $phandle_array[$i];
 | |
|                     $full_path_name = $full_path_name_array[$i];
 | |
|                     $chosen_adap_type = $adap_type[$i];
 | |
|                     last;
 | |
|                 }
 | |
|             }
 | |
|         } elsif ( $macaddress ne "" ) {          #rnetboot here     
 | |
|             $match = 0;
 | |
|             for ($i = 0; $i < $adapter_found; $i++) {
 | |
|                 if ($adap_type[$i] =~ /hfi-ent/) {
 | |
|                     $ping_rc = ping_server($phandle_array[$i], $full_path_name_array[$i], $rconsole, $node, $mac_address, $verbose, $adap_speed, $adap_duplex, $list_type, $server_ip, $client_ip, $gateway_ip);
 | |
|                 }
 | |
|                 $mac_address = get_mac_addr($phandle_array[$i], $rconsole, $node, $verbose);
 | |
|                 if ( $macaddress =~ /$mac_address/ ) {
 | |
|                     if ($discovery eq 1) {
 | |
|                         unless ( $adap_type[$i] eq "hfi-ent" ) {
 | |
|                            $ping_rc = ping_server($phandle_array[$i], $full_path_name_array[$i], $rconsole, $node, $mac_address, $verbose, $adap_speed, $adap_duplex, $list_type, $server_ip, $client_ip, $gateway_ip);
 | |
|                         }
 | |
|                         unless ( $ping_rc eq 0) {
 | |
|                             nc_msg($verbose, "Unable to boot network adapter.\n" );
 | |
|                             return [1];
 | |
|                         }
 | |
|                     }
 | |
|                 $phandle =  $phandle_array[$i];
 | |
|                 $full_path_name = $full_path_name_array[$i];
 | |
|                 $chosen_adap_type = $adap_type[$i];
 | |
|                 $match = 1;
 | |
|                 last;
 | |
|                 }
 | |
|             }
 | |
|             unless($match) {
 | |
|                 nc_msg($verbose, "Can not find mac address '$macaddress'\n");
 | |
|                 return [1];
 | |
|             }
 | |
|         } elsif ( $phys_loc ne "") {
 | |
|             $match = 0;
 | |
|             for ($i = 0; $i < $adapter_found; $i++) {
 | |
|                 $loc_code = get_adaptr_loc($phandle_array[$i], $rconsole, $node, $verbose);
 | |
|                 if ($loc_code =~ /$phys_loc/) {
 | |
|                     if ($discovery) {
 | |
|                         $ping_rc = ping_server($phandle_array[$i], $full_path_name_array[$i], $rconsole, $node, $mac_address, $verbose, $adap_speed, $adap_duplex, $list_type, $server_ip, $client_ip, $gateway_ip);
 | |
|                         unless ($ping_rc eq 0) {
 | |
|                             nc_msg($verbose, "Unable to boot network adapter.\n");
 | |
|                             return [1];
 | |
|                         }
 | |
|                     }
 | |
|                     $phandle =  $phandle_array[$i];
 | |
|                     $full_path_name = $full_path_name_array[$i];
 | |
|                     $chosen_adap_type = $adap_type[$i];
 | |
|                     $match = 1;
 | |
|                     last;
 | |
|                 }
 | |
|             }
 | |
|             if (!$match) {
 | |
|                 nc_msg($verbose, "Can not find physical location '$phys_loc'\n");
 | |
|                 return [1];
 | |
|             }
 | |
|         } else {
 | |
|         #
 | |
|         # Use the first ethernet adapter in the
 | |
|         # device tree.
 | |
|         #
 | |
|             for ($i = 0; $i < $adapter_found; $i++) {
 | |
|             nc_msg($verbose, " begint to boot from first adapter in the device tree \n");
 | |
|                 if ($adap_type[$i] eq $list_type ) {
 | |
|                     if ( $discovery eq 1 ){
 | |
|                         $ping_rc = ping_server($phandle_array[$i], $full_path_name_array[$i], $rconsole, $node, $mac_address, $verbose, $adap_speed, $adap_duplex, $list_type, $server_ip, $client_ip, $gateway_ip);
 | |
|                         unless ($ping_rc eq 0) {
 | |
|                             return [1];
 | |
|                         }
 | |
|                     }
 | |
|                     $phandle = $phandle_array[$i];
 | |
|                     $full_path_name = $full_path_name_array[$i];
 | |
|                     $chosen_adap_type = $adap_type[$i];
 | |
|                     last;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         my $result;
 | |
|         if ($full_path_name eq "") {
 | |
|             nc_msg($verbose, "Unable to boot network adapter.\n");
 | |
|             return [1];
 | |
|         } else {
 | |
|             nc_msg($verbose, "# Network booting install adapter.\n");
 | |
|             $result = xCAT::LparNetbootExp->boot_network($rconsole, $full_path_name, $adap_speed, $adap_duplex , $chosen_adap_type, $server_ip, $client_ip, $gateway_ip, $netmask, $dump_target, $dump_lun, $dump_port, $verbose, $extra_args, $node, $set_boot_order );
 | |
|         }
 | |
| 
 | |
| 
 | |
|         if ($result eq 0) {
 | |
|             nc_msg($verbose, "bootp sent over netowrk.\n");
 | |
|             my $res = Boot($rconsole, $node, $verbose);#, @expect_out);
 | |
|             unless ($res eq 0) {
 | |
|                 nc_msg($verbose, "Can not boot, result = $res. \n");
 | |
|             }
 | |
|         } else {
 | |
|             nc_msg($verbose, "return code $result from boot_network\n");
 | |
|         }
 | |
| 
 | |
|         ###########################################################################
 | |
|         # Need to retry network boot because of intermittant network failure
 | |
|         # after partition reboot.  Force partition to stop at Open Firmware prompt.
 | |
|         ###########################################################################
 | |
|         if ($result eq 5) {
 | |
| 
 | |
|             $timeout = 300;
 | |
|             $rconsole->expect(
 | |
|                 $timeout,
 | |
|                 [ qr/keyboard/i,
 | |
|                     sub {
 | |
|                         $rconsole->send("8\r");
 | |
|                         $rconsole->clear_accum();
 | |
|                         sleep 10;
 | |
|                     }
 | |
|                 ],
 | |
|                 [ qr/timeout/i,
 | |
|                     sub {
 | |
|                         nc_msg($verbose, "Timeout; exiting.\n");
 | |
|                         $rconsole->clear_accum();
 | |
|                         $rc = 1;
 | |
|                     }
 | |
|                 ],
 | |
|                 [ eof =>
 | |
|                     sub {
 | |
|                         nc_msg($verbose, "cannot connect to $node.\n");
 | |
|                         $rconsole->clear_accum();
 | |
|                         $rc = 1;
 | |
|                     }
 | |
|                 ],
 | |
|                 [
 | |
|                     sub {
 | |
|                         nc_msg($verbose, "# Network booting install adapter.\n");
 | |
|                         nc_msg($verbose, "Retrying network-boot from RESTART-CMD error.\n");
 | |
|                         $done = 0;
 | |
|                         while (! $done ) {
 | |
|                             my $res = xCAT::LparNetbootExp->boot_network($node,);
 | |
|                             if ($res eq 0) {
 | |
|                                 $done = 1;
 | |
|                             } else {
 | |
|                                 sleep 10;
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 ],
 | |
|             );
 | |
|             return [1] if ($rc eq 1);
 | |
|             nc_msg($verbose, "# bootp sent over network.\n");
 | |
|             $rc = Boot($rconsole, $node, $verbose);#, @expect_out);
 | |
|             unless ($rc eq 0) {
 | |
|                 nc_msg($verbose, "Can't boot here. \n");
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     ################################################
 | |
|     # mission accomplished, beam me up scotty.
 | |
|     #################################################
 | |
|     unless ($noboot) {  #if do the rnetboot, just return
 | |
|         if ( $rc eq 0) {
 | |
|             nc_msg($verbose, "# Finished.\n" );
 | |
|             $outputarrayindex++;
 | |
|             $outputarray[$outputarrayindex] = "Finished.";
 | |
|         } else {
 | |
|             nc_msg($verbose, "# Finished in an error.\n");
 | |
|             $outputarrayindex++;
 | |
|             $outputarray[$outputarrayindex] = "Finished in an error.";
 | |
|         }
 | |
|     } else {   #if not rnetboot, for example, getmacs, power off the node
 | |
|         $done = 0;
 | |
|         $query_count = 0;
 | |
|         while(!$done) {
 | |
|             $output = xCAT::LparNetbootExp->run_lssyscfg($subreq, $verbose, $node);
 | |
| 
 | |
|             ##############################################
 | |
|             # separate the nodename from the query status
 | |
|             ##############################################
 | |
|             if ($from_of != 1) {
 | |
|                 if (( $output =~ /^off$/i ) or ($output =~ /Not Activated/i)) {
 | |
|                     $done = 1;
 | |
|                 }
 | |
|             } else {
 | |
|                 if ( $output =~ /firmware/i ) {
 | |
|                     $done = 1;
 | |
|                 }
 | |
|             }
 | |
|             $query_count++;
 | |
|             if ( $query_count > 60 ){
 | |
|                 $done = 1;
 | |
|             }
 | |
|             sleep 1;
 | |
|         }
 | |
|     }
 | |
|     $cmd = "~.";
 | |
|     send_command($verbose, $rconsole, $cmd);
 | |
| 
 | |
|     $outputarray[0] = 0;
 | |
|     return \@outputarray;
 | |
| 
 | |
| }
 | |
| 
 |